<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IO/SizeExceededAction.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IO
{
    /// <summary>
    /// Specifies action what is done if requested action exceeds maximum allowed size.
    /// </summary>
    public enum SizeExceededAction
    {
        /// <summary>
        /// Throws exception at once when maximum size exceeded.
        /// </summary>
        ThrowException = 1,

        /// <summary>
        /// Junks all data what exceeds maximum allowed size and after requested operation completes,
        /// throws exception.
        /// </summary>
        JunkAndThrowException = 2,
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Entities/Deal.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Runtime.Serialization;

using ASC.Common.Security;

#endregion

namespace ASC.CRM.Core.Entities
{
    [DataContract]
    public class Deal : DomainObject, ISecurityObjectId
    {
        public Guid CreateBy { get; set; }

        public DateTime CreateOn { get; set; }

        public Guid? LastModifedBy { get; set; }

        public DateTime? LastModifedOn { get; set; }

        [DataMember(Name = "contact_id")]
        public int ContactID { get; set; }

        [DataMember(Name = "contact")]
        public Contact Contact { get; set; }

        [DataMember(Name = "title")]
        public string Title { get; set; }

        [DataMember(Name = "description")]
        public string Description { get; set; }

        [DataMember(Name = "responsible_id")]
        public Guid ResponsibleID { get; set; }

        [DataMember(Name = "bid_type")]
        public BidType BidType { get; set; }

        [DataMember(Name = "bid_value")]
        public decimal BidValue { get; set; }

        [DataMember(Name = "bid_currency")]
        public string BidCurrency { get; set; }

        [DataMember(Name = "per_period_value")]
        public int PerPeriodValue { get; set; }

        [DataMember(Name = "deal_milestone")]
        public int DealMilestoneID { get; set; }

        [DataMember(Name = "deal_milestone_probability")]
        public int DealMilestoneProbability { get; set; }

        public DateTime ActualCloseDate { get; set; }

        [DataMember(Name = "actual_close_date")]
        private String ActualCloseDateStr
        {
            get
            {
                return ActualCloseDate.Date == DateTime.MinValue.Date
                           ? string.Empty : ActualCloseDate.ToString(DateTimeExtension.DateFormatPattern);
            }
            set {; }
        }


        public DateTime ExpectedCloseDate { get; set; }

        [DataMember(Name = "expected_close_date")]
        private String ExpectedCloseDateStr
        {
            get
            {
                return ExpectedCloseDate.Date == DateTime.MinValue.Date
                           ? string.Empty : ExpectedCloseDate.ToString(DateTimeExtension.DateFormatPattern);
            }
            set {; }
        }

        public object SecurityId
        {
            get { return ID; }
        }

        public Type ObjectType
        {
            get { return GetType(); }
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Notify/Push/PushNotification.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

namespace ASC.Core.Common.Notify.Push
{
    [DataContract]
    public class PushNotification
    {
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public string Message { get; set; }

        [DataMember]
        public string ShortMessage { get; set; }

        [DataMember]
        public int? Badge { get; set; }

        [DataMember]
        public PushModule Module { get; set; }

        [DataMember]
        public PushAction Action { get; set; }

        [DataMember]
        public PushItem Item { get; set; }

        [DataMember]
        public PushItem ParentItem { get; set; }

        [DataMember]
        public DateTime QueuedOn { get; set; }

        public static PushNotification ApiNotification(string message, int? badge)
        {
            return new PushNotification { Message = message, Badge = badge };
        }
    }

    [DataContract]
    public class PushItem
    {
        [DataMember]
        public PushItemType Type { get; set; }

        [DataMember]
        public string ID { get; set; }

        [DataMember]
        public string Description { get; set; }

        public PushItem()
        {

        }

        public PushItem(PushItemType type, string id, string description)
        {
            Type = type;
            ID = id;
            Description = description;
        }
    }
}


<|start_filename|>module/ASC.Socket.IO/app/hubs/chat.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = (io, countersHub) => {
    const apiRequestManager = require('../apiRequestManager.js');
    const co = require('co');
    const baseTalkApiUrl = 'portal/talk/';
    const chat = io.of("/chat");
    const onlineUsers = [];

    chat.on('connection', (socket) => {
        const request = socket.client.request;
        if(!request.user || !request.user.id) return;
        const user = request.user;
        const portal = request.portal;
        const userId = user.id;
        const userName = user.userName.toLowerCase();
        const tenantId = portal.tenantId;
        const tenantDomain = portal.tenantDomain;

        socket
            .on('disconnect', onDisconnectUser)
            .on('connectUser', onConnectUser)
            .on('disconnectUser', onDisconnectUser)
            .on('send', onSend)
            .on('getStates', onGetStates)
            .on('getContactInfo', onGetContactInfo)
            .on('getInitData', onGetInitData)
            .on('sendTyping', onSendTyping)
            .on('sendStateToTenant', onSendStateToTenant)
            .on('getRecentMessages', onGetRecentMessages)
            .on('chatPing', onPing);

        function onDisconnectUser(change, fn) {
            co(function *() {
                let state;

                if (!onlineUsers[tenantId]) return;
                if (!onlineUsers[tenantId][userId] || !socket.onConnectUser) {
                    if(typeof fn == "function") fn();
                    return;
                }

                if (change === true || onlineUsers[tenantId][userId].counter === 1) {
                    delete onlineUsers[tenantId][userId];
                    state = yield apiRequestManager.dlt(`${baseTalkApiUrl}connection?connectionId=${userId}`, request);
                    socket.emit("disconnectUser");
                } else {
                    onlineUsers[tenantId][userId].counter--;
                    state = yield apiRequestManager.get(`${baseTalkApiUrl}state`, request, { userName });
                    if (state !== 4) {
                        // setStatus
                        socket.broadcast.to(`${tenantId}-${userName}`).emit('setStatus', state);
                    }
                }

                socket.broadcast.to(tenantId).emit('setState', userName, state);
            })
            .catch((err)=>{
                if(typeof fn == "function") fn(err);
            });
        }

        function onConnectUser(state) {
            socket.join([tenantId, `${tenantId}-${userName}`]);
            socket.onConnectUser = true;

            if (!onlineUsers[tenantId]) {
                onlineUsers[tenantId] = {};
            }

            var counter = onlineUsers[tenantId][userId];
            if (!counter) {
                counter = onlineUsers[tenantId][userId] = { counter: 1 };
            } else {
                counter.counter++;
            }

            co(function* () {
                if (counter.counter === 1) {
                    state = yield apiRequestManager.post(`${baseTalkApiUrl}connection`, request, { connectionId: userId, state });
                } else {
                    state = yield apiRequestManager.post(`${baseTalkApiUrl}state`, request, { state });

                    if (state !== 4) {
                        socket.broadcast.to(`${tenantId}-${userName}`).emit('setStatus', state);
                    }
                }
                socket.broadcast.to(tenantId).emit('setState', userName, state, false);
                chat.to(`${tenantId}-${userName}`).emit("connectUser");
            })
            .catch((err)=>{
                chat.to(`${tenantId}-${userName}`).emit("connectUser", err);
            });
        }

        function onSend(calleeUserName, messageText) {
            co(function* () {
                const message = { u: userName, t: messageText };

                if (calleeUserName) {
                    chat.to(`${tenantId}-${calleeUserName}`).emit('send', message, calleeUserName);
                    socket.broadcast.to(`${tenantId}-${userName}`).emit('send', message, calleeUserName);
                }
                yield apiRequestManager.post(`${baseTalkApiUrl}message`, request, { to: calleeUserName, text: messageText });
            });
        }

        function onGetStates(fn) {
            apiRequestManager.get(`${baseTalkApiUrl}states`, request)
                .then((result) => {
                    socket.emit('statesRetrieved', result);
                })
                .catch((err) => {
                    if (typeof fn === "function") fn(err);
                });;
        }

        function onGetContactInfo(calleeUserName, fn) {
            co(function* () {
                const calleeUser = yield apiRequestManager.get('people/' + calleeUserName, request);
                if (!calleeUser || calleeUser.id === "4A515A15-D4D6-4b8e-828E-E0586F18F3A3") throw "Can't get UserInfo";

                const calleeUserState = yield apiRequestManager.get(`${baseTalkApiUrl}state`, request, { userName: calleeUserName });
                if(typeof fn === "function") fn(calleeUserName, calleeUserState);
            })
            .catch((err) => {
                    if (err && typeof fn === "function") fn(null, null, err);
                });
        }

        function onGetInitData(fn) {
            co(function* () {
                const states = yield apiRequestManager.get(`${baseTalkApiUrl}states`, request);
                const users = yield apiRequestManager.get('people', request);
                const result = users
                    .filter((item) => item.id !== userId)
                    .sort((item1, item2) => {
                        if (item1.displayName < item2.displayName) return -1;
                        if (item1.displayName > item2.displayName) return 1;
                        return 0;
                    })
                    .map((item) => {
                    const uName = item.userName.toLowerCase();
                    return { u: uName, d: item.displayName, s: states[uName] || 4}
                });

                socket.emit('initDataRetrieved', userName, user.displayName, result, tenantId, tenantDomain);
            })
            .catch((err) => {
                if (typeof fn === "function") fn(err);
            });
        }

        function onSendTyping(calleeUserName) {
            chat.to(`${tenantId}-${calleeUserName}`).emit('sendTypingSignal', userName);
        }

        function onSendStateToTenant(state) {
            apiRequestManager.post(`${baseTalkApiUrl}state`, request, { state })
                .then((result) => {
                    socket.broadcast.to(tenantId).emit('setState', userName, result, false);
                });
        }

        function onGetRecentMessages(calleeUserName, id, fn) {
            apiRequestManager.get(`${baseTalkApiUrl}recentMessages`, request, { calleeUserName, id })
                .then((recentMessages) => {
                    if (typeof fn === "function") fn(recentMessages);
                })
                .catch((err) => {
                    if (typeof fn === "function") fn(null, err);
                });
        }

        function onPing(state) {
            apiRequestManager.post(`${baseTalkApiUrl}ping`, request, { state: state });
        }
    });

    function tenantPlusUserRoom(tenantId, userName) {
        return chat.to(`${tenantId}-${userName}`);
    }

    function send({ tenantId, callerUserName, calleeUserName, message, isTenantUser } = {}) {
        if (typeof tenantId === "undefined" || !calleeUserName || !message) {
            return;
        }

        tenantPlusUserRoom(tenantId, calleeUserName).emit('send', message, calleeUserName, isTenantUser);

        if (!isTenantUser) {
            tenantPlusUserRoom(tenantId, callerUserName).emit('send', message, calleeUserName, isTenantUser);
        }
    }

    function sendInvite({ tenantId, calleeUserName, message } = {}) {
        if (typeof tenantId === "undefined" || !calleeUserName || !message) {
            return;
        }

        tenantPlusUserRoom(tenantId, calleeUserName).emit('sendInvite', message);
    }

    function setState({ tenantId, from, state } = {}) {
        if (typeof tenantId === "undefined" || !from) {
            return;
        }

        chat.to(`${tenantId}`).emit('setState', from, state);
    }

    function sendOfflineMessages({ tenantId, callerUserName, users } = {}) {
        if (typeof tenantId === "undefined" || !callerUserName || !users) {
            return;
        }

        tenantPlusUserRoom(tenantId, callerUserName).emit('sendOfflineMessages', users);
    }

    return { send, sendInvite, setState, sendOfflineMessages };
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Code/PageNameUtil.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Text.RegularExpressions;
using System.Web;

namespace ASC.Web.UserControls.Wiki
{
    public class PageNameUtil
    {
        public static string ReplaceSpaces(string str)
        {
            return str.Replace(" ", "_");
        }

        public static string Clean(string str)
        {
            return str.Replace("_", " ");
        }

        public static string Encode(string str)
        {
            string result = str.Replace(" ", "_");
            return HttpUtility.UrlEncode(result);
        }

        public static string Decode(string str)
        {
            string result = str; //HttpUtility.UrlDecode(str);//BUG: removed due + problem
            Regex nameReg = new Regex(@"_", RegexOptions.CultureInvariant | RegexOptions.Singleline);
            result = nameReg.Replace(result, " ");
            return result;
        }

        public static string NormalizeNameCase(string str)
        {
            if (string.IsNullOrEmpty(str))
                return string.Empty;

            return str;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Mail/MailApi.Contacts.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Api.Attributes;
using ASC.Mail;
using ASC.Mail.Core.Dao.Expressions.Contact;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Enums;
using ASC.Mail.Extensions;

// ReSharper disable InconsistentNaming

namespace ASC.Api.Mail
{
    public partial class MailApi
    {
        /// <summary>
        ///    Returns the list of the contacts for auto complete feature.
        /// </summary>
        /// <param name="term">string part of contact name, lastname or email.</param>
        /// <returns>Strings list.  Strings format: "Name Lastname" email</returns>
        /// <short>Get contact list for auto complete</short> 
        /// <category>Contacts</category>
        /// <exception cref="ArgumentException">Exception happens when in parameters is invalid. Text description contains parameter name and text description.</exception>
        [Read(@"emails/search")]
        public IEnumerable<string> SearchEmails(string term)
        {
            if (string.IsNullOrEmpty(term))
                throw new ArgumentException(@"term parameter empty.", "term");

            var scheme = HttpContext.Current == null
                ? Uri.UriSchemeHttp
                : HttpContext.Current.Request.GetUrlRewriter().Scheme;

            return MailEngineFactory.ContactEngine.SearchEmails(TenantId, Username, term, MailAutocompleteMaxCountPerSystem,
                scheme, MailAutocompleteTimeout);
        }

        /// <summary>
        ///    Returns lists of mail contacts.
        /// </summary>
        /// <param optional="true" name="search">Text to search in contacts name or emails.</param>
        /// <param optional="true" name="contactType">Type of contacts</param>
        /// <param optional="true" name="pageSize">Count of contacts on page</param>
        /// <param optional="true" name="fromIndex">Page number</param> 
        /// <param name="sortorder">Sort order by name. String parameter: "ascending" - ascended, "descending" - descended.</param> 
        /// <returns>List of filtered contacts</returns>
        /// <short>Gets filtered contacts</short> 
        /// <category>Contacts</category>
        [Read(@"contacts")]
        public IEnumerable<MailContactData> GetContacts(string search, int? contactType, int? pageSize, int fromIndex,
            string sortorder)
        {
            var exp = string.IsNullOrEmpty(search) && !contactType.HasValue
                ? new SimpleFilterContactsExp(TenantId, Username, sortorder == Defines.ASCENDING, fromIndex, pageSize)
                : new FullFilterContactsExp(TenantId, Username, search, contactType,
                    orderAsc: sortorder == Defines.ASCENDING,
                    startIndex: fromIndex, limit: pageSize);

            var contacts = MailEngineFactory.ContactEngine.GetContactCards(exp);

            int totalCount;

            if (contacts.Any() && contacts.Count() < pageSize)
            {
                totalCount = fromIndex + contacts.Count;
            }
            else
            {
                totalCount = MailEngineFactory.ContactEngine.GetContactCardsCount(exp);
            }

            _context.SetTotalCount(totalCount);

            return contacts.ToMailContactDataList();
        }

        /// <summary>
        ///   Returns lists of mail contacts with contact information
        /// </summary>
        /// <param optional="false" name="infoType">infoType</param>
        /// <param optional="false" name="data">data</param>
        /// <param optional="true" name="isPrimary">isPrimary</param>
        /// <returns>List of filtered contacts</returns>
        /// <short>Gets filtered contacts</short> 
        /// <category>Contacts</category>
        [Read(@"contacts/bycontactinfo")]
        public IEnumerable<MailContactData> GetContactsByContactInfo(ContactInfoType infoType, String data, bool? isPrimary)
        {
            var exp = new FullFilterContactsExp(TenantId, Username, data, infoType: infoType, isPrimary: isPrimary);

            var contacts = MailEngineFactory.ContactEngine.GetContactCards(exp);

            return contacts.ToMailContactDataList();
        }

        /// <summary>
        ///    Create mail contact
        /// </summary>
        /// <param name="name">Contact's name</param>
        /// <param name="description">Description of contact</param>
        /// <param name="emails">List of emails</param>
        /// <param name="phoneNumbers">List of phone numbers</param>
        /// <returns>Information about created contact </returns>
        /// <short>Create mail contact</short>
        /// <category>Contacts</category>
        [Create(@"contact/add")]
        public MailContactData CreateContact(string name, string description, List<string> emails, List<string> phoneNumbers)
        {
            if (!emails.Any())
                throw new ArgumentException(@"Invalid list of emails.", "emails");

            var contactCard = new ContactCard(0, TenantId, Username, name, description, ContactType.Personal, emails,
                phoneNumbers);

            var newContact = MailEngineFactory.ContactEngine.SaveContactCard(contactCard);

            return newContact.ToMailContactData();
        }

        /// <summary>
        ///    Removes selected mail contacts
        /// </summary>
        /// <param name="ids">List of mail contact ids</param>
        /// <returns>List of removed mail contact ids </returns>
        /// <short>Remove mail contact </short> 
        /// <category>Contacts</category>
        [Update(@"contacts/remove")]
        public IEnumerable<int> RemoveContacts(List<int> ids)
        {
            if (!ids.Any())
                throw new ArgumentException(@"Empty ids collection", "ids");

            MailEngineFactory.ContactEngine.RemoveContacts(ids);

            return ids;
        }

        /// <summary>
        ///    Updates the existing mail contact
        /// </summary>
        /// <param name="id">id of mail contact</param>
        /// <param name="name">Contact's name</param>
        /// <param name="description">Description of contact</param>
        /// <param name="emails">List of emails</param>
        /// <param name="phoneNumbers">List of phone numbers</param>
        /// <returns>Information about updated contact </returns>
        /// <short>Update mail contact</short>
        /// <category>Contacts</category>
        [Update(@"contact/update")]
        public MailContactData UpdateContact(int id, string name, string description, List<string> emails, List<string> phoneNumbers)
        {
            if (id < 0)
                throw new ArgumentException(@"Invalid contact id.", "id");

            if (!emails.Any())
                throw new ArgumentException(@"Invalid list of emails.", "emails");

            var contactCard = new ContactCard(id, TenantId, Username, name, description, ContactType.Personal, emails, phoneNumbers);

            var contact = MailEngineFactory.ContactEngine.UpdateContactCard(contactCard);

            return contact.ToMailContactData();
        }

        /// <summary>
        ///    Returns list of crm entities linked with chain. Entity: contact, case or opportunity.
        /// </summary>
        /// <param name="message_id">Id of message included in the chain. It may be id any of messages included in the chain.</param>
        /// <returns>List of structures: {entity_id, entity_type, avatar_link, title}</returns>
        /// <short>Get crm linked entities</short> 
        /// <category>Contacts</category>
        ///<exception cref="ArgumentException">Exception happens when in parameters is invalid. Text description contains parameter name and text description.</exception>
        [Read(@"crm/linked/entities")]
        public IEnumerable<CrmContactData> GetLinkedCrmEntitiesInfo(int message_id)
        {
            if (message_id < 0)
                throw new ArgumentException(@"meesage_id must be positive integer", "message_id");

            return MailEngineFactory.CrmLinkEngine.GetLinkedCrmEntitiesId(message_id);
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Calendar/BusinessObjects/DataProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

using ASC.Api.Calendar.ExternalCalendars;
using ASC.Api.Calendar.iCalParser;
using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Web.Core.Calendars;

namespace ASC.Api.Calendar.BusinessObjects
{
    public class DataProvider : IDisposable
    {
        private readonly IDbManager db;
        private const string DBId = "calendar";
        private const string _calendarTable = "calendar_calendars cal";
        private const string _calendarItemTable = "calendar_calendar_item cal_itm";
        private const string _calendarUserTable = "calendar_calendar_user cal_usr";
        private const string _eventTable = "calendar_events evt";
        private const string _todoTable = "calendar_todos td";
        private const string _eventItemTable = "calendar_event_item evt_itm";

        public DataProvider()
        {
            db = DbManager.FromHttpContext(DBId);
        }

        public List<UserViewSettings> GetUserViewSettings(Guid userId, List<string> calendarIds)
        {
            var cc = new ColumnCollection();

            var extCalId = cc.RegistryColumn("ext_calendar_id");
            var usrId = cc.RegistryColumn("user_id");
            var hideEvents = cc.RegistryColumn("hide_events");
            var isAccepted = cc.RegistryColumn("is_accepted");
            var textColor = cc.RegistryColumn("text_color");
            var background = cc.RegistryColumn("background_color");
            var alertType = cc.RegistryColumn("alert_type");
            var calId = cc.RegistryColumn("convert(calendar_id using utf8)");
            var calName = cc.RegistryColumn("name");
            var timeZone = cc.RegistryColumn("time_zone");

            var query = new SqlQuery("calendar_calendar_user")
                .Select(cc.SelectQuery)
                .Where((Exp.In(extCalId.Name, calendarIds) |
                        Exp.In(calId.Name, calendarIds)) &
                       Exp.Eq(usrId.Name, userId));

            var data = db.ExecuteList(query);

            var options = new List<UserViewSettings>();
            foreach (var r in data)
            {
                options.Add(new UserViewSettings()
                {
                    CalendarId =
                            Convert.ToInt32(r[calId.Ind]) == 0
                                ? Convert.ToString(r[extCalId.Ind])
                                : Convert.ToString(r[calId.Ind]),
                    UserId = usrId.Parse<Guid>(r),
                    IsHideEvents = hideEvents.Parse<bool>(r),
                    IsAccepted = isAccepted.Parse<bool>(r),
                    TextColor = textColor.Parse<string>(r),
                    BackgroundColor = background.Parse<string>(r),
                    EventAlertType = (EventAlertType)alertType.Parse<int>(r),
                    Name = calName.Parse<string>(r),
                    TimeZone = timeZone.Parse<TimeZoneInfo>(r)
                });
            }

            return options;
        }

        public List<Calendar> LoadTodoCalendarsForUser(Guid userId)
        {
            var groups = CoreContext.UserManager.GetUserGroups(userId).Select(g => g.ID).ToList();
            groups.AddRange(
                CoreContext.UserManager.GetUserGroups(userId, Core.Users.Constants.SysGroupCategoryId).Select(g => g.ID));
            var currentTenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId;
            var queryGetCalIds = new SqlQuery(_calendarTable)
                           .Select("cal.id")
                           .Where("cal.owner_id", userId)
                           .Where("cal.is_todo", 1)
                           .Where("cal.tenant", currentTenantId);

            var calIds = db.ExecuteList(queryGetCalIds).Select(r => r[0]);

            var cals = GetCalendarsByIds(calIds.ToArray());

            return cals;
        }
        public void RemoveTodo(int todoId)
        {
            using (var tr = db.BeginTransaction())
            {
                var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;

                db.ExecuteNonQuery(new SqlDelete("calendar_todos").Where("id", todoId).Where("tenant", tenant));

                tr.Commit();
            }
        }
        public List<Calendar> LoadCalendarsForUser(Guid userId, out int newCalendarsCount)
        {
            var groups = CoreContext.UserManager.GetUserGroups(userId).Select(g => g.ID).ToList();
            groups.AddRange(
                CoreContext.UserManager.GetUserGroups(userId, Core.Users.Constants.SysGroupCategoryId).Select(g => g.ID));

            var currentTenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId;
            var queryGetCalIds = new SqlQuery(_calendarItemTable)
                .Select("cal_itm.calendar_id")
                .InnerJoin(_calendarTable, Exp.EqColumns("cal.id", "cal_itm.calendar_id"))
                .Where("cal.tenant", currentTenantId)
                .Where(Exp.Eq("cal_itm.item_id", userId) |
                       (Exp.In("cal_itm.item_id", groups.ToArray()) & Exp.Eq("cal_itm.is_group", true)))
                .Union(new SqlQuery(_calendarTable)
                           .Select("cal.id")
                           .Where("cal.owner_id", userId)
                           .Where("cal.tenant", currentTenantId));

            var calIds = db.ExecuteList(queryGetCalIds).Select(r => r[0]);

            var cals = GetCalendarsByIds(calIds.ToArray());

            //filter by is_accepted field
            newCalendarsCount =
                cals.RemoveAll(
                    c =>
                    (!c.OwnerId.Equals(userId) &&
                        !c.ViewSettings.Exists(v => v.UserId.Equals(userId) && v.IsAccepted))
                    || (c.IsiCalStream() && c.ViewSettings.Exists(v => v.UserId.Equals(userId) && !v.IsAccepted)));
            return cals;
        }

        public List<Calendar> LoadiCalStreamsForUser(Guid userId)
        {
            var queryGetCalIds = new SqlQuery(_calendarTable)
                .Select("cal.id")
                .Where("cal.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where("cal.owner_id", userId)
                .Where(!Exp.Eq("cal.ical_url", null));

            var calIds = db.ExecuteList(queryGetCalIds).Select(r => r[0]);

            var calendars = GetCalendarsByIds(calIds.ToArray());
            return calendars;
        }

        public List<Calendar> LoadSubscriptionsForUser(Guid userId)
        {
            var groups = CoreContext.UserManager.GetUserGroups(userId).Select(g => g.ID).ToList();
            groups.AddRange(CoreContext.UserManager.GetUserGroups(userId, Core.Users.Constants.SysGroupCategoryId).Select(g => g.ID));

            var calIds = db.ExecuteList(new SqlQuery(_calendarItemTable).Select("cal_itm.calendar_id")
                                                .InnerJoin(_calendarTable, Exp.EqColumns("cal.id", "cal_itm.calendar_id"))
                                                .Where("cal.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                                                .Where(Exp.Eq("cal_itm.item_id", userId) | (Exp.In("cal_itm.item_id", groups.ToArray()) & Exp.Eq("cal_itm.is_group", true)))
                                            ).Select(r => r[0]);

            var calendars = GetCalendarsByIds(calIds.ToArray());
            return calendars;
        }

        public TimeZoneInfo GetTimeZoneForSharedEventsCalendar(Guid userId)
        {
            var q = new SqlQuery(_calendarUserTable)
                .Select("time_zone")
                .Where("ext_calendar_id", SharedEventsCalendar.CalendarId)
                .Where("user_id", userId);

            var data = db.ExecuteList(q);
            if (data.Count > 0)
                return data.Select(r => TimeZoneConverter.GetTimeZone(Convert.ToString(r[0]))).First();

            return CoreContext.TenantManager.GetCurrentTenant().TimeZone;
        }

        public TimeZoneInfo GetTimeZoneForCalendar(Guid userId, int calendarId)
        {
            var timeZone = db.ExecuteList(new SqlQuery(_calendarUserTable).Select("cal_usr.time_zone")
                                                        .Where(Exp.Eq("cal_usr.user_id", userId))
                                                        .Where(Exp.Eq("cal_usr.calendar_id", calendarId)))
                                                        .Select(r => (r[0] == null || r[0] == DBNull.Value) ? null : TimeZoneConverter.GetTimeZone(Convert.ToString(r[0])));

            if (timeZone.Count() != 0 && timeZone.First() == null)
            {
                timeZone = db.ExecuteList(new SqlQuery(_calendarUserTable).Select("cal_usr.time_zone")
                                                        .Where(Exp.Eq("cal_usr.user_id", GetCalendarById(calendarId).OwnerId))
                                                        .Where(Exp.Eq("cal_usr.calendar_id", calendarId)))
                                                        .Select(r => (r[0] == null || r[0] == DBNull.Value) ? null : TimeZoneConverter.GetTimeZone(Convert.ToString(r[0])));
            }

            if (timeZone.Count() == 0)
            {
                return GetCalendarById(calendarId).TimeZone;
            }
            else
            {
                return timeZone.First();
            }
        }
        public List<object[]> GetCalendarIdByCaldavGuid(string caldavGuid)
        {
            var data = db.ExecuteList(new SqlQuery(_calendarTable).Select("id", "owner_id", "tenant").Where("caldav_guid", caldavGuid));
            return data;
        }
        public Event GetEventIdByUid(string uid, int calendarId)
        {
            var sql = new SqlQuery("calendar_events")
                .Select("id")
                .Where(Exp.Like("uid", uid))
                .Where("calendar_id", calendarId);

            var eventId = db.ExecuteScalar<int>(sql);

            return eventId == 0 ? null : GetEventById(eventId);
        }
        public Event GetEventIdOnlyByUid(string uid)
        {
            var sql = new SqlQuery("calendar_events")
                .Select("id")
                .Where(Exp.Like("uid", uid));

            var eventId = db.ExecuteScalar<int>(sql);

            return eventId == 0 ? null : GetEventById(eventId);
        }
        public List<Calendar> GetCalendarsByIds(object[] calIds)
        {
            var cc = new ColumnCollection();

            var calId = cc.RegistryColumn("cal.id");
            var calName = cc.RegistryColumn("cal.name");
            var calDescription = cc.RegistryColumn("cal.description");
            var calTenant = cc.RegistryColumn("cal.tenant");
            var calTextColor = cc.RegistryColumn("cal.text_color");
            var calBackground = cc.RegistryColumn("cal.background_color");
            var calOwner = cc.RegistryColumn("cal.owner_id");
            var calAlertType = cc.RegistryColumn("cal.alert_type");
            var calTimeZone = cc.RegistryColumn("cal.time_zone");
            var iCalUrl = cc.RegistryColumn("cal.ical_url");
            var calDavGuid = cc.RegistryColumn("cal.caldav_guid");
            var isTodo = cc.RegistryColumn("cal.is_todo");

            var usrId = cc.RegistryColumn("cal_usr.user_id");
            var usrHideEvents = cc.RegistryColumn("cal_usr.hide_events");
            var usrIsAccepted = cc.RegistryColumn("cal_usr.is_accepted");
            var usrTextColor = cc.RegistryColumn("cal_usr.text_color");
            var usrBackground = cc.RegistryColumn("cal_usr.background_color");
            var usrAlertType = cc.RegistryColumn("cal_usr.alert_type");
            var usrCalName = cc.RegistryColumn("cal_usr.name");
            var usrTimeZone = cc.RegistryColumn("cal_usr.time_zone");

            var data = db.ExecuteList(new SqlQuery(_calendarTable).Select(cc.SelectQuery)
                                                                            .LeftOuterJoin(_calendarUserTable,
                                                                                        Exp.EqColumns(calId.Name,
                                                                                                        "cal_usr.calendar_id"))
                                                                            .Where(Exp.In(calId.Name, calIds)));

            var cc1 = new ColumnCollection();

            var itemCalId = cc1.RegistryColumn("cal_itm.calendar_id");
            var itemId = cc1.RegistryColumn("cal_itm.item_id");
            var itemIsGroup = cc1.RegistryColumn("cal_itm.is_group");

            var sharingData = db.ExecuteList(new SqlQuery(_calendarItemTable).Select(cc1.SelectQuery)
                                                                                    .Where(Exp.In(itemCalId.Name,
                                                                                                    calIds)));


            //parsing
            var calendars = new List<Calendar>();
            foreach (var r in data)
            {
                var calendar =
                    calendars.Find(
                        c =>
                        string.Equals(c.Id, calId.Parse<int>(r).ToString(),
                                        StringComparison.InvariantCultureIgnoreCase));
                if (calendar == null)
                {
                    calendar = new Calendar
                    {
                        Id = calId.Parse<int>(r).ToString(),
                        Name = calName.Parse<string>(r),
                        Description = calDescription.Parse<string>(r),
                        TenantId = calTenant.Parse<int>(r),
                        OwnerId = calOwner.Parse<Guid>(r),
                        EventAlertType = (EventAlertType)calAlertType.Parse<int>(r),
                        TimeZone = calTimeZone.Parse<TimeZoneInfo>(r),
                        iCalUrl = iCalUrl.Parse<string>(r),
                        calDavGuid = calDavGuid.Parse<string>(r),
                        IsTodo = isTodo.Parse<int>(r)
                    };
                    calendar.Context.HtmlTextColor = calTextColor.Parse<string>(r);
                    calendar.Context.HtmlBackgroundColor = calBackground.Parse<string>(r);
                    if (!String.IsNullOrEmpty(calendar.iCalUrl))
                    {
                        calendar.Context.CanChangeTimeZone = false;
                        calendar.Context.CanChangeAlertType = false;
                    }

                    calendars.Add(calendar);

                    foreach (var row in sharingData)
                    {
                        var _calId = itemCalId.Parse<int>(row).ToString();
                        if (String.Equals(_calId, calendar.Id, StringComparison.InvariantCultureIgnoreCase))
                        {
                            calendar.SharingOptions.PublicItems.Add(new SharingOptions.PublicItem
                            {
                                Id = itemId.Parse<Guid>(row),
                                IsGroup = itemIsGroup.Parse<bool>(row)
                            });
                        }
                    }
                }

                if (!usrId.IsNull(r))
                {
                    var uvs = new UserViewSettings
                    {
                        CalendarId = calendar.Id,
                        UserId = usrId.Parse<Guid>(r),
                        IsHideEvents = usrHideEvents.Parse<bool>(r),
                        IsAccepted = usrIsAccepted.Parse<bool>(r),
                        TextColor = usrTextColor.Parse<string>(r),
                        BackgroundColor = usrBackground.Parse<string>(r),
                        EventAlertType = (EventAlertType)usrAlertType.Parse<int>(r),
                        Name = usrCalName.Parse<string>(r),
                        TimeZone = usrTimeZone.Parse<TimeZoneInfo>(r)
                    };

                    calendar.ViewSettings.Add(uvs);
                }
            }

            return calendars;
        }

        public Calendar GetCalendarById(int calendarId)
        {
            var calendars = GetCalendarsByIds(new object[] { calendarId });
            if (calendars.Count > 0)
                return calendars[0];

            return null;
        }

        public Calendar CreateCalendar(Guid ownerId, string name, string description, string textColor, string backgroundColor, TimeZoneInfo timeZone, EventAlertType eventAlertType, string iCalUrl, List<SharingOptions.PublicItem> publicItems, List<UserViewSettings> viewSettings, Guid calDavGuid, int isTodo = 0)
        {
            int calendarId;
            using (var tr = db.BeginTransaction())
            {

                calendarId = db.ExecuteScalar<int>(new SqlInsert("calendar_calendars")
                                                                .InColumnValue("id", 0)
                                                                .InColumnValue("tenant",
                                                                                CoreContext.TenantManager
                                                                                        .GetCurrentTenant().TenantId)
                                                                .InColumnValue("owner_id", ownerId)
                                                                .InColumnValue("name", name)
                                                                .InColumnValue("description", description)
                                                                .InColumnValue("text_color", textColor)
                                                                .InColumnValue("background_color", backgroundColor)
                                                                .InColumnValue("alert_type", (int)eventAlertType)
                                                                .InColumnValue("time_zone", timeZone.Id)
                                                                .InColumnValue("ical_url", iCalUrl)
                                                                .InColumnValue("caldav_guid", calDavGuid)
                                                                .InColumnValue("is_todo", isTodo)
                                                                .Identity(0, 0, true));

                if (publicItems != null)
                {
                    foreach (var item in publicItems)
                    {
                        db.ExecuteNonQuery(new SqlInsert("calendar_calendar_item")
                                                        .InColumnValue("calendar_id", calendarId)
                                                        .InColumnValue("item_id", item.Id)
                                                        .InColumnValue("is_group", item.IsGroup));
                    }
                }

                if (viewSettings != null)
                {
                    foreach (var view in viewSettings)
                    {
                        db.ExecuteNonQuery(new SqlInsert("calendar_calendar_user")
                                                        .InColumnValue("calendar_id", calendarId)
                                                        .InColumnValue("user_id", view.UserId)
                                                        .InColumnValue("hide_events", view.IsHideEvents)
                                                        .InColumnValue("is_accepted", view.IsAccepted)
                                                        .InColumnValue("text_color", view.TextColor)
                                                        .InColumnValue("background_color", view.BackgroundColor)
                                                        .InColumnValue("alert_type", (int)view.EventAlertType)
                                                        .InColumnValue("name", view.Name ?? "")
                                                        .InColumnValue("time_zone",
                                                                        view.TimeZone != null ? view.TimeZone.Id : null)
                            );

                    }
                }
                tr.Commit();
            }

            return GetCalendarById(calendarId);
        }

        public Calendar UpdateCalendarGuid(int calendarId, Guid calDavGuid)
        {
            using (var tr = db.BeginTransaction())
            {
                db.ExecuteNonQuery(new SqlUpdate("calendar_calendars")
                                                .Set("caldav_guid", calDavGuid)
                                                .Where("id", calendarId));
                tr.Commit();
            }
            return GetCalendarById(calendarId);
        }
        public Calendar UpdateCalendar(int calendarId, string name, string description, List<SharingOptions.PublicItem> publicItems, List<UserViewSettings> viewSettings)
        {
            using (var tr = db.BeginTransaction())
            {

                db.ExecuteNonQuery(new SqlUpdate("calendar_calendars")
                                                .Set("name", name)
                                                .Set("description", description)
                                                .Where("id", calendarId));

                //sharing
                var sqlQuery = new SqlQuery("calendar_calendar_item")
                    .Select("item_id", "is_group")
                    .Where(Exp.Eq("calendar_id", calendarId));
                var existsItems = db.ExecuteList(sqlQuery).ConvertAll(row => new SharingOptions.PublicItem
                {
                    Id = new Guid((string)row[0]),
                    IsGroup = Convert.ToBoolean(row[1])
                });

                foreach (var existCalendar in existsItems)
                {
                    db.ExecuteNonQuery(new SqlDelete("calendar_calendar_item")
                        .Where("calendar_id", calendarId)
                        .Where("item_id", existCalendar.Id)
                        .Where("is_group", existCalendar.IsGroup));
                }


                foreach (var item in publicItems)
                {
                    db.ExecuteNonQuery(new SqlInsert("calendar_calendar_item")
                                                    .InColumnValue("calendar_id", calendarId)
                                                    .InColumnValue("item_id", item.Id)
                                                    .InColumnValue("is_group", item.IsGroup));
                }

                //view
                sqlQuery = new SqlQuery("calendar_calendar_user")
                    .Select("ext_calendar_id", "user_id")
                    .Where(Exp.Eq("calendar_id", calendarId));
                var existsUsers = db.ExecuteList(sqlQuery).Select(row => new
                {
                    ExtCalendarId = (string)row[0],
                    Id = (string)row[1]
                }).ToList();

                foreach (var user in existsUsers)
                {
                    db.ExecuteNonQuery(new SqlDelete("calendar_calendar_user")
                        .Where("calendar_id", calendarId)
                        .Where("ext_calendar_id", user.ExtCalendarId)
                        .Where("user_id", user.Id));
                }

                foreach (var view in viewSettings)
                {
                    db.ExecuteNonQuery(new SqlInsert("calendar_calendar_user")
                                                    .InColumnValue("calendar_id", calendarId)
                                                    .InColumnValue("user_id", view.UserId)
                                                    .InColumnValue("hide_events", view.IsHideEvents)
                                                    .InColumnValue("is_accepted", view.IsAccepted)
                                                    .InColumnValue("text_color", view.TextColor)
                                                    .InColumnValue("background_color", view.BackgroundColor)
                                                    .InColumnValue("alert_type", (int)view.EventAlertType)
                                                    .InColumnValue("name", view.Name ?? "")
                                                    .InColumnValue("time_zone",
                                                                    view.TimeZone != null ? view.TimeZone.Id : null)
                        );

                }

                //update notifications
                var cc = new ColumnCollection();
                var eId = cc.RegistryColumn("e.id");
                var eStartDate = cc.RegistryColumn("e.start_date");
                var eAlertType = cc.RegistryColumn("e.alert_type");
                var eRRule = cc.RegistryColumn("e.rrule");
                var eIsAllDay = cc.RegistryColumn("e.all_day_long");
                var eTimeZone = cc.RegistryColumn("e.time_zone");

                var eventsData = db.ExecuteList(
                    new SqlQuery("calendar_events e")
                        .Select(cc.SelectQuery)
                        .Where("e.calendar_id", calendarId)
                        .Where("e.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId));

                foreach (var r in eventsData)
                {
                    UpdateEventNotifications(eId.Parse<int>(r), calendarId,
                                                eStartDate.Parse<DateTime>(r),
                                                (EventAlertType)eAlertType.Parse<int>(r),
                                                eRRule.Parse<RecurrenceRule>(r), null, publicItems,
                                                eIsAllDay.Parse<bool>(r),
                                                eTimeZone.Parse<TimeZoneInfo>(r));
                }

                tr.Commit();
            }

            return GetCalendarById(calendarId);
        }

        public void UpdateCalendarUserView(List<UserViewSettings> viewSettings)
        {
            using (var tr = db.BeginTransaction())
            {
                foreach (var s in viewSettings)
                    UpdateCalendarUserView(s);

                tr.Commit();
            }
        }
        public void UpdateCalendarUserView(UserViewSettings viewSettings)
        {
            var cc = new ColumnCollection();
            var eId = cc.RegistryColumn("e.id");
            var eStartDate = cc.RegistryColumn("e.start_date");
            var eAlertType = cc.RegistryColumn("e.alert_type");
            var eRRule = cc.RegistryColumn("e.rrule");
            var eCalId = cc.RegistryColumn("e.calendar_id");
            var eIsAllDay = cc.RegistryColumn("e.all_day_long");
            var eTimeZone = cc.RegistryColumn("e.time_zone");
            var tenant = CoreContext.TenantManager.GetCurrentTenant();

            int calendarId;
            if (int.TryParse(viewSettings.CalendarId, out calendarId))
            {
                db.ExecuteNonQuery(new SqlInsert("calendar_calendar_user", true)
                                                .InColumnValue("calendar_id", calendarId)
                                                .InColumnValue("user_id", viewSettings.UserId)
                                                .InColumnValue("hide_events", viewSettings.IsHideEvents)
                                                .InColumnValue("text_color", viewSettings.TextColor)
                                                .InColumnValue("background_color", viewSettings.BackgroundColor)
                                                .InColumnValue("is_accepted", viewSettings.IsAccepted)
                                                .InColumnValue("alert_type", (int)viewSettings.EventAlertType)
                                                .InColumnValue("name", viewSettings.Name ?? "")
                                                .InColumnValue("time_zone",
                                                                viewSettings.TimeZone != null
                                                                    ? viewSettings.TimeZone.Id
                                                                    : null)
                    );

                //update notifications
                var updateNotifications = new Task(() =>
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant);
                    try
                    {
                        using (var db = new DbManager(DBId))
                        {
                            using (var tr = db.BeginTransaction())
                            {
                                var eventsData = db.ExecuteList( new SqlQuery("calendar_events e")
                                .Select(cc.SelectQuery)
                                .Where("e.calendar_id", calendarId)
                                .Where("e.tenant", tenant.TenantId));

                                foreach (var r in eventsData)
                                {
                                    UpdateEventNotifications(eId.Parse<int>(r), calendarId,
                                                                eStartDate.Parse<DateTime>(r),
                                                                (EventAlertType)eAlertType.Parse<int>(r),
                                                                eRRule.Parse<RecurrenceRule>(r), null, null,
                                                                eIsAllDay.Parse<bool>(r),
                                                                eTimeZone.Parse<TimeZoneInfo>(r), db);
                                }
                            }

                        }

                    }
                    catch (Exception ex)
                    {
                        LogManager.GetLogger("ASC.Calendar").Error(ex);
                    }
                }, TaskCreationOptions.LongRunning);

                updateNotifications.ConfigureAwait(false);
                updateNotifications.Start();
                

            }
            else
            {
                db.ExecuteNonQuery(new SqlInsert("calendar_calendar_user", true)
                                                .InColumnValue("ext_calendar_id", viewSettings.CalendarId)
                                                .InColumnValue("user_id", viewSettings.UserId)
                                                .InColumnValue("hide_events", viewSettings.IsHideEvents)
                                                .InColumnValue("text_color", viewSettings.TextColor)
                                                .InColumnValue("background_color", viewSettings.BackgroundColor)
                                                .InColumnValue("alert_type", (int)viewSettings.EventAlertType)
                                                .InColumnValue("is_accepted", viewSettings.IsAccepted)
                                                .InColumnValue("name", viewSettings.Name ?? "")
                                                .InColumnValue("time_zone",
                                                                viewSettings.TimeZone != null
                                                                    ? viewSettings.TimeZone.Id
                                                                    : null)
                    );

                if (String.Equals(viewSettings.CalendarId, SharedEventsCalendar.CalendarId,
                                    StringComparison.InvariantCultureIgnoreCase))
                {

                    //update notifications
                    var updateNotifications = new Task(() =>
                    {
                        CoreContext.TenantManager.SetCurrentTenant(tenant);
                        try
                        {
                            using (var db = new DbManager(DBId))
                            {
                                using (var tr = db.BeginTransaction())
                                {
                                    var groups =
                                        CoreContext.UserManager.GetUserGroups(viewSettings.UserId).Select(g => g.ID).ToList();
                                    groups.AddRange(
                                        CoreContext.UserManager.GetUserGroups(viewSettings.UserId,
                                                                                Core.Users.Constants.SysGroupCategoryId)
                                                    .Select(g => g.ID));

                                    var q = new SqlQuery("calendar_events e")
                                        .Select(cc.SelectQuery)
                                        .InnerJoin("calendar_event_item ei", Exp.EqColumns("ei.event_id", eId.Name))
                                        .Where("e.tenant", tenant.TenantId)
                                        .Where((Exp.Eq("ei.is_group", false) & Exp.Eq("ei.item_id", viewSettings.UserId)) |
                                                (Exp.Eq("ei.is_group", true) & Exp.In("ei.item_id", groups.ToArray())));

                                    var eventsData = db.ExecuteList(q);

                                    foreach (var r in eventsData)
                                    {
                                        UpdateEventNotifications(eId.Parse<int>(r), eCalId.Parse<int>(r),
                                                                    eStartDate.Parse<DateTime>(r),
                                                                    (EventAlertType)eAlertType.Parse<int>(r),
                                                                    eRRule.Parse<RecurrenceRule>(r), null, null,
                                                                    eIsAllDay.Parse<bool>(r),
                                                                    eTimeZone.Parse<TimeZoneInfo>(r), db);
                                    }
                                }

                            }

                        }
                        catch (Exception ex)
                        {
                            LogManager.GetLogger("ASC.Calendar").Error(ex);
                        }
                    }, TaskCreationOptions.LongRunning);

                    updateNotifications.ConfigureAwait(false);
                    updateNotifications.Start();
                }
            }
        }

        public Guid RemoveCalendar(int calendarId)
        {
            using (var tr = db.BeginTransaction())
            {
                var caldavGuid = Guid.Empty;
                try
                {
                    var dataCaldavGuid =
                        db.ExecuteList(new SqlQuery("calendar_calendars").Select("caldav_guid").Where("id", calendarId))
                          .Select(r => r[0])
                          .ToArray();
                    if (dataCaldavGuid[0] != null) caldavGuid = Guid.Parse(dataCaldavGuid[0].ToString());
                }
                catch (Exception ex)
                {
                    LogManager.GetLogger("ASC.Calendar").Error(ex);
                }

                db.ExecuteNonQuery(new SqlDelete("calendar_calendars").Where("id", calendarId));
                db.ExecuteNonQuery(new SqlDelete("calendar_calendar_user").Where("calendar_id", calendarId));
                db.ExecuteNonQuery(new SqlDelete("calendar_calendar_item").Where("calendar_id", calendarId));

                var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;

                var data = db.ExecuteList(new SqlQuery("calendar_events")
                                                .Select("id")
                                                .Where("calendar_id", calendarId)
                                                .Where("tenant", tenant))
                                .Select(r => r[0])
                                .ToArray();

                db.ExecuteNonQuery(new SqlDelete("calendar_events").Where("calendar_id", calendarId).Where("tenant", tenant));
                db.ExecuteNonQuery(new SqlDelete("calendar_event_item").Where(Exp.In("event_id", data)));
                db.ExecuteNonQuery(new SqlDelete("calendar_event_user").Where(Exp.In("event_id", data)));
                db.ExecuteNonQuery(new SqlDelete("calendar_notifications").Where(Exp.In("event_id", data)));
                db.ExecuteNonQuery(new SqlDelete("calendar_event_history").Where("tenant", tenant).Where(Exp.In("event_id", data)));

                tr.Commit();

                return caldavGuid;
            }
        }

        public void RemoveExternalCalendarData(string calendarId)
        {
            using (var tr = db.BeginTransaction())
            {
                db.ExecuteNonQuery(new SqlDelete("calendar_calendar_user").Where("ext_calendar_id", calendarId));
                tr.Commit();
            }
        }


        public Todo GetTodoByUid(string todoUid)
        {
            var sql = new SqlQuery("calendar_todos t")
                .Select("t.id")
                .InnerJoin("calendar_calendars c", Exp.EqColumns("c.id", "t.calendar_id"))
                .Where("t.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where(Exp.Like("t.uid", todoUid))
                .Where("t.owner_id", SecurityContext.CurrentAccount.ID)
                .Where("c.owner_id", SecurityContext.CurrentAccount.ID)
                .Where("c.ical_url", null);

            var todoId = db.ExecuteScalar<int>(sql);

            return todoId == 0 ? null : GetTodoById(todoId);
        }
        public Todo GetTodoIdByUid(string uid, int calendarId)
        {
            var sql = new SqlQuery("calendar_todos")
                .Select("id")
                .Where(Exp.Like("uid", uid))
                .Where("calendar_id", calendarId);

            var todoId = db.ExecuteScalar<int>(sql);

            return todoId == 0 ? null : GetTodoById(todoId);
        }
        public Todo UpdateTodo(string id, int calendarId, Guid ownerId, string name, string description, DateTime utcStartDate, string uid, DateTime completed)
        {
            int todoId;


            using (var tr = db.BeginTransaction())
            {

                todoId = db.ExecuteScalar<int>(new SqlUpdate("calendar_todos")
                                                            .Set("name", name)
                                                            .Set("description", description)
                                                            .Set("calendar_id", calendarId)
                                                            .Set("owner_id", ownerId)
                                                            .Set("start_date", utcStartDate == DateTime.MinValue ? null : utcStartDate.ToString("yyyy-MM-dd HH:mm:ss"))
                                                            .Set("uid", GetEventUid(uid))
                                                            .Set("completed", completed == DateTime.MinValue ? null : completed.ToString("yyyy-MM-dd HH:mm:ss"))
                                                            .Where(Exp.Eq("id", id)));


                tr.Commit();
            }

            return GetTodoById(int.Parse(id));

        }

        public Todo CreateTodo(int calendarId,
                                 Guid ownerId,
                                 string name,
                                 string description,
                                 DateTime utcStartDate,
                                 string uid,
                                 DateTime completed)
        {
            int todoId;


            using (var tr = db.BeginTransaction())
            {

                todoId = db.ExecuteScalar<int>(new SqlInsert("calendar_todos")
                                                            .InColumnValue("id", 0)
                                                            .InColumnValue("tenant",
                                                                            CoreContext.TenantManager.GetCurrentTenant
                                                                                ().TenantId)
                                                            .InColumnValue("name", name)
                                                            .InColumnValue("description", description)
                                                            .InColumnValue("calendar_id", calendarId)
                                                            .InColumnValue("owner_id", ownerId)
                                                            .InColumnValue("start_date", utcStartDate == DateTime.MinValue ? null : utcStartDate.ToString("yyyy-MM-dd HH:mm:ss"))
                                                            .InColumnValue("uid", GetEventUid(uid))
                                                            .InColumnValue("completed", completed == DateTime.MinValue ? null : completed.ToString("yyyy-MM-dd HH:mm:ss"))
                                                            .Identity(0, 0, true));


                tr.Commit();
            }

            return GetTodoById(todoId);
        }
        public Todo GetTodoById(int todoId)
        {
            var todos = GetTodosByIds(new object[] { todoId }, SecurityContext.CurrentAccount.ID);
            if (todos.Count > 0)
                return todos[0];

            return null;
        }

        public List<Todo> GetTodosByIds(object[] todoIds, Guid userId, int tenantId = -1)
        {
            var cc = new ColumnCollection();
            var tdId = cc.RegistryColumn("td.id");
            var tdName = cc.RegistryColumn("td.name");
            var tdDescription = cc.RegistryColumn("td.description");
            var tdTenant = cc.RegistryColumn("td.tenant");
            var tdCalId = cc.RegistryColumn("td.calendar_id");
            var tdStartDate = cc.RegistryColumn("td.start_date");
            var tdCompleted = cc.RegistryColumn("td.completed");
            var tdOwner = cc.RegistryColumn("td.owner_id");
            var tdUid = cc.RegistryColumn("td.uid");

            var data = new List<Object[]>();

            if (todoIds.Length > 0)
            {
                if (tenantId != -1)
                {
                    data = db.ExecuteList(new SqlQuery(_todoTable)

                                              .Select(cc.SelectQuery)
                                              .Where(Exp.In(tdId.Name, todoIds))
                                              .Where("tenant", tenantId));
                }
                else
                {
                    data = db.ExecuteList(new SqlQuery(_todoTable)

                                                   .Select(cc.SelectQuery)
                                                   .Where(Exp.In(tdId.Name, todoIds)));
                }

            }


            //parsing           
            var todos = new List<Todo>();

            foreach (var r in data)
            {
                var td =
                    todos.Find(
                        e => String.Equals(e.Id, tdId.Parse<string>(r), StringComparison.InvariantCultureIgnoreCase));
                if (td == null)
                {
                    td = new Todo()
                    {
                        Id = tdId.Parse<string>(r),
                        Name = tdName.Parse<string>(r),
                        Description = tdDescription.Parse<string>(r),
                        TenantId = tdTenant.Parse<int>(r),
                        CalendarId = tdCalId.Parse<string>(r),
                        UtcStartDate = tdStartDate.Parse<DateTime>(r),
                        Completed = tdCompleted.Parse<DateTime>(r),
                        OwnerId = tdOwner.Parse<Guid>(r),
                        Uid = tdUid.Parse<string>(r)

                    };
                    todos.Add(td);
                }
            }
            return todos;
        }

        public List<Todo> LoadTodos(int calendarId, Guid userId, int tenantId, DateTime utcStartDate, DateTime utcEndDate)
        {
            var sqlQuery = new SqlQuery(_todoTable)
                .Select("td.id")
                .Where(
                    Exp.Eq("td.calendar_id", calendarId) &
                    Exp.Eq("td.tenant", tenantId)
                );

            var tdIds = db.ExecuteList(sqlQuery).Select(r => r[0]);

            return GetTodosByIds(tdIds.ToArray(), userId, tenantId);
        }
        internal List<Event> LoadSharedEvents(Guid userId, int tenantId, DateTime utcStartDate, DateTime utcEndDate)
        {
            var groups = CoreContext.UserManager.GetUserGroups(userId).Select(g => g.ID).ToList();
            groups.AddRange(CoreContext.UserManager.GetUserGroups(userId, Core.Users.Constants.SysGroupCategoryId).Select(g => g.ID));

            var evIds = db.ExecuteList(
                new SqlQuery(_eventTable).Select("evt.id")
                    .InnerJoin(_eventItemTable, Exp.EqColumns("evt_itm.event_id", "evt.id"))
                    .Where("evt.tenant", tenantId)
                    .Where(
                    (Exp.Eq("evt_itm.item_id", userId) | (Exp.In("evt_itm.item_id", groups.ToArray()) & Exp.Eq("evt_itm.is_group", true)))
                    & Exp.Eq("evt.tenant", tenantId)
                    & ((Exp.Ge("evt.start_date", utcStartDate) & Exp.Le("evt.start_date", utcEndDate) & Exp.Eq("evt.rrule", "")
                        | !Exp.Eq("evt.rrule", "")))

                    & !Exp.Eq("evt.owner_id", userId)

                    & !Exp.Exists(new SqlQuery("calendar_event_user evt_usr").Select("evt_usr.event_id")
                                                                                .Where(Exp.EqColumns("evt_usr.event_id", "evt.id")
                                                                                        & Exp.Eq("evt_usr.user_id", userId)
                                                                                        & Exp.Eq("evt_usr.is_unsubscribe", true)))
                    )).Select(r => r[0]);

            return GetEventsByIds(evIds.ToArray(), userId, tenantId);
        }

        public List<Event> LoadEvents(int calendarId, Guid userId, int tenantId, DateTime utcStartDate, DateTime utcEndDate)
        {
            var sqlQuery = new SqlQuery(_eventTable)
                .Select("evt.id")
                .Where(
                    Exp.Eq("evt.calendar_id", calendarId) &
                    Exp.Eq("evt.tenant", tenantId) &
                    (
                        !Exp.Eq("evt.rrule", "") |
                        (Exp.Eq("evt.rrule", "") &
                            (
                                    (Exp.Ge("evt.start_date", utcStartDate) & Exp.Le("evt.end_date", utcEndDate)) |
                                    (Exp.Le("evt.start_date", utcStartDate) & Exp.Ge("evt.end_date", utcStartDate)) |
                                    (Exp.Le("evt.start_date", utcEndDate) & Exp.Ge("evt.end_date", utcEndDate))
                                )
                        )
                    )
                );

            var evIds = db.ExecuteList(sqlQuery).Select(r => r[0]);

            return GetEventsByIds(evIds.ToArray(), userId, tenantId);
        }

        public Event GetEventById(int eventId)
        {
            var events = GetEventsByIds(new object[] { eventId }, SecurityContext.CurrentAccount.ID);
            if (events.Count > 0)
                return events[0];

            return null;
        }

        public List<Event> GetEventsByIds(object[] evtIds, Guid userId, int tenantId = -1)
        {
            var cc = new ColumnCollection();
            var eId = cc.RegistryColumn("evt.id");
            var eName = cc.RegistryColumn("evt.name");
            var eDescription = cc.RegistryColumn("evt.description");
            var eTenant = cc.RegistryColumn("evt.tenant");
            var eCalId = cc.RegistryColumn("evt.calendar_id");
            var eStartDate = cc.RegistryColumn("evt.start_date");
            var eEndDate = cc.RegistryColumn("evt.end_date");
            var eUpdateDate = cc.RegistryColumn("evt.update_date");
            var eIsAllDay = cc.RegistryColumn("evt.all_day_long");
            var eRRule = cc.RegistryColumn("evt.rrule");
            var eOwner = cc.RegistryColumn("evt.owner_id");
            var usrAlertType = cc.RegistryColumn("evt_usr.alert_type");
            var eAlertType = cc.RegistryColumn("evt.alert_type");
            var eUid = cc.RegistryColumn("evt.uid");
            var eStatus = cc.RegistryColumn("evt.status");
            var eTimeZone = cc.RegistryColumn("evt.time_zone");

            var data = new List<Object[]>();

            if (evtIds.Length > 0)
            {
                if (tenantId != -1)
                {
                    data = db.ExecuteList(new SqlQuery(_eventTable)
                                              .LeftOuterJoin("calendar_event_user evt_usr",
                                                             Exp.EqColumns(eId.Name, "evt_usr.event_id") &
                                                             Exp.Eq("evt_usr.user_id", userId))
                                              .Select(cc.SelectQuery)
                                              .Where(Exp.In(eId.Name, evtIds))
                                              .Where("tenant", tenantId));
                }
                else
                {
                    data = db.ExecuteList(new SqlQuery(_eventTable)
                                                .LeftOuterJoin("calendar_event_user evt_usr",
                                                               Exp.EqColumns(eId.Name, "evt_usr.event_id") &
                                                               Exp.Eq("evt_usr.user_id", userId))
                                                .Select(cc.SelectQuery)
                                                .Where(Exp.In(eId.Name, evtIds)));

                }

            }

            var cc1 = new ColumnCollection();
            var evId = cc1.RegistryColumn("evt_itm.event_id");
            var itemId = cc1.RegistryColumn("evt_itm.item_id");
            var itemIsGroup = cc1.RegistryColumn("evt_itm.is_group");

            var sharingData = new List<Object[]>();

            if (evtIds.Length > 0)
            {
                sharingData = db.ExecuteList(new SqlQuery(_eventItemTable).Select(cc1.SelectQuery)
                                                                                   .Where(Exp.In(evId.Name, evtIds)));
            }

            //parsing           
            var events = new List<Event>();

            foreach (var r in data)
            {
                var ev =
                    events.Find(
                        e => String.Equals(e.Id, eId.Parse<string>(r), StringComparison.InvariantCultureIgnoreCase));
                if (ev == null)
                {
                    ev = new Event
                    {
                        Id = eId.Parse<string>(r),
                        Name = eName.Parse<string>(r),
                        Description = eDescription.Parse<string>(r),
                        TenantId = eTenant.Parse<int>(r),
                        CalendarId = eCalId.Parse<string>(r),
                        UtcStartDate = eStartDate.Parse<DateTime>(r),
                        UtcEndDate = eEndDate.Parse<DateTime>(r),
                        UtcUpdateDate = eUpdateDate.Parse<DateTime>(r),
                        AllDayLong = eIsAllDay.Parse<bool>(r),
                        OwnerId = eOwner.Parse<Guid>(r),
                        AlertType =
                                (usrAlertType.IsNull(r))
                                    ? (EventAlertType)eAlertType.Parse<int>(r)
                                    : (EventAlertType)usrAlertType.Parse<int>(r),
                        RecurrenceRule = eRRule.Parse<RecurrenceRule>(r),
                        Uid = eUid.Parse<string>(r),
                        Status = (EventStatus)eStatus.Parse<int>(r),
                        TimeZone = eTimeZone.Parse<TimeZoneInfo>(r)
                    };
                    events.Add(ev);
                }

                foreach (var row in sharingData)
                {
                    if (String.Equals(evId.Parse<string>(row), ev.Id, StringComparison.InvariantCultureIgnoreCase))
                    {
                        ev.SharingOptions.PublicItems.Add(new SharingOptions.PublicItem
                        {
                            Id = itemId.Parse<Guid>(row),
                            IsGroup = itemIsGroup.Parse<bool>(row)
                        });
                    }
                }
            }
            return events;
        }

        public Event GetEventByUid(string eventUid)
        {
            var sql = new SqlQuery("calendar_events e")
                .Select("e.id")
                .InnerJoin("calendar_calendars c", Exp.EqColumns("c.id", "e.calendar_id"))
                .Where("e.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where("e.uid", eventUid)
                .Where("e.owner_id", SecurityContext.CurrentAccount.ID)
                .Where("c.owner_id", SecurityContext.CurrentAccount.ID)
                .Where("c.ical_url", null);

            var eventId = db.ExecuteScalar<int>(sql);

            return eventId == 0 ? null : GetEventById(eventId);
        }
        public Event GetEventOnlyByUid(string eventUid)
        {
            var sql = new SqlQuery("calendar_events e")
                .Select("e.id")
                .Where("e.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where("e.uid", eventUid);

            var eventId = db.ExecuteScalar<int>(sql);

            return eventId == 0 ? null : GetEventById(eventId);
        }

        public void SetEventUid(int eventId, string uid)
        {
            using (var tr = db.BeginTransaction())
            {
                db.ExecuteNonQuery(new SqlUpdate("calendar_events")
                                                .Set("uid", uid)
                                                .Where(Exp.Eq("id", eventId)));

                tr.Commit();
            }
        }

        public void UnsubscribeFromEvent(int eventID, Guid userId)
        {
            using (var tr = db.BeginTransaction())
            {
                if (db.ExecuteNonQuery(new SqlDelete("calendar_event_item").Where(Exp.Eq("event_id", eventID)
                                                                                & Exp.Eq("item_id", userId)
                                                                                & Exp.Eq("is_group", false))) == 0)
                {
                    db.ExecuteNonQuery(new SqlInsert("calendar_event_user", true).InColumnValue("event_id", eventID)
                                                                                        .InColumnValue("user_id", userId)
                                                                                        .InColumnValue("is_unsubscribe", true));
                }

                db.ExecuteNonQuery(new SqlDelete("calendar_notifications").Where(Exp.Eq("event_id", eventID) & Exp.Eq("user_id", userId)));

                tr.Commit();
            }
        }

        public void RemoveEvent(int eventId)
        {
            using (var tr = db.BeginTransaction())
            {
                var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;

                db.ExecuteNonQuery(new SqlDelete("calendar_events").Where("id", eventId).Where("tenant", tenant));
                db.ExecuteNonQuery(new SqlDelete("calendar_event_item").Where("event_id", eventId));
                db.ExecuteNonQuery(new SqlDelete("calendar_event_user").Where("event_id", eventId));
                db.ExecuteNonQuery(new SqlDelete("calendar_notifications").Where("event_id", eventId));
                db.ExecuteNonQuery(new SqlDelete("calendar_event_history").Where("tenant", tenant).Where("event_id", eventId));

                tr.Commit();
            }
        }

        public Event CreateEvent(int calendarId,
                                 Guid ownerId,
                                 string name,
                                 string description,
                                 DateTime utcStartDate,
                                 DateTime utcEndDate,
                                 RecurrenceRule rrule,
                                 EventAlertType alertType,
                                 bool isAllDayLong,
                                 List<SharingOptions.PublicItem> publicItems,
                                 string uid,
                                 EventStatus status,
                                 DateTime createDate,
                                 TimeZoneInfo timeZone)
        {
            int eventId;
            using (var tr = db.BeginTransaction())
            {

                eventId = db.ExecuteScalar<int>(new SqlInsert("calendar_events")
                                                            .InColumnValue("id", 0)
                                                            .InColumnValue("tenant",
                                                                            CoreContext.TenantManager.GetCurrentTenant
                                                                                ().TenantId)
                                                            .InColumnValue("name", name)
                                                            .InColumnValue("description", description)
                                                            .InColumnValue("calendar_id", calendarId)
                                                            .InColumnValue("owner_id", ownerId)
                                                            .InColumnValue("start_date",
                                                                            utcStartDate.ToString(
                                                                                "yyyy-MM-dd HH:mm:ss"))
                                                            .InColumnValue("end_date",
                                                                            utcEndDate.ToString("yyyy-MM-dd HH:mm:ss"))
                                                                            .InColumnValue("update_date", createDate.ToString("yyyy-MM-dd HH:mm:ss"))
                                                            .InColumnValue("all_day_long", isAllDayLong)
                                                            .InColumnValue("rrule", rrule.ToString())
                                                            .InColumnValue("alert_type", (int)alertType)
                                                            .InColumnValue("uid", GetEventUid(uid))
                                                            .InColumnValue("status", (int)status)
                                                            .InColumnValue("time_zone", timeZone?.Id)
                                                            .Identity(0, 0, true));

                foreach (var item in publicItems)
                {
                    db.ExecuteNonQuery(new SqlInsert("calendar_event_item")
                                                    .InColumnValue("event_id", eventId)
                                                    .InColumnValue("item_id", item.Id)
                                                    .InColumnValue("is_group", item.IsGroup));

                }

                //update notifications
                UpdateEventNotifications(eventId, calendarId, utcStartDate, alertType, rrule, publicItems, null, isAllDayLong, timeZone);

                tr.Commit();
            }

            return GetEventById(eventId);
        }

        public Event UpdateEvent(int eventId,
            int calendarId,
            Guid ownerId,
            string name,
            string description,
            DateTime utcStartDate,
            DateTime utcEndDate,
            RecurrenceRule rrule,
            EventAlertType alertType,
            bool isAllDayLong,
            List<SharingOptions.PublicItem> publicItems,
            EventStatus status,
            DateTime createDate,
            TimeZoneInfo timeZone
            )
        {
            using (var tr = db.BeginTransaction())
            {
                var query = new SqlUpdate("calendar_events")
                    .Set("name", name)
                    .Set("description", description)
                    .Set("calendar_id", calendarId)
                    .Set("owner_id", ownerId)
                    .Set("start_date", utcStartDate.ToString("yyyy-MM-dd HH:mm:ss"))
                    .Set("end_date", utcEndDate.ToString("yyyy-MM-dd HH:mm:ss"))
                    .Set("update_date", createDate.ToString("yyyy-MM-dd HH:mm:ss"))
                    .Set("all_day_long", isAllDayLong)
                    .Set("rrule", rrule.ToString())
                    .Set("status", (int)status)
                    .Set("time_zone", timeZone?.Id)
                    .Where(Exp.Eq("id", eventId));

                if (ownerId.Equals(SecurityContext.CurrentAccount.ID))
                    query = query.Set("alert_type", (int)alertType);
                else
                    db.ExecuteNonQuery(new SqlInsert("calendar_event_user", true)
                                                    .InColumnValue("event_id", eventId)
                                                    .InColumnValue("user_id", SecurityContext.CurrentAccount.ID)
                                                    .InColumnValue("alert_type", alertType));


                db.ExecuteNonQuery(query);

                var userIds = db.ExecuteList(new SqlQuery("calendar_event_user")
                                                        .Select("user_id")
                                                        .Where("event_id", eventId))
                                        .Select(r => new Guid(Convert.ToString(r[0])));

                foreach (var usrId in userIds)
                {
                    if (!publicItems.Exists(i => (i.IsGroup && CoreContext.UserManager.IsUserInGroup(usrId, i.Id))
                                                    || (!i.IsGroup && i.Id.Equals(usrId))))
                    {
                        db.ExecuteNonQuery(new SqlDelete("calendar_event_user")
                                                        .Where(Exp.Eq("user_id", usrId) & Exp.Eq("event_id", eventId)));
                    }
                }

                db.ExecuteNonQuery(new SqlDelete("calendar_event_item").Where("event_id", eventId));
                foreach (var item in publicItems)
                {
                    db.ExecuteNonQuery(new SqlInsert("calendar_event_item")
                                                    .InColumnValue("event_id", eventId)
                                                    .InColumnValue("item_id", item.Id)
                                                    .InColumnValue("is_group", item.IsGroup));


                }

                //update notifications
                var baseAlertType =
                    db.ExecuteList(new SqlQuery("calendar_events").Select("alert_type").Where("id", eventId))
                                .Select(r => (EventAlertType)Convert.ToInt32(r[0])).First();
                UpdateEventNotifications(eventId, calendarId, utcStartDate, baseAlertType, rrule, publicItems, null, isAllDayLong, timeZone);


                tr.Commit();
            }

            return GetEventById(eventId);
        }



        public EventHistory GetEventHistory(string eventUid)
        {
            var sql = new SqlQuery("calendar_event_history h")
                .Select("h.calendar_id")
                .Select("h.event_uid")
                .Select("h.event_id")
                .Select("h.ics")
                .InnerJoin("calendar_events e", Exp.EqColumns("e.uid", "h.event_uid") & Exp.EqColumns("e.tenant", "h.tenant"))
                .InnerJoin("calendar_calendars c", Exp.EqColumns("c.id", "h.calendar_id") & Exp.EqColumns("c.tenant", "h.tenant"))
                .Where("h.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where("h.event_uid", eventUid)
                .Where("e.owner_id", SecurityContext.CurrentAccount.ID)
                .Where("c.owner_id", SecurityContext.CurrentAccount.ID)
                .Where("c.ical_url", null);

            var items = db.ExecuteList(sql).ConvertAll(ToEventHistory);

            return items.Count > 0 ? items[0] : null;
        }

        public List<EventHistory> GetEventsHistory(int[] eventIds)
        {
            var sql = new SqlQuery("calendar_event_history")
                .Select("calendar_id")
                .Select("event_uid")
                .Select("event_id")
                .Select("ics")
                .Where("tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where(Exp.In("event_id", eventIds));

            return db.ExecuteList(sql).ConvertAll(ToEventHistory);
        }

        public EventHistory GetEventHistory(int eventId)
        {
            var items = GetEventsHistory(new[] { eventId });
            return items.Count > 0 ? items[0] : null;
        }

        public EventHistory AddEventHistory(int calendarId, string eventUid, int eventId, string ics)
        {
            var icsCalendars = DDayICalParser.DeserializeCalendar(ics);
            var icsCalendar = icsCalendars == null ? null : icsCalendars.FirstOrDefault();
            var icsEvents = icsCalendar == null ? null : icsCalendar.Events;
            var icsEvent = icsEvents == null ? null : icsEvents.FirstOrDefault();

            if (icsEvent == null) return null;

            EventHistory history;
            using (var tr = db.BeginTransaction())
            {
                ISqlInstruction sql;

                history = GetEventHistory(eventId);

                if (history == null)
                {
                    history = new EventHistory(calendarId, eventUid, eventId, ics);

                    sql = new SqlInsert("calendar_event_history")
                        .InColumnValue("tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                        .InColumnValue("calendar_id", calendarId)
                        .InColumnValue("event_uid", eventUid)
                        .InColumnValue("event_id", eventId)
                        .InColumnValue("ics", history.Ics);
                }
                else
                {
                    var exist = history.History
                                        .Where(x => x.Method == icsCalendar.Method)
                                        .Select(x => x.Events.FirstOrDefault())
                                        .Any(x => x.Uid == icsEvent.Uid &&
                                                    x.Sequence == icsEvent.Sequence &&
                                                    DDayICalParser.ToUtc(x.DtStamp) == DDayICalParser.ToUtc(icsEvent.DtStamp));

                    if (exist) return history;

                    history.Ics = history.Ics + Environment.NewLine + ics;

                    sql = new SqlUpdate("calendar_event_history")
                        .Set("ics", history.Ics)
                        .Where("tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                        .Where("calendar_id", calendarId)
                        .Where("event_uid", eventUid);
                }

                db.ExecuteNonQuery(sql);

                tr.Commit();
            }

            return history;
        }

        public void RemoveEventHistory(int calendarId, string eventUid)
        {
            var sql = new SqlDelete("calendar_event_history")
                .Where("tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where("calendar_id", calendarId)
                .Where("event_uid", eventUid);

            db.ExecuteNonQuery(sql);
        }

        public void RemoveEventHistory(int eventId)
        {
            var sql = new SqlDelete("calendar_event_history")
                .Where("tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where("event_id", eventId);

            db.ExecuteNonQuery(sql);
        }

        private static EventHistory ToEventHistory(object[] row)
        {
            return new EventHistory(Convert.ToInt32(row[0]),
                                    Convert.ToString(row[1]),
                                    Convert.ToInt32(row[2]),
                                    Convert.ToString(row[3]));
        }

        public static string GetEventUid(string uid, string id = null)
        {
            if (!string.IsNullOrEmpty(uid))
                return uid;

            return string.Format("{<EMAIL>", string.IsNullOrEmpty(id) ? Guid.NewGuid().ToString() : id);

        }

        #region Event Notifications

        internal static int GetBeforeMinutes(EventAlertType eventAlertType)
        {
            switch (eventAlertType)
            {
                case EventAlertType.Day:
                    return -24 * 60;
                case EventAlertType.FifteenMinutes:
                    return -15;
                case EventAlertType.FiveMinutes:
                    return -5;
                case EventAlertType.HalfHour:
                    return -30;
                case EventAlertType.Hour:
                    return -60;
                case EventAlertType.TwoHours:
                    return -120;
            }

            return 0;
        }

        private DateTime GetNextAlertDate(DateTime utcStartDate, RecurrenceRule rrule, EventAlertType eventAlertType, TimeZoneInfo timeZone, bool isAllDayLong, TimeZoneInfo eventTimeZone)
        {
            if (eventAlertType == EventAlertType.Never)
                return DateTime.MinValue;

            var offset = timeZone.GetOffset();
            var localFromDate = DateTime.UtcNow.Add(offset);
            var localStartDate = isAllDayLong ? utcStartDate : utcStartDate.Add(offset);
            var dates = rrule.GetDates(localStartDate, eventTimeZone, isAllDayLong, localFromDate, 3);
            for (var i = 0; i < dates.Count; i++)
            {
                dates[i] = dates[i].Subtract(offset);
            }

            foreach (var d in dates)
            {
                var dd = d.AddMinutes(GetBeforeMinutes(eventAlertType));
                if (dd > DateTime.UtcNow)
                    return dd;
            }

            return DateTime.MinValue;
        }

        private class UserAlertType
        {
            public Guid UserId { get; set; }
            public EventAlertType AlertType { get; set; }
            public EventAlertType AlertTypeCalendar { get; set; }
            public TimeZoneInfo TimeZone { get; set; }


            public UserAlertType(Guid userId, EventAlertType alertType, TimeZoneInfo timeZone)
            {
                UserId = userId;
                AlertType = alertType;
                TimeZone = timeZone;
            }

            public UserAlertType(Guid userId, EventAlertType alertType, TimeZoneInfo timeZone, EventAlertType alertTypeCalendar)
            {
                UserId = userId;
                AlertType = alertType;
                AlertTypeCalendar = alertTypeCalendar;
                TimeZone = timeZone;
            }
        }

        private void UpdateEventNotifications(int eventId, int calendarId, DateTime eventUtcStartDate, EventAlertType baseEventAlertType, RecurrenceRule rrule,
            IEnumerable<SharingOptions.PublicItem> eventPublicItems,
            IEnumerable<SharingOptions.PublicItem> calendarPublicItems,
            bool isAllDayLong, TimeZoneInfo eventTimeZone, IDbManager dbManager = null)
        {

            dbManager = dbManager == null ? db : dbManager;
            var cc = new ColumnCollection();
            var userIdCol = cc.RegistryColumn("user_id");
            var alertTypeCol = cc.RegistryColumn("alert_type");
            var isUnsubscribeCol = cc.RegistryColumn("is_unsubscribe");

            var eventUsersData = dbManager.ExecuteList(new SqlQuery("calendar_event_user").Select(cc.SelectQuery).Where(Exp.Eq("event_id", eventId)));

            var calendarData = dbManager.ExecuteList(new SqlQuery("calendar_calendars").Select("alert_type", "owner_id", "time_zone").Where(Exp.Eq("id", calendarId)));
            var calendarAlertType = calendarData.Select(r => (EventAlertType)Convert.ToInt32(r[0])).First();
            var calendarOwner = calendarData.Select(r => new Guid(Convert.ToString(r[1]))).First();
            var calendarTimeZone = calendarData.Select(r => TimeZoneConverter.GetTimeZone(Convert.ToString(r[2]))).First();

            var eventUsers = new List<UserAlertType>();

            #region shared event's data

            if (eventPublicItems == null)
            {
                eventPublicItems = new List<SharingOptions.PublicItem>(dbManager.ExecuteList(new SqlQuery("calendar_event_item").Select("item_id", "is_group").Where(Exp.Eq("event_id", eventId)))
                                                                        .Select(r => new SharingOptions.PublicItem { Id = new Guid(Convert.ToString(r[0])), IsGroup = Convert.ToBoolean(r[1]) }));
            }

            foreach (var item in eventPublicItems)
            {
                if (item.IsGroup)
                    eventUsers.AddRange(CoreContext.UserManager.GetUsersByGroup(item.Id).Select(u => new UserAlertType(u.ID, baseEventAlertType, calendarTimeZone)));
                else
                    eventUsers.Add(new UserAlertType(item.Id, baseEventAlertType, calendarTimeZone));
            }

            //remove calendar owner
            eventUsers.RemoveAll(u => u.UserId.Equals(calendarOwner));

            //remove unsubscribed and exec personal alert_type
            if (eventUsers.Count > 0)
            {
                foreach (var r in eventUsersData)
                {
                    if (isUnsubscribeCol.Parse<bool>(r))
                        eventUsers.RemoveAll(u => u.UserId.Equals(userIdCol.Parse<Guid>(r)));
                    else
                        eventUsers.ForEach(u =>
                        {
                            if (u.UserId.Equals(userIdCol.Parse<Guid>(r)))
                                u.AlertType = (EventAlertType)alertTypeCol.Parse<int>(r);
                        });

                }
            }

            //remove and exec sharing calendar options
            if (eventUsers.Count > 0)
            {
                var extCalendarAlertTypes = dbManager.ExecuteList(new SqlQuery("calendar_calendar_user cu")
                                                        .Select("cu.user_id", "cu.alert_type", "cu.is_accepted", "cu.time_zone")
                                                        .Where(Exp.Eq("cu.ext_calendar_id", SharedEventsCalendar.CalendarId) & Exp.In("cu.user_id", eventUsers.Select(u => u.UserId).ToArray())));

                foreach (var r in extCalendarAlertTypes)
                {
                    if (!Convert.ToBoolean(r[2]))
                    {
                        //remove unsubscribed from shared events calendar
                        eventUsers.RemoveAll(u => u.UserId.Equals(new Guid(Convert.ToString(r[0]))));
                        continue;
                    }
                    eventUsers.ForEach(u =>
                    {
                        if (u.UserId.Equals(new Guid(Convert.ToString(r[0]))))
                            u.TimeZone = ((r[3] == null || r[3] == DBNull.Value) ? calendarTimeZone : TimeZoneConverter.GetTimeZone(Convert.ToString(r[3])));

                        if (u.AlertType == EventAlertType.Default && u.UserId.Equals(new Guid(Convert.ToString(r[0]))))
                            u.AlertType = (EventAlertType)Convert.ToInt32(r[1]);
                    });
                }

                eventUsers.ForEach(u =>
                {
                    if (u.AlertType == EventAlertType.Default)
                        u.AlertType = EventAlertType.Hour;
                });

            }
            #endregion

            #region calendar's data

            if (calendarPublicItems == null)
            {
                calendarPublicItems = new List<SharingOptions.PublicItem>(dbManager.ExecuteList(new SqlQuery("calendar_calendar_item").Select("item_id", "is_group").Where(Exp.Eq("calendar_id", calendarId)))
                                                                        .Select(r => new SharingOptions.PublicItem { Id = new Guid(Convert.ToString(r[0])), IsGroup = Convert.ToBoolean(r[1]) }));
            }

            //calendar users
            var calendarUsers = new List<UserAlertType>();
            foreach (var item in eventPublicItems)
            {
                if (item.IsGroup)
                    calendarUsers.AddRange(CoreContext.UserManager.GetUsersByGroup(item.Id).Select(u => new UserAlertType(u.ID, baseEventAlertType, calendarTimeZone)));
                else
                    calendarUsers.Add(new UserAlertType(item.Id, baseEventAlertType, calendarTimeZone));
            }

            calendarUsers.Add(new UserAlertType(calendarOwner, baseEventAlertType, calendarTimeZone, calendarAlertType));

            var users = dbManager.ExecuteList(new SqlQuery(_calendarUserTable).Select("cal_usr.user_id", "cal_usr.alert_type")
                                                        .Where(Exp.Eq("cal_usr.calendar_id", calendarId))
                                                        .Where(!Exp.Eq("cal_usr.user_id", calendarOwner)))
                                                        .Select(r => new UserAlertType(new Guid(Convert.ToString(r[0])), baseEventAlertType, calendarTimeZone, (EventAlertType)Convert.ToInt32(r[1]))).ToList();
            calendarUsers = calendarUsers.Concat(users).ToList();

            //remove event's users
            calendarUsers.RemoveAll(u => eventUsers.Exists(eu => eu.UserId.Equals(u.UserId)));

            //calendar options            
            if (calendarUsers.Count > 0)
            {
                //set personal alert_type
                foreach (var r in eventUsersData)
                {
                    eventUsers.ForEach(u =>
                    {
                        if (u.UserId.Equals(new Guid(Convert.ToString(r[0]))))
                            u.AlertType = (EventAlertType)(Convert.ToInt32(r[1]));
                    });

                }

                var calendarAlertTypes = dbManager.ExecuteList(new SqlQuery("calendar_calendar_user")
                                                        .Select("user_id", "alert_type", "is_accepted", "time_zone")
                                                        .Where(Exp.Eq("calendar_id", calendarId) & Exp.In("user_id", calendarUsers.Select(u => u.UserId).ToArray())));

                foreach (var r in calendarAlertTypes)
                {
                    if (!Convert.ToBoolean(r[2]))
                    {
                        //remove unsubscribed
                        calendarUsers.RemoveAll(u => u.UserId.Equals(new Guid(Convert.ToString(r[0]))));
                        continue;
                    }
                    calendarUsers.ForEach(u =>
                    {
                        if (u.UserId.Equals(new Guid(Convert.ToString(r[0]))))
                            u.TimeZone = ((r[3] == null || r[3] == DBNull.Value) ? calendarTimeZone : TimeZoneConverter.GetTimeZone(Convert.ToString(r[3])));

                        if (u.AlertType == EventAlertType.Default && u.UserId.Equals(new Guid(Convert.ToString(r[0]))))
                            u.AlertType = (EventAlertType)Convert.ToInt32(r[1]);
                    });
                }

                calendarUsers.ForEach(u =>
                {
                    if (u.AlertType == EventAlertType.Default)
                        u.AlertType = u.AlertTypeCalendar;
                });
            }

            #endregion


            //clear notifications
            dbManager.ExecuteNonQuery(new SqlDelete("calendar_notifications").Where("event_id", eventId));

            eventUsers.AddRange(calendarUsers);

            foreach (var u in eventUsers)
            {
                //todo: recount
                var alertDate = GetNextAlertDate(eventUtcStartDate, rrule, u.AlertType, u.TimeZone, isAllDayLong, eventTimeZone ?? u.TimeZone);
                if (!alertDate.Equals(DateTime.MinValue))
                {
                    dbManager.ExecuteNonQuery(new SqlInsert("calendar_notifications", true).InColumnValue("user_id", u.UserId)
                                                                                        .InColumnValue("event_id", eventId)
                                                                                        .InColumnValue("rrule", rrule.ToString())
                                                                                        .InColumnValue("alert_type", (int)u.AlertType)
                                                                                        .InColumnValue("tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                                                                                        .InColumnValue("notify_date", alertDate)
                                                                                        .InColumnValue("time_zone", u.TimeZone.Id));
                }
            }
        }

        public List<EventNotificationData> ExtractAndRecountNotifications(DateTime utcDate)
        {
            List<EventNotificationData> data;
            using (var tr = db.BeginTransaction())
            {
                var cc = new ColumnCollection();
                var userIdCol = cc.RegistryColumn("user_id");
                var tenantCol = cc.RegistryColumn("tenant");
                var eventIdCol = cc.RegistryColumn("event_id");
                var notifyDateCol = cc.RegistryColumn("notify_date");
                var rruleCol = cc.RegistryColumn("rrule");
                var alertTypeCol = cc.RegistryColumn("alert_type");
                var timeZoneCol = cc.RegistryColumn("time_zone");

                data = new List<EventNotificationData>(db.ExecuteList(new SqlQuery("calendar_notifications").Select(cc.SelectQuery)
                                        .Where(Exp.Le(notifyDateCol.Name, utcDate)))
                                        .Select(r => new EventNotificationData
                                        {
                                            UserId = userIdCol.Parse<Guid>(r),
                                            TenantId = tenantCol.Parse<int>(r),
                                            EventId = eventIdCol.Parse<int>(r),
                                            NotifyUtcDate = notifyDateCol.Parse<DateTime>(r),
                                            RRule = rruleCol.Parse<RecurrenceRule>(r),
                                            AlertType = (EventAlertType)alertTypeCol.Parse<int>(r),
                                            TimeZone = timeZoneCol.Parse<TimeZoneInfo>(r)
                                        }));


                var events = GetEventsByIds(data.Select(d => (object)d.EventId).Distinct().ToArray(), Guid.Empty);
                data.ForEach(d => d.Event = events.Find(e => String.Equals(e.Id, d.EventId.ToString(CultureInfo.InvariantCulture), StringComparison.InvariantCultureIgnoreCase)));

                foreach (var d in data)
                {
                    if (d.RRule.Freq == Frequency.Never)
                        db.ExecuteNonQuery(new SqlDelete("calendar_notifications").Where(Exp.Eq("user_id", d.UserId) & Exp.Eq("event_id", d.EventId)));
                    else
                    {
                        var alertDate = GetNextAlertDate(d.Event.UtcStartDate, d.RRule, d.AlertType, d.TimeZone, d.Event.AllDayLong, d.Event.TimeZone ?? d.TimeZone);
                        if (!alertDate.Equals(DateTime.MinValue))
                        {
                            db.ExecuteNonQuery(new SqlInsert("calendar_notifications", true).InColumnValue("user_id", d.UserId)
                                                                                                .InColumnValue("event_id", d.EventId)
                                                                                                .InColumnValue("rrule", d.RRule.ToString())
                                                                                                .InColumnValue("alert_type", (int)d.AlertType)
                                                                                                .InColumnValue("tenant", d.TenantId)
                                                                                                .InColumnValue("notify_date", alertDate)
                                                                                                .InColumnValue("time_zone", d.TimeZone.Id));
                        }
                        else
                            db.ExecuteNonQuery(new SqlDelete("calendar_notifications").Where(Exp.Eq("user_id", d.UserId) & Exp.Eq("event_id", d.EventId)));
                    }
                }

                tr.Commit();
            }

            return data;
        }

        #endregion

        public void Dispose()
        {
            if (HttpContext.Current == null && db != null)
            {
                db.Dispose();
            }
        }
    }
}


<|start_filename|>module/ASC.UrlShortener/app/urlShortener.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/*
 * ShortURL (https://github.com/delight-im/ShortURL)
 * Copyright (c) delight.im (https://www.delight.im/)
 * Licensed under the MIT License (https://opensource.org/licenses/MIT)
 */

/**
 * ShortURL: Bijective conversion between natural numbers (IDs) and short strings
 *
 * ShortURL.encode() takes an ID and turns it into a short string
 * ShortURL.decode() takes a short string and turns it into an ID
 *
 * Features:
 * + large alphabet (51 chars) and thus very short resulting strings
 * + proof against offensive words (removed 'a', 'e', 'i', 'o' and 'u')
 * + unambiguous (removed 'I', 'l', '1', 'O' and '0')
 *
 * Example output:
 * 123456789 <=> pgK8p
 */

 //'23456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ-_'

var _alphabet = "<KEY>",
	_base = _alphabet.length,
	_initial = _base * _base;

module.exports = {

	encode: function(num) {
		num += _initial;
		var str = '';
		while (num > 0) {
			str = _alphabet.charAt(num % _base) + str;
			num = Math.floor(num / _base);
		}
		return str;
	},

	decode: function(str) {
		var num = 0;
		for (var i = 0; i < str.length; i++) {
            let index = _alphabet.indexOf(str.charAt(i));
            if (index < 0) return null;
			num = num * _base + index;
		}
		return num - _initial;
    }

};

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/App_Themes/default/css/filetype_style.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.ftUnknown, .ftArchive, .ftVideo, .ftAudio, .ftImage, .ftSpreadsheet, .ftPresentation, .ftDocument
{
	background-position: 7px center !important;
	background-repeat:no-repeat;
}

.ftUnknown
{
	background-image:url('../images/filetype/file_na.png');
}
.ftArchive
{
	background-image:url('../images/filetype/file_zip.png');
}
.ftVideo
{
	background-image:url('../images/filetype/file_mpg.png');
}
.ftAudio
{
	background-image:url('../images/filetype/file_sound.png');
}
.ftImage
{
	background-image:url('../images/filetype/file_image.png');
}
.ftSpreadsheet
{
	background-image:url('../images/filetype/file_xls.png');
}
.ftPresentation
{
	background-image:url('../images/filetype/file_ppt.png');
}
.ftDocument
{
	background-image:url('../images/filetype/file_txt.png');
}

<|start_filename|>common/ASC.Core.Common/Notify/NotifySource.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;

using ASC.Notify;
using ASC.Notify.Model;
using ASC.Notify.Patterns;
using ASC.Notify.Recipients;

namespace ASC.Core.Notify
{
    public abstract class NotifySource : INotifySource
    {
        private readonly object syncRoot = new object();
        private bool initialized;

        private readonly IDictionary<CultureInfo, IActionProvider> actions = new Dictionary<CultureInfo, IActionProvider>();

        private readonly IDictionary<CultureInfo, IPatternProvider> patterns = new Dictionary<CultureInfo, IPatternProvider>();


        protected ISubscriptionProvider SubscriprionProvider;

        protected IRecipientProvider RecipientsProvider;


        protected IActionProvider ActionProvider
        {
            get { return GetActionProvider(); }
        }

        protected IPatternProvider PatternProvider
        {
            get { return GetPatternProvider(); }
        }


        public string ID
        {
            get;
            private set;
        }


        public NotifySource(string id)
        {
            if (string.IsNullOrEmpty(id)) throw new ArgumentNullException("id");

            ID = id;
        }

        public NotifySource(Guid id)
            : this(id.ToString())
        {
        }

        public IActionProvider GetActionProvider()
        {
            lock (actions)
            {
                var culture = Thread.CurrentThread.CurrentCulture;
                if (!actions.ContainsKey(culture))
                {
                    actions[culture] = CreateActionProvider();
                }
                return actions[culture];
            }
        }

        public IPatternProvider GetPatternProvider()
        {
            lock (patterns)
            {
                var culture = Thread.CurrentThread.CurrentCulture;
                if (Thread.CurrentThread.CurrentUICulture != culture)
                {
                    Thread.CurrentThread.CurrentUICulture = culture;
                }
                if (!patterns.ContainsKey(culture))
                {
                    patterns[culture] = CreatePatternsProvider();
                }
                return patterns[culture];
            }
        }

        public IRecipientProvider GetRecipientsProvider()
        {
            LazyInitializeProviders();
            return RecipientsProvider;
        }

        public ISubscriptionProvider GetSubscriptionProvider()
        {
            LazyInitializeProviders();
            return SubscriprionProvider;
        }

        protected void LazyInitializeProviders()
        {
            if (!initialized)
            {
                lock (syncRoot)
                {
                    if (!initialized)
                    {
                        RecipientsProvider = CreateRecipientsProvider();
                        if (RecipientsProvider == null)
                        {
                            throw new NotifyException(String.Format("Provider {0} not instanced.", "IRecipientsProvider"));
                        }

                        SubscriprionProvider = CreateSubscriptionProvider();
                        if (SubscriprionProvider == null)
                        {
                            throw new NotifyException(String.Format("Provider {0} not instanced.", "ISubscriprionProvider"));
                        }

                        initialized = true;
                    }
                }
            }
        }


        protected abstract IPatternProvider CreatePatternsProvider();

        protected abstract IActionProvider CreateActionProvider();


        protected virtual ISubscriptionProvider CreateSubscriptionProvider()
        {
            var subscriptionProvider = new DirectSubscriptionProvider(ID, CoreContext.SubscriptionManager, RecipientsProvider);
            return new TopSubscriptionProvider(RecipientsProvider, subscriptionProvider, WorkContext.DefaultClientSenders);
        }

        protected virtual IRecipientProvider CreateRecipientsProvider()
        {
            return new RecipientProviderImpl();
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/Common/Presentation/BookmarkInfoBase.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Bookmarking;
using ASC.Bookmarking.Business.Permissions;
using ASC.Bookmarking.Common;
using ASC.Bookmarking.Pojo;
using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Community.Modules.Bookmarking.UserControls.Resources;
using ASC.Web.Core.Helpers;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.UserControls.Bookmarking.Common.Util;

namespace ASC.Web.UserControls.Bookmarking.Common.Presentation
{
    public abstract class BookmarkInfoBase : System.Web.UI.UserControl
    {
        #region Fields

        protected void Page_Load(object sender, EventArgs e)
        {
            InitUserControl();
        }

        public abstract void InitUserControl();

        protected BookmarkingServiceHelper ServiceHelper = BookmarkingServiceHelper.GetCurrentInstanse();

        #endregion

        #region Bookmark Fields

        public Bookmark Bookmark { get; set; }

        public UserBookmark UserBookmark { get; set; }

        public string Description
        {
            get { return Bookmark.Description.ReplaceSingleQuote(); }
        }

        public string URL
        {
            get { return Bookmark.URL; }
        }

        public string Name
        {
            get { return Bookmark.Name.ReplaceSingleQuote(); }
        }

        public long Raiting
        {
            get { return ServiceHelper.GetUserBookmarksCount(Bookmark); }
        }

        public string TagsString
        {
            get { return BookmarkingServiceHelper.ConvertBookmarkToTagsString(Bookmark).ReplaceSingleQuote(); }
        }

        public DateTime Date
        {
            get { return Bookmark.Date; }
        }

        public long GetBookmarkID()
        {
            return Bookmark == null ? 0 : Bookmark.ID;
        }

        public string UserBookmarkDescription
        {
            get
            {
                return UserBookmark == null
                           ? Description
                           : UserBookmark.Description.ReplaceSingleQuote();
            }
        }

        public bool HasDescription()
        {
            return !string.IsNullOrEmpty(UserBookmarkDescription);
        }

        public string UserBookmarkName
        {
            get
            {
                return UserBookmark == null
                           ? Name
                           : UserBookmark.Name.ReplaceSingleQuote();
            }
        }

        public string UserTagsString { get; set; }

        public DateTime UserDate
        {
            get
            {
                return UserBookmark == null
                           ? Date
                           : UserBookmark.DateAdded;
            }
        }

        public bool IsTagsIncluded()
        {
            if (Bookmark != null)
            {
                var tags = Bookmark.Tags;
                if (tags != null && tags.Count > 0)
                {
                    return true;
                }
            }
            return false;
        }

        public bool IsCurrentUserBookmark()
        {
            return ServiceHelper.IsCurrentUserBookmark(Bookmark);
        }

        public string GetThumbnailUrl()
        {
            return BookmarkingServiceHelper.GetThumbnailUrl(URL);
        }

        public string GetMediumThumbnailUrl()
        {
            return BookmarkingServiceHelper.GetMediumThumbnailUrl(URL);
        }

        public string GetTagsWebPath()
        {
            return WebImageSupplier.GetAbsoluteWebPath(BookmarkingRequestConstants.TagsImageName, BookmarkingSettings.ModuleId);
        }

        public string GetSearchByTagUrl(object bookmarkTagName)
        {
            var name = bookmarkTagName as string;
            return ServiceHelper.GetSearchByTagUrl(name);
        }

        public string GetBookmarkInfoUrlAddedByTab()
        {
            var url = string.Format("{0}&{1}={2}",
                                    BookmarkingServiceHelper.GenerateBookmarkInfoUrl(URL),
                                    BookmarkingRequestConstants.SelectedTab,
                                    BookmarkingRequestConstants.SelectedTabBookmarkAddedBy
                );
            return url;
        }

        public string GetBookmarkInfoUrl()
        {
            return BookmarkingServiceHelper.GenerateBookmarkInfoUrl(URL);
        }

        public string GetBookmarkRaiting()
        {
            return new BookmarkRaitingUserControl().GetBookmarkRaiting(Bookmark, GetUniqueId().ToString(), GetSingleBookmarkID());
        }

        public string GetUserBookmarkRaiting()
        {
            return new BookmarkRaitingUserControl().GetBookmarkRaiting(Bookmark, UserBookmark, GetUniqueId().ToString(), GetSingleBookmarkID());
        }

        public string GetSingleBookmarkID()
        {
            return GetUniqueId() + "SingleBookmark";
        }

        #endregion

        #region User Info

        public bool ShowAddedByUserInfo
        {
            get
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                switch (displayMode)
                {
                    case BookmarkDisplayMode.AllBookmarks:
                        return true;
                    case BookmarkDisplayMode.SelectedBookmark:
                        return true;
                }
                return false;
            }
        }

        public string RenderProfileLink()
        {
            return RenderProfileLink(GetBookmarkCreator());
        }

        public string RenderProfileLink(UserInfo userInfo)
        {
            try
            {
                return userInfo.RenderCustomProfileLink("describe-text", "link gray");
            }
            catch
            {
                return string.Empty;
            }
        }

        public string RenderProfileLink(Object userID)
        {
            var user = GetUserInfoByUserID(userID);
            return RenderProfileLink(user);
        }

        public string GetBookmarkCreatorImageUrl()
        {
            return GetImageUrl(GetBookmarkCreator());
        }

        private static string GetImageUrl(UserInfo userInfo)
        {
            try
            {
                return userInfo.GetMediumPhotoURL();
            }
            catch
            {
                return string.Empty;
            }
        }

        protected UserInfo GetBookmarkCreator()
        {
            return Bookmark == null
                       ? null
                       : CoreContext.UserManager.GetUsers(Bookmark.UserCreatorID);
        }

        public string GetUserImageUrl(object userID)
        {
            var user = GetUserInfoByUserID(userID);
            return GetImageUrl(user);
        }

        public string GetUserImage(object userID)
        {
            var user = GetUserInfoByUserID(userID);
            return BookmarkingServiceHelper.GetHTMLUserAvatar(user.ID);
        }

        private static UserInfo GetUserInfoByUserID(object userID)
        {
            try
            {
                var id = (Guid)userID;
                return CoreContext.UserManager.GetUsers(id);
            }
            catch
            {
                return null;
            }
        }

        #endregion

        #region Uuid

        private Guid _uniqueId;

        public Guid UniqueId
        {
            get
            {
                if (Guid.Empty.Equals(_uniqueId))
                {
                    _uniqueId = Guid.NewGuid();
                }
                return _uniqueId;
            }
            set { _uniqueId = value; }
        }

        /// <summary>
        /// Return unique id, which will be upted for every instance.
        /// Calling this method for the same instance will return the same result.
        /// </summary>
        /// <returns></returns>
        public Guid GetUniqueId()
        {
            return UniqueId;
        }

        #endregion

        #region Added By Info

        public string GetDateAddedAsString(object date)
        {
            try
            {
                var dateAdded = (DateTime)date;
                return BookmarkingConverter.GetDateAsString(dateAdded);
            }
            catch
            {
                return string.Empty;
            }
        }

        public string GetDateAddedAsString()
        {
            try
            {
                return Date.ToShortTimeString() + " " + Date.ToShortDateString();
            }
            catch
            {
                return string.Empty;
            }
        }

        public long CommentsCount
        {
            get
            {
                return Bookmark != null
                           ? ServiceHelper.GetCommentsCount(Bookmark)
                           : 0;
            }
        }

        public string CommentString
        {
            get
            {
                var commentsCount = CommentsCount;
                if (commentsCount == 0)
                {
                    return string.Empty;
                }
                var comments = GrammaticalHelper.ChooseNumeralCase((int)commentsCount,
                                                                   BookmarkingUCResource.CommentsNominative,
                                                                   BookmarkingUCResource.CommentsGenitiveSingular,
                                                                   BookmarkingUCResource.CommentsGenitivePlural);

                return String.Format("{0} {1}", commentsCount, comments);
            }
        }

        public string GetUserPageLink(object userID)
        {
            return BookmarkingServiceHelper.GetUserPageLink(new Guid(userID.ToString()));
        }

        #endregion

        #region Display Mode

        public bool IsAllBookmarksMode()
        {
            var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

            return BookmarkDisplayMode.AllBookmarks == displayMode;
        }

        public bool IsBookmarkInfoMode
        {
            get
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                return BookmarkDisplayMode.SelectedBookmark == displayMode;
            }
        }

        public string FavouriteBookmarksMode
        {
            get
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                return (BookmarkDisplayMode.Favourites == displayMode).ToString().ToLower();
            }
        }

        #endregion

        #region Permissions Check

        public static bool PermissionCheckAddToFavourite()
        {
            return BookmarkingPermissionsCheck.PermissionCheckAddToFavourite();
        }

        public bool PermissionCheckRemoveFromFavourite()
        {
            return UserBookmark != null && BookmarkingPermissionsCheck.PermissionCheckRemoveFromFavourite(UserBookmark);
        }

        #endregion

        public string GetUniqueIDFromSingleBookmark(string SingleBookmarkDivID)
        {
            if (!string.IsNullOrEmpty(SingleBookmarkDivID))
            {
                var a = SingleBookmarkDivID.Split(new string[] { "SingleBookmark" }, StringSplitOptions.None);
                if (a.Length == 2)
                {
                    return a[0];
                }
            }
            return Guid.NewGuid().ToString();
        }

        public string GetRandomGuid()
        {
            return Guid.NewGuid().ToString();
        }

        public string GetUserBookmarkDescriptionIfChanged(object o)
        {
            try
            {
                if (o is UserBookmark)
                {
                    var ub = o as UserBookmark;
                    return Bookmark != null
                               ? BookmarkingServiceHelper.GetUserBookmarkDescriptionIfChanged(Bookmark, ub)
                               : BookmarkingServiceHelper.GetUserBookmarkDescriptionIfChanged(ub);
                }
            }
            catch
            {
            }
            return string.Empty;
        }
    }
}

<|start_filename|>module/ASC.UrlShortener/app/sqlConsts.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = {
    exists: "SELECT short,id FROM short_links WHERE link = ?",
    insert: "INSERT INTO short_links SET link = ?",
    update: "UPDATE short_links SET short = ? WHERE id = ?",
    find: "SELECT link FROM short_links WHERE id = ?",
};

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/userfolders/dropdown.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.userFoldersDropdown = (function($) {
    var popup,
        popupId = "#selectUserFolderDropdown",
        container,
        showButton,
        isInit = false,
        idPrefix = "uf_dp_f_",
        idPrefixDefault = "uf_dp_def_",
        idRoot = "v_dp_root",
        rootChildren = null,
        isLoading = false,
        stateId = "jstreeUserFoldersDropdown",
        curOptions = null,
        selected = null,
        onCloseClaback = null;

    function init() {
        if (isInit === true) return;

        isInit = true;

        popup = $(popupId);

        container = $("#selectUserFolderDropdown .existsUserFolders")
            .on("loading.jstree",
                function (e) {
                    $(e.currentTarget).find(".jstree-anchor").text(ASC.Mail.Resources.MailResource.LoadingLabel);
                })
            .jstree({
                "plugins": ["wholerow", "state", "types", "themes"],
                'core': {
                    "animation": 0,
                    "check_callback": true,
                    "multiple": false,
                    "force_text": true,
                    'data': loadTree,
                    "keyboard": {
                        "f2": false
                    }
                },
                "themes": {
                    "theme": "default",
                    "dots": false,
                    "icons": true
                },
                "types": {
                    "inbox": {
                        "valid_children": ["none"],
                        "icon": "menu-item-icon inbox",
                        "max_depth": 1
                    },
                    "sent": {
                        "valid_children": ["none"],
                        "icon": "menu-item-icon sent",
                        "max_depth": 1
                    },
                    "draft": {
                        "valid_children": ["none"],
                        "icon": "menu-item-icon drafts",
                        "max_depth": 1
                    },
                    "template": {
                        "valid_children": ["none"],
                        "icon": "menu-item-icon templates",
                        "max_depth": 1
                    },
                    "spam": {
                        "valid_children": ["none"],
                        "icon": "menu-item-icon spam",
                        "max_depth": 1
                    },
                    "trash": {
                        "valid_children": ["none"],
                        "icon": "menu-item-icon trash",
                        "max_depth": 1
                    }
                },
                "state": { "key": stateId }
            });

        userFoldersManager.bind(userFoldersManager.events.OnCreate, onCreated);
        userFoldersManager.bind(userFoldersManager.events.OnUpdate, onEdited);
        userFoldersManager.bind(userFoldersManager.events.OnDelete, onDeleted);

        popup.keyup(function (e) {
                var movetoBtn = popup.find(".moveto_button").not(".disable");

                if (!movetoBtn || !e) return true;

                var code;

                if (e.keyCode)
                    code = e.keyCode;
                else if (e.which)
                    code = e.which;

                if (code === 13) {
                    movetoBtn.trigger("click");
                    return false;
                }

                return true;
            });
    }

    var rootNode = {
        id: idRoot,
        text: window.ASC.Mail.Resources.MailScriptResource.UserFolderNoSelected,
        icon: "",
        state: {
            opened: true,
            disabled: false,
            selected: true
        },
        children: false,
        a_attr: { "class": "noSelected" }
    };

    function loadTree(node, cb) {
        isLoading = true;

        userFoldersManager.loadTree(node.id === "#" ? 0 : node.id.replace(idPrefix, ""))
            .then(function(params, data) {
                    var result = data.map(function(v) {
                        var newNode = {
                            id: idPrefix + v.id,
                            parent: v.parent === 0 ? "#" : idPrefix + v.parent,
                            text: v.name,
                            icon: "",
                            state: {
                                opened: false,
                                disabled: false,
                                selected: false
                            },
                            a_attr: { href: "#userfolder={0}".format(v.id) },
                            children: v.folder_count > 0 ? true : false
                        };

                        if (curOptions) {
                            if (curOptions.disableDefaultId === newNode.id) {
                                newNode.state.disabled = true;
                            } else if (curOptions.disableUFolderId === newNode.id) {
                                newNode.state.disabled = true;
                            } else if (curOptions.hideDefaultId === newNode.id) {
                                newNode.state.hidden = true;
                            } else if (curOptions.hideUFolderId === newNode.id) {
                                newNode.state.hidden = true;
                            }else if (curOptions.hideChildrenId === newNode.parent) {
                                newNode.state.hidden = true;
                            }
                        }

                        return newNode;
                    });

                    if (node.id === "#") {
                        var defaultFolders = getDefaultFolders();
                        var folders = defaultFolders.concat(result);
                        rootNode.children = folders;
                        cb(rootNode);
                        isLoading = false;
                        return;
                    }

                    cb(result);

                    isLoading = false;
                },
                function(params, errors) {
                    console.error("Error", errors, arguments);
                    isLoading = false;
                });
    }

    function getDefaultFolders() {
        var folders = [
            {
                id: idPrefixDefault + TMMail.sysfolders.inbox.id,
                parent:"#",
                text: TMMail.sysfolders.inbox.displayName,
                type: "inbox",
                state: {
                    opened: false,
                    disabled: false,
                    selected: false
                },
                a_attr: { href: "#inbox" },
                children: false
            },
            {
                id: idPrefixDefault + TMMail.sysfolders.sent.id,
                parent: "#",
                text: TMMail.sysfolders.sent.displayName,
                type: "sent",
                state: {
                    opened: false,
                    disabled: false,
                    selected: false
                },
                a_attr: { href: "#sent" },
                children: false
            },
            {
                id: idPrefixDefault + TMMail.sysfolders.drafts.id,
                parent: "#",
                text: TMMail.sysfolders.drafts.displayName,
                type: "draft",
                state: {
                    opened: false,
                    disabled: false,
                    selected: false
                },
                a_attr: { href: "#drafts" },
                children: false
            },
            {
                id: idPrefixDefault + TMMail.sysfolders.templates.id,
                parent: "#",
                text: TMMail.sysfolders.templates.displayName,
                type: "template",
                state: {
                    opened: false,
                    disabled: false,
                    selected: false
                },
                children: false
            },
            {
                id: idPrefixDefault + TMMail.sysfolders.trash.id,
                parent: "#",
                text: TMMail.sysfolders.trash.displayName,
                type: "trash",
                state: {
                    opened: false,
                    disabled: false,
                    selected: false
                },
                a_attr: { href: "#trash" },
                children: false
            },
            {
                id: idPrefixDefault + TMMail.sysfolders.spam.id,
                parent: "#",
                text: TMMail.sysfolders.spam.displayName,
                type: "spam",
                state: {
                    opened: false,
                    disabled: false,
                    selected: false
                },
                a_attr: { href: "#spam" },
                children: false
            }
        ];

        return folders;
    }

    function filteredHide(event) {
        var elt = (event.target) ? event.target : event.srcElement;
        if (!($(elt).is(popupId + ' *') || $(elt).is(popupId))) {
            hide();
        }
    }

    function onScroll() {
        var offset = $(showButton).offset();
        popup.css({ left: offset.left, top: offset.top + 17 }).show();
    }

    function showRoot(needShow) {
        var treeData = container.jstree(true).get_json('#', { flat: false });
        var jsTree = container.jstree(true);

        var newData;

        if (!rootChildren) {
            rootChildren = treeData[0].children;
        }

        if (needShow) {
            rootNode.children = rootChildren;
            newData = rootNode;
        } else {
            newData = rootChildren;
        }

        jsTree.settings.core.data = newData;
        jsTree.refresh();
        jsTree.settings.core.data = loadTree;
    }

    function showDefaults(isShow) {
        var jstree = container.jstree(true);

        var folders = getDefaultFolders();
        var i, n = folders.length;
        for (i = 0; i < n; i++) {
            var id = folders[i].id;

            if (isShow) {
                jstree.show_node(id);
            } else {
                jstree.hide_node(id);
            }
        }
    }

    function hideId(id) {
        var jstree = container.jstree(true);
        jstree.hide_node(id);
    }

    function hideChildren(id) {
        var jstree = container.jstree(true);
        var children = jstree.get_node(id).children;
        jstree.hide_node(children);
    }

    function disableId(id) {
        var jstree = container.jstree(true);
        jstree.disable_node(id);
    }

    function prepareOptions(opts) {
        if (!opts || typeof opts !== "object")
            opts = {};

        var options = {};

        options.hideDefaults = typeof opts.hideDefaults === "undefined" ||
            opts.hideDefaults === null
            ? false
            : opts.hideDefaults;

        options.hideRoot = typeof opts.hideRoot === "undefined" || opts.hideRoot === null
            ? true
            : opts.hideRoot;

        options.hideDefaultId = typeof opts.hideDefaultId === "undefined" || opts.hideDefaultId === null
            ? null
            : idPrefixDefault + opts.hideDefaultId;

        options.hideUFolderId = typeof opts.hideUFolderId === "undefined" || opts.hideUFolderId === null
            ? null
            : idPrefix + opts.hideUFolderId;

        options.hideChildrenId = typeof opts.hideChildrenId === "undefined" || opts.hideChildrenId === null
            ? null
            : idPrefix + opts.hideChildrenId;

        options.disableDefaultId = typeof opts.disableDefaultId === "undefined" || opts.disableDefaultId === null
            ? null
            : idPrefixDefault + opts.disableDefaultId;

        options.disableUFolderId = typeof opts.disableUFolderId === "undefined" || opts.disableUFolderId === null
            ? null
            : idPrefix + opts.disableUFolderId;

        options.callback = typeof opts.callback === "undefined" || typeof opts.callback !== "function"
            ? function(e, folder) {
                console.log("Default callback has been called", folder);
            }
            : opts.callback;

        options.btnCaption = typeof opts.btnCaption === "undefined" || opts.btnCaption === null
            ? window.MailResource.MoveHere
            : opts.btnCaption;

        options.onClose = typeof opts.onClose === "undefined" || typeof opts.onClose !== "function"
            ? function() {
                console.log("Default onClose has been called");
            }
            : opts.onClose;

        return options;
    }

    function show(obj, opts) {
        if (isLoading || userFoldersManager.isLoading()) {
            setTimeout(function () { show(obj, opts); }, 100);
            return;
        }

        if ($(popupId + ':visible').length) {
            hide();
            return;
        }

        var options = prepareOptions(opts);

        curOptions = options;

        showRoot(!options.hideRoot);

        showDefaults(!options.hideDefaults);

        if (options.hideDefaultId) {
            hideId(options.hideDefaultId);
        }

        if (options.hideUFolderId) {
            hideId(options.hideUFolderId);
        }

        if (options.hideChildrenId) {
            hideChildren(options.hideChildrenId);
        }

        if (options.disableDefaultId) {
            disableId(options.disableDefaultId);
        }

        if (options.disableUFolderId) {
            disableId(options.disableUFolderId);
        }

        showButton = obj;
        var offset = $(showButton).offset();
        popup.css({ left: offset.left, top: offset.top + 17 }).show();

        dropdown.regHide(filteredHide);
        dropdown.regScroll(onScroll);

        selected = null;

        var movetoBtn = popup.find(".moveto_button");

        movetoBtn.text(options.btnCaption);
        movetoBtn.attr("title", options.btnCaption);

        movetoBtn.toggleClass('disable', true);

        movetoBtn.unbind("click").bind("click",
            function (e) {
                if ($(this).hasClass('disable') || !selected)
                    return;

                hide();
                options.callback.call(e, selected);
            });

        container.jstree(true).deselect_all();

        container
            .unbind("select_node.jstree")
            .bind("select_node.jstree", function (e, data) {
                movetoBtn.toggleClass('disable', false);

                if (!data.node.state.opened) {
                    data.instance.open_node(data.node);
                }

                var isUserFolder = data.node.id.indexOf(idPrefix) > -1;

                var id = data.node.id === idRoot
                    ? 0
                    : (isUserFolder
                        ? data.node.id.replace(idPrefix, "")
                        : data.node.id.replace(idPrefixDefault, ""));

                var folderType = isUserFolder ? +TMMail.sysfolders.userfolder.id : +id;
                var userFolderId = isUserFolder ? +id : null;

                selected = {
                    id: id,
                    name: data.node.text,
                    folderType: folderType,
                    userFolderId: userFolderId
                }
            });

        if (options.onClose) {
            onCloseClaback = options.onClose;
        }
    }

    function hide() {
        if (!popup) return;

        popup.hide();
        dropdown.unregHide(filteredHide);
        dropdown.unregHide(onScroll);

        var jstree = container.jstree(true);

        showRoot(true);
        showDefaults(true);

        jstree.deselect_all();
        jstree.show_all();
        rootChildren = null;

        if (onCloseClaback) {
            onCloseClaback();
            onCloseClaback = null;
        }
    }

    function refresh() {
        console.log("userFoldersDropdown -> refresh");

        container.jstree(true).refresh();
    }

    function onCreated(e, folder) {
        console.log("userFoldersDropdown -> onCreated", folder);

        var ref = container.jstree(true);

        var parentId = folder.parent === 0 ? idRoot : idPrefix + folder.parent;

        var res = ref.create_node(parentId, {
            id: idPrefix + folder.id,
            parent: parentId,
            text: folder.name,
            icon: "",
            state: {
                opened: false,
                disabled: false,
                selected: false
            },
            a_attr: { href: "#userfolder={0}".format(folder.id) },
            children: false
        });

        if (!res) {
            refresh();
        }
    }

    function onEdited(e, newFolder, oldFolder) {
        console.log("userFoldersDropdown -> onEdited", newFolder, oldFolder);

        var ref = container.jstree(true);

        var id = idPrefix + newFolder.id;

        ref.set_text(id, newFolder.name);

        var oldParentId = oldFolder.parent === 0 ? idRoot : idPrefix + oldFolder.parent;
        var newParentId = newFolder.parent === 0 ? idRoot : idPrefix + newFolder.parent;

        if (oldParentId !== newParentId) {
            if (newParentId !== idRoot && ref.is_loaded(newParentId)) {
                var res = ref.move_node(id,
                    newParentId,
                    "last");

                if (!res) {
                    refresh();
                }
            } else {
                refresh();
            }
        }
    }

    function onDeleted(e, folder) {
        console.log("userFoldersDropdown -> onDeleted", folder);

        var ref = container.jstree(true);

        var id = idPrefix + folder.id;

        var res = ref.delete_node(id);

        if (!res) {
            refresh();
        }
    }

    return {
        init: init,
        show: show,
        hide: hide,
        refresh: refresh
    };
})(jQuery);

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Entities/ContactCard.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Mail.Enums;

namespace ASC.Mail.Core.Entities
{
    public class ContactCard
    {
        public ContactCard(Contact contact, List<ContactInfo> contactItems)
        {
            ContactInfo = contact;
            ContactItems = contactItems;
        }

        public ContactCard(int id, int tenant, string user, string name, string description, ContactType type,
            IReadOnlyList<string> emails, IReadOnlyList<string> phoneNumbers = null)
        {
            ContactInfo = new Contact
            {
                Id = id,
                User = user,
                Tenant = tenant,
                ContactName = name,
                Address = emails[0],
                Description = description,
                Type = type,
                HasPhoto = false
            };

            ContactItems = new List<ContactInfo>();

            if (emails != null && emails.Any())
            {
                for (var i = 0; i < emails.Count; i++)
                {
                    var isPrimary = i == 0;

                    ContactItems
                        .Add(new ContactInfo
                        {
                            Id = 0,
                            ContactId = id,
                            Tenant = tenant,
                            User = user,
                            Type = (int)ContactInfoType.Email,
                            Data = emails[i],
                            IsPrimary = isPrimary
                        });
                }
            }

            if (phoneNumbers != null && phoneNumbers.Any())
            {
                for (var i = 0; i < phoneNumbers.Count; i++)
                {
                    var isPrimary = i == 0;

                    ContactItems
                        .Add(new ContactInfo
                        {
                            Id = 0,
                            ContactId = id,
                            Tenant = tenant,
                            User = user,
                            Type = (int)ContactInfoType.Phone,
                            Data = phoneNumbers[i],
                            IsPrimary = isPrimary
                        });
                }
            }
        }

        public Contact ContactInfo { get; set; }
        public List<ContactInfo> ContactItems { get; set; }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Entities/UserFolder.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Mail.Core.Entities
{
    public class UserFolder : IEquatable<UserFolder>
    {
        public uint Id { get; set; }
        public uint ParentId { get; set; }
        public string User { get; set; }
        public int Tenant { get; set; }
        public string Name { get; set; }
        public int FolderCount { get; set; }
        public int UnreadCount { get; set; }
        public int TotalCount { get; set; }
        public int UnreadChainCount { get; set; }
        public int TotalChainCount { get; set; }
        public DateTime TimeModified { get; set; }

        public bool Equals(UserFolder other)
        {
            if (other == null) return false;
            return string.Equals(User, other.User, StringComparison.InvariantCultureIgnoreCase)
                   && Tenant == other.Tenant
                   && Id == other.Id
                   && ParentId == other.ParentId
                   && string.Equals(Name, other.Name, StringComparison.InvariantCultureIgnoreCase)
                   && FolderCount == other.FolderCount
                   && UnreadCount == other.UnreadCount
                   && TotalCount == other.TotalCount
                   && UnreadChainCount == other.UnreadChainCount
                   && TotalChainCount == other.TotalChainCount;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;
            return Equals(obj as UserFolder);
        }

        public override int GetHashCode()
        {
            return Tenant.GetHashCode()
                   ^ User.GetHashCode()
                   ^ Id.GetHashCode()
                   ^ ParentId.GetHashCode()
                   ^ Name.GetHashCode()
                   ^ FolderCount.GetHashCode()
                   ^ UnreadCount.GetHashCode()
                   ^ TotalCount.GetHashCode()
                   ^ UnreadChainCount.GetHashCode()
                   ^ TotalChainCount.GetHashCode();
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Core/UserGroupRef.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Diagnostics;

namespace ASC.Core
{
    [DebuggerDisplay("{UserId} - {GroupId}")]
    public class UserGroupRef
    {
        public Guid UserId
        {
            get;
            set;
        }

        public Guid GroupId
        {
            get;
            set;
        }

        public bool Removed
        {
            get;
            set;
        }

        public DateTime LastModified
        {
            get;
            set;
        }

        public UserGroupRefType RefType
        {
            get;
            set;
        }

        public int Tenant
        {
            get;
            set;
        }


        public UserGroupRef()
        {
        }

        public UserGroupRef(Guid userId, Guid groupId, UserGroupRefType refType)
        {
            UserId = userId;
            GroupId = groupId;
            RefType = refType;
        }

        public static string CreateKey(int tenant, Guid userId, Guid groupId, UserGroupRefType refType)
        {
            return tenant.ToString() + userId.ToString("N") + groupId.ToString("N") + ((int)refType).ToString();
        }

        public string CreateKey()
        {
            return CreateKey(Tenant, UserId, GroupId, RefType);
        }

        public override int GetHashCode()
        {
            return UserId.GetHashCode() ^ GroupId.GetHashCode() ^ Tenant.GetHashCode() ^ RefType.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            var r = obj as UserGroupRef;
            return r != null && r.Tenant == Tenant && r.UserId == UserId && r.GroupId == GroupId && r.RefType == RefType;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Server/_FetchHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP.Server
{
    #region usings

    using System;
    using System.IO;
    using System.Text;
    using Mime;

    #endregion

    /// <summary>
    /// FETCH command helper methods.
    /// </summary>
    internal class FetchHelper
    {
        #region Methods

        /// <summary>
        /// Returns requested header fields lines.
        /// Note: Header terminator blank line is included.
        /// </summary>
        /// <param name="fieldsStr">Header fields to get.</param>
        /// <param name="entity">Entity which header field lines to get.</param>
        /// <returns></returns>
        public static byte[] ParseHeaderFields(string fieldsStr, MimeEntity entity)
        {
            return ParseHeaderFields(fieldsStr, Encoding.Default.GetBytes(entity.HeaderString));
        }

        /// <summary>
        /// Returns requested header fields lines.
        /// Note: Header terminator blank line is included.
        /// </summary>
        /// <param name="fieldsStr">Header fields to get.</param>
        /// <param name="data">Message data.</param>
        /// <returns></returns>
        public static byte[] ParseHeaderFields(string fieldsStr, byte[] data)
        {
            fieldsStr = fieldsStr.Trim();
            if (fieldsStr.StartsWith("("))
            {
                fieldsStr = fieldsStr.Substring(1, fieldsStr.Length - 1);
            }
            if (fieldsStr.EndsWith(")"))
            {
                fieldsStr = fieldsStr.Substring(0, fieldsStr.Length - 1);
            }

            string retVal = "";

            string[] fields = fieldsStr.Split(' ');
            using (MemoryStream mStrm = new MemoryStream(data))
            {
                TextReader r = new StreamReader(mStrm);
                string line = r.ReadLine();

                bool fieldFound = false;
                // Loop all header lines
                while (line != null)
                {
                    // End of header
                    if (line.Length == 0)
                    {
                        break;
                    }

                    // Field continues
                    if (fieldFound && line.StartsWith("\t"))
                    {
                        retVal += line + "\r\n";
                    }
                    else
                    {
                        fieldFound = false;

                        // Check if wanted field
                        foreach (string field in fields)
                        {
                            if (line.Trim().ToLower().StartsWith(field.Trim().ToLower()))
                            {
                                retVal += line + "\r\n";
                                fieldFound = true;
                            }
                        }
                    }

                    line = r.ReadLine();
                }
            }

            // Add header terminating blank line
            retVal += "\r\n";

            return Encoding.ASCII.GetBytes(retVal);
        }

        /// <summary>
        /// Returns header fields lines except requested.
        /// Note: Header terminator blank line is included.
        /// </summary>
        /// <param name="fieldsStr">Header fields to skip.</param>
        /// <param name="entity">Entity which header field lines to get.</param>
        /// <returns></returns>
        public static byte[] ParseHeaderFieldsNot(string fieldsStr, MimeEntity entity)
        {
            return ParseHeaderFieldsNot(fieldsStr, Encoding.Default.GetBytes(entity.HeaderString));
        }

        /// <summary>
        /// Returns header fields lines except requested.
        /// Note: Header terminator blank line is included.
        /// </summary>
        /// <param name="fieldsStr">Header fields to skip.</param>
        /// <param name="data">Message data.</param>
        /// <returns></returns>
        public static byte[] ParseHeaderFieldsNot(string fieldsStr, byte[] data)
        {
            fieldsStr = fieldsStr.Trim();
            if (fieldsStr.StartsWith("("))
            {
                fieldsStr = fieldsStr.Substring(1, fieldsStr.Length - 1);
            }
            if (fieldsStr.EndsWith(")"))
            {
                fieldsStr = fieldsStr.Substring(0, fieldsStr.Length - 1);
            }

            string retVal = "";

            string[] fields = fieldsStr.Split(' ');
            using (MemoryStream mStrm = new MemoryStream(data))
            {
                TextReader r = new StreamReader(mStrm);
                string line = r.ReadLine();

                bool fieldFound = false;
                // Loop all header lines
                while (line != null)
                {
                    // End of header
                    if (line.Length == 0)
                    {
                        break;
                    }

                    // Filed continues
                    if (fieldFound && line.StartsWith("\t"))
                    {
                        retVal += line + "\r\n";
                    }
                    else
                    {
                        fieldFound = false;

                        // Check if wanted field
                        foreach (string field in fields)
                        {
                            if (line.Trim().ToLower().StartsWith(field.Trim().ToLower()))
                            {
                                fieldFound = true;
                            }
                        }

                        if (!fieldFound)
                        {
                            retVal += line + "\r\n";
                        }
                    }

                    line = r.ReadLine();
                }
            }

            return Encoding.ASCII.GetBytes(retVal);
        }

        /// <summary>
        /// Gets specified mime entity. Returns null if specified mime entity doesn't exist.
        /// </summary>
        /// <param name="parser">Reference to mime parser.</param>
        /// <param name="mimeEntitySpecifier">Mime entity specifier. Nested mime entities are pointed by '.'. 
        /// For example: 1,1.1,2.1, ... .</param>
        /// <returns></returns>
        public static MimeEntity GetMimeEntity(Mime parser, string mimeEntitySpecifier)
        {
            // TODO: nested rfc 822 message

            // For single part message there is only one entity with value 1.
            // Example:
            //		header
            //		entity -> 1

            // For multipart message, entity counting starts from MainEntity.ChildEntities
            // Example:
            //		header
            //		multipart/mixed
            //			entity1  -> 1
            //			entity2  -> 2
            //          ...

            // Single part
            if ((parser.MainEntity.ContentType & MediaType_enum.Multipart) == 0)
            {
                if (mimeEntitySpecifier.Length == 1 && Convert.ToInt32(mimeEntitySpecifier) == 1)
                {
                    return parser.MainEntity;
                }
                else
                {
                    return null;
                }
            }
                // multipart
            else
            {
                MimeEntity entity = parser.MainEntity;
                string[] parts = mimeEntitySpecifier.Split('.');
                foreach (string part in parts)
                {
                    int mEntryNo = Convert.ToInt32(part) - 1;
                        // Enitites are zero base, mimeEntitySpecifier is 1 based.
                    if (mEntryNo > -1 && mEntryNo < entity.ChildEntities.Count)
                    {
                        entity = entity.ChildEntities[mEntryNo];
                    }
                    else
                    {
                        return null;
                    }
                }

                return entity;
            }
        }

        /// <summary>
        /// Gets specified mime entity header.
        /// Note: Header terminator blank line is included.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <returns></returns>
        public static byte[] GetMimeEntityHeader(MimeEntity entity)
        {
            return Encoding.ASCII.GetBytes(entity.HeaderString + "\r\n");
        }

        /// <summary>
        /// Gets requested mime entity header. Returns null if specified mime entity doesn't exist.
        /// Note: Header terminator blank line is included.
        /// </summary>
        /// <param name="parser">Reference to mime parser.</param>
        /// <param name="mimeEntitySpecifier">Mime entity specifier. Nested mime entities are pointed by '.'. 
        /// For example: 1,1.1,2.1, ... .</param>
        /// <returns>Returns requested mime entity data or NULL if requested entry doesn't exist.</returns>
        public static byte[] GetMimeEntityHeader(Mime parser, string mimeEntitySpecifier)
        {
            MimeEntity mEntry = GetMimeEntity(parser, mimeEntitySpecifier);
            if (mEntry != null)
            {
                return GetMimeEntityHeader(mEntry);
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Gets requested mime entity data. Returns null if specified mime entity doesn't exist.
        /// </summary>
        /// <param name="parser">Reference to mime parser.</param>
        /// <param name="mimeEntitySpecifier">Mime entity specifier. Nested mime entities are pointed by '.'. 
        /// For example: 1,1.1,2.1, ... .</param>
        /// <returns>Returns requested mime entity data or NULL if requested entry doesn't exist.</returns>
        public static byte[] GetMimeEntityData(Mime parser, string mimeEntitySpecifier)
        {
            MimeEntity entity = GetMimeEntity(parser, mimeEntitySpecifier);
            if (entity != null)
            {
                return entity.DataEncoded;
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region Utility methods

        private static string Escape(string text)
        {
            text = text.Replace("\\", "\\\\");
            text = text.Replace("\"", "\\\"");

            return text;
        }

        #endregion
    }
}

<|start_filename|>web/core/ASC.Web.Core/WhiteLabel/TenantWhiteLabelSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Common.Logging;
using ASC.Core.Common.Settings;
using ASC.Core.Tenants;
using ASC.Data.Storage;
using ASC.Web.Core.Users;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Utility;

using TMResourceData;

namespace ASC.Web.Core.WhiteLabel
{
    [Serializable]
    [DataContract]
    public class TenantWhiteLabelSettings : BaseSettings<TenantWhiteLabelSettings>
    {
        public const string DefaultLogoText = "ONLYOFFICE";

        #region Logos information: extension, isDefault, text for img auto generating

        [DataMember(Name = "LogoLightSmallExt")]
        private string _logoLightSmallExt;
        [DataMember(Name = "DefaultLogoLightSmall")]
        private bool _isDefaultLogoLightSmall { get; set; }

        [DataMember(Name = "LogoDarkExt")]
        private string _logoDarkExt;
        [DataMember(Name = "DefaultLogoDark")]
        private bool _isDefaultLogoDark { get; set; }

        [DataMember(Name = "LogoFaviconExt")]
        private string _logoFaviconExt;
        [DataMember(Name = "DefaultLogoFavicon")]
        private bool _isDefaultLogoFavicon { get; set; }

        [DataMember(Name = "LogoDocsEditorExt")]
        private string _logoDocsEditorExt;
        [DataMember(Name = "DefaultLogoDocsEditor")]
        private bool _isDefaultLogoDocsEditor { get; set; }


        [DataMember(Name = "LogoText")]
        public string _logoText { get; set; }

        public string LogoText
        {
            get
            {
                if (!String.IsNullOrEmpty(_logoText) && _logoText != DefaultLogoText)
                    return _logoText;

                var partnerSettings = LoadForDefaultTenant();
                return String.IsNullOrEmpty(partnerSettings._logoText) ? DefaultLogoText : partnerSettings._logoText;
            }
            set { _logoText = value; }
        }

        private const String moduleName = "whitelabel";

        #endregion

        #region Logo available sizes

        public static readonly Size logoLightSmallSize = new Size(284, 46);
        public static readonly Size logoDarkSize = new Size(432, 70);
        public static readonly Size logoFaviconSize = new Size(32, 32);
        public static readonly Size logoDocsEditorSize = new Size(172, 40);

        #endregion

        #region ISettings Members

        public override ISettings GetDefault()
        {
            return new TenantWhiteLabelSettings
            {
                _logoLightSmallExt = null,
                _logoDarkExt = null,
                _logoFaviconExt = null,
                _logoDocsEditorExt = null,

                _isDefaultLogoLightSmall = true,
                _isDefaultLogoDark = true,
                _isDefaultLogoFavicon = true,
                _isDefaultLogoDocsEditor = true,

                LogoText = null
            };
        }
        #endregion

        #region Restore default

        public bool IsDefault
        {
            get
            {
                var defaultSettings = GetDefault() as TenantWhiteLabelSettings;

                if (defaultSettings == null) return false;

                return _logoLightSmallExt == defaultSettings._logoLightSmallExt &&
                       _logoDarkExt == defaultSettings._logoDarkExt &&
                       _logoFaviconExt == defaultSettings._logoFaviconExt &&
                       _logoDocsEditorExt == defaultSettings._logoDocsEditorExt &&

                       _isDefaultLogoLightSmall == defaultSettings._isDefaultLogoLightSmall &&
                       _isDefaultLogoDark == defaultSettings._isDefaultLogoDark &&
                       _isDefaultLogoFavicon == defaultSettings._isDefaultLogoFavicon &&
                       _isDefaultLogoDocsEditor == defaultSettings._isDefaultLogoDocsEditor &&

                       LogoText == defaultSettings.LogoText;
            }
        }

        public void RestoreDefault(int tenantId, IDataStore storage = null)
        {
            _logoLightSmallExt = null;
            _logoDarkExt = null;
            _logoFaviconExt = null;
            _logoDocsEditorExt = null;

            _isDefaultLogoLightSmall = true;
            _isDefaultLogoDark = true;
            _isDefaultLogoFavicon = true;
            _isDefaultLogoDocsEditor = true;

            LogoText = null;

            var store = storage ?? StorageFactory.GetStorage(tenantId.ToString(), moduleName);
            try
            {
                store.DeleteFiles("", "*", false);
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC").Error(e);
            }

            Save(tenantId, true);
        }

        public void RestoreDefault(WhiteLabelLogoTypeEnum type)
        {
            if (!GetIsDefault(type))
            {
                try
                {
                    SetIsDefault(type, true);
                    var store = StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(), moduleName);
                    DeleteLogoFromStore(store, type);
                }
                catch (Exception e)
                {
                    LogManager.GetLogger("ASC").Error(e);
                }
            }
        }

        #endregion

        #region Set logo

        public void SetLogo(WhiteLabelLogoTypeEnum type, string logoFileExt, byte[] data, IDataStore storage = null)
        {
            var store = storage ?? StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(), moduleName);

            #region delete from storage if already exists

            var isAlreadyHaveBeenChanged = !GetIsDefault(type);

            if (isAlreadyHaveBeenChanged)
            {
                try
                {
                    DeleteLogoFromStore(store, type);
                }
                catch (Exception e)
                {
                    LogManager.GetLogger("ASC").Error(e);
                }
            }
            #endregion

            using (var memory = new MemoryStream(data))
            using (var image = Image.FromStream(memory))
            {
                var logoSize = image.Size;
                var logoFileName = BuildLogoFileName(type, logoFileExt, false);

                memory.Seek(0, SeekOrigin.Begin);
                store.Save(logoFileName, memory);
            }

            SetExt(type, logoFileExt);
            SetIsDefault(type, false);

            var generalSize = GetSize(type, true);
            var generalFileName = BuildLogoFileName(type, logoFileExt, true);
            ResizeLogo(type, generalFileName, data, -1, generalSize, store);
        }

        public void SetLogo(Dictionary<int, string> logo, IDataStore storage = null)
        {
            var xStart = @"data:image/png;base64,";

            foreach (var currentLogo in logo)
            {
                var currentLogoType = (WhiteLabelLogoTypeEnum)(currentLogo.Key);
                var currentLogoPath = currentLogo.Value;

                if (!String.IsNullOrEmpty(currentLogoPath))
                {
                    var fileExt = "png";
                    byte[] data = null;

                    if (!currentLogoPath.StartsWith(xStart))
                    {
                        var fileName = Path.GetFileName(currentLogoPath);
                        fileExt = fileName.Split('.').Last();
                        data = UserPhotoManager.GetTempPhotoData(fileName);
                        try
                        {
                            UserPhotoManager.RemoveTempPhoto(fileName);
                        }
                        catch (Exception ex)
                        {
                            LogManager.GetLogger("ASC").Error(ex);
                        }
                    }
                    else
                    {
                        var xB64 = currentLogoPath.Substring(xStart.Length); // Get the Base64 string
                        data = System.Convert.FromBase64String(xB64); // Convert the Base64 string to binary data
                    }

                    if (data != null)
                    {
                        SetLogo(currentLogoType, fileExt, data, storage);
                    }
                }
            }
        }

        public void SetLogoFromStream(WhiteLabelLogoTypeEnum type, string fileExt, Stream fileStream, IDataStore storage = null)
        {
            byte[] data = null;
            using (var memoryStream = new MemoryStream())
            {
                fileStream.CopyTo(memoryStream);
                data = memoryStream.ToArray();
            }

            if (data != null)
            {
                SetLogo(type, fileExt, data, storage);
            }
        }

        #endregion

        #region Get/Set IsDefault and Extension

        private bool GetIsDefault(WhiteLabelLogoTypeEnum type)
        {
            switch (type)
            {
                case WhiteLabelLogoTypeEnum.LightSmall:
                    return _isDefaultLogoLightSmall;
                case WhiteLabelLogoTypeEnum.Dark:
                    return _isDefaultLogoDark;
                case WhiteLabelLogoTypeEnum.Favicon:
                    return _isDefaultLogoFavicon;
                case WhiteLabelLogoTypeEnum.DocsEditor:
                    return _isDefaultLogoDocsEditor;
            }
            return true;
        }

        private void SetIsDefault(WhiteLabelLogoTypeEnum type, bool value)
        {
            switch (type)
            {
                case WhiteLabelLogoTypeEnum.LightSmall:
                    _isDefaultLogoLightSmall = value;
                    break;
                case WhiteLabelLogoTypeEnum.Dark:
                    _isDefaultLogoDark = value;
                    break;
                case WhiteLabelLogoTypeEnum.Favicon:
                    _isDefaultLogoFavicon = value;
                    break;
                case WhiteLabelLogoTypeEnum.DocsEditor:
                    _isDefaultLogoDocsEditor = value;
                    break;
            }
        }

        private string GetExt(WhiteLabelLogoTypeEnum type)
        {
            switch (type)
            {
                case WhiteLabelLogoTypeEnum.LightSmall:
                    return _logoLightSmallExt;
                case WhiteLabelLogoTypeEnum.Dark:
                    return _logoDarkExt;
                case WhiteLabelLogoTypeEnum.Favicon:
                    return _logoFaviconExt;
                case WhiteLabelLogoTypeEnum.DocsEditor:
                    return _logoDocsEditorExt;
            }
            return "";
        }

        private void SetExt(WhiteLabelLogoTypeEnum type, String fileExt)
        {
            switch (type)
            {
                case WhiteLabelLogoTypeEnum.LightSmall:
                    _logoLightSmallExt = fileExt;
                    break;
                case WhiteLabelLogoTypeEnum.Dark:
                    _logoDarkExt = fileExt;
                    break;
                case WhiteLabelLogoTypeEnum.Favicon:
                    _logoFaviconExt = fileExt;
                    break;
                case WhiteLabelLogoTypeEnum.DocsEditor:
                    _logoDocsEditorExt = fileExt;
                    break;
            }
        }

        #endregion

        #region Get logo path

        public string GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum type, bool general = true)
        {
            if (GetIsDefault(type))
            {
                return GetAbsoluteDefaultLogoPath(type, general);
            }

            return GetAbsoluteStorageLogoPath(type, general);
        }

        private string GetAbsoluteStorageLogoPath(WhiteLabelLogoTypeEnum type, bool general)
        {
            var store = StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(), moduleName);
            var fileName = BuildLogoFileName(type, GetExt(type), general);

            if (store.IsFile(fileName))
            {
                return store.GetUri(fileName).ToString();
            }
            return GetAbsoluteDefaultLogoPath(type, general);
        }

        public static string GetAbsoluteDefaultLogoPath(WhiteLabelLogoTypeEnum type, bool general)
        {
            var partnerLogoPath = GetPartnerStorageLogoPath(type, general);
            if (!String.IsNullOrEmpty(partnerLogoPath))
                return partnerLogoPath;

            switch (type)
            {
                case WhiteLabelLogoTypeEnum.LightSmall:
                    return general ? WebImageSupplier.GetAbsoluteWebPath("logo/light_small_general.svg") : WebImageSupplier.GetAbsoluteWebPath("logo/light_small.svg");
                case WhiteLabelLogoTypeEnum.Dark:
                    return general ? WebImageSupplier.GetAbsoluteWebPath("logo/dark_general.png") : WebImageSupplier.GetAbsoluteWebPath("logo/dark.png");
                case WhiteLabelLogoTypeEnum.DocsEditor:
                    return general ? WebImageSupplier.GetAbsoluteWebPath("logo/editor_logo_general.png") : WebImageSupplier.GetAbsoluteWebPath("logo/editor_logo.png");
                case WhiteLabelLogoTypeEnum.Favicon:
                    return general ? WebImageSupplier.GetAbsoluteWebPath("logo/favicon_general.ico") : WebImageSupplier.GetAbsoluteWebPath("logo/favicon.ico");
            }
            return "";
        }

        private static string GetPartnerStorageLogoPath(WhiteLabelLogoTypeEnum type, bool general)
        {
            var partnerSettings = LoadForDefaultTenant();

            if (partnerSettings.GetIsDefault(type)) return null;

            var partnerStorage = StorageFactory.GetStorage(string.Empty, "static_partnerdata");

            if (partnerStorage == null) return null;

            var logoPath = BuildLogoFileName(type, partnerSettings.GetExt(type), general);

            return partnerStorage.IsFile(logoPath) ? partnerStorage.GetUri(logoPath).ToString() : null;
        }

        #endregion

        #region Get Whitelabel Logo Stream

        /// <summary>
        /// Get logo stream or null in case of default whitelabel
        /// </summary>
        public Stream GetWhitelabelLogoData(WhiteLabelLogoTypeEnum type, bool general)
        {
            if (GetIsDefault(type))
                return GetPartnerStorageLogoData(type, general);

            return GetStorageLogoData(type, general);
        }

        private Stream GetStorageLogoData(WhiteLabelLogoTypeEnum type, bool general)
        {
            var storage = StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(CultureInfo.InvariantCulture), moduleName);

            if (storage == null) return null;

            var fileName = BuildLogoFileName(type, GetExt(type), general);

            return storage.IsFile(fileName) ? storage.GetReadStream(fileName) : null;
        }

        private Stream GetPartnerStorageLogoData(WhiteLabelLogoTypeEnum type, bool general)
        {
            var partnerSettings = LoadForDefaultTenant();

            if (partnerSettings.GetIsDefault(type)) return null;

            var partnerStorage = StorageFactory.GetStorage(string.Empty, "static_partnerdata");

            if (partnerStorage == null) return null;

            var fileName = BuildLogoFileName(type, partnerSettings.GetExt(type), general);

            return partnerStorage.IsFile(fileName) ? partnerStorage.GetReadStream(fileName) : null;
        }

        #endregion

        public static string BuildLogoFileName(WhiteLabelLogoTypeEnum type, String fileExt, bool general)
        {
            return String.Format("logo_{0}{2}.{1}", type.ToString().ToLowerInvariant(), fileExt, general ? "_general" : "");
        }

        public static Size GetSize(WhiteLabelLogoTypeEnum type, bool general)
        {
            switch (type)
            {
                case WhiteLabelLogoTypeEnum.LightSmall:
                    return new Size(
                        general ? TenantWhiteLabelSettings.logoLightSmallSize.Width / 2 : TenantWhiteLabelSettings.logoLightSmallSize.Width,
                        general ? TenantWhiteLabelSettings.logoLightSmallSize.Height / 2 : TenantWhiteLabelSettings.logoLightSmallSize.Height);
                case WhiteLabelLogoTypeEnum.Dark:
                    return new Size(
                        general ? TenantWhiteLabelSettings.logoDarkSize.Width / 2 : TenantWhiteLabelSettings.logoDarkSize.Width,
                        general ? TenantWhiteLabelSettings.logoDarkSize.Height / 2 : TenantWhiteLabelSettings.logoDarkSize.Height);
                case WhiteLabelLogoTypeEnum.Favicon:
                    return new Size(
                        general ? TenantWhiteLabelSettings.logoFaviconSize.Width / 2 : TenantWhiteLabelSettings.logoFaviconSize.Width,
                        general ? TenantWhiteLabelSettings.logoFaviconSize.Height / 2 : TenantWhiteLabelSettings.logoFaviconSize.Height);
                case WhiteLabelLogoTypeEnum.DocsEditor:
                    return new Size(
                        general ? TenantWhiteLabelSettings.logoDocsEditorSize.Width / 2 : TenantWhiteLabelSettings.logoDocsEditorSize.Width,
                        general ? TenantWhiteLabelSettings.logoDocsEditorSize.Height / 2 : TenantWhiteLabelSettings.logoDocsEditorSize.Height);
            }
            return new Size(0, 0);
        }

        private static void ResizeLogo(WhiteLabelLogoTypeEnum type, String fileName, byte[] data, long maxFileSize, Size size, IDataStore store)
        {
            //Resize synchronously
            if (data == null || data.Length <= 0) throw new UnknownImageFormatException();
            if (maxFileSize != -1 && data.Length > maxFileSize) throw new ImageWeightLimitException();

            try
            {
                using (var stream = new MemoryStream(data))
                using (var img = Image.FromStream(stream))
                {
                    var imgFormat = img.RawFormat;
                    if (size != img.Size)
                    {
                        using (var img2 = CommonPhotoManager.DoThumbnail(img, size, false, true, false))
                        {
                            data = CommonPhotoManager.SaveToBytes(img2);
                        }
                    }
                    else
                    {
                        data = CommonPhotoManager.SaveToBytes(img);
                    }

                    //fileExt = CommonPhotoManager.GetImgFormatName(imgFormat);

                    using (var stream2 = new MemoryStream(data))
                    {
                        store.Save(fileName, stream2);
                        //NOTE: Update cache here
                        //var filePath = Path.GetFileName(photoUrl);

                        //AddToCache(item.UserId, item.Size, fileNPath, true);
                    }
                }
            }
            catch (ArgumentException error)
            {
                throw new UnknownImageFormatException(error);
            }
        }

        public override Guid ID
        {
            get { return new Guid("{05d35540-c80b-4b17-9277-abd9e543bf93}"); }
        }

        #region Save for Resource replacement

        private static readonly List<int> AppliedTenants = new List<int>();

        public static void Apply(int tenantId)
        {
            if (AppliedTenants.Contains(tenantId)) return;

            var whiteLabelSettings = LoadForTenant(tenantId);
            whiteLabelSettings.SetNewLogoText(tenantId);

            if (!AppliedTenants.Contains(tenantId)) AppliedTenants.Add(tenantId);
        }

        public void Save(int tenantId, bool restore = false)
        {
            SaveForTenant(tenantId);

            if (tenantId == Tenant.DEFAULT_TENANT)
            {
                AppliedTenants.Clear();
            }
            else
            {
                SetNewLogoText(tenantId, restore);
                TenantLogoManager.RemoveMailLogoDataFromCache();
            }
        }

        private void SetNewLogoText(int tenantId, bool restore = false)
        {
            WhiteLabelHelper.DefaultLogoText = DefaultLogoText;

            var partnerSettings = LoadForDefaultTenant();

            if (restore && String.IsNullOrEmpty(partnerSettings._logoText))
            {
                WhiteLabelHelper.RestoreOldText(tenantId);
            }
            else
            {
                WhiteLabelHelper.SetNewText(tenantId, LogoText);
            }
        }

        #endregion

        #region Delete from Store

        private void DeleteLogoFromStore(IDataStore store, WhiteLabelLogoTypeEnum type)
        {
            DeleteLogoFromStoreByGeneral(store, type, false);
            DeleteLogoFromStoreByGeneral(store, type, true);
        }

        private void DeleteLogoFromStoreByGeneral(IDataStore store, WhiteLabelLogoTypeEnum type, bool general)
        {
            var fileExt = GetExt(type);
            var logo = BuildLogoFileName(type, fileExt, general);
            if (store.IsFile(logo))
            {
                store.Delete(logo);
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Resources/MilestoneResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Projects.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class MilestoneResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal MilestoneResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Projects.Resources.MilestoneResource", typeof(MilestoneResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string AddMilestoneButton {
            get {
                return ResourceManager.GetString("AddMilestoneButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose the project.
        /// </summary>
        public static string ChooseProject {
            get {
                return ResourceManager.GetString("ChooseProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose the responsible.
        /// </summary>
        public static string ChooseResponsible {
            get {
                return ResourceManager.GetString("ChooseResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close Milestone.
        /// </summary>
        public static string CloseMilestone {
            get {
                return ResourceManager.GetString("CloseMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to d.
        /// </summary>
        public static string Days {
            get {
                return ResourceManager.GetString("Days", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Month.
        /// </summary>
        public static string DeadlineInMonth {
            get {
                return ResourceManager.GetString("DeadlineInMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Two months.
        /// </summary>
        public static string DeadlineInTwoMonths {
            get {
                return ResourceManager.GetString("DeadlineInTwoMonths", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Week.
        /// </summary>
        public static string DeadlineInWeek {
            get {
                return ResourceManager.GetString("DeadlineInWeek", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete Milestone.
        /// </summary>
        public static string DeleteMilestone {
            get {
                return ResourceManager.GetString("DeleteMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete the milestone?.
        /// </summary>
        public static string DeleteMilestonePopup {
            get {
                return ResourceManager.GetString("DeleteMilestonePopup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete Milestones.
        /// </summary>
        public static string DeleteMilestones {
            get {
                return ResourceManager.GetString("DeleteMilestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete milestones?.
        /// </summary>
        public static string DeleteMilestonesPopup {
            get {
                return ResourceManager.GetString("DeleteMilestonesPopup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No milestones matching your filter can be displayed in this section..
        /// </summary>
        public static string DescrEmptyListMilFilter {
            get {
                return ResourceManager.GetString("DescrEmptyListMilFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Description.
        /// </summary>
        public static string Description {
            get {
                return ResourceManager.GetString("Description", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no milestones matching this filter.
        /// </summary>
        public static string FilterNoMilestones {
            get {
                return ResourceManager.GetString("FilterNoMilestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone.
        /// </summary>
        public static string Milestone {
            get {
                return ResourceManager.GetString("Milestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Due Date.
        /// </summary>
        public static string MilestoneDeadline {
            get {
                return ResourceManager.GetString("MilestoneDeadline", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No milestones have been planned yet.
        /// </summary>
        public static string MilestoneNotFound_Header {
            get {
                return ResourceManager.GetString("MilestoneNotFound_Header", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestones.
        /// </summary>
        public static string Milestones {
            get {
                return ResourceManager.GetString("Milestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestones mark the major timestamps in project planning process. Once a milestone is created you can fill it with tasks for all project participants. Plan a milestone and set a due date to make sure that the tasks are completed on time..
        /// </summary>
        public static string MilestonesMarkMajorTimestamps {
            get {
                return ResourceManager.GetString("MilestonesMarkMajorTimestamps", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestones mark the major timestamps in project planning process. Once a milestone is created it can be filled with tasks for all project participants..
        /// </summary>
        public static string MilestonesMarkMajorTimestampsVisitor {
            get {
                return ResourceManager.GetString("MilestonesMarkMajorTimestampsVisitor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upcoming.
        /// </summary>
        public static string Next {
            get {
                return ResourceManager.GetString("Next", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You cannot close a milestone with open tasks..
        /// </summary>
        public static string NotCloseMilWithActiveTasks {
            get {
                return ResourceManager.GetString("NotCloseMilWithActiveTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Notify.
        /// </summary>
        public static string NotifyResponsible {
            get {
                return ResourceManager.GetString("NotifyResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each milestone must have a title.
        /// </summary>
        public static string NoTitleMessage {
            get {
                return ResourceManager.GetString("NoTitleMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Overdue.
        /// </summary>
        public static string Overdue {
            get {
                return ResourceManager.GetString("Overdue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Plan the first milestone.
        /// </summary>
        public static string PlanFirstMilestone {
            get {
                return ResourceManager.GetString("PlanFirstMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Remind me 48 hours before the due date.
        /// </summary>
        public static string RemindMe {
            get {
                return ResourceManager.GetString("RemindMe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Responsible.
        /// </summary>
        public static string Responsible {
            get {
                return ResourceManager.GetString("Responsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Key milestone.
        /// </summary>
        public static string RootMilestone {
            get {
                return ResourceManager.GetString("RootMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string Title {
            get {
                return ResourceManager.GetString("Title", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/ColorThemes/js/colorthemes.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.Controls.ColorThemesSettings = function () {
    var isInit = false;

    var init = function() {
        if (isInit) {
            return;
        }
        isInit = true;

        jq("input[name='colorTheme']").on("click", function() {
            var theme = jq(this).val(),
                $preview = jq(".preview-theme-image");
            
            jq("input[name='colorTheme']").each(function() {
                var className = jq(this).val();
                if ($preview.hasClass(className)) {
                    $preview.removeClass(className);
                }
            });
            $preview.addClass(theme);
        });

        jq("#colorThemeBlock .button.blue").on("click", function() {
            saveColorThemeSettings();
        });

        var saveColorThemeSettings = function() {
            var color = jq("input[name='colorTheme']:checked").val();
            Teamlab.setColorTheme({ color: color }, color, {
                success: function (params, response) {
                    jq("body").addClass(params.color);
                    window.location.reload(true);
                }
            });
        };
    };
    return {
        init: init
    };
}();

jq(function () {
    ASC.Controls.ColorThemesSettings.init();
})

<|start_filename|>module/ASC.Api/ASC.Api.CRM/CRMApi.Invoices.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Api.Attributes;
using ASC.Api.Collections;
using ASC.Api.CRM.Wrappers;
using ASC.Api.Documents;
using ASC.Api.Exceptions;
using ASC.Core;
using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.MessagingSystem;
using ASC.Specific;
using ASC.Web.CRM.Classes;
using ASC.Web.Studio.Utility;

namespace ASC.Api.CRM
{
    public partial class CRMApi
    {
        /// <summary>
        ///  Returns the detailed information about the invoice with the ID specified in the request
        /// </summary>
        /// <param name="invoiceid">Invoice ID</param>
        /// <short>Get invoice by ID</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice</returns>
        [Read(@"invoice/{invoiceid:[0-9]+}")]
        public InvoiceWrapper GetInvoiceByID(int invoiceid)
        {
            if (invoiceid <= 0) throw new ArgumentException();

            var invoice = DaoFactory.InvoiceDao.GetByID(invoiceid);
            if (invoice == null) throw new ItemNotFoundException();

            if (!CRMSecurity.CanAccessTo(invoice))
            {
                throw CRMSecurity.CreateSecurityException();
            }

            return ToInvoiceWrapper(invoice);
        }

        /// <summary>
        ///  Returns the detailed information about the invoice sample
        /// </summary>
        /// <short>Get invoice sample</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice</returns>
        [Read(@"invoice/sample")]
        public InvoiceWrapper GetInvoiceSample()
        {
            var sample = InvoiceWrapper.GetSample();
            sample.Number = DaoFactory.InvoiceDao.GetNewInvoicesNumber();
            sample.Terms = DaoFactory.InvoiceDao.GetSettings().Terms ?? string.Empty;

            sample.IssueDate = (ApiDateTime)DateTime.UtcNow;
            sample.DueDate = (ApiDateTime)DateTime.UtcNow.AddDays(30);
            sample.CreateOn = (ApiDateTime)DateTime.UtcNow;

            sample.Currency = new CurrencyInfoWrapper(Global.TenantSettings.DefaultCurrency);

            sample.InvoiceLines.First().Quantity = 1;

            return sample;
        }

        /// <summary>
        ///  Returns the json data of the invoice with the ID specified in the request
        /// </summary>
        /// <param name="invoiceid">Invoice ID</param>
        /// <short>Get invoice json data</short> 
        /// <category>Invoices</category>
        /// <returns>Json Data</returns>
        [Read(@"invoice/jsondata/{invoiceid:[0-9]+}")]
        public string GetInvoiceJsonData(int invoiceid)
        {
            var invoice = DaoFactory.InvoiceDao.GetByID(invoiceid);
            if (invoice == null) throw new ItemNotFoundException();

            if (!CRMSecurity.CanAccessTo(invoice))
            {
                throw CRMSecurity.CreateSecurityException();
            }

            return invoice.JsonData;
        }

        /// <summary>
        ///   Returns the list of invoices matching the creteria specified in the request
        /// </summary>
        /// <param name="status">Invoice status</param>
        /// <param name="issueDateFrom">Invoice issue date from</param>
        /// <param name="issueDateTo">Invoice issue date to</param>
        /// <param name="dueDateFrom">Invoice due date from</param>
        /// <param name="dueDateTo">Invoice due date to</param>
        /// <param name="entityType">Invoice entity type</param>
        /// <param name="entityid">Invoice entity ID</param>
        /// <param name="currency" remark="Allowed values: EUR, RUB etc. You can get the whole list of available currencies by api">Invoice currency</param>
        /// <short>Get invoice list</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice list</returns>
        [Read(@"invoice/filter")]
        public IEnumerable<InvoiceBaseWrapper> GetInvoices(
            InvoiceStatus? status,
            ApiDateTime issueDateFrom,
            ApiDateTime issueDateTo,
            ApiDateTime dueDateFrom,
            ApiDateTime dueDateTo,
            String entityType,
            int entityid,
            String currency
            )
        {
            if (!String.IsNullOrEmpty(entityType) && !(
                                                          String.Compare(entityType, "contact", true) == 0 ||
                                                          String.Compare(entityType, "opportunity", true) == 0 ||
                                                          String.Compare(entityType, "case", true) == 0))
                throw new ArgumentException();

            IEnumerable<InvoiceBaseWrapper> result;

            InvoiceSortedByType sortBy;

            OrderBy invoiceOrderBy;

            var searchString = _context.FilterValue;

            if (InvoiceSortedByType.TryParse(_context.SortBy, true, out sortBy))
            {
                invoiceOrderBy = new OrderBy(sortBy, !_context.SortDescending);
            }
            else if (String.IsNullOrEmpty(_context.SortBy))
            {
                invoiceOrderBy = new OrderBy(InvoiceSortedByType.Number, true);
            }
            else
            {
                invoiceOrderBy = null;
            }

            var fromIndex = (int)_context.StartIndex;
            var count = (int)_context.Count;

            if (invoiceOrderBy != null)
            {
                result = ToListInvoiceBaseWrappers(
                    DaoFactory.InvoiceDao.GetInvoices(
                        searchString,
                        status,
                        issueDateFrom, issueDateTo,
                        dueDateFrom, dueDateTo,
                        ToEntityType(entityType), entityid,
                        currency,
                        fromIndex, count,
                        invoiceOrderBy));

                _context.SetDataPaginated();
                _context.SetDataFiltered();
                _context.SetDataSorted();
            }
            else
            {
                result = ToListInvoiceBaseWrappers(
                    DaoFactory.InvoiceDao.GetInvoices(
                        searchString,
                        status,
                        issueDateFrom, issueDateTo,
                        dueDateFrom, dueDateTo,
                        ToEntityType(entityType), entityid,
                        currency,
                        0,
                        0,
                        null));
            }

            int totalCount;

            if (result.Count() < count)
            {
                totalCount = fromIndex + result.Count();
            }
            else
            {
                totalCount = DaoFactory.InvoiceDao.GetInvoicesCount(
                    searchString,
                    status,
                    issueDateFrom, issueDateTo,
                    dueDateFrom, dueDateTo,
                    ToEntityType(entityType), entityid,
                    currency);
            }

            _context.SetTotalCount(totalCount);

            return result.ToSmartList();
        }

        /// <summary>
        ///  Returns the list of all invoices associated with the entity with the ID and type specified in the request
        /// </summary>
        /// <param name="entityType">Invoice entity type</param>
        /// <param name="entityid">Invoice entity ID</param>
        /// <short>Get entity invoices</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice list</returns>
        [Read(@"{entityType:(contact|person|company|opportunity)}/invoicelist/{entityid:[0-9]+}")]
        public IEnumerable<InvoiceBaseWrapper> GetEntityInvoices(String entityType, int entityid)
        {
            if (String.IsNullOrEmpty(entityType) || entityid <= 0) throw new ArgumentException();

            return ToListInvoiceBaseWrappers(DaoFactory.InvoiceDao.GetEntityInvoices(ToEntityType(entityType), entityid));
        }

        /// <summary>
        ///   Updates the status of invoices with the IDs specified in the request
        /// </summary>
        /// <param name="invoiceids">Invoice ID list</param>
        /// <param name="status">Status</param>
        /// <short>Update invoice group status</short> 
        /// <category>Invoices</category>
        /// <returns>KeyValuePair of Invoices and InvoiceItems</returns>
        [Update(@"invoice/status/{status:[\w\d-]+}")]
        public KeyValuePair<IEnumerable<InvoiceBaseWrapper>, IEnumerable<InvoiceItemWrapper>> UpdateInvoiceBatchStatus(
            int[] invoiceids,
            InvoiceStatus status
            )
        {
            if (invoiceids == null || !invoiceids.Any()) throw new ArgumentException();

            var oldInvoices = DaoFactory.InvoiceDao.GetByID(invoiceids).Where(CRMSecurity.CanAccessTo).ToList();

            var updatedInvoices = DaoFactory.InvoiceDao.UpdateInvoiceBatchStatus(oldInvoices.ToList().Select(i => i.ID).ToArray(), status);

            // detect what really changed
            var realUpdatedInvoices = updatedInvoices
                .Select(t => oldInvoices.FirstOrDefault(x => x.ID == t.ID && x.Status != t.Status))
                .Where(inv => inv != null)
                .ToList();

            if (realUpdatedInvoices.Any())
            {
                MessageService.Send(Request, MessageAction.InvoicesUpdatedStatus, MessageTarget.Create(realUpdatedInvoices.Select(x => x.ID)), realUpdatedInvoices.Select(x => x.Number), status.ToLocalizedString());
            }

            var invoiceItemsUpdated = new List<InvoiceItem>();

            if (status == InvoiceStatus.Sent || status == InvoiceStatus.Rejected)
            {
                var invoiceItemsAll = DaoFactory.InvoiceItemDao.GetAll();
                var invoiceItemsWithTrackInventory = invoiceItemsAll.Where(item => item.TrackInventory).ToList();

                if (status == InvoiceStatus.Sent && invoiceItemsWithTrackInventory != null && invoiceItemsWithTrackInventory.Count != 0)
                {
                    foreach (var inv in updatedInvoices)
                    {
                        if (inv.Status == InvoiceStatus.Sent)
                        {
                            //could be changed
                            var oldInv = oldInvoices.FirstOrDefault(i => i.ID == inv.ID);
                            if (oldInv != null && oldInv.Status == InvoiceStatus.Draft)
                            {
                                //was changed to Sent
                                var invoiceLines = DaoFactory.InvoiceLineDao.GetInvoiceLines(inv.ID);

                                foreach (var line in invoiceLines)
                                {
                                    var item = invoiceItemsWithTrackInventory.FirstOrDefault(ii => ii.ID == line.InvoiceItemID);
                                    if (item != null)
                                    {
                                        item.StockQuantity -= line.Quantity;
                                        DaoFactory.InvoiceItemDao.SaveOrUpdateInvoiceItem(item);
                                        var oldItem = invoiceItemsUpdated.Find(i => i.ID == item.ID);
                                        if (oldItem != null)
                                        {
                                            invoiceItemsUpdated.Remove(oldItem);
                                        }
                                        invoiceItemsUpdated.Add(item);
                                    }
                                }
                            }
                        }
                    }
                }

                if (status == InvoiceStatus.Rejected && invoiceItemsWithTrackInventory != null && invoiceItemsWithTrackInventory.Count != 0)
                {
                    foreach (var inv in updatedInvoices)
                    {
                        if (inv.Status == InvoiceStatus.Rejected)
                        {
                            //could be changed
                            var oldInv = oldInvoices.FirstOrDefault(i => i.ID == inv.ID);
                            if (oldInv != null && oldInv.Status == InvoiceStatus.Sent)
                            {
                                //was changed from Sent to Rejectes
                                var invoiceLines = DaoFactory.InvoiceLineDao.GetInvoiceLines(inv.ID);

                                foreach (var line in invoiceLines)
                                {
                                    var item = invoiceItemsWithTrackInventory.FirstOrDefault(ii => ii.ID == line.InvoiceItemID);
                                    if (item != null)
                                    {
                                        item.StockQuantity += line.Quantity;
                                        DaoFactory.InvoiceItemDao.SaveOrUpdateInvoiceItem(item);
                                        var oldItem = invoiceItemsUpdated.Find(i => i.ID == item.ID);
                                        if (oldItem != null)
                                        {
                                            invoiceItemsUpdated.Remove(oldItem);
                                        }
                                        invoiceItemsUpdated.Add(item);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            var listInvoiceBaseWrappers = ToListInvoiceBaseWrappers(updatedInvoices);

            return new KeyValuePair<IEnumerable<InvoiceBaseWrapper>, IEnumerable<InvoiceItemWrapper>>(listInvoiceBaseWrappers, invoiceItemsUpdated.ConvertAll(i => ToInvoiceItemWrapper(i)));
        }

        /// <summary>
        ///   Delete the invoice with the ID specified in the request
        /// </summary>
        /// <param name="invoiceid">Invoice ID</param>
        /// <short>Delete invoice</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice</returns>
        [Delete(@"invoice/{invoiceid:[0-9]+}")]
        public InvoiceBaseWrapper DeleteInvoice(int invoiceid)
        {
            if (invoiceid <= 0) throw new ArgumentException();

            var invoice = DaoFactory.InvoiceDao.DeleteInvoice(invoiceid);
            if (invoice == null) throw new ItemNotFoundException();

            MessageService.Send(Request, MessageAction.InvoiceDeleted, MessageTarget.Create(invoice.ID), invoice.Number);
            return ToInvoiceBaseWrapper(invoice);
        }

        /// <summary>
        ///   Deletes the group of invoices with the IDs specified in the request
        /// </summary>
        /// <param name="invoiceids">Invoice ID list</param>
        /// <short>Delete invoice group</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice list</returns>
        [Delete(@"invoice")]
        public IEnumerable<InvoiceBaseWrapper> DeleteBatchInvoices(IEnumerable<int> invoiceids)
        {
            if (invoiceids == null || !invoiceids.Any()) throw new ArgumentException();

            var invoices = DaoFactory.InvoiceDao.DeleteBatchInvoices(invoiceids.ToArray());
            MessageService.Send(Request, MessageAction.InvoicesDeleted, MessageTarget.Create(invoices.Select(x => x.ID)), invoices.Select(x => x.Number));

            return ToListInvoiceBaseWrappers(invoices);
        }

        /// <summary>
        ///  Creates the invoice with the parameters (contactId, consigneeId, etc.) specified in the request
        /// </summary>
        /// <param optional="false" name="number">Invoice number</param>
        /// <param optional="false" name="issueDate">Invoice issue date</param>
        /// <param optional="true" name="templateType">Invoice template type</param>
        /// <param optional="false" name="contactId">Invoice contact ID</param>
        /// <param optional="true" name="consigneeId">Invoice consignee ID</param>
        /// <param optional="true" name="entityId">Invoice entity ID</param>
        /// <param optional="true" name="billingAddressID">Invoice billing address ID</param>
        /// <param optional="true" name="deliveryAddressID">Invoice delivery address ID</param>
        /// <param optional="false" name="dueDate">Invoice due date</param>
        /// <param optional="false" name="language">Invoice language</param>
        /// <param optional="false" name="currency" remark="Allowed values: EUR, RUB etc. You can get the whole list of available currencies by api">Invoice currency</param>
        /// <param optional="false" name="exchangeRate">Invoice exchange rate</param>
        /// <param optional="true" name="purchaseOrderNumber">Invoice purchase order number</param>
        /// <param optional="false" name="terms">Invoice terms</param>
        /// <param optional="true" name="description">Invoice description</param>
        /// <param optional="false" name="invoiceLines">Invoice lines list</param>
        /// <short>Create invoice</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice</returns>
        /// <example>
        /// <![CDATA[
        /// 
        /// Data transfer in application/json format:
        /// 
        /// data: {
        ///    number: "invoice000001",
        ///    issueDate: "2015-06-01T00:00:00",
        ///    contactId: 10,
        ///    dueDate: "2025-06-01T00:00:00",
        ///    language: "es-ES",
        ///    currency: "rub",
        ///    exchangeRate: 54.32,
        ///    terms: "Terms for this invoice",
        ///    invoiceLines:
        ///    [{
        ///          invoiceItemID: 1,
        ///          invoiceTax1ID: 1,
        ///          invoiceTax2ID: 2,
        ///          description: "description for invoice line 1",
        ///          quantity: 100,
        ///          price: 7.7,
        ///          discount: 25
        ///    }]  
        /// }
        /// 
        /// where invoiceItemID, invoiceTax1ID, invoiceTax2ID - ids of the real existing invoice item and invoice taxes,
        /// contactId - id of the existing contact
        /// 
        /// ]]>
        /// </example>
        [Create(@"invoice")]
        public InvoiceWrapper CreateInvoice(
            string number,
            ApiDateTime issueDate,
            int templateType,
            int contactId,
            int consigneeId,
            int entityId,
            int billingAddressID,
            int deliveryAddressID,
            ApiDateTime dueDate,
            string language,
            string currency,
            decimal exchangeRate,
            string purchaseOrderNumber,
            string terms,
            string description,
            IEnumerable<InvoiceLine> invoiceLines
            )
        {
            var invoiceLinesList = invoiceLines != null ? invoiceLines.ToList() : new List<InvoiceLine>();
            if (!invoiceLinesList.Any() || !IsLinesForInvoiceCorrect(invoiceLinesList)) throw new ArgumentException();

            var invoice = new Invoice
            {
                Status = InvoiceStatus.Draft,
                Number = number,
                IssueDate = issueDate,
                TemplateType = (InvoiceTemplateType)templateType,
                ContactID = contactId,
                ConsigneeID = consigneeId,
                EntityType = EntityType.Opportunity,
                EntityID = entityId,
                DueDate = dueDate,
                Language = language,
                Currency = !String.IsNullOrEmpty(currency) ? currency.ToUpper() : null,
                ExchangeRate = exchangeRate,
                PurchaseOrderNumber = purchaseOrderNumber,
                Terms = terms,
                Description = description
            };

            CRMSecurity.DemandCreateOrUpdate(invoice);

            if (billingAddressID > 0)
            {
                var address = DaoFactory.ContactInfoDao.GetByID(billingAddressID);
                if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Billing || address.ContactID != contactId)
                    throw new ArgumentException();
            }

            if (deliveryAddressID > 0)
            {
                var address = DaoFactory.ContactInfoDao.GetByID(deliveryAddressID);
                if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Postal || address.ContactID != consigneeId)
                    throw new ArgumentException();
            }


            invoice.ID = DaoFactory.InvoiceDao.SaveOrUpdateInvoice(invoice);

            CreateInvoiceLines(invoiceLinesList, invoice);

            DaoFactory.InvoiceDao.UpdateInvoiceJsonData(invoice, billingAddressID, deliveryAddressID);
            return ToInvoiceWrapper(invoice);
        }


        private bool IsLinesForInvoiceCorrect(List<InvoiceLine> invoiceLines)
        {
            foreach (var line in invoiceLines)
            {
                if (line.InvoiceItemID <= 0 ||
                    line.Quantity < 0 || line.Price < 0 ||
                    line.Discount < 0 || line.Discount > 100 ||
                    line.InvoiceTax1ID < 0 || line.InvoiceTax2ID < 0)
                    return false;
                if (!DaoFactory.InvoiceItemDao.IsExist(line.InvoiceItemID))
                    return false;

                if (line.InvoiceTax1ID > 0 && !DaoFactory.InvoiceTaxDao.IsExist(line.InvoiceTax1ID))
                    return false;

                if (line.InvoiceTax2ID > 0 && !DaoFactory.InvoiceTaxDao.IsExist(line.InvoiceTax2ID))
                    return false;
            }
            return true;
        }

        private List<InvoiceLine> CreateInvoiceLines(List<InvoiceLine> invoiceLines, Invoice invoice)
        {
            var result = new List<InvoiceLine>();
            for (var i = 0; i < invoiceLines.Count; i++)
            {
                var line = new InvoiceLine
                {
                    ID = 0,
                    InvoiceID = invoice.ID,
                    InvoiceItemID = invoiceLines[i].InvoiceItemID,
                    InvoiceTax1ID = invoiceLines[i].InvoiceTax1ID,
                    InvoiceTax2ID = invoiceLines[i].InvoiceTax2ID,
                    SortOrder = i,
                    Description = invoiceLines[i].Description,
                    Quantity = invoiceLines[i].Quantity,
                    Price = invoiceLines[i].Price,
                    Discount = invoiceLines[i].Discount
                };

                line.ID = DaoFactory.InvoiceLineDao.SaveOrUpdateInvoiceLine(line);
                result.Add(line);
            }
            return result;
        }

        /// <summary>
        ///   Updates the selected invoice with the parameters (contactId, consigneeId, etc.) specified in the request
        /// </summary>
        /// <param optional="false" name="id">Invoice ID</param>
        /// <param optional="false" name="issueDate">Invoice issue date</param>
        /// <param optional="true" name="templateType">Invoice template type</param>
        /// <param optional="false" name="contactId">Invoice contact ID</param>
        /// <param optional="true" name="consigneeId">Invoice consignee ID</param>
        /// <param optional="true" name="entityId">Invoice entity ID</param>
        /// <param optional="true" name="billingAddressID">Invoice billing address ID</param>
        /// <param optional="true" name="deliveryAddressID">Invoice delivery address ID</param>
        /// <param name="dueDate">Invoice due date</param>
        /// <param optional="false" name="language">Invoice language</param>
        /// <param optional="false" name="currency" remark="Allowed values: EUR, RUB etc. You can get the whole list of available currencies by api">Invoice currency</param>
        /// <param optional="false" name="exchangeRate">Invoice exchange rate</param>
        /// <param optional="true" name="purchaseOrderNumber">Invoice purchase order number</param>
        /// <param optional="false" name="terms">Invoice terms</param>
        /// <param optional="true" name="description">Invoice description</param>
        /// <param optional="false" name="invoiceLines">Invoice lines list</param>
        /// <short>Update invoice</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice</returns>
        /// <example>
        /// <![CDATA[
        /// 
        /// Data transfer in application/json format:
        /// 
        /// data: {
        ///    id: 5,
        ///    issueDate: "2015-06-01T00:00:00",
        ///    contactId: 10,
        ///    dueDate: "2025-06-01T00:00:00",
        ///    language: "es-ES",
        ///    currency: "rub",
        ///    exchangeRate: 54.32,
        ///    terms: "Terms for this invoice",
        ///    invoiceLines:
        ///    [{
        ///          invoiceItemID: 1,
        ///          invoiceTax1ID: 1,
        ///          invoiceTax2ID: 2,
        ///          description: "description for invoice line 1",
        ///          quantity: 100,
        ///          price: 7.7,
        ///          discount: 25
        ///    }]
        /// }
        /// 
        /// where invoiceItemID, invoiceTax1ID, invoiceTax2ID - ids of the real existing invoice item and invoice taxes,
        /// contactId - id of the existing contact
        /// 
        /// ]]>
        /// </example>
        [Update(@"invoice/{id:[0-9]+}")]
        public InvoiceWrapper UpdateInvoice(
            int id,
            ApiDateTime issueDate,
            int templateType,
            int contactId,
            int consigneeId,
            int entityId,
            int billingAddressID,
            int deliveryAddressID,
            ApiDateTime dueDate,
            string language,
            string currency,
            decimal exchangeRate,
            string purchaseOrderNumber,
            string terms,
            string description,
            IEnumerable<InvoiceLine> invoiceLines)
        {

            var invoiceLinesList = invoiceLines != null ? invoiceLines.ToList() : new List<InvoiceLine>();
            if (!invoiceLinesList.Any() || !IsLinesForInvoiceCorrect(invoiceLinesList)) throw new ArgumentException();

            var invoice = DaoFactory.InvoiceDao.GetByID(id);
            if (invoice == null || !CRMSecurity.CanEdit(invoice)) throw new ItemNotFoundException();

            invoice.IssueDate = issueDate;
            invoice.TemplateType = (InvoiceTemplateType)templateType;
            invoice.ContactID = contactId;
            invoice.ConsigneeID = consigneeId;
            invoice.EntityType = EntityType.Opportunity;
            invoice.EntityID = entityId;
            invoice.DueDate = dueDate;
            invoice.Language = language;
            invoice.Currency = !String.IsNullOrEmpty(currency) ? currency.ToUpper() : null; ;
            invoice.ExchangeRate = exchangeRate;
            invoice.PurchaseOrderNumber = purchaseOrderNumber;
            invoice.Terms = terms;
            invoice.Description = description;
            invoice.JsonData = null;

            CRMSecurity.DemandCreateOrUpdate(invoice);

            if (billingAddressID > 0)
            {
                var address = DaoFactory.ContactInfoDao.GetByID(billingAddressID);
                if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Billing || address.ContactID != contactId)
                    throw new ArgumentException();
            }

            if (deliveryAddressID > 0)
            {
                var address = DaoFactory.ContactInfoDao.GetByID(deliveryAddressID);
                if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Postal || address.ContactID != consigneeId)
                    throw new ArgumentException();
            }

            DaoFactory.InvoiceDao.SaveOrUpdateInvoice(invoice);


            DaoFactory.InvoiceLineDao.DeleteInvoiceLines(invoice.ID);
            CreateInvoiceLines(invoiceLinesList, invoice);

            DaoFactory.InvoiceDao.UpdateInvoiceJsonData(invoice, billingAddressID, deliveryAddressID);

            if (Global.CanDownloadInvoices)
            {
                PdfQueueWorker.StartTask(HttpContext.Current, TenantProvider.CurrentTenantID, SecurityContext.CurrentAccount.ID, invoice.ID);
            }

            return ToInvoiceWrapper(invoice);
        }

        /// <summary>
        ///  Returns the pdf file associated with the invoice with the ID specified in the request
        /// </summary>
        /// <param name="invoiceid">Invoice ID</param>
        /// <short>Get invoice pdf file</short> 
        /// <category>Invoices</category>
        /// <returns>File</returns>
        [Read(@"invoice/{invoiceid:[0-9]+}/pdf")]
        public FileWrapper GetInvoicePdfExistOrCreate(int invoiceid)
        {
            if (invoiceid <= 0) throw new ArgumentException();

            var invoice = DaoFactory.InvoiceDao.GetByID(invoiceid);
            if (invoice == null) throw new ItemNotFoundException();

            if (!CRMSecurity.CanAccessTo(invoice))
            {
                throw CRMSecurity.CreateSecurityException();
            }

            return new FileWrapper(Global.GetInvoicePdfExistingOrCreate(invoice, DaoFactory));
        }

        /// <summary>
        ///  Returns information about the generation of the pdf file of the invoice
        /// </summary>
        /// <param name="invoiceId">Invoice ID</param>
        /// <param name="storageUrl">Storage Url</param>
        /// <param name="revisionId">Revision ID</param>
        /// <short>Check invoice pdf file</short> 
        /// <category>Invoices</category>
        /// <returns>ConverterData</returns>
        [Create(@"invoice/converter/data")]
        public ConverterData GetInvoiceConverterData(int invoiceId, string storageUrl, string revisionId)
        {
            if (invoiceId <= 0) throw new ArgumentException();

            var invoice = DaoFactory.InvoiceDao.GetByID(invoiceId);
            if (invoice == null) throw new ItemNotFoundException();

            if (!CRMSecurity.CanAccessTo(invoice))
            {
                throw CRMSecurity.CreateSecurityException();
            }

            var converterData = new ConverterData
            {
                StorageUrl = storageUrl,
                RevisionId = revisionId,
                InvoiceId = invoiceId
            };

            var existingFile = invoice.GetInvoiceFile(DaoFactory);
            if (existingFile != null)
            {
                converterData.FileId = invoice.FileID;
                return converterData;
            }

            if (string.IsNullOrEmpty(storageUrl) || string.IsNullOrEmpty(revisionId))
            {
                return PdfCreator.StartCreationFileAsync(invoice);
            }
            else
            {
                var convertedFile = PdfCreator.GetConvertedFile(converterData, DaoFactory);
                if (convertedFile != null)
                {
                    invoice.FileID = Int32.Parse(convertedFile.ID.ToString());
                    DaoFactory.InvoiceDao.UpdateInvoiceFileID(invoice.ID, invoice.FileID);
                    DaoFactory.RelationshipEventDao.AttachFiles(invoice.ContactID, invoice.EntityType, invoice.EntityID, new[] { invoice.FileID });

                    converterData.FileId = invoice.FileID;
                    return converterData;
                }
                else
                {
                    return converterData;
                }
            }
        }

        /// <summary>
        ///  Returns the existence of the invoice with the Number specified in the request
        /// </summary>
        /// <param name="number">Invoice number</param>
        /// <short>Check invoice existence by number</short> 
        /// <category>Invoices</category>
        /// <returns>IsExist</returns>
        [Read(@"invoice/bynumber/exist")]
        public Boolean GetInvoiceByNumberExistence(string number)
        {
            if (String.IsNullOrEmpty(number)) throw new ArgumentException();
            return DaoFactory.InvoiceDao.IsExist(number);
        }

        /// <summary>
        ///  Returns the detailed information about the invoice with the Number specified in the request
        /// </summary>
        /// <param name="number">Invoice number</param>
        /// <short>Get invoice by number</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice</returns>
        [Read(@"invoice/bynumber")]
        public InvoiceWrapper GetInvoiceByNumber(string number)
        {
            if (String.IsNullOrEmpty(number)) throw new ArgumentException();

            var invoice = DaoFactory.InvoiceDao.GetByNumber(number);
            if (invoice == null) throw new ItemNotFoundException();
            if (!CRMSecurity.CanAccessTo(invoice))
            {
                throw CRMSecurity.CreateSecurityException();
            }

            return new InvoiceWrapper(invoice);
        }

        /// <summary>
        ///   Returns the list of invoice items matching the creteria specified in the request
        /// </summary>
        /// <param name="status">Status</param>
        /// <param optional="true" name="inventoryStock">InventoryStock</param>
        /// <short>Get invoice item list</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceItem list</returns>
        [Read(@"invoiceitem/filter")]
        public IEnumerable<InvoiceItemWrapper> GetInvoiceItems(int status, bool? inventoryStock)
        {
            IEnumerable<InvoiceItemWrapper> result;

            InvoiceItemSortedByType sortBy;

            OrderBy invoiceOrderBy;

            var searchString = _context.FilterValue;

            if (InvoiceItemSortedByType.TryParse(_context.SortBy, true, out sortBy))
            {
                invoiceOrderBy = new OrderBy(sortBy, !_context.SortDescending);
            }
            else if (String.IsNullOrEmpty(_context.SortBy))
            {
                invoiceOrderBy = new OrderBy(InvoiceItemSortedByType.Name, true);
            }
            else
            {
                invoiceOrderBy = null;
            }

            var fromIndex = (int)_context.StartIndex;
            var count = (int)_context.Count;

            if (invoiceOrderBy != null)
            {
                result = DaoFactory.InvoiceItemDao.GetInvoiceItems(
                    searchString,
                    status,
                    inventoryStock,
                    fromIndex, count,
                    invoiceOrderBy)
                                   .ConvertAll(ToInvoiceItemWrapper);

                _context.SetDataPaginated();
                _context.SetDataFiltered();
                _context.SetDataSorted();
            }
            else
            {
                result = DaoFactory.InvoiceItemDao.GetInvoiceItems(
                    searchString,
                    status,
                    inventoryStock,
                    0, 0,
                    null)
                                   .ConvertAll(ToInvoiceItemWrapper);
            }

            int totalCount;

            if (result.Count() < count)
            {
                totalCount = fromIndex + result.Count();
            }
            else
            {
                totalCount = DaoFactory.InvoiceItemDao.GetInvoiceItemsCount(
                    searchString,
                    status,
                    inventoryStock);
            }

            _context.SetTotalCount(totalCount);

            return result.ToSmartList();
        }

        /// <summary>
        ///  Returns the detailed information about the invoice item with the ID specified in the request
        /// </summary>
        /// <param name="invoiceitemid">Invoice Item ID</param>
        /// <short>Get invoice item by ID</short> 
        /// <category>Invoices</category>
        /// <returns>Invoice Item</returns>
        [Read(@"invoiceitem/{invoiceitemid:[0-9]+}")]
        public InvoiceItemWrapper GetInvoiceItemByID(int invoiceitemid)
        {
            if (invoiceitemid <= 0) throw new ArgumentException();

            var invoiceItem = DaoFactory.InvoiceItemDao.GetByID(invoiceitemid);
            if (invoiceItem == null) throw new ItemNotFoundException();

            return ToInvoiceItemWrapper(invoiceItem);
        }

        /// <summary>
        ///  Creates the invoice line with the parameters (invoiceId, invoiceItemId, etc.) specified in the request
        /// </summary>
        /// <param optional="false" name="invoiceId">Invoice ID</param>
        /// <param optional="false" name="invoiceItemId">Invoice item ID</param>
        /// <param optional="true" name="invoiceTax1Id">First invoice tax ID</param>
        /// <param optional="true" name="invoiceTax2Id">Second invoice tax ID</param>
        /// <param optional="true" name="sortOrder">Sort Order</param>
        /// <param optional="true" name="description">Description</param>
        /// <param optional="true" name="quantity">Quantity</param>
        /// <param optional="true" name="price">Price</param>
        /// <param optional="true" name="discount">Discount</param>
        /// <short>Create invoice line</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceLine</returns>
        [Create(@"invoiceline")]
        public InvoiceLineWrapper CreateInvoiceLine(
            int invoiceId,
            int invoiceItemId,
            int invoiceTax1Id,
            int invoiceTax2Id,
            int sortOrder,
            string description,
            decimal quantity,
            decimal price,
            decimal discount
            )
        {
            var invoiceLine = new InvoiceLine
            {
                InvoiceID = invoiceId,
                InvoiceItemID = invoiceItemId,
                InvoiceTax1ID = invoiceTax1Id,
                InvoiceTax2ID = invoiceTax2Id,
                SortOrder = sortOrder,
                Description = description,
                Quantity = quantity,
                Price = price,
                Discount = discount
            };

            if (invoiceId <= 0)
                throw new ArgumentException();
            var invoice = DaoFactory.InvoiceDao.GetByID(invoiceId);
            CRMSecurity.DemandCreateOrUpdate(invoiceLine, invoice);

            invoiceLine.ID = DaoFactory.InvoiceLineDao.SaveOrUpdateInvoiceLine(invoiceLine);

            DaoFactory.InvoiceDao.UpdateInvoiceJsonDataAfterLinesUpdated(invoice);
            if (Global.CanDownloadInvoices)
            {
                PdfQueueWorker.StartTask(HttpContext.Current, TenantProvider.CurrentTenantID, SecurityContext.CurrentAccount.ID, invoice.ID);
            }

            return ToInvoiceLineWrapper(invoiceLine);
        }

        /// <summary>
        ///   Updates the selected invoice line with the parameters (invoiceId, invoiceItemId, etc.) specified in the request
        /// </summary>
        /// <param optional="false" name="id">Line ID</param>
        /// <param optional="false" name="invoiceId">Invoice ID</param>
        /// <param optional="false" name="invoiceItemId">Invoice item ID</param>
        /// <param optional="true" name="invoiceTax1Id">First invoice tax ID</param>
        /// <param optional="true" name="invoiceTax2Id">Second invoice tax ID</param>
        /// <param optional="true" name="sortOrder">Sort Order</param>
        /// <param optional="true" name="description">Description</param>
        /// <param optional="true" name="quantity">Quantity</param>
        /// <param optional="true" name="price">Price</param>
        /// <param optional="true" name="discount">Discount</param>
        /// <short>Update invoice line</short>
        /// <category>Invoices</category>
        /// <returns>InvoiceLine</returns>
        [Update(@"invoiceline/{id:[0-9]+}")]
        public InvoiceLineWrapper UpdateInvoiceLine(
            int id,
            int invoiceId,
            int invoiceItemId,
            int invoiceTax1Id,
            int invoiceTax2Id,
            int sortOrder,
            string description,
            decimal quantity,
            decimal price,
            decimal discount
            )
        {
            if (invoiceId <= 0)
                throw new ArgumentException();

            var invoiceLine = DaoFactory.InvoiceLineDao.GetByID(id);
            if (invoiceLine == null || invoiceLine.InvoiceID != invoiceId) throw new ItemNotFoundException();


            invoiceLine.InvoiceID = invoiceId;
            invoiceLine.InvoiceItemID = invoiceItemId;
            invoiceLine.InvoiceTax1ID = invoiceTax1Id;
            invoiceLine.InvoiceTax2ID = invoiceTax2Id;
            invoiceLine.SortOrder = sortOrder;
            invoiceLine.Description = description;
            invoiceLine.Quantity = quantity;
            invoiceLine.Price = price;
            invoiceLine.Discount = discount;

            var invoice = DaoFactory.InvoiceDao.GetByID(invoiceId);
            CRMSecurity.DemandCreateOrUpdate(invoiceLine, invoice);

            DaoFactory.InvoiceLineDao.SaveOrUpdateInvoiceLine(invoiceLine);

            DaoFactory.InvoiceDao.UpdateInvoiceJsonDataAfterLinesUpdated(invoice);
            if (Global.CanDownloadInvoices)
            {
                PdfQueueWorker.StartTask(HttpContext.Current, TenantProvider.CurrentTenantID, SecurityContext.CurrentAccount.ID, invoice.ID);
            }

            return ToInvoiceLineWrapper(invoiceLine);
        }

        /// <summary>
        ///    Deletes the invoice line with the ID specified in the request
        /// </summary>
        /// <param optional="false" name="id">Line ID</param>
        /// <short>Delete invoice line</short> 
        /// <category>Invoices</category>
        /// <returns>Line ID</returns>
        [Delete(@"invoiceline/{id:[0-9]+}")]
        public int DeleteInvoiceLine(int id)
        {
            var invoiceLine = DaoFactory.InvoiceLineDao.GetByID(id);
            if (invoiceLine == null) throw new ItemNotFoundException();
            if (!DaoFactory.InvoiceLineDao.CanDelete(invoiceLine.ID)) throw new Exception("Can't delete invoice line");

            var invoice = DaoFactory.InvoiceDao.GetByID(invoiceLine.InvoiceID);
            if (invoice == null) throw new ItemNotFoundException();
            if (!CRMSecurity.CanEdit(invoice)) throw CRMSecurity.CreateSecurityException();

            DaoFactory.InvoiceLineDao.DeleteInvoiceLine(id);

            DaoFactory.InvoiceDao.UpdateInvoiceJsonDataAfterLinesUpdated(invoice);
            if (Global.CanDownloadInvoices)
            {
                PdfQueueWorker.StartTask(HttpContext.Current, TenantProvider.CurrentTenantID, SecurityContext.CurrentAccount.ID, invoice.ID);
            }

            return id;
        }

        private InvoiceBaseWrapper ToInvoiceBaseWrapper(Invoice invoice)
        {
            var result = new InvoiceBaseWrapper(invoice);

            if (invoice.ContactID > 0)
            {
                result.Contact = ToContactBaseWrapperQuick(DaoFactory.ContactDao.GetByID(invoice.ContactID));
            }

            if (invoice.ConsigneeID > 0)
            {
                result.Consignee = ToContactBaseWrapperQuick(DaoFactory.ContactDao.GetByID(invoice.ConsigneeID));
            }

            if (invoice.EntityID > 0)
            {
                result.Entity = ToEntityWrapper(invoice.EntityType, invoice.EntityID);
            }

            result.Cost = invoice.GetInvoiceCost(DaoFactory);

            return result;
        }

        /// <summary>
        ///  Creates the invoice item with the parameters (title, description, price, etc.) specified in the request
        /// </summary>
        /// <param optional="false" name="title">Item title</param>
        /// <param optional="true" name="description">Item description</param>
        /// <param optional="false" name="price">Item price</param>
        /// <param optional="true" name="sku">Item stock keeping unit</param>
        /// <param optional="true" name="stockQuantity">Item stock quantity</param>
        /// <param optional="true" name="trackInventory">Track inventory</param>
        /// <param optional="true" name="invoiceTax1id">Item first invoice tax ID</param>
        /// <param optional="true" name="invoiceTax2id">Item second invoice tax ID</param>
        /// <short>Create invoice item</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceItem</returns>
        [Create(@"invoiceitem")]
        public InvoiceItemWrapper CreateInvoiceItem(
            string title,
            string description,
            decimal price,
            string sku,
            decimal stockQuantity,
            bool trackInventory,
            int invoiceTax1id,
            int invoiceTax2id)
        {
            if (!CRMSecurity.IsAdmin)
            {
                throw CRMSecurity.CreateSecurityException();
            }

            if (String.IsNullOrEmpty(title) || price <= 0) throw new ArgumentException();

            var invoiceItem = new InvoiceItem
            {
                Title = title,
                Description = description,
                Price = price,
                StockKeepingUnit = sku,
                StockQuantity = stockQuantity,
                TrackInventory = trackInventory,
                InvoiceTax1ID = invoiceTax1id,
                InvoiceTax2ID = invoiceTax2id
            };

            invoiceItem = DaoFactory.InvoiceItemDao.SaveOrUpdateInvoiceItem(invoiceItem);
            MessageService.Send(Request, MessageAction.InvoiceItemCreated, MessageTarget.Create(invoiceItem.ID), invoiceItem.Title);

            return ToInvoiceItemWrapper(invoiceItem);
        }

        /// <summary>
        ///   Updates the selected invoice item with the parameters (title, description, price, etc.) specified in the request
        /// </summary>
        /// <param optional="false" name="id">Item ID</param>
        /// <param optional="false" name="title">Item title</param>
        /// <param optional="true" name="description">Item description</param>
        /// <param optional="false" name="price">Item price</param>
        /// <param optional="true" name="sku">Item stock keeping unit</param>
        /// <param optional="true" name="stockQuantity">Item stock quantity</param>
        /// <param optional="true" name="trackInventory">Track inventory</param>
        /// <param optional="true" name="invoiceTax1id">Item first invoice tax ID</param>
        /// <param optional="true" name="invoiceTax2id">Item second invoice tax ID</param>
        /// <short>Update invoice item</short>
        /// <category>Invoices</category>
        /// <returns>InvoiceItem</returns>
        [Update(@"invoiceitem/{id:[0-9]+}")]
        public InvoiceItemWrapper UpdateInvoiceItem(int id,
                                                    string title,
                                                    string description,
                                                    decimal price,
                                                    string sku,
                                                    decimal stockQuantity,
                                                    bool trackInventory,
                                                    int invoiceTax1id,
                                                    int invoiceTax2id)
        {
            if (!CRMSecurity.IsAdmin)
            {
                throw CRMSecurity.CreateSecurityException();
            }

            if (id <= 0 || String.IsNullOrEmpty(title) || price <= 0) throw new ArgumentException();

            if (!DaoFactory.InvoiceItemDao.IsExist(id)) throw new ItemNotFoundException();

            var invoiceItem = new InvoiceItem
            {
                ID = id,
                Title = title,
                Description = description,
                Price = price,
                StockKeepingUnit = sku,
                StockQuantity = stockQuantity,
                TrackInventory = trackInventory,
                InvoiceTax1ID = invoiceTax1id,
                InvoiceTax2ID = invoiceTax2id
            };

            invoiceItem = DaoFactory.InvoiceItemDao.SaveOrUpdateInvoiceItem(invoiceItem);
            MessageService.Send(Request, MessageAction.InvoiceItemUpdated, MessageTarget.Create(invoiceItem.ID), invoiceItem.Title);

            return ToInvoiceItemWrapper(invoiceItem);
        }

        /// <summary>
        ///    Deletes the invoice item with the ID specified in the request
        /// </summary>
        /// <param name="id">Item ID</param>
        /// <short>Delete invoice item</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceItem</returns>
        [Delete(@"invoiceitem/{id:[0-9]+}")]
        public InvoiceItemWrapper DeleteInvoiceItem(int id)
        {
            if (!CRMSecurity.IsAdmin)
            {
                throw CRMSecurity.CreateSecurityException();
            }

            if (id <= 0) throw new ArgumentException();

            var invoiceItem = DaoFactory.InvoiceItemDao.DeleteInvoiceItem(id);
            if (invoiceItem == null) throw new ItemNotFoundException();

            MessageService.Send(Request, MessageAction.InvoiceItemDeleted, MessageTarget.Create(invoiceItem.ID), invoiceItem.Title);
            return ToInvoiceItemWrapper(invoiceItem);
        }

        /// <summary>
        ///   Deletes the group of invoice items with the IDs specified in the request
        /// </summary>
        /// <param name="ids">Item ID list</param>
        /// <short>Delete Invoice item group</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceItem list</returns>
        [Delete(@"invoiceitem")]
        public IEnumerable<InvoiceItemWrapper> DeleteBatchItems(IEnumerable<int> ids)
        {
            if (!CRMSecurity.IsAdmin)
            {
                throw CRMSecurity.CreateSecurityException();
            }

            if (ids == null) throw new ArgumentException();
            ids = ids.Distinct();

            var items = DaoFactory.InvoiceItemDao.DeleteBatchInvoiceItems(ids.ToArray());
            MessageService.Send(Request, MessageAction.InvoiceItemsDeleted, MessageTarget.Create(ids), items.Select(x => x.Title));

            return items.ConvertAll(ToInvoiceItemWrapper);
        }

        /// <summary>
        ///   Returns the list of invoice taxes
        /// </summary>
        /// <short>Get invoice taxes list</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceTax list</returns>
        [Read(@"invoice/tax")]
        public IEnumerable<InvoiceTaxWrapper> GetInvoiceTaxes()
        {
            return DaoFactory.InvoiceTaxDao.GetAll().ConvertAll(ToInvoiceTaxWrapper);
        }

        /// <summary>
        ///  Creates the invoice tax with the parameters (name, description, rate) specified in the request
        /// </summary>
        /// <param name="name">Tax name</param>
        /// <param name="description">Tax description</param>
        /// <param name="rate">Tax rate</param>
        /// <short>Create invoice tax</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceTax</returns>
        [Create(@"invoice/tax")]
        public InvoiceTaxWrapper CreateInvoiceTax(
            string name,
            string description,
            decimal rate)
        {
            if (!CRMSecurity.IsAdmin)
            {
                throw CRMSecurity.CreateSecurityException();
            }

            if (String.IsNullOrEmpty(name)) throw new ArgumentException(Web.CRM.Resources.CRMInvoiceResource.EmptyTaxNameError);
            if (DaoFactory.InvoiceTaxDao.IsExist(name)) throw new ArgumentException(Web.CRM.Resources.CRMInvoiceResource.ExistTaxNameError);

            var invoiceTax = new InvoiceTax
            {
                Name = name,
                Description = description,
                Rate = rate
            };

            invoiceTax = DaoFactory.InvoiceTaxDao.SaveOrUpdateInvoiceTax(invoiceTax);
            MessageService.Send(Request, MessageAction.InvoiceTaxCreated, MessageTarget.Create(invoiceTax.ID), invoiceTax.Name);

            return ToInvoiceTaxWrapper(invoiceTax);
        }

        /// <summary>
        ///   Updates the selected invoice tax with the parameters (name, description, rate) specified in the request
        /// </summary>
        /// <param name="id">Tax ID</param>
        /// <param name="name">Tax name</param>
        /// <param name="description">Tax description</param>
        /// <param name="rate">Tax rate</param>
        /// <short>Update invoice tax</short>
        /// <category>Invoices</category>
        /// <returns>InvoiceTax</returns>
        [Update(@"invoice/tax/{id:[0-9]+}")]
        public InvoiceTaxWrapper UpdateInvoiceTax(
            int id,
            string name,
            string description,
            decimal rate)
        {
            if (!CRMSecurity.IsAdmin)
            {
                throw CRMSecurity.CreateSecurityException();
            }

            if (id <= 0 || String.IsNullOrEmpty(name)) throw new ArgumentException(Web.CRM.Resources.CRMInvoiceResource.EmptyTaxNameError);

            if (!DaoFactory.InvoiceTaxDao.IsExist(id)) throw new ItemNotFoundException();

            var invoiceTax = new InvoiceTax
            {
                ID = id,
                Name = name,
                Description = description,
                Rate = rate
            };

            invoiceTax = DaoFactory.InvoiceTaxDao.SaveOrUpdateInvoiceTax(invoiceTax);
            MessageService.Send(Request, MessageAction.InvoiceTaxUpdated, MessageTarget.Create(invoiceTax.ID), invoiceTax.Name);

            return ToInvoiceTaxWrapper(invoiceTax);
        }

        /// <summary>
        ///   Delete the invoice tax with the ID specified in the request
        /// </summary>
        /// <param name="id">Tax ID</param>
        /// <short>Delete invoice tax</short> 
        /// <category>Invoices</category>
        /// <returns>InvoiceTax</returns>
        [Delete(@"invoice/tax/{id:[0-9]+}")]
        public InvoiceTaxWrapper DeleteInvoiceTax(int id)
        {
            if (!CRMSecurity.IsAdmin)
            {
                throw CRMSecurity.CreateSecurityException();
            }

            if (id <= 0) throw new ArgumentException();

            var invoiceTax = DaoFactory.InvoiceTaxDao.DeleteInvoiceTax(id);
            if (invoiceTax == null) throw new ItemNotFoundException();

            MessageService.Send(Request, MessageAction.InvoiceTaxDeleted, MessageTarget.Create(invoiceTax.ID), invoiceTax.Name);
            return ToInvoiceTaxWrapper(invoiceTax);
        }

        /// <summary>
        ///  Get default invoice settings
        /// </summary>
        /// <short>Get default invoice settings</short>
        /// <category>Invoices</category>
        /// <returns>InvoiceSetting</returns>
        [Read(@"invoice/settings")]
        public InvoiceSetting GetSettings()
        {
            return DaoFactory.InvoiceDao.GetSettings();
        }

        /// <summary>
        ///  Save default invoice number
        /// </summary>
        /// <param name="autogenerated">Is autogenerated</param>
        /// <param name="prefix">Prefix</param>
        /// <param name="number">Number</param>
        /// <short>Save default invoice number</short>
        /// <category>Invoices</category>
        /// <returns>InvoiceSetting</returns>
        [Update(@"invoice/settings/name")]
        public InvoiceSetting SaveNumberSettings(bool autogenerated, string prefix, string number)
        {
            if (!CRMSecurity.IsAdmin) throw CRMSecurity.CreateSecurityException();

            if (autogenerated && string.IsNullOrEmpty(number))
                throw new ArgumentException();

            if (autogenerated && DaoFactory.InvoiceDao.IsExist(prefix + number))
                throw new ArgumentException();

            var invoiceSetting = GetSettings();

            invoiceSetting.Autogenerated = autogenerated;
            invoiceSetting.Prefix = prefix;
            invoiceSetting.Number = number;

            var settings = DaoFactory.InvoiceDao.SaveInvoiceSettings(invoiceSetting);
            MessageService.Send(Request, MessageAction.InvoiceNumberFormatUpdated);

            return settings;
        }

        /// <summary>
        ///  Save default invoice terms
        /// </summary>
        /// <param name="terms">Terms</param>
        /// <short>Save default invoice terms</short>
        /// <category>Invoices</category>
        /// <returns>InvoiceSetting</returns>
        [Update(@"invoice/settings/terms")]
        public InvoiceSetting SaveTermsSettings(string terms)
        {
            if (!CRMSecurity.IsAdmin) throw CRMSecurity.CreateSecurityException();

            var invoiceSetting = GetSettings();

            invoiceSetting.Terms = terms;

            var result = DaoFactory.InvoiceDao.SaveInvoiceSettings(invoiceSetting);
            MessageService.Send(Request, MessageAction.InvoiceDefaultTermsUpdated);

            return result;
        }

        /// <visible>false</visible>
        [Update(@"invoice/{invoiceid:[0-9]+}/creationdate")]
        public void SetInvoiceCreationDate(int invoiceid, ApiDateTime creationDate)
        {
            var dao = DaoFactory.InvoiceDao;
            var invoice = dao.GetByID(invoiceid);

            if (invoice == null || !CRMSecurity.CanAccessTo(invoice))
                throw new ItemNotFoundException();

            dao.SetInvoiceCreationDate(invoiceid, creationDate);
        }

        /// <visible>false</visible>
        [Update(@"invoice/{invoiceid:[0-9]+}/lastmodifeddate")]
        public void SetInvoiceLastModifedDate(int invoiceid, ApiDateTime lastModifedDate)
        {
            var dao = DaoFactory.InvoiceDao;
            var invoice = dao.GetByID(invoiceid);

            if (invoice == null || !CRMSecurity.CanAccessTo(invoice))
                throw new ItemNotFoundException();

            dao.SetInvoiceLastModifedDate(invoiceid, lastModifedDate);
        }

        private InvoiceWrapper ToInvoiceWrapper(Invoice invoice)
        {
            var result = new InvoiceWrapper(invoice);

            if (invoice.ContactID > 0)
            {
                result.Contact = ToContactBaseWrapperQuick(DaoFactory.ContactDao.GetByID(invoice.ContactID));
            }

            if (invoice.ConsigneeID > 0)
            {
                result.Consignee = ToContactBaseWrapperQuick(DaoFactory.ContactDao.GetByID(invoice.ConsigneeID));
            }

            if (invoice.EntityID > 0)
            {
                result.Entity = ToEntityWrapper(invoice.EntityType, invoice.EntityID);
            }

            result.Cost = invoice.GetInvoiceCost(DaoFactory);

            result.InvoiceLines = invoice.GetInvoiceLines(DaoFactory).Select(ToInvoiceLineWrapper).ToList();

            return result;
        }

        private InvoiceItemWrapper ToInvoiceItemWrapper(InvoiceItem invoiceItem)
        {
            var result = new InvoiceItemWrapper(invoiceItem);

            if (invoiceItem.InvoiceTax1ID > 0)
            {
                result.InvoiceTax1 = ToInvoiceTaxWrapper(DaoFactory.InvoiceTaxDao.GetByID(invoiceItem.InvoiceTax1ID));
            }
            if (invoiceItem.InvoiceTax2ID > 0)
            {
                result.InvoiceTax2 = ToInvoiceTaxWrapper(DaoFactory.InvoiceTaxDao.GetByID(invoiceItem.InvoiceTax2ID));
            }

            return result;
        }

        private InvoiceTaxWrapper ToInvoiceTaxWrapper(InvoiceTax invoiceTax)
        {
            return new InvoiceTaxWrapper(invoiceTax);
        }

        private InvoiceLineWrapper ToInvoiceLineWrapper(InvoiceLine invoiceLine)
        {
            return new InvoiceLineWrapper(invoiceLine);
        }

        private IEnumerable<InvoiceBaseWrapper> ToListInvoiceBaseWrappers(ICollection<Invoice> invoices)
        {
            if (invoices == null || invoices.Count == 0) return new List<InvoiceWrapper>();

            var result = new List<InvoiceBaseWrapper>();

            var invoiceIDs = new HashSet<int>();
            var contactIDs = new HashSet<int>();
            var dealsIDs = new HashSet<int>();

            foreach (var invoice in invoices)
            {
                invoiceIDs.Add(invoice.ID);
                contactIDs.Add(invoice.ContactID);
                contactIDs.Add(invoice.ConsigneeID);
                dealsIDs.Add(invoice.EntityID);
            }

            var contacts = DaoFactory.ContactDao.GetContacts(contactIDs.ToArray())
                            .ToDictionary(contact => contact.ID, ToContactBaseWrapperQuick);

            var deals = DaoFactory.DealDao.GetDeals(dealsIDs.ToArray())
                            .ToDictionary(
                                deal => deal.ID,
                                deal => new EntityWrapper
                                {
                                    EntityId = deal.ID,
                                    EntityTitle = deal.Title,
                                    EntityType = "opportunity"
                                }
                            );

            var invoiceLines = DaoFactory.InvoiceLineDao.GetInvoicesLines(invoiceIDs.ToArray());

            var invoiceTaxIDs = new HashSet<int>();

            foreach (var invoiceLine in invoiceLines)
            {
                invoiceTaxIDs.Add(invoiceLine.InvoiceTax1ID);
                invoiceTaxIDs.Add(invoiceLine.InvoiceTax2ID);
            }

            var invoiceTaxes = DaoFactory.InvoiceTaxDao.GetByID(invoiceTaxIDs.ToArray());

            var invoiceCosts = invoiceLines
                                .GroupBy(invoiceLine => invoiceLine.InvoiceID)
                                .ToDictionary(
                                    item => item.Key,
                                    item => DaoFactory.InvoiceDao.CalculateInvoiceCost(item.Select(invoiceLine => invoiceLine), invoiceTaxes)
                                );

            foreach (var invoice in invoices)
            {
                var invoiceWrapper = new InvoiceBaseWrapper(invoice);

                if (contacts.ContainsKey(invoice.ContactID))
                {
                    invoiceWrapper.Contact = contacts[invoice.ContactID];
                }

                if (contacts.ContainsKey(invoice.ConsigneeID))
                {
                    invoiceWrapper.Consignee = contacts[invoice.ConsigneeID];
                }

                if (invoice.EntityID > 0 && deals.ContainsKey(invoice.EntityID))
                {
                    invoiceWrapper.Entity = deals[invoice.EntityID];
                }

                if (invoiceCosts.ContainsKey(invoice.ID))
                {
                    invoiceWrapper.Cost = invoiceCosts[invoice.ID];
                }

                result.Add(invoiceWrapper);
            }

            return result;
        }
    }
}

<|start_filename|>common/ASC.Common/Notify/Patterns/IPatternProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Notify.Engine;
using ASC.Notify.Model;

namespace ASC.Notify.Patterns
{
    public interface IPatternProvider
    {
        Func<INotifyAction, string, NotifyRequest, IPattern> GetPatternMethod { get; set; }

        IPattern GetPattern(INotifyAction action, string senderName);

        IPatternFormatter GetFormatter(IPattern pattern);
    }
}

<|start_filename|>common/ASC.Common/Data/Sql/Dialects/SqlDialect.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Data;
using System.Text;

namespace ASC.Common.Data.Sql
{
    public class SqlDialect : ISqlDialect
    {
        public static readonly ISqlDialect Default = new SqlDialect();


        public virtual string IdentityQuery
        {
            get { return "@@identity"; }
        }

        public virtual string Autoincrement
        {
            get { return "AUTOINCREMENT"; }
        }

        public virtual string InsertIgnore
        {
            get { return "insert ignore"; }
        }


        public virtual bool SupportMultiTableUpdate
        {
            get { return true; }
        }

        public virtual bool SeparateCreateIndex
        {
            get { return true; }
        }


        public virtual string DbTypeToString(DbType type, int size, int precision)
        {
            var s = new StringBuilder(type.ToString().ToLower());
            if (0 < size)
            {
                s.AppendFormat(0 < precision ? "({0}, {1})" : "({0})", size, precision);
            }
            return s.ToString();
        }

        public virtual IsolationLevel GetSupportedIsolationLevel(IsolationLevel il)
        {
            return il;
        }

        public string UseIndex(string index)
        {
            return string.Empty;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/CommentsUserControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Bookmarking.Business.Permissions;
using ASC.Bookmarking.Pojo;
using ASC.Web.Studio.UserControls.Common.Comments;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;
using ASC.Web.UserControls.Bookmarking.Common.Util;

namespace ASC.Web.UserControls.Bookmarking
{
    public partial class CommentsUserControl : System.Web.UI.UserControl
    {
        #region Fields

        private readonly BookmarkingServiceHelper _serviceHelper = BookmarkingServiceHelper.GetCurrentInstanse();

        public long BookmarkID { get; set; }

        #region Bookmark Comments

        private IList<Comment> _bookmarkComments;

        public IList<Comment> BookmarkComments
        {
            get { return _bookmarkComments ?? new List<Comment>(); }
            set { _bookmarkComments = value; }
        }

        #endregion

        public CommentsList Comments
        {
            get
            {
                CommentList = _serviceHelper.Comments;
                return _serviceHelper.Comments;
            }
            set
            {
                _serviceHelper.Comments = CommentList;
                BookmarkingServiceHelper.UpdateCurrentInstanse(_serviceHelper);
            }
        }

        #endregion

        protected void Page_Load(object sender, EventArgs e)
        {
            InitComments();
        }

        public void InitComments()
        {
            ConfigureComments(CommentList);
            CommentList.Items = BookmarkingConverter.ConvertCommentList(BookmarkComments);
            Comments = CommentList;
        }

        private void ConfigureComments(CommentsList commentList)
        {
            CommonControlsConfigurer.CommentsConfigure(commentList);

            // add comments permission check		
            commentList.IsShowAddCommentBtn = BookmarkingPermissionsCheck.PermissionCheckCreateComment();

            commentList.BehaviorID = "commentsObj";
            commentList.ModuleName = "bookmarks";
            commentList.FckDomainName = "bookmarking_comments";
            commentList.TotalCount = BookmarkComments.Count;
            commentList.ShowCaption = false;
            commentList.ObjectID = BookmarkID.ToString();
        }

    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Server/IMAP_SearchKey.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP.Server
{
    #region usings

    using System;
    using Mime;

    #endregion

    /// <summary>
    /// IMAP search key (RFC 3501 6.4.4 SEARCH Command).
    /// </summary>
    internal class SearchKey
    {
        #region Members

        private readonly string m_SearchKeyName = "";
        private readonly object m_SearchKeyValue;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SearchKey(string searchKeyName, object value)
        {
            m_SearchKeyName = searchKeyName;
            m_SearchKeyValue = value;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses one search key from current position. Returns null if there isn't any search key left.
        /// </summary>
        /// <param name="reader"></param>
        public static SearchKey Parse(StringReader reader)
        {
            string searchKeyName = "";
            object searchKeyValue = null;

            //Remove spaces from string start
            reader.ReadToFirstChar();

            // Search keyname is always 1 word
            string word = reader.ReadWord();
            if (word == null)
            {
                return null;
            }
            word = word.ToUpper().Trim();

            //Remove spaces from string start
            reader.ReadToFirstChar();

            #region ALL

            // ALL
            //		All messages in the mailbox; the default initial key for ANDing.
            if (word == "ALL")
            {
                searchKeyName = "ALL";
            }

                #endregion

                #region ANSWERED

                // ANSWERED
                //		Messages with the \Answered flag set.
            else if (word == "ANSWERED")
            {
                // We internally use KEYWORD ANSWERED
                searchKeyName = "KEYWORD";
                searchKeyValue = "ANSWERED";
            }

                #endregion

                #region BCC

                // BCC <string>
                //		Messages that contain the specified string in the envelope structure's BCC field.
            else if (word == "BCC")
            {
                // We internally use HEADER "BCC:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = new[] {"BCC:", TextUtils.UnQuoteString(val)};
                }
                else
                {
                    throw new Exception("BCC <string> value is missing !");
                }
            }

                #endregion

                #region BEFORE

                //	BEFORE <date>
                //		Messages whose internal date (disregarding time and timezone) is earlier than the specified date.
            else if (word == "BEFORE")
            {
                searchKeyName = "BEFORE";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    // Parse date
                    try
                    {
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                        // Invalid date
                    catch
                    {
                        throw new Exception("Invalid BEFORE <date> value '" + val +
                                            "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else
                {
                    throw new Exception("BEFORE <date> value is missing !");
                }
            }

                #endregion

                #region BODY

                //	BODY <string>
                //		Messages that contain the specified string in the body of the message.
            else if (word == "BODY")
            {
                searchKeyName = "BODY";

                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = val;
                }
                else
                {
                    throw new Exception("BODY <string> value is missing !");
                }
            }

                #endregion

                #region CC

                //	CC <string>
                //		Messages that contain the specified string in the envelope structure's CC field.
            else if (word == "CC")
            {
                // We internally use HEADER "CC:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = new[] {"CC:", TextUtils.UnQuoteString(val)};
                }
                else
                {
                    throw new Exception("CC <string> value is missing !");
                }
            }

                #endregion

                #region DELETED

                // DELETED
                //		Messages with the \Deleted flag set.
            else if (word == "DELETED")
            {
                // We internally use KEYWORD DELETED
                searchKeyName = "KEYWORD";
                searchKeyValue = "DELETED";
            }

                #endregion

                #region DRAFT

                //	DRAFT
                //		Messages with the \Draft flag set.
            else if (word == "DRAFT")
            {
                // We internally use KEYWORD DRAFT
                searchKeyName = "KEYWORD";
                searchKeyValue = "DRAFT";
            }

                #endregion

                #region FLAGGED

                //	FLAGGED
                //		Messages with the \Flagged flag set.
            else if (word == "FLAGGED")
            {
                // We internally use KEYWORD FLAGGED
                searchKeyName = "KEYWORD";
                searchKeyValue = "FLAGGED";
            }

                #endregion

                #region FROM

                //	FROM <string>
                //		Messages that contain the specified string in the envelope structure's FROM field.
            else if (word == "FROM")
            {
                // We internally use HEADER "FROM:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = new[] {"FROM:", TextUtils.UnQuoteString(val)};
                }
                else
                {
                    throw new Exception("FROM <string> value is missing !");
                }
            }

                #endregion

                #region HEADER

                //	HEADER <field-name> <string>
                //		Messages that have a header with the specified field-name (as
                //		defined in [RFC-2822]) and that contains the specified string
                //		in the text of the header (what comes after the colon).  If the
                //		string to search is zero-length, this matches all messages that
                //		have a header line with the specified field-name regardless of
                //		the contents.
            else if (word == "HEADER")
            {
                searchKeyName = "HEADER";

                // Read <field-name>
                string fieldName = ReadString(reader);
                if (fieldName != null)
                {
                    fieldName = TextUtils.UnQuoteString(fieldName);
                }
                else
                {
                    throw new Exception("HEADER <field-name> value is missing !");
                }

                // Read <string>
                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = new[] {fieldName, TextUtils.UnQuoteString(val)};
                }
                else
                {
                    throw new Exception("(HEADER <field-name>) <string> value is missing !");
                }
            }

                #endregion

                #region KEYWORD

                //	KEYWORD <flag>
                //		Messages with the specified keyword flag set.
            else if (word == "KEYWORD")
            {
                searchKeyName = "KEYWORD";

                // Read <flag>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    searchKeyValue = TextUtils.UnQuoteString(val);
                }
                else
                {
                    throw new Exception("KEYWORD <flag> value is missing !");
                }
            }

                #endregion

                #region LARGER

                //	LARGER <n>
                //		Messages with an [RFC-2822] size larger than the specified number of octets.
            else if (word == "LARGER")
            {
                searchKeyName = "LARGER";

                // Read <n>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    // Parse <n> - must be integer value
                    try
                    {
                        searchKeyValue = Convert.ToInt64(TextUtils.UnQuoteString(val));
                    }
                        // Invalid <n>
                    catch
                    {
                        throw new Exception("Invalid LARGER <n> value '" + val +
                                            "', it must be numeric value !");
                    }
                }
                else
                {
                    throw new Exception("LARGER <n> value is missing !");
                }
            }

                #endregion

                #region NEW

                //	NEW
                //		Messages that have the \Recent flag set but not the \Seen flag.
                //		This is functionally equivalent to "(RECENT UNSEEN)".
            else if (word == "NEW")
            {
                // We internally use KEYWORD RECENT
                searchKeyName = "KEYWORD";
                searchKeyValue = "RECENT";
            }

                #endregion

                #region NOT

                //	NOT <search-key> or (<search-key> <search-key> ...)(SearchGroup)
                //		Messages that do not match the specified search key.
            else if (word == "NOT")
            {
                searchKeyName = "NOT";

                object searchItem = SearchGroup.ParseSearchKey(reader);
                if (searchItem != null)
                {
                    searchKeyValue = searchItem;
                }
                else
                {
                    throw new Exception("Required NOT <search-key> isn't specified !");
                }
            }

                #endregion

                #region OLD

                //	OLD
                //		Messages that do not have the \Recent flag set.  This is
                //		functionally equivalent to "NOT RECENT" (as opposed to "NOT	NEW").
            else if (word == "OLD")
            {
                // We internally use UNKEYWORD RECENT
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "RECENT";
            }

                #endregion

                #region ON

                //	ON <date>
                //		Messages whose internal date (disregarding time and timezone) is within the specified date.
            else if (word == "ON")
            {
                searchKeyName = "ON";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    // Parse date
                    try
                    {
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                        // Invalid date
                    catch
                    {
                        throw new Exception("Invalid ON <date> value '" + val +
                                            "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else
                {
                    throw new Exception("ON <date> value is missing !");
                }
            }

                #endregion

                #region OR

                //	OR <search-key1> <search-key2> - SearckKey can be parenthesis list of keys !
                //		Messages that match either search key.
            else if (word == "OR")
            {
                searchKeyName = "OR";

                //--- <search-key1> ----------------------------------------------------//
                object searchKey1 = SearchGroup.ParseSearchKey(reader);
                if (searchKey1 == null)
                {
                    throw new Exception("Required OR <search-key1> isn't specified !");
                }
                //----------------------------------------------------------------------//

                //--- <search-key2> ----------------------------------------------------//
                object searchKey2 = SearchGroup.ParseSearchKey(reader);
                if (searchKey2 == null)
                {
                    throw new Exception("Required (OR <search-key1>) <search-key2> isn't specified !");
                }
                //-----------------------------------------------------------------------//

                searchKeyValue = new[] {searchKey1, searchKey2};
            }

                #endregion

                #region RECENT

                //	RECENT
                //		Messages that have the \Recent flag set.
            else if (word == "RECENT")
            {
                // We internally use KEYWORD RECENT
                searchKeyName = "KEYWORD";
                searchKeyValue = "RECENT";
            }

                #endregion

                #region SEEN

                //	SEEN
                //		Messages that have the \Seen flag set.
            else if (word == "SEEN")
            {
                // We internally use KEYWORD SEEN
                searchKeyName = "KEYWORD";
                searchKeyValue = "SEEN";
            }

                #endregion

                #region SENTBEFORE

                //	SENTBEFORE <date>
                //		Messages whose [RFC-2822] Date: header (disregarding time and
                //		timezone) is earlier than the specified date.
            else if (word == "SENTBEFORE")
            {
                searchKeyName = "SENTBEFORE";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    // Parse date
                    try
                    {
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                        // Invalid date
                    catch
                    {
                        throw new Exception("Invalid SENTBEFORE <date> value '" + val +
                                            "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else
                {
                    throw new Exception("SENTBEFORE <date> value is missing !");
                }
            }

                #endregion

                #region SENTON

                //	SENTON <date>
                //		Messages whose [RFC-2822] Date: header (disregarding time and
                //		timezone) is within the specified date.
            else if (word == "SENTON")
            {
                searchKeyName = "SENTON";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    // Parse date
                    try
                    {
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                        // Invalid date
                    catch
                    {
                        throw new Exception("Invalid SENTON <date> value '" + val +
                                            "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else
                {
                    throw new Exception("SENTON <date> value is missing !");
                }
            }

                #endregion

                #region SENTSINCE

                //	SENTSINCE <date>
                //		Messages whose [RFC-2822] Date: header (disregarding time and
                //		timezone) is within or later than the specified date.
            else if (word == "SENTSINCE")
            {
                searchKeyName = "SENTSINCE";

                // Read <date>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    // Parse date
                    try
                    {
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                        // Invalid date
                    catch
                    {
                        throw new Exception("Invalid SENTSINCE <date> value '" + val +
                                            "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else
                {
                    throw new Exception("SENTSINCE <date> value is missing !");
                }
            }

                #endregion

                #region SINCE

                //	SINCE <date>
                //		Messages whose internal date (disregarding time and timezone)
                //		is within or later than the specified date.
            else if (word == "SINCE")
            {
                searchKeyName = "SINCE";

                // Read <date>
                string val = reader.ReadWord();
                if (val != null)
                {
                    // Parse date
                    try
                    {
                        searchKeyValue = IMAP_Utils.ParseDate(TextUtils.UnQuoteString(val));
                    }
                        // Invalid date
                    catch
                    {
                        throw new Exception("Invalid SINCE <date> value '" + val +
                                            "', valid date syntax: {dd-MMM-yyyy} !");
                    }
                }
                else
                {
                    throw new Exception("SINCE <date> value is missing !");
                }
            }

                #endregion

                #region SMALLER

                //	SMALLER <n>
                //		Messages with an [RFC-2822] size smaller than the specified number of octets.
            else if (word == "SMALLER")
            {
                searchKeyName = "SMALLER";

                // Read <n>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    val = TextUtils.UnQuoteString(val);

                    // Parse <n> - must be integer value
                    try
                    {
                        searchKeyValue = Convert.ToInt64(val);
                    }
                        // Invalid <n>
                    catch
                    {
                        throw new Exception("Invalid SMALLER <n> value '" + val +
                                            "', it must be numeric value !");
                    }
                }
                else
                {
                    throw new Exception("SMALLER <n> value is missing !");
                }
            }

                #endregion

                #region SUBJECT

                //	SUBJECT <string>
                //		Messages that contain the specified string in the envelope structure's SUBJECT field.
            else if (word == "SUBJECT")
            {
                // We internally use HEADER "SUBJECT:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = new[] {"SUBJECT:", TextUtils.UnQuoteString(val)};
                }
                else
                {
                    throw new Exception("SUBJECT <string> value is missing !");
                }
            }

                #endregion

                #region TEXT

                //	TEXT <string>
                //		Messages that contain the specified string in the header or body of the message.
            else if (word == "TEXT")
            {
                searchKeyName = "TEXT";

                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = val;
                }
                else
                {
                    throw new Exception("TEXT <string> value is missing !");
                }
            }

                #endregion

                #region TO

                //	TO <string>
                //		Messages that contain the specified string in the envelope structure's TO field.
            else if (word == "TO")
            {
                // We internally use HEADER "TO:" "value"
                searchKeyName = "HEADER";

                // Read <string>
                string val = ReadString(reader);
                if (val != null)
                {
                    searchKeyValue = new[] {"TO:", TextUtils.UnQuoteString(val)};
                }
                else
                {
                    throw new Exception("TO <string> value is missing !");
                }
            }

                #endregion

                #region UID

                //	UID <sequence set>
                //		Messages with unique identifiers corresponding to the specified
                //		unique identifier set.  Sequence set ranges are permitted.
            else if (word == "UID")
            {
                searchKeyName = "UID";

                // Read <sequence set>
                string val = reader.QuotedReadToDelimiter(' ');

                if (val != null)
                {
                    try
                    {
                        IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
                        sequenceSet.Parse(TextUtils.UnQuoteString(val), long.MaxValue);

                        searchKeyValue = sequenceSet;
                    }
                    catch
                    {
                        throw new Exception("Invalid UID <sequence-set> value '" + val + "' !");
                    }
                }
                else
                {
                    throw new Exception("UID <sequence-set> value is missing !");
                }
            }

                #endregion

                #region UNANSWERED

                //	UNANSWERED
                //		Messages that do not have the \Answered flag set.
            else if (word == "UNANSWERED")
            {
                // We internally use UNKEYWORD SEEN
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "ANSWERED";
            }

                #endregion

                #region UNDELETED

                //	UNDELETED
                //		Messages that do not have the \Deleted flag set.
            else if (word == "UNDELETED")
            {
                // We internally use UNKEYWORD UNDELETED
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "DELETED";
            }

                #endregion

                #region UNDRAFT

                //	UNDRAFT
                //		Messages that do not have the \Draft flag set.
            else if (word == "UNDRAFT")
            {
                // We internally use UNKEYWORD UNDRAFT
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "DRAFT";
            }

                #endregion

                #region UNFLAGGED

                //	UNFLAGGED
                //		Messages that do not have the \Flagged flag set.
            else if (word == "UNFLAGGED")
            {
                // We internally use UNKEYWORD UNFLAGGED
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "FLAGGED";
            }

                #endregion

                #region UNKEYWORD

                //	UNKEYWORD <flag>
                //		Messages that do not have the specified keyword flag set.
            else if (word == "UNKEYWORD")
            {
                searchKeyName = "UNKEYWORD";

                // Read <flag>
                string val = reader.QuotedReadToDelimiter(' ');
                if (val != null)
                {
                    searchKeyValue = TextUtils.UnQuoteString(val);
                }
                else
                {
                    throw new Exception("UNKEYWORD <flag> value is missing !");
                }
            }

                #endregion

                #region UNSEEN

                //	UNSEEN
                //		Messages that do not have the \Seen flag set.
            else if (word == "UNSEEN")
            {
                // We internally use UNKEYWORD UNSEEN
                searchKeyName = "UNKEYWORD";
                searchKeyValue = "SEEN";
            }

                #endregion

                #region Unknown or SEQUENCESET

                // Unkown keyword or <sequence set>
            else
            {
                // DUMMY palce(bad design) in IMAP.
                // Active keyword can be <sequence set> or bad keyword, there is now way to distinguish what is meant.
                // Why they don't key work SEQUENCESET <sequence set> ?  

                // <sequence set>
                //		Messages with message sequence numbers corresponding to the
                //		specified message sequence number set.

                // Just try if it can be parsed as sequence-set
                try
                {
                    IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
                    sequenceSet.Parse(word, long.MaxValue);

                    searchKeyName = "SEQUENCESET";
                    searchKeyValue = sequenceSet;
                }
                    // This isn't vaild sequnce-set value
                catch
                {
                    throw new Exception("Invalid search key or <sequnce-set> value '" + word + "' !");
                }
            }

            #endregion

            // REMOVE ME:
            //	Console.WriteLine(searchKeyName + " : " + Convert.ToString(searchKeyValue));

            return new SearchKey(searchKeyName, searchKeyValue);
        }

        // TODO: We have envelope, see if Header is needed or can use envelope for it

        /// <summary>
        /// Gets if message Header is needed for matching.
        /// </summary>
        /// <returns></returns>
        public bool IsHeaderNeeded()
        {
            if (m_SearchKeyName == "HEADER")
            {
                return true;
            }
            else if (m_SearchKeyName == "NOT")
            {
                return SearchGroup.IsHeaderNeededForKey(m_SearchKeyValue);
            }
            else if (m_SearchKeyName == "OR")
            {
                object serachKey1 = ((object[]) m_SearchKeyValue)[0];
                object serachKey2 = ((object[]) m_SearchKeyValue)[1];

                if (SearchGroup.IsHeaderNeededForKey(serachKey1) ||
                    SearchGroup.IsHeaderNeededForKey(serachKey2))
                {
                    return true;
                }
            }
            else if (m_SearchKeyName == "SENTBEFORE")
            {
                return true;
            }
            else if (m_SearchKeyName == "SENTON")
            {
                return true;
            }
            else if (m_SearchKeyName == "SENTSINCE")
            {
                return true;
            }
            else if (m_SearchKeyName == "TEXT")
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Gets if message body text is needed for matching.
        /// </summary>
        /// <returns></returns>
        public bool IsBodyTextNeeded()
        {
            if (m_SearchKeyName == "BODY")
            {
                return true;
            }
            else if (m_SearchKeyName == "NOT")
            {
                return SearchGroup.IsBodyTextNeededForKey(m_SearchKeyValue);
            }
            else if (m_SearchKeyName == "OR")
            {
                object serachKey1 = ((object[]) m_SearchKeyValue)[0];
                object serachKey2 = ((object[]) m_SearchKeyValue)[1];

                if (SearchGroup.IsBodyTextNeededForKey(serachKey1) ||
                    SearchGroup.IsBodyTextNeededForKey(serachKey2))
                {
                    return true;
                }
            }
            else if (m_SearchKeyName == "TEXT")
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Gets if specified message matches with this class search-key.
        /// </summary>
        /// <param name="no">IMAP message sequence number.</param>
        /// <param name="uid">IMAP message UID.</param>
        /// <param name="size">IMAP message size in bytes.</param>
        /// <param name="internalDate">IMAP message INTERNALDATE (dateTime when server stored message).</param>
        /// <param name="flags">IMAP message flags.</param>
        /// <param name="mime">Mime message main header only.</param>
        /// <param name="bodyText">Message body text.</param>
        /// <returns></returns>
        public bool Match(long no,
                          long uid,
                          long size,
                          DateTime internalDate,
                          IMAP_MessageFlags flags,
                          Mime mime,
                          string bodyText)
        {
            #region ALL

            // ALL
            //		All messages in the mailbox; the default initial key for ANDing.
            if (m_SearchKeyName == "ALL")
            {
                return true;
            }

                #endregion

                #region BEFORE

                // BEFORE <date>
                //	Messages whose internal date (disregarding time and timezone)
                //	is earlier than the specified date.
            else if (m_SearchKeyName == "BEFORE")
            {
                if (internalDate.Date < (DateTime) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region BODY

                // BODY <string>
                //	Messages that contain the specified string in the body of the message.
                //
                //	NOTE: Compare must be done on decoded header and decoded body of message.
                //		  In all search keys that use strings, a message matches the key if
                //		  the string is a substring of the field.  The matching is case-insensitive.
            else if (m_SearchKeyName == "BODY")
            {
                string val = bodyText;
                if (val != null && val.ToLower().IndexOf(((string) m_SearchKeyValue).ToLower()) > -1)
                {
                    return true;
                }
            }

                #endregion

                #region HEADER

                // HEADER <field-name> <string>
                //	Messages that have a header with the specified field-name (as
                //	defined in [RFC-2822]) and that contains the specified string
                //	in the text of the header (what comes after the colon).  If the
                //	string to search is zero-length, this matches all messages that
                //	have a header line with the specified field-name regardless of
                //	the contents.
                //
                //	NOTE: Compare must be done on decoded header field value.
                //		  In all search keys that use strings, a message matches the key if
                //		  the string is a substring of the field.  The matching is case-insensitive.
            else if (m_SearchKeyName == "HEADER")
            {
                string[] headerField_value = (string[]) m_SearchKeyValue;

                // If header field name won't end with :, add it
                if (!headerField_value[0].EndsWith(":"))
                {
                    headerField_value[0] = headerField_value[0] + ":";
                }

                if (mime.MainEntity.Header.Contains(headerField_value[0]))
                {
                    if (headerField_value[1].Length == 0)
                    {
                        return true;
                    }
                    else if (
                        mime.MainEntity.Header.GetFirst(headerField_value[0]).Value.ToLower().IndexOf(
                            headerField_value[1].ToLower()) > -1)
                    {
                        return true;
                    }
                }
            }

                #endregion

                #region KEYWORD

                // KEYWORD <flag>
                //	Messages with the specified keyword flag set.
            else if (m_SearchKeyName == "KEYWORD")
            {
                if ((flags & IMAP_Utils.ParseMessageFlags((string) m_SearchKeyValue)) != 0)
                {
                    return true;
                }
            }

                #endregion
				
                #region LARGER
	
                // LARGER <n>
                //	Messages with an [RFC-2822] size larger than the specified number of octets.
            else if (m_SearchKeyName == "LARGER")
            {
                if (size > (long) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region NOT

                //	NOT <search-key> or (<search-key> <search-key> ...)(SearchGroup)
                //		Messages that do not match the specified search key.
            else if (m_SearchKeyName == "NOT")
            {
                return
                    !SearchGroup.Match_Key_Value(m_SearchKeyValue,
                                                 no,
                                                 uid,
                                                 size,
                                                 internalDate,
                                                 flags,
                                                 mime,
                                                 bodyText);
            }

                #endregion

                #region ON

                // ON <date>
                //	Messages whose internal date (disregarding time and timezone)
                //	is within the specified date.
            else if (m_SearchKeyName == "ON")
            {
                if (internalDate.Date == (DateTime) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region OR

                //	OR <search-key1> <search-key2> - SearckKey can be parenthesis list of keys !
                //		Messages that match either search key.
            else if (m_SearchKeyName == "OR")
            {
                object serachKey1 = ((object[]) m_SearchKeyValue)[0];
                object serachKey2 = ((object[]) m_SearchKeyValue)[1];

                if (
                    SearchGroup.Match_Key_Value(serachKey1, no, uid, size, internalDate, flags, mime, bodyText) ||
                    SearchGroup.Match_Key_Value(serachKey2, no, uid, size, internalDate, flags, mime, bodyText))
                {
                    return true;
                }
            }

                #endregion

                #region SENTBEFORE

                // SENTBEFORE <date>
                //	Messages whose [RFC-2822] Date: header (disregarding time and
                //	timezone) is earlier than the specified date.
            else if (m_SearchKeyName == "SENTBEFORE")
            {
                if (mime.MainEntity.Date.Date < (DateTime) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region SENTON

                // SENTON <date>
                //	Messages whose [RFC-2822] Date: header (disregarding time and
                //	timezone) is within the specified date.
            else if (m_SearchKeyName == "SENTON")
            {
                if (mime.MainEntity.Date.Date == (DateTime) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region SENTSINCE

                // SENTSINCE <date>
                //	Messages whose [RFC-2822] Date: header (disregarding time and
                //	timezone) is within or later than the specified date.
            else if (m_SearchKeyName == "SENTSINCE")
            {
                if (mime.MainEntity.Date.Date >= (DateTime) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region SINCE

                // SINCE <date>
                //	Messages whose internal date (disregarding time and timezone)
                //	is within or later than the specified date.	
            else if (m_SearchKeyName == "SINCE")
            {
                if (internalDate.Date >= (DateTime) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region SMALLER

                // SMALLER <n>
                //	Messages with an [RFC-2822] size smaller than the specified	number of octets.
            else if (m_SearchKeyName == "SMALLER")
            {
                if (size < (long) m_SearchKeyValue)
                {
                    return true;
                }
            }

                #endregion

                #region TEXT

                // TEXT <string>
                //	Messages that contain the specified string in the header or	body of the message.
                //
                //  NOTE: Compare must be done on decoded header and decoded body of message.
                //		  In all search keys that use strings, a message matches the key if
                //		  the string is a substring of the field.  The matching is case-insensitive.
            else if (m_SearchKeyName == "TEXT")
            {
                // See body first
                string val = bodyText;
                if (val != null && val.ToLower().IndexOf(((string) m_SearchKeyValue).ToLower()) > -1)
                {
                    return true;
                }

                // If we reach so far, that means body won't contain specified text and we need to check header.
                foreach (HeaderField headerField in mime.MainEntity.Header)
                {
                    if (headerField.Value.ToLower().IndexOf(((string) m_SearchKeyValue).ToLower()) > -1)
                    {
                        return true;
                    }
                }
            }

                #endregion

                #region UID

                // UID <sequence set>
                //	Messages with unique identifiers corresponding to the specified
                //	unique identifier set.  Sequence set ranges are permitted.
            else if (m_SearchKeyName == "UID")
            {
                return ((IMAP_SequenceSet) m_SearchKeyValue).Contains(uid);
            }

                #endregion

                #region UNKEYWORD

                // UNKEYWORD <flag>
                //	Messages that do not have the specified keyword flag set.
            else if (m_SearchKeyName == "UNKEYWORD")
            {
                if ((flags & IMAP_Utils.ParseMessageFlags((string) m_SearchKeyValue)) == 0)
                {
                    return true;
                }
            }

                #endregion

                #region SEQUENCESET

                // <sequence set>
                //		Messages with message sequence numbers corresponding to the
                //		specified message sequence number set.
            else if (m_SearchKeyName == "SEQUENCESET")
            {
                return ((IMAP_SequenceSet) m_SearchKeyValue).Contains(no);
            }

            #endregion

            return false;
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Reads search-key &lt;string&gt; value.
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        private static string ReadString(StringReader reader)
        {
            //Remove spaces from string start
            reader.ReadToFirstChar();

            // We must support:
            //	word
            //  "text"
            //	{string_length}data(string_length)

            // {string_length}data(string_length)
            if (reader.StartsWith("{"))
            {
                // Remove {
                reader.ReadSpecifiedLength("{".Length);

                int dataLength = Convert.ToInt32(reader.QuotedReadToDelimiter('}'));
                return reader.ReadSpecifiedLength(dataLength);
            }

            return TextUtils.UnQuoteString(reader.QuotedReadToDelimiter(' '));
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/MailboxAutoreplyDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class MailboxAutoreplyDao : BaseDao, IMailboxAutoreplyDao
    {
        protected static ITable table = new MailTableFactory().Create<MailboxAutoreplyTable>();

        protected string CurrentUserId { get; private set; }

        private const string AUTOREPLY_ALIAS = "r";
        private const string MB_ALIAS = "mb";

        public MailboxAutoreplyDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public MailboxAutoreply GetAutoreply(int mailboxId)
        {
            var query = Query(AUTOREPLY_ALIAS)
                .InnerJoin(MailboxTable.TABLE_NAME.Alias(MB_ALIAS),
                    Exp.EqColumns(MailboxTable.Columns.Id.Prefix(MB_ALIAS),
                        MailboxAutoreplyTable.Columns.MailboxId.Prefix(AUTOREPLY_ALIAS)))
                .Where(MailboxAutoreplyTable.Columns.Tenant.Prefix(AUTOREPLY_ALIAS), Tenant)
                .Where(MailboxAutoreplyTable.Columns.MailboxId.Prefix(AUTOREPLY_ALIAS), mailboxId);

            return Db.ExecuteList(query)
                .ConvertAll(ToAutoreply)
                .DefaultIfEmpty(new MailboxAutoreply
                {
                    MailboxId = mailboxId,
                    Tenant = Tenant,
                    TurnOn = false,
                    OnlyContacts = false,
                    TurnOnToDate = false,
                    FromDate = DateTime.MinValue,
                    ToDate = DateTime.MinValue,
                    Subject = string.Empty,
                    Html = string.Empty
                })
                .Single();
        }

        public List<MailboxAutoreply> GetAutoreplies(List<int> mailboxIds)
        {
            var query = Query(AUTOREPLY_ALIAS)
                .InnerJoin(MailboxTable.TABLE_NAME.Alias(MB_ALIAS),
                    Exp.EqColumns(MailboxTable.Columns.Id.Prefix(MB_ALIAS),
                        MailboxAutoreplyTable.Columns.MailboxId.Prefix(AUTOREPLY_ALIAS)))
                .Where(MailboxAutoreplyTable.Columns.Tenant.Prefix(AUTOREPLY_ALIAS), Tenant)
                .Where(Exp.In(MailboxAutoreplyTable.Columns.MailboxId.Prefix(AUTOREPLY_ALIAS), mailboxIds));

            var list = Db.ExecuteList(query)
                .ConvertAll(ToAutoreply);

            return (from mailboxId in mailboxIds
                    let autoreply = list.FirstOrDefault(s => s.MailboxId == mailboxId)
                    select autoreply ?? new MailboxAutoreply
                    {
                        MailboxId = mailboxId,
                        Tenant = Tenant,
                        TurnOn = false,
                        OnlyContacts = false,
                        TurnOnToDate = false,
                        FromDate = DateTime.MinValue,
                        ToDate = DateTime.MinValue,
                        Subject = string.Empty,
                        Html = string.Empty
                    })
                .ToList();
        }

        public int SaveAutoreply(MailboxAutoreply autoreply)
        {
            var query = new SqlInsert(MailboxAutoreplyTable.TABLE_NAME, true)
                .InColumnValue(MailboxAutoreplyTable.Columns.MailboxId, autoreply.MailboxId)
                .InColumnValue(MailboxAutoreplyTable.Columns.Tenant, autoreply.Tenant)
                .InColumnValue(MailboxAutoreplyTable.Columns.TurnOn, autoreply.TurnOn)
                .InColumnValue(MailboxAutoreplyTable.Columns.OnlyContacts, autoreply.OnlyContacts)
                .InColumnValue(MailboxAutoreplyTable.Columns.TurnOnToDate, autoreply.TurnOnToDate)
                .InColumnValue(MailboxAutoreplyTable.Columns.FromDate, autoreply.FromDate)
                .InColumnValue(MailboxAutoreplyTable.Columns.ToDate, autoreply.ToDate)
                .InColumnValue(MailboxAutoreplyTable.Columns.Subject, autoreply.Subject)
                .InColumnValue(MailboxAutoreplyTable.Columns.Html, autoreply.Html);

            return Db.ExecuteNonQuery(query);
        }

        public int DeleteAutoreply(int mailboxId)
        {
            var query = new SqlDelete(MailboxAutoreplyTable.TABLE_NAME)
                .Where(MailboxAutoreplyTable.Columns.MailboxId, mailboxId)
                .Where(MailboxAutoreplyTable.Columns.Tenant, Tenant);

            return Db.ExecuteNonQuery(query);
        }

        protected MailboxAutoreply ToAutoreply(object[] r)
        {
            var obj = new MailboxAutoreply
            {
                MailboxId = Convert.ToInt32(r[0]),
                Tenant = Convert.ToInt32(r[1]),
                TurnOn = Convert.ToBoolean(r[2]),
                OnlyContacts = Convert.ToBoolean(r[3]),
                TurnOnToDate = Convert.ToBoolean(r[4]),
                FromDate = Convert.ToDateTime(r[5]),
                ToDate = Convert.ToDateTime(r[6]),
                Subject = Convert.ToString(r[7]),
                Html = Convert.ToString(r[8])
            };

            return obj;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/core/asc.pagenavigator.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof window.ASC === 'undefined') {
    window.ASC = {};
}
if (typeof window.ASC.Controls == 'undefined') {
    ASC.Controls = {};
}

window.ASC.Controls.PageNavigator = new function () {
    this.init = function (
                    objName,
                    navigatorParent,
                    entryCountOnPage,
                    visiblePageCount,
                    currentPageNumber,
                    previousButton,
                    nextButton) {
        this.ObjName = objName;
        this.EntryCountOnPage = entryCountOnPage;
        this.VisiblePageCount = visiblePageCount;
        this.CurrentPageNumber = currentPageNumber;
        this.PreviousButton = previousButton;
        this.NextButton = nextButton;

        this.NavigatorParent = navigatorParent;
        this.TotalPageCount = 0;

        this.changePageCallback = function () {
        };

        this.drawPageNavigator = function (currentPageNumber, countTotal) {
            this.CurrentPageNumber = currentPageNumber;
            var amountPage = (countTotal / this.EntryCountOnPage).toFixed(0) * 1;
            if (amountPage - (countTotal / this.EntryCountOnPage) < 0) {
                amountPage++;
            }
            this.TotalPageCount = amountPage;
            if (amountPage == 0) {
                jq(this.NavigatorParent).html("");
                return;
            }

            if (currentPageNumber < 1) {
                currentPageNumber = 1;
            }
            if (currentPageNumber > amountPage) {
                currentPageNumber = amountPage;
            }

            //Navigator
            var startPage = currentPageNumber - (this.VisiblePageCount / 2).toFixed(0) * 1;

            if (startPage + this.VisiblePageCount > amountPage) {
                startPage = amountPage - this.VisiblePageCount;
            }
            if (startPage < 0) {
                startPage = 0;
            }
            var endPage = startPage + this.VisiblePageCount;

            if (endPage > amountPage) {
                endPage = amountPage;
            }
            var sb = new String("<div class='pagerNavigationLinkBox'>");

            //button Prev
            if (currentPageNumber > 1)
                sb += "<a class='pagerPrevButtonCSSClass' href='javascript:void(0)' onclick='" + this.ObjName + ".changePageCallback(" + (currentPageNumber - 1) + "); " + this.ObjName + ".drawPageNavigator(" + (currentPageNumber - 1) + "," + countTotal + ");return false;'>" + this.PreviousButton + "</a>";

            for (var i = startPage; i < endPage && endPage - startPage > 1; i++) {
                //to 1 page
                if (i == startPage && i != 0) {
                    sb += "<a class='pagerNavigationLinkCSSClass' href='javascript:void(0)' onclick='" + this.ObjName + ".changePageCallback(1); " + this.ObjName + ".drawPageNavigator(1, " + countTotal + ");return false;'>1</a>";
                    if (i != 1) {
                        sb += "<span class='splitter'>...</span>";
                    }
                }
                if ((currentPageNumber - 1) == i) {
                    sb += "<span class='pagerCurrentPosition'>" + currentPageNumber + "</span>";
                } else {
                    sb += "<a class='pagerNavigationLinkCSSClass' href='javascript:void(0)' onclick='" + this.ObjName + ".changePageCallback(" + (i + 1) + "); " + this.ObjName + ".drawPageNavigator(" + (i + 1) + "," + countTotal + ");return false;'>" + (i + 1) + "</a>";
                }
                //button to the end
                if (i == endPage - 1 && i != amountPage - 1) {
                    if (i != amountPage - 2) {
                        sb += "<span class='splitter'>...</span>";
                    }
                    sb += "<a class='pagerNavigationLinkCSSClass' href='javascript:void(0)' onclick='" + this.ObjName + ".changePageCallback(" + amountPage + "); " + this.ObjName + ".drawPageNavigator(" + amountPage + "," + countTotal + ");return false;'>" + amountPage + "</a>";
                }
            }

            //button Next
            if (currentPageNumber != amountPage && amountPage != 1) {
                sb += "<a class='pagerNextButtonCSSClass' href='javascript:void(0)' onclick='" + this.ObjName + ".changePageCallback(" + (currentPageNumber + 1) + "); " + this.ObjName + ".drawPageNavigator(" + (currentPageNumber + 1) + "," + countTotal + ");return false;'>" + this.NextButton + "</a>";
            }

            sb += "</div>";

            jq(this.NavigatorParent).html(sb);
            jq(".mainPageContent").scrollTop(0);
        };
    };
};

<|start_filename|>module/ASC.UrlShortener.Svc/Launcher.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Reflection;

using ASC.Common.Logging;
using ASC.Common.Module;

namespace ASC.UrlShortener.Svc
{
    public class Launcher : IServiceController
    {
        private ProcessStartInfo startInfo;
        private Process proc;
        private static readonly ILog Logger = LogManager.GetLogger("ASC");

        public void Start()
        {
            try
            {
                var cfg = (ConfigHandler)ConfigurationManagerExtension.GetSection("urlshortener");

                startInfo = new ProcessStartInfo
                {
                    CreateNoWindow = false,
                    UseShellExecute = false,
                    FileName = "node",
                    WindowStyle = ProcessWindowStyle.Hidden,
                    Arguments = string.Format("\"{0}\"", Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), cfg.Path, "index.js"))),
                    WorkingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
                };

                var appSettings = ConfigurationManagerExtension.AppSettings;

                startInfo.EnvironmentVariables.Add("core.machinekey", appSettings["core.machinekey"]);
                startInfo.EnvironmentVariables.Add("port", cfg.Port);

                var conString = ConfigurationManager.ConnectionStrings["default"].ConnectionString;

                var dict = new Dictionary<string, string>
                {
                    {"Server", "host"},
                    {"Database", "database"},
                    {"User ID", "user"},
                    {"Password", "password"}
                };

                foreach (var conf in conString.Split(';'))
                {
                    var splited = conf.Split('=');
                    if (splited.Length < 2) continue;

                    if (dict.ContainsKey(splited[0]))
                    {
                        startInfo.EnvironmentVariables.Add("sql:" + dict[splited[0]], splited[1]);
                    }
                }

                startInfo.EnvironmentVariables.Add("logPath", Path.Combine(Logger.LogDirectory, "web.urlshortener.log"));

                StartNode();
            }
            catch (Exception e)
            {
                Logger.Fatal("Start", e);
            }
        }

        public void Stop()
        {
            try
            {
                if (proc != null && !proc.HasExited)
                {
                    proc.Kill();
                    proc.WaitForExit(10000);

                    proc.Close();
                    proc.Dispose();
                    proc = null;
                }
            }
            catch (Exception e)
            {
                Logger.Error("stop", e);
            }
        }

        private void StartNode()
        {
            Stop();
            proc = Process.Start(startInfo);
        }
    }
}


<|start_filename|>common/ASC.Common/Notify/Model/TopSubscriptionProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Notify.Recipients;


namespace ASC.Notify.Model
{
    public class TopSubscriptionProvider : ISubscriptionProvider
    {
        private readonly string[] defaultSenderMethods = new string[0];
        private readonly ISubscriptionProvider subscriptionProvider;
        private readonly IRecipientProvider recipientProvider;


        public TopSubscriptionProvider(IRecipientProvider recipientProvider, ISubscriptionProvider directSubscriptionProvider)
        {
            if (recipientProvider == null) throw new ArgumentNullException("recipientProvider");
            if (directSubscriptionProvider == null) throw new ArgumentNullException("directSubscriptionProvider");

            this.recipientProvider = recipientProvider;
            subscriptionProvider = directSubscriptionProvider;
        }

        public TopSubscriptionProvider(IRecipientProvider recipientProvider, ISubscriptionProvider directSubscriptionProvider, string[] defaultSenderMethods)
            : this(recipientProvider, directSubscriptionProvider)
        {
            this.defaultSenderMethods = defaultSenderMethods;
        }


        public virtual string[] GetSubscriptionMethod(INotifyAction action, IRecipient recipient)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            var senders = subscriptionProvider.GetSubscriptionMethod(action, recipient);
            if (senders == null || senders.Length == 0)
            {
                var parents = WalkUp(recipient);
                foreach (var parent in parents)
                {
                    senders = subscriptionProvider.GetSubscriptionMethod(action, parent);
                    if (senders != null && senders.Length != 0) break;
                }
            }

            return senders != null && 0 < senders.Length ? senders : defaultSenderMethods;
        }

        public virtual IRecipient[] GetRecipients(INotifyAction action, string objectID)
        {
            if (action == null) throw new ArgumentNullException("action");

            var recipents = new List<IRecipient>(5);
            var directRecipients = subscriptionProvider.GetRecipients(action, objectID) ?? new IRecipient[0];
            recipents.AddRange(directRecipients);
            return recipents.ToArray();
        }

        public virtual bool IsUnsubscribe(IDirectRecipient recipient, INotifyAction action, string objectID)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            return subscriptionProvider.IsUnsubscribe(recipient, action, objectID);
        }


        public virtual void Subscribe(INotifyAction action, string objectID, IRecipient recipient)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            subscriptionProvider.Subscribe(action, objectID, recipient);
        }

        public virtual void UnSubscribe(INotifyAction action, string objectID, IRecipient recipient)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            subscriptionProvider.UnSubscribe(action, objectID, recipient);
        }

        public void UnSubscribe(INotifyAction action, string objectID)
        {
            if (action == null) throw new ArgumentNullException("action");

            subscriptionProvider.UnSubscribe(action, objectID);
        }

        public void UnSubscribe(INotifyAction action)
        {
            if (action == null) throw new ArgumentNullException("action");

            subscriptionProvider.UnSubscribe(action);
        }

        public virtual void UnSubscribe(INotifyAction action, IRecipient recipient)
        {
            var objects = GetSubscriptions(action, recipient);
            foreach (string objectID in objects)
            {
                subscriptionProvider.UnSubscribe(action, objectID, recipient);
            }
        }

        public virtual void UpdateSubscriptionMethod(INotifyAction action, IRecipient recipient, params string[] senderNames)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");
            if (senderNames == null) throw new ArgumentNullException("senderNames");

            subscriptionProvider.UpdateSubscriptionMethod(action, recipient, senderNames);
        }

        public virtual object GetSubscriptionRecord(INotifyAction action, IRecipient recipient, string objectID)
        {
            if (recipient == null) throw new ArgumentNullException("recipient");
            if (action == null) throw new ArgumentNullException("action");

            var subscriptionRecord = subscriptionProvider.GetSubscriptionRecord(action, recipient, objectID);

            if (subscriptionRecord != null) return subscriptionRecord;

            var parents = WalkUp(recipient);

            foreach (var parent in parents)
            {
                subscriptionRecord = subscriptionProvider.GetSubscriptionRecord(action, parent, objectID);

                if (subscriptionRecord != null) break;
            }

            return subscriptionRecord;
        }

        public virtual string[] GetSubscriptions(INotifyAction action, IRecipient recipient, bool checkSubscription = true)
        {
            if (recipient == null) throw new ArgumentNullException("recipient");
            if (action == null) throw new ArgumentNullException("action");

            var objects = new List<string>();
            var direct = subscriptionProvider.GetSubscriptions(action, recipient, checkSubscription) ?? new string[0];
            MergeObjects(objects, direct);
            var parents = WalkUp(recipient);
            foreach (var parent in parents)
            {
                direct = subscriptionProvider.GetSubscriptions(action, parent, checkSubscription) ?? new string[0];
                if (recipient is IDirectRecipient)
                {
                    foreach (var groupsubscr in direct)
                    {
                        if (!objects.Contains(groupsubscr) && !subscriptionProvider.IsUnsubscribe(recipient as IDirectRecipient, action, groupsubscr))
                        {
                            objects.Add(groupsubscr);
                        }
                    }
                }
                else
                {
                    MergeObjects(objects, direct);
                }
            }
            return objects.ToArray();
        }


        private List<IRecipient> WalkUp(IRecipient recipient)
        {
            var parents = new List<IRecipient>();
            var groups = recipientProvider.GetGroups(recipient) ?? new IRecipientsGroup[0];
            foreach (var group in groups)
            {
                parents.Add(group);
                parents.AddRange(WalkUp(group));
            }
            return parents;
        }

        private void MergeActions(List<INotifyAction> result, IEnumerable<INotifyAction> additions)
        {
            foreach (var addition in additions)
            {
                if (!result.Contains(addition)) result.Add(addition);
            }
        }

        private void MergeObjects(List<string> result, IEnumerable<string> additions)
        {
            foreach (var addition in additions)
            {
                if (!result.Contains(addition)) result.Add(addition);
            }
        }
    }
}

<|start_filename|>common/ASC.Common/Notify/Model/ISubscriptionProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region usings

using System;
using System.Linq;

using ASC.Common.Logging;
using ASC.Notify.Recipients;

#endregion

namespace ASC.Notify.Model
{
    public interface ISubscriptionProvider
    {
        string[] GetSubscriptions(INotifyAction action, IRecipient recipient, bool checkSubscribe = true);

        string[] GetSubscriptionMethod(INotifyAction action, IRecipient recipient);

        IRecipient[] GetRecipients(INotifyAction action, string objectID);

        object GetSubscriptionRecord(INotifyAction action, IRecipient recipient, string objectID);

        bool IsUnsubscribe(IDirectRecipient recipient, INotifyAction action, string objectID);

        void Subscribe(INotifyAction action, string objectID, IRecipient recipient);

        void UnSubscribe(INotifyAction action, string objectID, IRecipient recipient);

        void UnSubscribe(INotifyAction action, string objectID);

        void UnSubscribe(INotifyAction action);

        void UnSubscribe(INotifyAction action, IRecipient recipient);

        void UpdateSubscriptionMethod(INotifyAction action, IRecipient recipient, params string[] senderNames);
    }

    public static class SubscriptionProviderHelper
    {
        public static bool IsSubscribed(this ISubscriptionProvider provider, INotifyAction action, IRecipient recipient, string objectID)
        {
            var result = false;

            try
            {
                var subscriptionRecord = provider.GetSubscriptionRecord(action, recipient, objectID);
                if (subscriptionRecord != null)
                {
                    var properties = subscriptionRecord.GetType().GetProperties();
                    if (properties.Any())
                    {
                        var property = properties.Single(p => p.Name == "Subscribed");
                        if (property != null)
                        {
                            result = (bool)property.GetValue(subscriptionRecord, null);
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                LogManager.GetLogger("ASC").Error(exception);
            }

            return result;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/contacts/filter/crmfilter.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.crmFilter = (function($) {
    var isInit = false;
    var filter;
    var events = $({});

    var init = function() {
        if (!isInit) {
            isInit = true;

            $('#crmFilter').advansedFilter({
                anykey: true,
                anykeytimeout: 1000,
                maxfilters: -1,
                hintDefaultDisable: false,
                sorters: [
                    { id: 'displayname', title: MailScriptResource.FilterByTitle, sortOrder: 'ascending', def: true },
                    { id: 'contacttype', title: MailScriptResource.FilterByContactStage, sortOrder: 'ascending' }
                ],
                filters: [
                    {
                        type: "combobox",
                        id: "company",
                        apiparamname: "contactListView",
                        title: MailScriptResource.FilterCompany,
                        filtertitle: MailScriptResource.FilterShowGroup,
                        group: MailScriptResource.FilterShowGroup,
                        groupby: 'type',
                        options:
                        [
                            { value: "company", classname: '', title: MailScriptResource.FilterCompany, def: true },
                            { value: "person", classname: '', title: MailScriptResource.FilterPerson },
                            { value: "withopportunity", classname: '', title: MailScriptResource.FilterWithOpportunity }
                        ]
                    },
                    {
                        type: "combobox",
                        id: "person",
                        apiparamname: "contactListView",
                        title: MailScriptResource.FilterPerson,
                        filtertitle: MailScriptResource.FilterShowGroup,
                        group: MailScriptResource.FilterShowGroup,
                        groupby: 'type',
                        options:
                        [
                            { value: "company", classname: '', title: MailScriptResource.FilterCompany },
                            { value: "person", classname: '', title: MailScriptResource.FilterPerson, def: true },
                            { value: "withopportunity", classname: '', title: MailScriptResource.FilterWithOpportunity }
                        ]
                    },
                    {
                        type: "combobox",
                        id: "withopportunity",
                        apiparamname: "contactListView",
                        title: MailScriptResource.FilterWithOpportunity,
                        filtertitle: MailScriptResource.FilterShowGroup,
                        group: MailScriptResource.FilterShowGroup,
                        groupby: 'type',
                        options:
                        [
                            { value: "company", classname: '', title: MailScriptResource.FilterCompany },
                            { value: "person", classname: '', title: MailScriptResource.FilterPerson },
                            { value: "withopportunity", classname: '', title: MailScriptResource.FilterWithOpportunity, def: true }
                        ]
                    },
                    {
                        type: "combobox",
                        id: "stages",
                        apiparamname: "contactStage",
                        title: MailScriptResource.FilterContactStage,
                        group: MailScriptResource.FilterAnotherGroup,
                        options: [],
                        defaulttitle: MailScriptResource.FilterChoose,
                        enable: false
                    },
                    {
                        type: "combobox",
                        id: "tags",
                        apiparamname: "tags",
                        title: MailScriptResource.FilterWithTags,
                        group: MailScriptResource.FilterAnotherGroup,
                        options: [],
                        defaulttitle: MailScriptResource.FilterChoose,
                        multiple: true,
                        enable: false
                    }
                ]
            }).bind('setfilter', onSetFilter).bind('resetfilter', onResetFilter).bind('resetallfilters', onResetAllFilters);

            // filter object initialization should follow after advansed filter plugin call - because
            // its replace target element with new markup
            filter = $('#crmFilter');

            tagsManager.bind(tagsManager.events.OnRefresh, onUpdateTags);
            tagsManager.bind(tagsManager.events.OnDelete, onUpdateTags);
            tagsManager.bind(tagsManager.events.OnCreate, onUpdateTags);
            tagsManager.bind(tagsManager.events.OnUpdate, onUpdateTags);

            contactStages.events.bind('update', onUpdateStages);
        }
    };

    var onSetFilter = function(evt, $container, filterItem, value, selectedfilters) {
        events.trigger('set', [filterItem, value, selectedfilters]);
    };

    var onResetFilter = function(evt, $container, filterItem, selectedfilters) {
        events.trigger('reset', [filterItem, selectedfilters]);
    };

    var onResetAllFilters = function(evt, $container, filterid, selectedfilters) {
        events.trigger('resetall', [selectedfilters]);
    };

    var showItem = function(id, params) {
        if (!params) {
            params = {};
        }
        filter.advansedFilter({ filters: [{ id: id, params: params }] });
    };

    var show = function() {
        filter.parent().show();
    };

    var hide = function() {
        filter.parent().hide();
    };

    var update = function() {
        filter.advansedFilter('resize');
        onUpdateTags();
        contactStages.update();
    };

    var onUpdateTags = function() {
        var tags = [];
        $.each(tagsManager.getAllTags(), function(index, value) {
            if (0 > value.id) {
                tags.push({ value: value.name, classname: 'to', title: value.name });
            }
        });
        filter.advansedFilter({ filters: [{ type: 'combobox', id: 'tags', options: tags, enable: tags.length > 0 }] });
    };

    var onUpdateStages = function() {
        var stages = [];
        $.each(contactStages.getStages(), function(index, value) {
            stages.push({ value: value.id, classname: 'colorFilterItem color_' + value.color.replace('#', ''), title: value.title });
        });
        filter.advansedFilter({ filters: [{ type: 'combobox', id: 'stages', options: stages, enable: stages.length > 0 }] });
        events.trigger('ready');
    };

    var clear = function() {
        filter.advansedFilter(null);
    };

    var setCompany = function() {
        showItem('company', { value: 'company' });
    };

    var setPerson = function() {
        showItem('person', { value: 'person' });
    };

    var setOpportunity = function() {
        showItem('withopportunity', { value: 'withopportunity' });
    };

    var setStage = function(value) {
        filter.advansedFilter({ filters: [{ type: 'combobox', id: 'stages', params: { value: value } }] });
    };
    var setTags = function(tags) {
        filter.advansedFilter({ filters: [{ type: 'combobox', id: 'tags', params: { value: tags } }] });
    };

    var setSearch = function(text) {
        filter.advansedFilter({ filters: [{ type: 'text', id: 'text', params: { value: text } }] });
    };

    var setSort = function(sort, order) {
        filter.advansedFilter({ sorters: [{ id: sort, selected: true, dsc: 'descending' == order }] });
    };

    return {
        init: init,

        clear: clear,
        update: update,

        show: show,
        hide: hide,

        setCompany: setCompany,
        setPerson: setPerson,
        setOpportunity: setOpportunity,
        setStage: setStage,
        setTags: setTags,
        setSearch: setSearch,
        setSort: setSort,

        events: events
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/plugins/jquery.helper.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function (jq, win, doc, body) {
    jq.fn.helper = function(opts) {
        var options = jQuery.extend({
            addTop: 0,
            addLeft: 0,
            position: "absolute",
            fixWinSize: false,
            popup: false,
            BlockHelperID: '', //obligatory  parameter
            enableAutoHide: true,
            close: false,
            next: false,
            posDown: false,
            inRelativeCnt: false
        }, opts);

        return this.each(function() {
            var w = jq(window),
                scrWidth = w.width(),
                scrHeight = w.height(),
                addTop = options.addTop-20,
                addLeft = options.addLeft-29,         // the left padding of the arrow
                topPadding = w.scrollTop(),
                leftPadding = w.scrollLeft();            

            if (options.position == "fixed") {
                addTop -= topPadding;
                addLeft -= leftPadding;
            }


            var $helpBlock = jq('#' + options.BlockHelperID),
                elem = jq(this),
                elemPos = elem.offset(),
                elemPosLeft = elemPos.left,
                elemPosTop = elemPos.top - $helpBlock.outerHeight();

            if (options.popup || options.inRelativeCnt) {
                elemPosTop = elem.position().top - $helpBlock.outerHeight();
                elemPosLeft = elem.position().left;
            }

            if (options.close) {
                if (jq('#' + options.BlockHelperID + ' .closeBlock').length == 0) {
                    $helpBlock.prepend('<div class="closeBlock"></div>');
                    jq('#' + options.BlockHelperID + ' .closeBlock').click(function() {
                        $helpBlock.hide();
                    });
                }
            }
            if (options.next) {
                if (jq('#' + options.BlockHelperID + ' .buttons').length == 0) {
                     $helpBlock.append('<div class="buttons"><a class="button gray nextHelp">' 
                     + ASC.Resources.Master.ResourceJS.ShowNext + '</a><a class="neverShow">'
                     + ASC.Resources.Master.ResourceJS.NeverShow + '</a></div>');                                     
                }
            }          

            jq('#' + options.BlockHelperID + ' ' + '.cornerHelpBlock').remove();

            if (options.fixWinSize && (elemPosLeft + addLeft + $helpBlock.outerWidth()) > (leftPadding + scrWidth)) {
                elemPosLeft = Math.max(0, leftPadding + scrWidth - $helpBlock.outerWidth()) - addLeft;
            }

            if ((elemPosTop + addTop < 0) && (!options.inRelativeCnt) || ((options.fixWinSize) && (elemPosTop > topPadding) &&
               ((elemPos.top + $helpBlock.outerHeight() + jq(this).outerHeight()) > (topPadding + scrHeight))) || (options.posDown)) {

                if ((elemPosLeft + addLeft + $helpBlock.outerWidth()) > jq(document).width()) {
                    elemPosLeft = elemPosLeft - addLeft - $helpBlock.outerWidth() + 40; // 40 for correct display of the direction corner
                    $helpBlock.prepend('<div class="cornerHelpBlock pos_bottom_left"></div>');
                } else {
                    $helpBlock.prepend('<div class="cornerHelpBlock pos_bottom"></div>');
                }
                elemPosTop = elemPos.top + jq(this).outerHeight();
                addTop = -addTop;

            } else {
                if ((elemPosLeft + addLeft + $helpBlock.outerWidth()) > jq(document).width()) {
                    elemPosLeft = elemPosLeft - addLeft - $helpBlock.outerWidth() + 40; // 40 for correct display of the direction corner
                    $helpBlock.append('<div class="cornerHelpBlock pos_top_left"></div>');
                } else {
                    $helpBlock.append('<div class="cornerHelpBlock pos_top"></div>');
                }
            }

            if (options.enableAutoHide) {

                jq(document).click(function(e) {
                    if (!jq(e.target).parents().addBack().is(elem)) {
                        $helpBlock.hide();
                    }
                });
                //                elem.click(function(e) {
                //                    e.stopPropagation();
                //                });
            }

            $helpBlock.css(
            {
              "top": elemPosTop + addTop,
              "left": elemPosLeft + addLeft,
              "position": options.position
            });
            jq(window).resize(function(){
                elemPosLeft = elem.offset().left;
                if ((elemPosLeft + addLeft + $helpBlock.outerWidth()) > jq(window).width()) {
                    elemPosLeft = elemPosLeft - addLeft - $helpBlock.outerWidth() + 40;
                }
                $helpBlock.css(
                {
                    "left": elemPosLeft + addLeft
                });
            });

            if ($helpBlock.css('display') == "none") {
                $helpBlock.show();
            } else {
                $helpBlock.hide();
            }
        });
    };

})(jQuery, window, document, document.body);

<|start_filename|>web/studio/ASC.Web.Studio/Core/CustomNavigationSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;

namespace ASC.Web.Studio.Core
{
    [Serializable]
    [DataContract]
    public class CustomNavigationSettings : BaseSettings<CustomNavigationSettings>
    {
        [DataMember]
        public List<CustomNavigationItem> Items { get; set; }

        public override Guid ID
        {
            get { return new Guid("{32E02E4C-925D-4391-BAA4-3B5D223A2104}"); }
        }

        public override ISettings GetDefault()
        {
            return new CustomNavigationSettings { Items = new List<CustomNavigationItem>() };
        }
    }

    [Serializable]
    [DataContract]
    public class CustomNavigationItem
    {
        [DataMember]
        public Guid Id { get; set; }

        [DataMember]
        public string Label { get; set; }

        [DataMember]
        public string Url { get; set; }

        [DataMember]
        public string BigImg { get; set; }

        [DataMember]
        public string SmallImg { get; set; }

        [DataMember]
        public bool ShowInMenu { get; set; }

        [DataMember]
        public bool ShowOnHomePage { get; set; }

        private static string GetDefaultBigImg()
        {
            return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkAgMAAAANjH3HAAAADFBMVEUAAADJycnJycnJycmiuNtHAAAAA3RSTlMAf4C/aSLHAAAAyElEQVR4Xu3NsQ3CMBSE4YubFB4ilHQegdGSjWACvEpGoEyBYiL05AdnXUGHolx10lf82MmOpfLeo5UoJUhBlpKkRCnhUy7b9XCWkqQMUkYlXVHSf8kTvkHKqKQrSnopg5SRxTMklLmS1MwaSWpmCSQ1MyOzWGZCYrEMEFksA4QqlAFuJJYBcCKxjM3FMySeIfEMC2dMOONCGZZgmdr1ly3TSrJMK9EyJBaaGrHQikYstAiJZRYSyiQEdyg5S8Evckih/YPscsdej0H6dc0TYw4AAAAASUVORK5CYII=";
        }

        private static string GetDefaultSmallImg()
        {
            return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAUUlEQVR4AWMY/KC5o/cAEP9HxxgKcSpCGELYADyu2E6mAQjNxBlAWPNxkHdwGkBIM3KYYDUAr2ZCAE+oH8eujrAXDsA0k2EAAtDXAGLx4MpsADUgvkRKUlqfAAAAAElFTkSuQmCC";
        }

        public static CustomNavigationItem GetSample()
        {
            return new CustomNavigationItem
            {
                Id = Guid.Empty,
                ShowInMenu = true,
                ShowOnHomePage = true,
                BigImg = GetDefaultBigImg(),
                SmallImg = GetDefaultSmallImg()
            };
        }
    }
}


<|start_filename|>web/core/ASC.Web.Core/Client/Bundling/CloudFrontTransform.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Threading;
using System.Web.Optimization;

using Amazon;
using Amazon.S3;
using Amazon.S3.Model;
using Amazon.S3.Util;

using ASC.Common.Logging;
using ASC.Data.Storage.Configuration;

namespace ASC.Web.Core.Client.Bundling
{
    class CloudFrontTransform : IBundleTransform
    {
        private static readonly ILog log = LogManager.GetLogger("ASC.Web.Bundle.CloudFrontTransform");
        private static readonly ConcurrentQueue<CdnItem> queue = new ConcurrentQueue<CdnItem>();
        private static readonly Dictionary<string, string> appenders = new Dictionary<string, string>();
        private static readonly string s3publickey;
        private static readonly string s3privatekey;
        private static readonly string s3bucket;
        private static readonly string s3region;
        private static readonly bool successInitialized = false;
        private static int work = 0;


        static CloudFrontTransform()
        {
            try
            {
                var section = (StorageConfigurationSection)ConfigurationManagerExtension.GetSection("storage");
                if (section == null)
                {
                    throw new Exception("Storage section not found.");
                }

                if (section.Appenders.Count == 0)
                {
                    throw new Exception("Appenders not found.");
                }
                foreach (AppenderConfigurationElement a in section.Appenders)
                {
                    var url = string.IsNullOrEmpty(a.AppendSecure) ? a.Append : a.AppendSecure;
                    if (url.StartsWith("~"))
                    {
                        throw new Exception("Only absolute cdn path supported. Can not use " + url);
                    }

                    appenders[a.Extensions + "|"] = url.TrimEnd('/') + "/";
                }

                foreach (HandlerConfigurationElement h in section.Handlers)
                {
                    if (h.Name == "cdn")
                    {
                        s3publickey = h.HandlerProperties["acesskey"].Value;
                        s3privatekey = h.HandlerProperties["secretaccesskey"].Value;
                        s3bucket = h.HandlerProperties["bucket"].Value;
                        s3region = h.HandlerProperties["region"].Value;
                        break;
                    }
                }

                successInitialized = true;
            }
            catch (Exception fatal)
            {
                log.Fatal(fatal);
            }
        }


        public void Process(BundleContext context, BundleResponse response)
        {
            if (successInitialized && BundleTable.Bundles.UseCdn)
            {
                try
                {
                    var bundle = context.BundleCollection.GetBundleFor(context.BundleVirtualPath);
                    if (bundle != null)
                    {
                        queue.Enqueue(new CdnItem { Bundle = bundle, Response = response });
                        Action upload = UploadToCdn;
                        upload.BeginInvoke(null, null);
                    }
                }
                catch (Exception fatal)
                {
                    log.Fatal(fatal);
                    throw;
                }
            }
        }

        private void UploadToCdn()
        {
            try
            {
                // one thread only
                if (Interlocked.CompareExchange(ref work, 1, 0) == 0)
                {
                    var @continue = false;
                    try
                    {
                        CdnItem item;
                        if (queue.TryDequeue(out item))
                        {
                            @continue = true;

                            var cdnpath = GetCdnPath(item.Bundle.Path);
                            var key = new Uri(cdnpath).PathAndQuery.TrimStart('/');
                            var content = Encoding.UTF8.GetBytes(item.Response.Content);
                            var inputStream = new MemoryStream();

                            if (ClientSettings.GZipEnabled)
                            {
                                using (var zip = new GZipStream(inputStream, CompressionMode.Compress, true))
                                {
                                    zip.Write(content, 0, content.Length);
                                    zip.Flush();
                                }
                            }
                            else
                            {
                                inputStream.Write(content, 0, content.Length);
                            }

                            var checksum = AmazonS3Util.GenerateChecksumForContent(item.Response.Content, true);

                            var config = new AmazonS3Config
                            {
                                RegionEndpoint = RegionEndpoint.GetBySystemName(s3region),
                                UseHttp = true
                            };
                            using (var s3 = new AmazonS3Client(s3publickey, s3privatekey, config))
                            {
                                var upload = false;
                                try
                                {
                                    var request = new GetObjectMetadataRequest
                                    {
                                        BucketName = s3bucket,
                                        Key = key,
                                    };
                                    var response = s3.GetObjectMetadata(request);
                                    upload = !string.Equals(checksum, response.Metadata["x-amz-meta-etag"], StringComparison.InvariantCultureIgnoreCase);
                                }
                                catch (AmazonS3Exception ex)
                                {
                                    if (ex.StatusCode == HttpStatusCode.NotFound)
                                    {
                                        upload = true;
                                    }
                                    else
                                    {
                                        throw;
                                    }
                                }

                                if (upload)
                                {
                                    var request = new PutObjectRequest
                                    {
                                        BucketName = s3bucket,
                                        CannedACL = S3CannedACL.PublicRead,
                                        AutoCloseStream = true,
                                        AutoResetStreamPosition = true,
                                        Key = key,
                                        ContentType = AmazonS3Util.MimeTypeFromExtension(Path.GetExtension(key).ToLowerInvariant()),
                                        InputStream = inputStream
                                    };

                                    if (ClientSettings.GZipEnabled)
                                    {
                                        request.Headers.ContentEncoding = "gzip";
                                    }

                                    var cache = TimeSpan.FromDays(365);
                                    request.Headers.CacheControl = string.Format("public, maxage={0}", (int)cache.TotalSeconds);
                                    request.Headers.ExpiresUtc = DateTime.UtcNow.Add(cache);
                                    request.Headers["x-amz-meta-etag"] = checksum;

                                    s3.PutObject(request);
                                }
                                else
                                {
                                    inputStream.Close();
                                }

                                item.Bundle.CdnPath = cdnpath;
                            }
                        }
                    }
                    catch (Exception err)
                    {
                        log.Error(err);
                    }
                    finally
                    {
                        work = 0;
                        if (@continue)
                        {
                            Action upload = () => UploadToCdn();
                            upload.BeginInvoke(null, null);
                        }
                    }
                }
            }
            catch (Exception fatal)
            {
                log.Fatal(fatal);
            }
        }

        private static string GetCdnPath(string path)
        {
            var ext = Path.GetExtension(path).ToLowerInvariant();
            var abspath = string.Empty;
            foreach (var a in appenders)
            {
                abspath = a.Value;
                if (a.Key.ToLowerInvariant().Contains(ext + "|"))
                {
                    break;
                }
            }

            return abspath + path.TrimStart('~', '/');
        }
    }

    class CdnItem
    {
        public Bundle Bundle { get; set; }

        public BundleResponse Response { get; set; }
    }
}

<|start_filename|>common/ASC.Core.Common/HostedSolution.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Security;

using ASC.Core.Billing;
using ASC.Core.Data;
using ASC.Core.Security.Authentication;
using ASC.Core.Tenants;
using ASC.Core.Users;

namespace ASC.Core
{
    public class HostedSolution
    {
        private readonly ITenantService tenantService;
        private readonly IUserService userService;
        private readonly IQuotaService quotaService;
        private readonly ITariffService tariffService;
        private readonly TenantManager clientTenantManager;
        private readonly DbSettingsManager settingsManager;

        public string Region
        {
            get;
            private set;
        }

        public string DbId
        {
            get;
            private set;
        }


        public HostedSolution(ConnectionStringSettings connectionString)
            : this(connectionString, null)
        {
        }

        public HostedSolution(ConnectionStringSettings connectionString, string region)
        {
            tenantService = new DbTenantService(connectionString);
            userService = new DbUserService(connectionString);
            quotaService = new DbQuotaService(connectionString);
            tariffService = new TariffService(connectionString, quotaService, tenantService);
            clientTenantManager = new TenantManager(tenantService, quotaService, tariffService);
            settingsManager = new DbSettingsManager(connectionString);
            Region = region ?? string.Empty;
            DbId = connectionString.Name;
        }

        public List<Tenant> GetTenants(DateTime from)
        {
            return tenantService.GetTenants(from).Select(AddRegion).ToList();
        }

        public List<Tenant> FindTenants(string login)
        {
            return FindTenants(login, null);
        }

        public List<Tenant> FindTenants(string login, string passwordHash)
        {
            if (!string.IsNullOrEmpty(passwordHash) && userService.GetUserByPasswordHash(Tenant.DEFAULT_TENANT, login, passwordHash) == null)
            {
                throw new SecurityException("Invalid login or password.");
            }
            return tenantService.GetTenants(login, passwordHash).Select(AddRegion).ToList();
        }

        public Tenant GetTenant(String domain)
        {
            return AddRegion(tenantService.GetTenant(domain));
        }

        public Tenant GetTenant(int id)
        {
            return AddRegion(tenantService.GetTenant(id));
        }

        public void CheckTenantAddress(string address)
        {
            tenantService.ValidateDomain(address);
        }

        public void RegisterTenant(TenantRegistrationInfo ri, out Tenant tenant)
        {
            tenant = null;

            if (ri == null) throw new ArgumentNullException("registrationInfo");
            if (string.IsNullOrEmpty(ri.Address)) throw new Exception("Address can not be empty");

            if (string.IsNullOrEmpty(ri.Email)) throw new Exception("Account email can not be empty");
            if (ri.FirstName == null) throw new Exception("Account firstname can not be empty");
            if (ri.LastName == null) throw new Exception("Account lastname can not be empty");
            if (!UserFormatter.IsValidUserName(ri.FirstName, ri.LastName)) throw new Exception("Incorrect firstname or lastname");

            if (string.IsNullOrEmpty(ri.PasswordHash)) ri.PasswordHash = <PASSWORD>.NewGuid().ToString();

            // create tenant
            tenant = new Tenant(ri.Address.ToLowerInvariant())
            {
                Name = ri.Name,
                Language = ri.Culture.Name,
                TimeZone = ri.TimeZoneInfo,
                HostedRegion = ri.HostedRegion,
                PartnerId = ri.PartnerId,
                AffiliateId = ri.AffiliateId,
                Campaign = ri.Campaign,
                Industry = ri.Industry,
                Spam = ri.Spam,
                Calls = ri.Calls
            };

            tenant = tenantService.SaveTenant(tenant);

            // create user
            var user = new UserInfo
            {
                UserName = ri.Email.Substring(0, ri.Email.IndexOf('@')),
                LastName = ri.LastName,
                FirstName = ri.FirstName,
                Email = ri.Email,
                MobilePhone = ri.MobilePhone,
                WorkFromDate = TenantUtil.DateTimeNow(tenant.TimeZone),
                ActivationStatus = ri.ActivationStatus
            };
            user = userService.SaveUser(tenant.TenantId, user);
            userService.SetUserPasswordHash(tenant.TenantId, user.ID, ri.PasswordHash);
            userService.SaveUserGroupRef(tenant.TenantId, new UserGroupRef(user.ID, Constants.GroupAdmin.ID, UserGroupRefType.Contains));

            // save tenant owner
            tenant.OwnerId = user.ID;
            tenant = tenantService.SaveTenant(tenant);

            settingsManager.SaveSettings(new TenantControlPanelSettings { LimitedAccess = ri.LimitedControlPanel }, tenant.TenantId);
        }

        public Tenant SaveTenant(Tenant tenant)
        {
            return tenantService.SaveTenant(tenant);
        }

        public void RemoveTenant(Tenant tenant)
        {
            tenantService.RemoveTenant(tenant.TenantId);
        }

        public string CreateAuthenticationCookie(int tenantId, Guid userId)
        {
            var u = userService.GetUser(tenantId, userId);
            return CreateAuthenticationCookie(tenantId, u);
        }

        private string CreateAuthenticationCookie(int tenantId, UserInfo user)
        {
            if (user == null) return null;

            var tenantSettings = settingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, Guid.Empty);
            var expires = tenantSettings.IsDefault() ? DateTime.UtcNow.AddYears(1) : DateTime.UtcNow.AddMinutes(tenantSettings.LifeTime);
            var userSettings = settingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, user.ID);
            return CookieStorage.EncryptCookie(tenantId, user.ID, tenantSettings.Index, expires, userSettings.Index);
        }

        public Tariff GetTariff(int tenant, bool withRequestToPaymentSystem = true)
        {
            return tariffService.GetTariff(tenant, withRequestToPaymentSystem);
        }

        public TenantQuota GetTenantQuota(int tenant)
        {
            return clientTenantManager.GetTenantQuota(tenant);
        }

        public IEnumerable<TenantQuota> GetTenantQuotas()
        {
            return clientTenantManager.GetTenantQuotas();
        }

        public TenantQuota SaveTenantQuota(TenantQuota quota)
        {
            return clientTenantManager.SaveTenantQuota(quota);
        }

        public void SetTariff(int tenant, bool paid)
        {
            var quota = quotaService.GetTenantQuotas().FirstOrDefault(q => paid ? q.NonProfit : q.Trial);
            if (quota != null)
            {
                tariffService.SetTariff(tenant, new Tariff { QuotaId = quota.Id, DueDate = DateTime.MaxValue, });
            }
        }

        public void SetTariff(int tenant, Tariff tariff)
        {
            tariffService.SetTariff(tenant, tariff);
        }

        public void SaveButton(int tariffId, string partnerId, string buttonUrl)
        {
            tariffService.SaveButton(tariffId, partnerId, buttonUrl);
        }


        private Tenant AddRegion(Tenant tenant)
        {
            if (tenant != null)
            {
                tenant.HostedRegion = Region;
            }
            return tenant;
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Client/Bundling/RackspaceCloudStorageTransform.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web.Optimization;

using ASC.Common.Logging;
using ASC.Common.Web;
using ASC.Data.Storage.Configuration;
using ASC.Data.Storage.RackspaceCloud;

using net.openstack.Core.Domain;
using net.openstack.Providers.Rackspace;

namespace ASC.Web.Core.Client.Bundling
{
    class RackspaceCloudStorageTransform : IBundleTransform
    {
        private static readonly ILog log = LogManager.GetLogger("ASC.Web.Bundle.RackspaceCloudStorageTransform");
        private static readonly bool successInitialized = false;
        private static readonly Dictionary<string, string> appenders = new Dictionary<string, string>();
        private static int work = 0;
        private static readonly ConcurrentQueue<CdnItem> queue = new ConcurrentQueue<CdnItem>();

        private static readonly String _username = String.Empty;
        private static readonly String _apiKey = String.Empty;
        private static readonly String _container = String.Empty;
        private static readonly String _subDir = String.Empty;

        static RackspaceCloudStorageTransform()
        {
            try
            {
                var section = (StorageConfigurationSection)ConfigurationManagerExtension.GetSection("storage");

                if (section == null)
                {
                    throw new Exception("Storage section not found.");
                }

                if (section.Appenders.Count == 0)
                {
                    throw new Exception("Appenders not found.");
                }

                foreach (AppenderConfigurationElement a in section.Appenders)
                {
                    var url = string.IsNullOrEmpty(a.AppendSecure) ? a.Append : a.AppendSecure;
                    if (url.StartsWith("~"))
                    {
                        throw new Exception("Only absolute cdn path supported. Can not use " + url);
                    }

                    appenders[a.Extensions + "|"] = url.TrimEnd('/') + "/";
                }

                foreach (HandlerConfigurationElement h in section.Handlers)
                {
                    if (h.Type.Equals(typeof(RackspaceCloudStorage)) && h.Name == "cdn")
                    {
                        _username = h.HandlerProperties["username"].Value;
                        _apiKey = h.HandlerProperties["apiKey"].Value;
                        _container = h.HandlerProperties["container"].Value;
                        _subDir = h.HandlerProperties["subdir"].Value;

                        successInitialized = true;

                        break;
                    }
                }


            }
            catch (Exception fatal)
            {
                log.Fatal(fatal);
            }
        }

        public void Process(BundleContext context, BundleResponse response)
        {
            if (successInitialized && BundleTable.Bundles.UseCdn)
            {
                try
                {
                    var bundle = context.BundleCollection.GetBundleFor(context.BundleVirtualPath);
                    if (bundle != null)
                    {
                        queue.Enqueue(new CdnItem { Bundle = bundle, Response = response });
                        Action upload = UploadToCdn;
                        upload.BeginInvoke(null, null);
                    }
                }
                catch (Exception fatal)
                {
                    log.Fatal(fatal);
                    throw;
                }
            }
        }

        private CloudFilesProvider GetClient()
        {
            CloudIdentity cloudIdentity = new CloudIdentity()
            {
                Username = _username,
                APIKey = _apiKey
            };

            return new CloudFilesProvider(cloudIdentity);
        }


        private void UploadToCdn()
        {
            try
            {
                // one thread only
                if (Interlocked.CompareExchange(ref work, 1, 0) == 0)
                {
                    var @continue = false;
                    try
                    {
                        CdnItem item;
                        if (queue.TryDequeue(out item))
                        {
                            @continue = true;

                            var cdnpath = GetCdnPath(item.Bundle.Path);
                            var key = new Uri(cdnpath).PathAndQuery.TrimStart('/');
                            var path = key.Remove(0, _container.Length + 1);

                            var content = Encoding.UTF8.GetBytes(item.Response.Content);
                            var inputStream = new MemoryStream();

                            if (ClientSettings.GZipEnabled)
                            {
                                using (var zip = new GZipStream(inputStream, CompressionMode.Compress, true))
                                {
                                    zip.Write(content, 0, content.Length);
                                    zip.Flush();
                                }
                            }
                            else
                            {
                                inputStream.Write(content, 0, content.Length);
                            }

                            inputStream.Position = 0;

                            bool upload = true;

                            var client = GetClient();

                            var etag = SelectelSharp.Common.Helpers.CalculateSHA1(item.Response.Content);

                            var fileInfo = client.ListObjects(_container, 1, null, null, path);

                            if (fileInfo != null && fileInfo.Any())
                            {
                                upload = fileInfo.Single().Hash != etag;
                            }

                            if (upload)
                            {
                                var contentType = String.Empty;

                                var mime = string.IsNullOrEmpty(contentType) ? MimeMapping.GetMimeMapping(Path.GetFileName(key))
                             : contentType;

                                var customHeaders = new Dictionary<string, string>();

                                if (ClientSettings.GZipEnabled)
                                {
                                    customHeaders.Add("Content-Encoding", "gzip");
                                }

                                var cache = TimeSpan.FromDays(365);

                                customHeaders.Add("Cache-Control", String.Format("public, maxage={0}", (int)cache.TotalSeconds));
                                customHeaders.Add("Expires", DateTime.UtcNow.Add(cache).ToString());

                                client.CreateObject(_container, inputStream, path, mime, 4096, customHeaders);
                            }
                            else
                            {
                                inputStream.Close();
                            }

                            item.Bundle.CdnPath = cdnpath;
                        }
                    }
                    catch (Exception err)
                    {
                        log.Error(err);
                    }
                    finally
                    {
                        work = 0;
                        if (@continue)
                        {
                            Action upload = () => UploadToCdn();
                            upload.BeginInvoke(null, null);
                        }
                    }
                }
            }
            catch (Exception fatal)
            {
                log.Fatal(fatal);
            }
        }

        private static string GetCdnPath(string path)
        {
            var ext = Path.GetExtension(path).ToLowerInvariant();
            var abspath = string.Empty;
            foreach (var a in appenders)
            {
                abspath = a.Value;
                if (a.Key.ToLowerInvariant().Contains(ext + "|"))
                {
                    break;
                }
            }

            return abspath + path.TrimStart('~', '/');
        }

    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Community/CommunityApi.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Api.Impl;
using ASC.Api.Interfaces;

namespace ASC.Api.Community
{
    ///<summary>
    ///Provides access to community data api
    ///</summary>
    public partial class CommunityApi : IApiEntryPoint
    {
        private readonly ApiContext _context;


        ///<summary>
        /// Starting entry point name
        ///</summary>
        public string Name
        {
            get { return "community"; }
        }

        ///<summary>
        /// Constructor
        ///</summary>
        ///<param name="context"></param>
        public CommunityApi(ApiContext context)
        {
            _context = context;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_Parameter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class represents SIP value parameter.
    /// </summary>
    public class SIP_Parameter
    {
        #region Members

        private readonly string m_Name = "";
        private string m_Value = "";

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        public SIP_Parameter(string name) : this(name, "") {}

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        /// <param name="value">Parameter value.</param>
        public SIP_Parameter(string name, string value)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (name == "")
            {
                throw new ArgumentException("Parameter 'name' value may no be empty string !");
            }

            m_Name = name;
            m_Value = value;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets parameter name.
        /// </summary>
        public string Name
        {
            get { return m_Name; }
        }

        /// <summary>
        /// Gets or sets parameter name. Value null means value less tag prameter.
        /// </summary>
        public string Value
        {
            get { return m_Value; }

            set { m_Value = value; }
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Common/Notify/Patterns/NVelocityPatternFormatter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Utils;
using ASC.Notify.Messages;

using NVelocity;
using NVelocity.App.Events;

namespace ASC.Notify.Patterns
{
    public sealed class NVelocityPatternFormatter : PatternFormatter
    {
        public const string DefaultPattern = @"(^|[^\\])\$[\{]{0,1}(?<tagName>[a-zA-Z0-9_]+)";
        public const string NoStylePreffix = "==";
        public const string NoStyleSuffix = "==";

        private VelocityContext _nvelocityContext;

        public NVelocityPatternFormatter()
            : base(DefaultPattern)
        {
        }

        protected override void BeforeFormat(INoticeMessage message, ITagValue[] tagsValues)
        {
            _nvelocityContext = new VelocityContext();
            _nvelocityContext.AttachEventCartridge(new EventCartridge());
            _nvelocityContext.EventCartridge.ReferenceInsertion += EventCartridgeReferenceInsertion;
            foreach (var tagValue in tagsValues)
            {
                _nvelocityContext.Put(tagValue.Tag, tagValue.Value);
            }
            base.BeforeFormat(message, tagsValues);
        }

        protected override string FormatText(string text, ITagValue[] tagsValues)
        {
            if (String.IsNullOrEmpty(text)) return text;
            return VelocityFormatter.FormatText(text, _nvelocityContext);
        }

        protected override void AfterFormat(INoticeMessage message)
        {
            _nvelocityContext = null;
            base.AfterFormat(message);
        }

        private static void EventCartridgeReferenceInsertion(object sender, ReferenceInsertionEventArgs e)
        {
            var originalString = e.OriginalValue as string;
            if (originalString == null) return;
            var lines = originalString.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            if (lines.Length == 0) return;
            e.NewValue = string.Empty;
            for (var i = 0; i < lines.Length - 1; i++)
            {
                e.NewValue += string.Format("{0}{1}{2}\n", NoStylePreffix, lines[i], NoStyleSuffix);
            }
            e.NewValue += string.Format("{0}{1}{2}", NoStylePreffix, lines[lines.Length - 1], NoStyleSuffix);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Core/Notify/TagValues.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Notify.Patterns;

namespace ASC.Web.Studio.Core.Notify
{
    public static class TagValues
    {
        public static ITagValue WithoutUnsubscribe()
        {
            return new TagValue(CommonTags.WithoutUnsubscribe, true);
        }

        public static ITagValue PersonalHeaderStart()
        {
            return new TagValue("PersonalHeaderStart",
                                "<table style=\"margin: 0; border-spacing: 0; empty-cells: show; width: 540px; width: 100%;\" cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td style=\"width: 100%;color: #333333;font-size: 18px;font-weight: bold;margin: 0;height: 71px;padding-right:165px;background: url('https://d2nlctn12v279m.cloudfront.net/media/newsletters/images/personal-header-bg.png') top right no-repeat;\">");
        }

        public static ITagValue PersonalHeaderEnd()
        {
            return new TagValue("PersonalHeaderEnd", "</td></tr></tbody></table>");
        }

        public static ITagValue BlueButton(Func<string> btnTextFunc, string btnUrl)
        {
            Func<string> action = () =>
                {
                    var btnText = btnTextFunc != null ? btnTextFunc() ?? string.Empty : string.Empty;

                    return
                        string.Format(
                            @"<table style=""height: 48px; width: 540px; border-collapse: collapse; empty-cells: show; vertical-align: middle; text-align: center; margin: 30px auto; padding: 0;""><tbody><tr cellpadding=""0"" cellspacing=""0"" border=""0"">{2}<td style=""height: 48px; width: 380px; margin:0; padding:0; background-color: #66b76d; -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px;""><a style=""{3}"" target=""_blank"" href=""{0}"">{1}</a></td>{2}</tr></tbody></table>",
                            btnUrl,
                            btnText,
                            "<td style=\"height: 48px; width: 80px; margin:0; padding:0;\">&nbsp;</td>",
                            "color: #fff; font-family: Helvetica, Arial, Tahoma; font-size: 18px; font-weight: 600; vertical-align: middle; display: block; padding: 12px 0; text-align: center; text-decoration: none; background-color: #66b76d;");
                };

            return new TagActionValue("BlueButton", action);
        }

        public static ITagValue GreenButton(Func<string> btnTextFunc, string btnUrl)
        {
            Func<string> action = () =>
                {
                    var btnText = btnTextFunc != null ? btnTextFunc() ?? string.Empty : string.Empty;

                    return
                        string.Format(
                            @"<table style=""height: 48px; width: 540px; border-collapse: collapse; empty-cells: show; vertical-align: middle; text-align: center; margin: 30px auto; padding: 0;""><tbody><tr cellpadding=""0"" cellspacing=""0"" border=""0"">{2}<td style=""height: 48px; width: 380px; margin:0; padding:0; background-color: #66b76d; -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px;""><a style=""{3}"" target=""_blank"" href=""{0}"">{1}</a></td>{2}</tr></tbody></table>",
                            btnUrl,
                            btnText,
                            "<td style=\"height: 48px; width: 80px; margin:0; padding:0;\">&nbsp;</td>",
                            "color: #fff; font-family: Helvetica, Arial, Tahoma; font-size: 18px; font-weight: 600; vertical-align: middle; display: block; padding: 12px 0; text-align: center; text-decoration: none; background-color: #66b76d;");
                };

            return new TagActionValue("GreenButton", action);
        }

        public static ITagValue TableTop()
        {
            return new TagValue("TableItemsTop",
                                "<table cellpadding=\"0\" cellspacing=\"0\" style=\"margin: 20px 0 0; border-spacing: 0; empty-cells: show; width: 540px; font-size: 14px;\">");
        }

        public static ITagValue TableBottom()
        {
            return new TagValue("TableItemsBtm", "</table>");
        }

        public static ITagValue TableItem(
            int number,
            Func<string> linkTextFunc,
            string linkUrl,
            string imgSrc,
            Func<string> commentFunc,
            Func<string> bottomlinkTextFunc,
            string bottomlinkUrl)
        {
            Func<string> action = () =>
                {
                    var linkText = linkTextFunc != null ? linkTextFunc() ?? string.Empty : string.Empty;
                    var comment = commentFunc != null ? commentFunc() ?? string.Empty : string.Empty;
                    var bottomlinkText = bottomlinkTextFunc != null
                                             ? bottomlinkTextFunc() ?? string.Empty
                                             : string.Empty;

                    var imgHtml = string.Format(
                        "<img style=\"border: 0; padding: 0 15px 0 5px; width: auto; height: auto;\" alt=\"{1}\" src=\"{0}\"/>",
                        imgSrc ?? string.Empty,
                        linkText);

                    var linkHtml = string.Empty;

                    if (!string.IsNullOrEmpty(linkText))
                    {
                        linkHtml =
                            !string.IsNullOrEmpty(linkUrl)
                                ? string.Format(
                                    "<a target=\"_blank\" style=\"color:#0078bd; font-family: Arial; font-size: 14px; font-weight: bold;\" href=\"{0}\">{1}</a><br/>",
                                    linkUrl,
                                    linkText)
                                : string.Format(
                                    "<div style=\"display:block; color:#333333; font-family: Arial; font-size: 14px; font-weight: bold;margin-bottom: 10px;\">{0}</div>",
                                    linkText);
                    }

                    var underCommentLinkHtml =
                        string.IsNullOrEmpty(bottomlinkUrl)
                            ? string.Empty
                            : string.Format(
                                "<br/><a target=\"_blank\" style=\"color: #0078bd; font-family: Arial; font-size: 14px;\" href=\"{0}\">{1}</a>",
                                bottomlinkUrl,
                                bottomlinkText);

                    var html =
                        "<tr><td style=\"vertical-align: top; padding: 5px 10px; width: 70px;\">" +
                        imgHtml +
                        "</td><td style=\" vertical-align: middle; padding: 5px 10px; font-size: 14px; width: 470px; color: #333333;\">" +
                        linkHtml +
                        comment +
                        underCommentLinkHtml +
                        "</td></tr>";

                    return html;
                };

            return new TagActionValue("TableItem" + number, action);
        }

        public static ITagValue Image(int id, string imageFileName)
        {
            var imgSrc = StudioNotifyHelper.GetNotificationImageUrl(imageFileName);

            var imgHtml = string.Format("<img style=\"border: 0; padding: 0; width: auto; height: auto;\" alt=\"\" src=\"{0}\"/>", imgSrc);

            var tagName = "Image" + (id > 0 ? id.ToString() : string.Empty);

            return new TagValue(tagName, imgHtml);
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Extensions/MailMessageExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

using ASC.Common.Logging;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Utils;

using HtmlAgilityPack;

using MimeKit;
using MimeKit.Text;
using MimeKit.Tnef;

namespace ASC.Mail.Extensions
{
    public static class MailMessageExtensions
    {
        public static void LoadCalendarInfo(this MailMessageData mail, MimeMessage message, ILog log = null)
        {
            if (!message.BodyParts.Any())
                return;

            log = log ?? new NullLog();

            try
            {
                var calendarParts = message.BodyParts.Where(p => p.ContentType.IsMimeType("text", "calendar")).ToList();

                if (!calendarParts.Any())
                    return;

                log.DebugFormat("LoadCalendarInfo found {0} calendars", calendarParts.Count);

                foreach (var calendarPart in calendarParts)
                {
                    var p = calendarPart as TextPart;
                    if (p == null)
                        continue;

                    var ics = p.Text;

                    var calendar = MailUtil.ParseValidCalendar(ics, log);

                    if (calendar == null)
                        continue;

                    if (calendar.Events[0].Organizer == null &&
                        calendar.Method.Equals(Defines.ICAL_REPLY, StringComparison.OrdinalIgnoreCase))
                    {
                        // Fix reply organizer (Outlook style of Reply)
                        var toAddress = message.To.Mailboxes.FirstOrDefault();
                        if (toAddress != null)
                        {
                            calendar.Events[0].Organizer = new Ical.Net.DataTypes.Organizer("mailto:" + toAddress.Address)
                            {
                                CommonName = string.IsNullOrEmpty(toAddress.Name)
                                    ? toAddress.Address
                                    : toAddress.Name
                            };

                            ics = MailUtil.SerializeCalendar(calendar);
                        }
                    }

                    mail.CalendarUid = calendar.Events[0].Uid;
                    mail.CalendarId = -1;
                    mail.CalendarEventIcs = ics;
                    mail.CalendarEventCharset = string.IsNullOrEmpty(p.ContentType.Charset) ? Encoding.UTF8.HeaderName : p.ContentType.Charset;
                    mail.CalendarEventMimeType = p.ContentType.MimeType;

                    log.DebugFormat("Calendar UID: {0} Method: {1} ics: {2}", mail.CalendarUid, calendar.Method, mail.CalendarEventIcs);

                    var calendarExists =
                        message.Attachments
                            .Any(
                                attach =>
                                {
                                    var subType = attach.ContentType.MediaSubtype.ToLower().Trim();

                                    if (string.IsNullOrEmpty(subType) ||
                                        (!subType.Equals("ics") &&
                                         !subType.Equals("ical") &&
                                         !subType.Equals("ifb") &&
                                         !subType.Equals("icalendar") &&
                                         !subType.Equals("calendar")))
                                    {
                                        return false;
                                    }

                                    var icsTextPart = attach as TextPart;
                                    string icsAttach;

                                    if (icsTextPart != null)
                                    {
                                        icsAttach = icsTextPart.Text;
                                    }
                                    else
                                    {
                                        using (var stream = new MemoryStream())
                                        {
                                            p.Content.DecodeTo(stream);
                                            var bytes = stream.ToArray();
                                            var encoding = MailUtil.GetEncoding(p.ContentType.Charset);
                                            icsAttach = encoding.GetString(bytes);
                                        }
                                    }

                                    var cal = MailUtil.ParseValidCalendar(icsAttach, log);

                                    if (cal == null)
                                        return false;

                                    return mail.CalendarUid == cal.Events[0].Uid;
                                });

                    if (calendarExists)
                    {
                        log.Debug("Calendar exists as attachment");
                        continue;
                    }

                    if (calendarPart.ContentDisposition == null)
                    {
                        calendarPart.ContentDisposition = new ContentDisposition();
                    }

                    if (string.IsNullOrEmpty(calendarPart.ContentDisposition.FileName))
                    {
                        calendarPart.ContentDisposition.FileName = calendar.Method == Defines.ICAL_REQUEST
                            ? "invite.ics"
                            : calendar.Method == Defines.ICAL_REPLY ? "reply.ics" : "cancel.ics";
                    }

                    mail.LoadAttachments(new List<MimeEntity> { calendarPart }, true);
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("LoadCalendarInfo() \r\n Exception: \r\n{0}\r\n", ex.ToString());
            }
        }

        private static string ConvertToHtml(TextPart entity)
        {
            try
            {
                TextConverter converter;

                if (entity.IsHtml)
                {
                    converter = new HtmlToHtml();
                }
                else if (entity.IsFlowed)
                {
                    var flowed = new FlowedToHtml();
                    string delsp;

                    if (entity.ContentType.Parameters.TryGetValue("delsp", out delsp))
                        flowed.DeleteSpace = delsp.ToLowerInvariant() == "yes";

                    converter = flowed;

                }
                else
                {
                    converter = new TextToHtml();
                }

                var body = converter.Convert(entity.Text);

                return body;
            }
            catch (Exception)
            {
                // skip
            }

            return entity.Text ?? "";
        }

        public static void ExtractMainParts(this MailMessageData mail, MimeMessage message)
        {
            var htmlStream = new MemoryStream();
            var textStream = new MemoryStream();

            Action<MimeEntity> loadRealAttachment = (part) =>
            {
                if ((part.ContentDisposition != null && !string.IsNullOrEmpty(part.ContentDisposition.FileName))
                    || part.ContentType != null && !string.IsNullOrEmpty(part.ContentType.Name))
                {
                    mail.LoadAttachments(new List<MimeEntity> { part });
                }
            };

            Action<MimePart> setBodyOrAttachment = (part) =>
            {
                var entity = part as TextPart;

                if (htmlStream == null || textStream == null)
                    throw new Exception("Streams are not initialized");

                if ((entity == null
                     || htmlStream.Length != 0 && entity.IsHtml
                     || textStream.Length != 0 && !entity.IsHtml))
                {
                    loadRealAttachment(part);
                }
                else
                {

                    if (mail.Introduction.Length < 200 && (!entity.IsHtml && !string.IsNullOrEmpty(entity.Text)))
                    {
                        if (string.IsNullOrEmpty(mail.Introduction))
                        {
                            mail.Introduction = (entity.Text.Length > 200 ? entity.Text.Substring(0, 200) : entity.Text);
                        }
                        else
                        {
                            var need = 200 - mail.Introduction.Length;
                            mail.Introduction += (entity.Text.Length > need ? entity.Text.Substring(0, need) : entity.Text);
                        }

                        mail.Introduction = mail.Introduction.Replace("\r\n", " ").Replace("\n", " ").Trim();
                    }

                    var body = ConvertToHtml(entity);

                    if (entity.IsHtml)
                    {
                        using (var sw = new StreamWriter(htmlStream, Encoding.UTF8, 1024, true))
                        {
                            sw.Write(body);
                            sw.Flush();
                            htmlStream.Seek(0, SeekOrigin.Begin);
                        }
                    }
                    else
                    {
                        using (var sw = new StreamWriter(textStream, Encoding.UTF8, 1024, true))
                        {
                            sw.Write(body);
                            sw.Flush();
                            textStream.Seek(0, SeekOrigin.Begin);
                        }
                    }
                }
            };

            var newPathIndex = "";

            using (var sw = new StreamWriter(mail.HtmlBodyStream, Encoding.UTF8, 1024, true))
            {
                using (var iter = new MimeIterator(message))
                {
                    while (string.IsNullOrEmpty(newPathIndex) ? iter.MoveNext() : iter.MoveTo(newPathIndex))
                    {
                        if (!string.IsNullOrEmpty(newPathIndex))
                            newPathIndex = "";

                        var multipart = iter.Parent as Multipart;
                        var part = iter.Current as MimePart;

                        var subMessage = iter.Current as MessagePart;
                        if (subMessage != null)
                        {
                            if ((subMessage.ContentDisposition != null &&
                                 !string.IsNullOrEmpty(subMessage.ContentDisposition.FileName))
                                || subMessage.ContentType != null && !string.IsNullOrEmpty(subMessage.ContentType.Name))
                            {
                                mail.LoadAttachments(new List<MimeEntity> { subMessage }, true);
                            }
                            else
                            {
                                subMessage.ContentDisposition = new ContentDisposition
                                {
                                    Disposition = ContentDisposition.Attachment,
                                    FileName = "message.eml"
                                };

                                mail.LoadAttachments(new List<MimeEntity> { subMessage }, true);
                            }

                            float pathIndex;

                            if (float.TryParse(iter.PathSpecifier, out pathIndex))
                            {
                                pathIndex++;
                                newPathIndex = ((int)pathIndex).ToString();
                                continue;
                            }
                        }

                        if (part == null || iter.Parent is MessagePart)
                        {
                            continue;
                        }

                        if (part.IsAttachment)
                        {
                            if (part is TnefPart)
                            {
                                var tnefPart = iter.Current as TnefPart;

                                if (tnefPart != null)
                                    mail.LoadAttachments(tnefPart.ExtractAttachments(), true);
                            }
                            else
                            {
                                mail.LoadAttachments(new List<MimeEntity> { part },
                                    multipart == null || !multipart.ContentType.MimeType.ToLowerInvariant().Equals("multipart/related"));
                            }
                        }
                        else if (multipart != null)
                        {
                            switch (multipart.ContentType.MimeType.ToLowerInvariant())
                            {
                                case "multipart/report":
                                    if (part is TextPart)
                                    {
                                        var entity = part as TextPart;

                                        if (entity == null)
                                        {
                                            entity = new TextPart(TextFormat.Plain);

                                            entity.SetText(Encoding.UTF8, part.ToString());
                                        }

                                        var body = ConvertToHtml(entity);

                                        if (mail.HtmlBodyStream.Length == 0)
                                        {
                                            sw.Write(body);
                                        }
                                        else
                                        {
                                            sw.Write("<hr /><br/>");
                                            sw.Write(body);
                                        }

                                        sw.Flush();
                                    }
                                    else if (part is MessageDeliveryStatus)
                                    {
                                        var entity = new TextPart(TextFormat.Plain);

                                        var mds = (MessageDeliveryStatus)part;

                                        using (var memory = new MemoryStream())
                                        {
                                            mds.Content.DecodeTo(memory);

                                            var text =
                                                Encoding.ASCII.GetString(memory.GetBuffer(), 0, (int)memory.Length)
                                                    .Replace("\r\n", "\n");

                                            entity.SetText(Encoding.UTF8, text);
                                        }

                                        var body = ConvertToHtml(entity);

                                        if (mail.HtmlBodyStream.Length == 0)
                                        {
                                            sw.Write(body);
                                        }
                                        else
                                        {
                                            sw.Write("<hr /><br/>");
                                            sw.Write(body);
                                        }

                                        sw.Flush();
                                    }
                                    else
                                    {
                                        loadRealAttachment(part);
                                    }

                                    break;
                                case "multipart/mixed":
                                    if (part is TextPart)
                                    {
                                        var entity = part as TextPart;

                                        var body = ConvertToHtml(entity);

                                        if (mail.HtmlBodyStream.Length == 0)
                                        {
                                            sw.Write(body);
                                        }
                                        else
                                        {
                                            sw.Write("<hr /><br/>");
                                            sw.Write(body);
                                        }

                                        sw.Flush();
                                    }
                                    else
                                    {
                                        if (part.ContentType != null
                                            && part.ContentType.MediaType.Equals("image",
                                            StringComparison.InvariantCultureIgnoreCase)
                                            && part.ContentDisposition != null
                                            && part.ContentDisposition.Disposition.Equals(ContentDisposition.Inline,
                                                StringComparison.InvariantCultureIgnoreCase))
                                        {
                                            if (string.IsNullOrEmpty(part.ContentId))
                                                part.ContentId = Guid.NewGuid().ToString("N").ToLower();

                                            mail.LoadAttachments(new List<MimeEntity> { part });

                                            sw.Write("<hr /><br/>");
                                            sw.Write("<img src=\"cid:{0}\">", part.ContentId);
                                            sw.Flush();
                                        }
                                        else
                                        {
                                            loadRealAttachment(part);
                                        }
                                    }

                                    break;
                                case "multipart/alternative":
                                    if (part is TextPart)
                                    {
                                        setBodyOrAttachment(part);
                                    }
                                    else
                                    {
                                        loadRealAttachment(part);
                                    }
                                    break;
                                case "multipart/related":
                                    if (part is TextPart)
                                    {
                                        setBodyOrAttachment(part);
                                    }
                                    else if (!string.IsNullOrEmpty(part.ContentId) || part.ContentLocation != null)
                                    {
                                        mail.LoadAttachments(new List<MimeEntity> { part });
                                    }
                                    else
                                    {
                                        loadRealAttachment(part);
                                    }

                                    break;
                                default:
                                    if (part is TextPart)
                                    {
                                        setBodyOrAttachment(part);
                                    }
                                    else
                                    {
                                        loadRealAttachment(part);
                                    }
                                    break;
                            }
                        }
                        else
                        {
                            if (part is TextPart)
                            {
                                setBodyOrAttachment(part);
                            }
                            else
                            {
                                loadRealAttachment(part);
                            }
                        }
                    }
                }

                if (htmlStream.Length != 0)
                {
                    if (mail.HtmlBodyStream.Length > 0)
                    {
                        sw.Write("<hr /><br/>");
                        sw.Flush();
                    }

                    htmlStream.CopyTo(sw.BaseStream);
                }
                else if (textStream.Length != 0)
                {
                    if (mail.HtmlBodyStream.Length == 0)
                    {
                        mail.TextBodyOnly = true;
                    }
                    else
                    {
                        sw.Write("<hr /><br/>");
                        sw.Flush();
                    }

                    textStream.CopyTo(sw.BaseStream);
                }

                htmlStream.Dispose();
                textStream.Dispose();
            }

            if (mail.HtmlBodyStream.Length != 0)
                return;

            mail.HtmlBody = "<body><pre>&nbsp;</pre></body>";
            mail.Introduction = "";
            mail.TextBodyOnly = true;
        }

        public static void LoadAttachments(this MailMessageData mail, IEnumerable<MimeEntity> attachments, bool skipContentId = false)
        {
            if (mail.Attachments == null)
                mail.Attachments = new List<MailAttachmentData>();

            foreach (var attachment in attachments)
            {
                var mailAttach = ConvertToMailAttachment(attachment, skipContentId);

                if (mailAttach == null)
                    continue;

                mail.Attachments.Add(mailAttach);
                mail.HasAttachments = true;
            }

        }

        private static MailAttachmentData ConvertToMailAttachment(MimeEntity attachment, bool skipContentId = false)
        {
            var messagePart = attachment as MessagePart;
            var mimePart = attachment as MimePart;

            if (messagePart == null && mimePart == null)
                return null;

            var filename = attachment.ContentDisposition != null &&
                           !string.IsNullOrEmpty(attachment.ContentDisposition.FileName)
                ? attachment.ContentDisposition.FileName
                : attachment.ContentType != null && !string.IsNullOrEmpty(attachment.ContentType.Name)
                    ? attachment.ContentType.Name
                    : "";

            filename = MailUtil.ImproveFilename(filename, attachment.ContentType);

            var mailAttach = new MailAttachmentData
            {
                contentId = skipContentId ? null : attachment.ContentId,
                fileName = filename,
                contentType = attachment.ContentType != null ? attachment.ContentType.MimeType : null,
                contentLocation =
                    !skipContentId && attachment.ContentLocation != null
                        ? attachment.ContentLocation.ToString()
                        : null,
                dataStream = new MemoryStream()
            };

            if (messagePart != null)
                messagePart.Message.WriteTo(mailAttach.dataStream);
            else
                mimePart.Content.DecodeTo(mailAttach.dataStream);

            mailAttach.size = mailAttach.dataStream.Length;

            return mailAttach;
        }

        public static void ReplaceEmbeddedImages(this MailMessageData mail, ILog log = null)
        {
            log = log ?? new NullLog();

            try
            {
                var attchments = mail.Attachments.Where(a => a.isEmbedded && !string.IsNullOrEmpty(a.storedFileUrl)).ToList();

                if (!attchments.Any())
                    return;

                if (mail.HtmlBodyStream.Length > 0)
                {
                    mail.HtmlBodyStream.Seek(0, SeekOrigin.Begin);

                    var doc = new HtmlDocument();
                    doc.Load(mail.HtmlBodyStream, Encoding.UTF8);

                    var hasChanges = false;

                    foreach (var attach in attchments)
                    {
                        HtmlNodeCollection oldNodes = null;

                        if (!string.IsNullOrEmpty(attach.contentId))
                        {
                            oldNodes =
                                doc.DocumentNode.SelectNodes("//img[@src and (contains(@src,'cid:" +
                                                             attach.contentId.Trim('<').Trim('>') + "'))]");
                        }

                        if (!string.IsNullOrEmpty(attach.contentLocation) && oldNodes == null)
                        {
                            oldNodes =
                                doc.DocumentNode.SelectNodes("//img[@src and (contains(@src,'" +
                                                             attach.contentLocation + "'))]");
                        }

                        if (oldNodes == null)
                        {
                            //This attachment is not embedded;
                            attach.contentId = null;
                            attach.contentLocation = null;
                            continue;
                        }

                        foreach (var node in oldNodes)
                        {
                            node.SetAttributeValue("src", attach.storedFileUrl);
                            hasChanges = true;
                        }
                    }

                    mail.HtmlBodyStream.Seek(0, SeekOrigin.Begin);

                    if (!hasChanges)
                        return;

                    mail.HtmlBodyStream.Close();
                    mail.HtmlBodyStream.Dispose();

                    mail.HtmlBodyStream = new MemoryStream();

                    using (var sw = new StreamWriter(mail.HtmlBodyStream, Encoding.UTF8, 1024, true))
                    {
                        doc.DocumentNode.WriteTo(sw);
                        sw.Flush();
                        mail.HtmlBodyStream.Seek(0, SeekOrigin.Begin);
                    }

                    mail.HtmlBodyStream.Seek(0, SeekOrigin.Begin);
                }
                else
                {
                    foreach (var attach in attchments)
                    {
                        if (!string.IsNullOrEmpty(attach.contentId))
                        {
                            mail.HtmlBody = mail.HtmlBody.Replace(string.Format("cid:{0}", attach.contentId.Trim('<').Trim('>')),
                                attach.storedFileUrl);
                        }
                        else if (!string.IsNullOrEmpty(attach.contentLocation))
                        {
                            mail.HtmlBody = mail.HtmlBody.Replace(string.Format("{0}", attach.contentLocation),
                                attach.storedFileUrl);
                        }
                        else
                        {
                            //This attachment is not embedded;
                            attach.contentId = null;
                            attach.contentLocation = null;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("ReplaceEmbeddedImages() \r\n Exception: \r\n{0}\r\n", ex.ToString());
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SMTP/Server/old/SMTP_Session.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Text;

using LumiSoft.Net;
using LumiSoft.Net.SMTP;
using LumiSoft.Net.AUTH;

namespace LumiSoft.Net.SMTP.Server
{
	/// <summary>
	/// SMTP Session.
	/// </summary>
	public class SMTP_Session : SocketServerSession
	{				
		private SMTP_Server        m_pServer          = null;
		private Stream             m_pMsgStream       = null;
        private SMTP_Cmd_Validator m_CmdValidator     = null;
        private long               m_BDAT_ReadedCount = 0;
		private string             m_EhloName         = "";      
		private string             m_Reverse_path     = "";      // Holds sender's reverse path.
		private Hashtable          m_Forward_path     = null;    // Holds Mail to.	
		private int                m_BadCmdCount      = 0;       // Holds number of bad commands.
		private BodyType           m_BodyType;
		private bool               m_BDat             = false;

		/// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="sessionID">Session ID.</param>
        /// <param name="socket">Server connected socket.</param>
        /// <param name="bindInfo">BindInfo what accepted socket.</param>
        /// <param name="server">Reference to server.</param>
        internal SMTP_Session(string sessionID,SocketEx socket,IPBindInfo bindInfo,SMTP_Server server) : base(sessionID,socket,bindInfo,server)
        {	        
            m_pServer      = server;
			m_BodyType     = BodyType.x7_bit;
			m_Forward_path = new Hashtable();
			m_CmdValidator = new SMTP_Cmd_Validator();

			// Start session proccessing
			StartSession();
		}


		#region method StartSession

		/// <summary>
		/// Starts session.
		/// </summary>
		private void StartSession()
		{
			// Add session to session list
			m_pServer.AddSession(this);

			try{	
				// Check if ip is allowed to connect this computer
				ValidateIP_EventArgs oArg = m_pServer.OnValidate_IpAddress(this);
				if(oArg.Validated){
                    //--- Dedicated SSL connection, switch to SSL -----------------------------------//
                    if(this.BindInfo.SslMode == SslMode.SSL){
                        try{
                            this.Socket.SwitchToSSL(this.BindInfo.Certificate);

                            if(this.Socket.Logger != null){
                                this.Socket.Logger.AddTextEntry("SSL negotiation completed successfully.");
                            }
                        }
                        catch(Exception x){
                            if(this.Socket.Logger != null){
                                this.Socket.Logger.AddTextEntry("SSL handshake failed ! " + x.Message);

                                EndSession();
                                return;
                            }
                        }
                    }
                    //-------------------------------------------------------------------------------//

					if(!string.IsNullOrEmpty(m_pServer.GreetingText)){
						this.Socket.WriteLine("220 " + m_pServer.GreetingText);
					}
					else{
						this.Socket.WriteLine("220 " + Net_Utils.GetLocalHostName(this.BindInfo.HostName) + " SMTP Server ready");
					}

					BeginRecieveCmd();
				}
				else{
					// There is user specified error text, send it to connected socket
					if(oArg.ErrorText.Length > 0){
						this.Socket.WriteLine(oArg.ErrorText);
					}

					EndSession();
				}
			}
			catch(Exception x){
				OnError(x);
			}
		}

		#endregion

		#region method EndSession

		/// <summary>
		/// Ends session, closes socket.
		/// </summary>
		private void EndSession()
		{
			try{
                try{
                    // Message storing not completed successfully, otherwise it must be null here. 
                    // This can happen if BDAT -> QUIT and LAST BDAT block wasn't sent or
                    // when session times out on DATA or BDAT command.
                    if(m_pMsgStream != null){
                        // We must call that method to notify Message stream owner to close/dispose that stream.
                        m_pServer.OnMessageStoringCompleted(this,"Message storing not completed successfully",m_pMsgStream);
                        m_pMsgStream = null;
                    }
                }
                catch{
                }

				if(this.Socket != null){
                    // Write logs to log file, if needed
				    if(m_pServer.LogCommands){
					    this.Socket.Logger.Flush();
				    }

					this.Socket.Shutdown(SocketShutdown.Both);
					this.Socket.Disconnect();
					//this.Socket = null;
				}
			}
			catch{ // We don't need to check errors here, because they only may be Socket closing errors.
			}
			finally{
				m_pServer.RemoveSession(this);
			}
		}

		#endregion


        #region method Kill

        /// <summary>
        /// Kill this session.
        /// </summary>
        public override void Kill()
        {
            EndSession();
        }

        #endregion

		#region method OnSessionTimeout

		/// <summary>
		/// Is called by server when session has timed out.
		/// </summary>
		internal protected override void OnSessionTimeout()
		{
			try{
				this.Socket.WriteLine("421 Session timeout, closing transmission channel");
			}
			catch{
			}

			EndSession();
		}

		#endregion

		#region method OnError

		/// <summary>
		/// Is called when error occures.
		/// </summary>
		/// <param name="x"></param>
		private void OnError(Exception x)
		{
			try{
                // We must see InnerException too, SocketException may be as inner exception.
                SocketException socketException = null;
                if(x is SocketException){
                    socketException = (SocketException)x;
                }
                else if(x.InnerException != null && x.InnerException is SocketException){
                    socketException = (SocketException)x.InnerException;
                }

				if(socketException != null){
					// Client disconnected without shutting down.
					if(socketException.ErrorCode == 10054 || socketException.ErrorCode == 10053){
						if(m_pServer.LogCommands){
							this.Socket.Logger.AddTextEntry("Client aborted/disconnected");
						}

						EndSession();

						// Exception handled, return
						return;
					}
                    // Connection timed out.
                    else if(socketException.ErrorCode == 10060){
                        if(m_pServer.LogCommands){
							this.Socket.Logger.AddTextEntry("Connection timeout.");
						}

						EndSession();

						// Exception handled, return
						return;
                    }
				}

				m_pServer.OnSysError("",x);
			}
			catch(Exception ex){
				m_pServer.OnSysError("",ex);
			}
		}

		#endregion


		#region method BeginRecieveCmd
		
		/// <summary>
		/// Starts recieveing command.
		/// </summary>
		private void BeginRecieveCmd()
		{
			MemoryStream strm = new MemoryStream();
			this.Socket.BeginReadLine(strm,1024,strm,new SocketCallBack(this.EndRecieveCmd));
		}

		#endregion

		#region method EndRecieveCmd

		/// <summary>
		/// Is called if command is recieved.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="count"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		private void EndRecieveCmd(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			try{
				switch(result)
				{
					case SocketCallBackResult.Ok:
						MemoryStream strm = (MemoryStream)tag;

						string cmdLine = System.Text.Encoding.Default.GetString(strm.ToArray());

						// Exceute command
						if(SwitchCommand(cmdLine)){
							// Session end, close session
							EndSession();
						}
						break;

					case SocketCallBackResult.LengthExceeded:
						this.Socket.WriteLine("500 Line too long.");

						BeginRecieveCmd();
						break;

					case SocketCallBackResult.SocketClosed:
						EndSession();
						break;

					case SocketCallBackResult.Exception:
						OnError(exception);
						break;
				}
			}
            catch(ReadException x){
                if(x.ReadReplyCode == ReadReplyCode.LengthExceeded){
			        this.Socket.WriteLine("500 Line too long.");
                
					BeginRecieveCmd();
				}
                else if(x.ReadReplyCode == ReadReplyCode.SocketClosed){
					EndSession();
				}
                else if(x.ReadReplyCode == ReadReplyCode.UnKnownError){
					OnError(x);
				}
            }
			catch(Exception x){
				 OnError(x);
			}
		}

		#endregion

		
		#region method SwitchCommand

		/// <summary>
		/// Executes SMTP command.
		/// </summary>
		/// <param name="SMTP_commandTxt">Original command text.</param>
		/// <returns>Returns true if must end session(command loop).</returns>
		private bool SwitchCommand(string SMTP_commandTxt)
		{
			//---- Parse command --------------------------------------------------//
			string[] cmdParts = SMTP_commandTxt.TrimStart().Split(new char[]{' '});
			string SMTP_command = cmdParts[0].ToUpper().Trim();
			string argsText = Core.GetArgsText(SMTP_commandTxt,SMTP_command);
			//---------------------------------------------------------------------//

			bool getNextCmd = true;

			switch(SMTP_command)
			{
				case "HELO":
					HELO(argsText);
					getNextCmd = false;
					break;

				case "EHLO":
					EHLO(argsText);
					getNextCmd = false;
					break;

                case "STARTTLS":
					STARTTLS(argsText);
					getNextCmd = false;
					break;

				case "AUTH":
					AUTH(argsText);
					break;

				case "MAIL":
					MAIL(argsText);
					getNextCmd = false;
					break;
					
				case "RCPT":
					RCPT(argsText);
					getNextCmd = false;
					break;

				case "DATA":
					BeginDataCmd(argsText);
					getNextCmd = false;
					break;

				case "BDAT":
					BeginBDATCmd(argsText);
					getNextCmd =  false;
					break;

				case "RSET":
					RSET(argsText);
					getNextCmd = false;
					break;

			//	case "VRFY":
			//		VRFY();
			//		break;

			//	case "EXPN":
			//		EXPN();
			//		break;

				case "HELP":
					HELP();
					break;

				case "NOOP":
					NOOP();
					getNextCmd = false;
				break;
				
				case "QUIT":
					QUIT(argsText);
					getNextCmd = false;
					return true;
										
				default:					
					this.Socket.WriteLine("500 command unrecognized");

					//---- Check that maximum bad commands count isn't exceeded ---------------//
					if(m_BadCmdCount > m_pServer.MaxBadCommands-1){
						this.Socket.WriteLine("421 Too many bad commands, closing transmission channel");
						return true;
					}
					m_BadCmdCount++;
					//-------------------------------------------------------------------------//

					break;				
			}

			if(getNextCmd){
				BeginRecieveCmd();
			}
			
			return false;
		}

		#endregion


		#region method HELO

		private void HELO(string argsText)
		{
			/* Rfc 2821 192.168.127.12
			    These commands, and a "250 OK" reply to one of them, confirm that
			    both the SMTP client and the SMTP server are in the initial state,
			    that is, there is no transaction in progress and all state tables and
			    buffers are cleared.
    		    
                Arguments:
                     Host name.
             
			    Syntax:
				     "HELO" SP Domain CRLF
			*/

			m_EhloName = argsText;

			ResetState();

			this.Socket.BeginWriteLine("250 " + Net_Utils.GetLocalHostName(this.BindInfo.HostName) + " Hello [" + this.RemoteEndPoint.Address.ToString() + "]",new SocketCallBack(this.EndSend));
			m_CmdValidator.Helo_ok = true;
		}

		#endregion

		#region method EHLO

		private void EHLO(string argsText)
		{		
			/* Rfc 2821 192.168.127.12
			These commands, and a "250 OK" reply to one of them, confirm that
			both the SMTP client and the SMTP server are in the initial state,
			that is, there is no transaction in progress and all state tables and
			buffers are cleared.
			*/

			m_EhloName = argsText;

			ResetState();

			//--- Construct supported AUTH types value ----------------------------//
			string authTypesString = "";
			if((m_pServer.SupportedAuthentications & SaslAuthTypes.Login) != 0){
				authTypesString += "LOGIN ";
			}
			if((m_pServer.SupportedAuthentications & SaslAuthTypes.Cram_md5) != 0){
				authTypesString += "CRAM-MD5 ";
			}
			if((m_pServer.SupportedAuthentications & SaslAuthTypes.Digest_md5) != 0){
				authTypesString += "DIGEST-MD5 ";
			}
			authTypesString = authTypesString.Trim();
			//-----------------------------------------------------------------------//

			string reply = "";
				reply += "250-" + Net_Utils.GetLocalHostName(this.BindInfo.HostName) + " Hello [" + this.RemoteEndPoint.Address.ToString() + "]\r\n";
				reply += "250-PIPELINING\r\n";
				reply += "250-SIZE " + m_pServer.MaxMessageSize + "\r\n";
		//		reply += "250-DSN\r\n";
		//		reply += "250-HELP\r\n";
				reply += "250-8BITMIME\r\n";
				reply += "250-BINARYMIME\r\n";
				reply += "250-CHUNKING\r\n";
				if(authTypesString.Length > 0){	
					reply += "250-AUTH " + authTypesString +  "\r\n";
				}
                if(!this.Socket.SSL && this.BindInfo.Certificate != null){
                    reply += "250-STARTTLS\r\n";
                }
			    reply += "250 Ok\r\n";
			
			this.Socket.BeginWriteLine(reply,null,new SocketCallBack(this.EndSend));
				
			m_CmdValidator.Helo_ok = true;
		}

		#endregion

        #region method STARTTLS

        private void STARTTLS(string argsText)
        {
            /* RFC 2487 STARTTLS 5. STARTTLS Command.
                The format for the STARTTLS command is:

               STARTTLS

               with no parameters.

               After the client gives the STARTTLS command, the server responds with
               one of the following reply codes:

               220 Ready to start TLS
               501 Syntax error (no parameters allowed)
               454 TLS not available due to temporary reason
             
               5.2 Result of the STARTTLS Command
                    Upon completion of the TLS handshake, the SMTP protocol is reset to
                    the initial state (the state in SMTP after a server issues a 220
                    service ready greeting).             
            */

            if(this.Socket.SSL){
                this.Socket.WriteLine("500 TLS already started !");
				return;
            }
                        
            if(this.BindInfo.Certificate == null){
                this.Socket.WriteLine("454 TLS not available, SSL certificate isn't specified !");
				return;
            }

            this.Socket.WriteLine("220 Ready to start TLS");

            try{               
                this.Socket.SwitchToSSL(this.BindInfo.Certificate);

                if(m_pServer.LogCommands){
                    this.Socket.Logger.AddTextEntry("TLS negotiation completed successfully.");
                }
            }
            catch(Exception x){
                this.Socket.WriteLine("500 TLS handshake failed ! " + x.Message);
            }

            ResetState();

            BeginRecieveCmd();
        }

        #endregion

        #region method AUTH

        private void AUTH(string argsText)
		{
			/* Rfc 2554 AUTH --------------------------------------------------//
			Restrictions:
		         After an AUTH command has successfully completed, no more AUTH
				 commands may be issued in the same session.  After a successful
				 AUTH command completes, a server MUST reject any further AUTH
				 commands with a 503 reply.
				 
			Remarks: 
				If an AUTH command fails, the server MUST behave the same as if
				the client had not issued the AUTH command.
			*/
			if(this.Authenticated){
				this.Socket.WriteLine("503 already authenticated");
				return;
			}
			
            try{				
			    //------ Parse parameters -------------------------------------//
			    string userName = "";
			    string password = "";
			    AuthUser_EventArgs aArgs = null;
    
	    		string[] param = argsText.Split(new char[]{' '});
		    	switch(param[0].ToUpper())
			    {
				    case "PLAIN":
					    this.Socket.WriteLine("504 Unrecognized authentication type.");
					    break;

				    case "LOGIN":

					    #region LOGIN authentication

				        //---- AUTH = LOGIN ------------------------------
					    /* Login
					        C: AUTH LOGIN
					        S: 334 VXNlcm5hbWU6
					        C: username_in_base64
	    			        S: 334 UGFzc3dvcmQ6
		        			C: password_in_base64
                        
                            or (initial-response argument included to avoid one 334 server response)
                    
                            C: AUTH LOGIN username_in_base64
					        S: 334 UGFzc3dvcmQ6
					        C: password_in_base64
                    
					
					        VXNlcm5hbWU6 base64_decoded= USERNAME
					        UGFzc3dvcmQ6 base64_decoded= PASSWORD
					    */
					    // Note: all strings are base64 strings eg. VXNlcm5hbWU6 = UserName.
			
                        // No user name included (initial-response argument)
                        if(param.Length == 1){
                            // Query UserName
					        this.Socket.WriteLine("334 VXNlcm5hbWU6");

					        string userNameLine = this.Socket.ReadLine();
					        // Encode username from base64
					        if(userNameLine.Length > 0){
						        userName = System.Text.Encoding.Default.GetString(Convert.FromBase64String(userNameLine));
					        }
                        }
                        // User name included, use it
                        else{
                            userName = System.Text.Encoding.Default.GetString(Convert.FromBase64String(param[1]));
                        }					
											
					    // Query Password
					    this.Socket.WriteLine("334 UGFzc3dvcmQ6");

					    string passwordLine = this.Socket.ReadLine();
					    // Encode password from base64
					    if(passwordLine.Length > 0){
						    password = System.Text.Encoding.Default.GetString(Convert.FromBase64String(passwordLine));
					    }
					
					    aArgs = m_pServer.OnAuthUser(this,userName,password,"",AuthType.Plain);
					    if(aArgs.Validated){
						    this.Socket.WriteLine("235 Authentication successful.");
						
						    this.SetUserName(userName);
					    }
					    else{
						    this.Socket.WriteLine("535 Authentication failed");
					    }

    					#endregion

					    break;

				    case "CRAM-MD5":
					
					    #region CRAM-MD5 authentication

					    /* Cram-M5
					        C: AUTH CRAM-MD5
					        S: 334 <md5_calculation_hash_in_base64>
					        C: base64(username password_hash)
					    */
					
					    string md5Hash = "<" + Guid.NewGuid().ToString().ToLower() + ">";
					    this.Socket.WriteLine("334 " + Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(md5Hash)));

					    string reply = this.Socket.ReadLine();

					    reply = System.Text.Encoding.Default.GetString(Convert.FromBase64String(reply));
					    string[] replyArgs = reply.Split(' ');
					    userName = replyArgs[0];
					
					    aArgs = m_pServer.OnAuthUser(this,userName,replyArgs[1],md5Hash,AuthType.CRAM_MD5);
					    if(aArgs.Validated){
						    this.Socket.WriteLine("235 Authentication successful.");
						
						    this.SetUserName(userName);
					    }
					    else{
						    this.Socket.WriteLine("535 Authentication failed");
					    }

    					#endregion

	    				break;

		    		case "DIGEST-MD5":
					
			    		#region DIGEST-MD5 authentication

				    	/* RFC 2831 AUTH DIGEST-MD5
					     * 
					    * Example:
					    * 
					    * C: AUTH DIGEST-MD5
					    * S: 334 base64(realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",qop="auth",algorithm=md5-sess)
					    * C: base64(username="chris",realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",
					    *    nc=00000001,cnonce="OA6MHXh6VqTrRk",digest-uri="smtp/elwood.innosoft.com",
                        *    response=d388dad90d4bbd760a152321f2143af7,qop=auth)
					    * S: 334 base64(rspauth=ea40f60335c427b5527b84dbabcdfffd)
					    * C:
					    * S: 235 Authentication successful.
					    */
                    
                        string nonce  = Auth_HttpDigest.CreateNonce();
                        string opaque = Auth_HttpDigest.CreateOpaque(); 
                        Auth_HttpDigest digest = new Auth_HttpDigest(this.BindInfo.HostName,nonce,opaque);
                        digest.Algorithm = "md5-sess";
                                        
                        this.Socket.WriteLine("334 " + AuthHelper.Base64en(digest.ToChallange(false)));

                        string clientResponse = AuthHelper.Base64de(this.Socket.ReadLine());
                        digest = new Auth_HttpDigest(clientResponse,"AUTHENTICATE");

                        // Check that realm,nonce and opaque in client response are same as we specified.
                        if(this.BindInfo.HostName != digest.Realm){
                            this.Socket.WriteLine("535 Authentication failed, 'realm' won't match.");
                            return;
                        }
                        if(nonce != digest.Nonce){
                            this.Socket.WriteLine("535 Authentication failed, 'nonce' won't match.");
                            return;
                        }
                        if(opaque != digest.Opaque){
                            this.Socket.WriteLine("535 Authentication failed, 'opaque' won't match.");
                            return;
                        }

                        userName = digest.UserName;
                    					
                        aArgs = m_pServer.OnAuthUser(this,userName,digest.Response,clientResponse,AuthType.DIGEST_MD5);
					    if(aArgs.Validated){
    					    // Send server computed password hash
	    					this.Socket.WriteLine("334 " + AuthHelper.Base64en("rspauth=" + aArgs.ReturnData));
					
		    				// We must got empty line here
			    			clientResponse = this.Socket.ReadLine();
				    		if(clientResponse == ""){
					    		this.Socket.WriteLine("235 Authentication successful.");
								
						    	this.SetUserName(userName);
						    }
						    else{
							    this.Socket.WriteLine("535 Authentication failed, unexpected client response.");
						    }
					    }
					    else{
						    this.Socket.WriteLine("535 Authentication failed.");
					    }

					    #endregion
                    
					    break;

				    default:
					    this.Socket.WriteLine("504 Unrecognized authentication type.");
					    break;
			    }
			    //-----------------------------------------------------------------//
            }
            catch{
                this.Socket.WriteLine("535 Authentication failed.");
            }
		}

		#endregion

		#region method MAIL

		private void MAIL(string argsText)
		{
			/* RFC 2821 3.3
			NOTE:
				This command tells the SMTP-receiver that a new mail transaction is
				starting and to reset all its state tables and buffers, including any
				recipients or mail data.  The <reverse-path> portion of the first or
				only argument contains the source mailbox (between "<" and ">"
				brackets), which can be used to report errors (see section 4.2 for a
				discussion of error reporting).  If accepted, the SMTP server returns
				 a 250 OK reply.
				 
				MAIL FROM:<reverse-path> [SP <mail-parameters> ] <CRLF>
				reverse-path = "<" [ A-d-l ":" ] Mailbox ">"
				Mailbox = Local-part "@" Domain
				
				body-value ::= "7BIT" / "8BITMIME" / "BINARYMIME"
				
				Examples:
					C: MAIL FROM:<<EMAIL>>
					C: MAIL FROM:<<EMAIL>> SIZE=500000 BODY=8BITMIME AUTH=xxxx
			*/

			if(!m_CmdValidator.MayHandle_MAIL){
				if(m_CmdValidator.MailFrom_ok){
					this.Socket.BeginWriteLine("503 Sender already specified",new SocketCallBack(this.EndSend));
				}
				else{
					this.Socket.BeginWriteLine("503 Bad sequence of commands",new SocketCallBack(this.EndSend));
				}
				return;
			}

			//------ Parse parameters -------------------------------------------------------------------//
			string   senderEmail  = "";
			long     messageSize  = 0;
			BodyType bodyType     = BodyType.x7_bit;
			bool     isFromParam  = false;

			// Parse while all params parsed or while is breaked
			while(argsText.Length > 0){
				if(argsText.ToLower().StartsWith("from:")){
					// Remove from:
                    argsText = argsText.Substring(5).Trim();

					// If there is more parameters
					if(argsText.IndexOf(" ") > -1){
						senderEmail = argsText.Substring(0,argsText.IndexOf(" "));
						argsText = argsText.Substring(argsText.IndexOf(" ")).Trim();
					}
					else{
						senderEmail = argsText;
						argsText = "";
					}

					// If address between <>, remove <>
					if(senderEmail.StartsWith("<") && senderEmail.EndsWith(">")){
						senderEmail = senderEmail.Substring(1,senderEmail.Length - 2);
					}

					isFromParam = true;
				}
				else if(argsText.ToLower().StartsWith("size=")){
					// Remove size=
					argsText = argsText.Substring(5).Trim();

					string sizeS = "";
					// If there is more parameters
					if(argsText.IndexOf(" ") > -1){
						sizeS = argsText.Substring(0,argsText.IndexOf(" "));
						argsText  = argsText.Substring(argsText.IndexOf(" ")).Trim();
					}
					else{
						sizeS = argsText;
						argsText  = "";
					}

					// See if value ok
					if(Core.IsNumber(sizeS)){
						messageSize = Convert.ToInt64(sizeS);
					}
					else{
						this.Socket.BeginWriteLine("501 SIZE parameter value is invalid. Syntax:{MAIL FROM:<address> [SIZE=msgSize] [BODY=8BITMIME]}",new SocketCallBack(this.EndSend));
						return;
					}
				}
				else if(argsText.ToLower().StartsWith("body=")){
					// Remove body=
					argsText = argsText.Substring(5).Trim();

					string bodyTypeS = "";
					// If there is more parameters
					if(argsText.IndexOf(" ") > -1){
						bodyTypeS = argsText.Substring(0,argsText.IndexOf(" "));
						argsText = argsText.Substring(argsText.IndexOf(" ")).Trim();
					}
					else{
						bodyTypeS = argsText;
						argsText = "";
					}

					// See if value ok
					switch(bodyTypeS.ToUpper())
					{						
						case "7BIT":
							bodyType = BodyType.x7_bit;
							break;
						case "8BITMIME":
							bodyType = BodyType.x8_bit;
							break;
						case "BINARYMIME":
							bodyType = BodyType.binary;									
							break;
						default:
							this.Socket.BeginWriteLine("501 BODY parameter value is invalid. Syntax:{MAIL FROM:<address> [BODY=(7BIT/8BITMIME)]}",new SocketCallBack(this.EndSend));
							return;					
					}
				}
				else if(argsText.ToLower().StartsWith("auth=")){
					// Currently just eat AUTH keyword

					// Remove auth=
					argsText = argsText.Substring(5).Trim();

					string authS = "";
					// If there is more parameters
					if(argsText.IndexOf(" ") > -1){
						authS = argsText.Substring(0,argsText.IndexOf(" "));
						argsText  = argsText.Substring(argsText.IndexOf(" ")).Trim();
					}
					else{
						authS = argsText;
						argsText  = "";
					}
				}
				else{
					this.Socket.BeginWriteLine("501 Error in parameters. Syntax:{MAIL FROM:<address> [SIZE=msgSize] [BODY=8BITMIME]}",new SocketCallBack(this.EndSend));
					return;
				}
			}
			
			// If required parameter 'FROM:' is missing
			if(!isFromParam){
				this.Socket.BeginWriteLine("501 Required param FROM: is missing. Syntax:{MAIL FROM:<address> [SIZE=msgSize] [BODY=8BITMIME]}",new SocketCallBack(this.EndSend));
				return;
			}
			//---------------------------------------------------------------------------------------------//
			
			//--- Check message size
			if(m_pServer.MaxMessageSize > messageSize){
				// Check if sender is ok
				ValidateSender_EventArgs eArgs = m_pServer.OnValidate_MailFrom(this,senderEmail,senderEmail);
				if(eArgs.Validated){															
					// See note above
					ResetState();

					// Store reverse path
					m_Reverse_path = senderEmail;
					m_CmdValidator.MailFrom_ok = true;

					//-- Store params
					m_BodyType = bodyType;

					this.Socket.BeginWriteLine("250 OK <" + senderEmail + "> Sender ok",new SocketCallBack(this.EndSend));
				}			
				else{
					if(eArgs.ErrorText != null && eArgs.ErrorText.Length > 0){
						this.Socket.BeginWriteLine("550 " + eArgs.ErrorText,new SocketCallBack(this.EndSend));
					}
					else{
						this.Socket.BeginWriteLine("550 You are refused to send mail here",new SocketCallBack(this.EndSend));
					}
				}
			}
			else{
				this.Socket.BeginWriteLine("552 Message exceeds allowed size",new SocketCallBack(this.EndSend));
			}			
		}

		#endregion

		#region method RCPT

		private void RCPT(string argsText)
		{
			/* RFC 2821 4.1.1.3 RCPT
			NOTE:
				This command is used to identify an individual recipient of the mail
				data; multiple recipients are specified by multiple use of this
				command.  The argument field contains a forward-path and may contain
				optional parameters.
				
				Relay hosts SHOULD strip or ignore source routes, and
				names MUST NOT be copied into the reverse-path.  
				
				Example:
					RCPT TO:<@hosta.int,@jkl.org:<EMAIL>>

					will normally be sent directly on to host d.bar.org with envelope
					commands

					RCPT TO:<<EMAIL>>
					RCPT TO:<<EMAIL>> SIZE=40000
						
				RCPT TO:<forward-path> [ SP <rcpt-parameters> ] <CRLF>			
			*/

			/* RFC 2821 3.3
				If a RCPT command appears without a previous MAIL command, 
				the server MUST return a 503 "Bad sequence of commands" response.
			*/
			if(!m_CmdValidator.MayHandle_RCPT || m_BDat){
				this.Socket.BeginWriteLine("503 Bad sequence of commands",new SocketCallBack(this.EndSend));
				return;
			}

			// Check that recipient count isn't exceeded
			if(m_Forward_path.Count > m_pServer.MaxRecipients){
				this.Socket.BeginWriteLine("452 Too many recipients",new SocketCallBack(this.EndSend));
				return;
			}

			//------ Parse parameters -------------------------------------------------------------------//
			string recipientEmail = "";
			long   messageSize    = 0;
			bool   isToParam      = false;

			// Parse while all params parsed or while is breaked
			while(argsText.Length > 0){
				if(argsText.ToLower().StartsWith("to:")){
					// Remove to:
                    argsText = argsText.Substring(3).Trim();

					// If there is more parameters
					if(argsText.IndexOf(" ") > -1){
						recipientEmail = argsText.Substring(0,argsText.IndexOf(" "));
						argsText = argsText.Substring(argsText.IndexOf(" ")).Trim();
					}
					else{
						recipientEmail = argsText;
						argsText = "";
					}

					// If address between <>, remove <>
					if(recipientEmail.StartsWith("<") && recipientEmail.EndsWith(">")){
						recipientEmail = recipientEmail.Substring(1,recipientEmail.Length - 2);
					}

					// See if value ok
					if(recipientEmail.Length == 0){
						this.Socket.BeginWriteLine("501 Recipient address isn't specified. Syntax:{RCPT TO:<address> [SIZE=msgSize]}",new SocketCallBack(this.EndSend));
						return;
					}

					isToParam = true;
				}
				else if(argsText.ToLower().StartsWith("size=")){
					// Remove size=
					argsText = argsText.Substring(5).Trim();

					string sizeS = "";
					// If there is more parameters
					if(argsText.IndexOf(" ") > -1){
						sizeS = argsText.Substring(0,argsText.IndexOf(" "));
						argsText  = argsText.Substring(argsText.IndexOf(" ")).Trim();
					}
					else{
						sizeS = argsText;
						argsText  = "";
					}

					// See if value ok
					if(Core.IsNumber(sizeS)){
						messageSize = Convert.ToInt64(sizeS);
					}
					else{
						this.Socket.BeginWriteLine("501 SIZE parameter value is invalid. Syntax:{RCPT TO:<address> [SIZE=msgSize]}",new SocketCallBack(this.EndSend));
						return;
					}
				}
				else{
					this.Socket.BeginWriteLine("501 Error in parameters. Syntax:{RCPT TO:<address> [SIZE=msgSize]}",new SocketCallBack(this.EndSend));
					return;
				}
			}
			
			// If required parameter 'TO:' is missing
			if(!isToParam){
				this.Socket.BeginWriteLine("501 Required param TO: is missing. Syntax:<RCPT TO:{address> [SIZE=msgSize]}",new SocketCallBack(this.EndSend));
				return;
			}
			//---------------------------------------------------------------------------------------------//

			// Check message size
			if(m_pServer.MaxMessageSize > messageSize){
				// Check if email address is ok
				ValidateRecipient_EventArgs rcpt_args = m_pServer.OnValidate_MailTo(this,recipientEmail,recipientEmail,this.Authenticated);
				if(rcpt_args.Validated){
					// Check if mailbox size isn't exceeded
					if(m_pServer.Validate_MailBoxSize(this,recipientEmail,messageSize)){
						// Store reciptient
						if(!m_Forward_path.Contains(recipientEmail)){
							m_Forward_path.Add(recipientEmail,recipientEmail);
						}				
						m_CmdValidator.RcptTo_ok = true;

						this.Socket.BeginWriteLine("250 OK <" + recipientEmail + "> Recipient ok",new SocketCallBack(this.EndSend));						
					}
					else{					
						this.Socket.BeginWriteLine("552 Mailbox size limit exceeded",new SocketCallBack(this.EndSend));
					}
				}
				// Recipient rejected
				else{
					if(rcpt_args.LocalRecipient){
						this.Socket.BeginWriteLine("550 <" + recipientEmail + "> No such user here",new SocketCallBack(this.EndSend));
					}
					else{
						this.Socket.BeginWriteLine("550 <" + recipientEmail + "> Relay not allowed",new SocketCallBack(this.EndSend));
					}
				}
			}
			else{
				this.Socket.BeginWriteLine("552 Message exceeds allowed size",new SocketCallBack(this.EndSend));
			}
		}

		#endregion

		#region method DATA

		#region method BeginDataCmd

		private void BeginDataCmd(string argsText)
		{	
			/* RFC 2821 4.1.1
			NOTE:
				Several commands (RSET, DATA, QUIT) are specified as not permitting
				parameters.  In the absence of specific extensions offered by the
				server and accepted by the client, clients MUST NOT send such
				parameters and servers SHOULD reject commands containing them as
				having invalid syntax.
			*/

			if(argsText.Length > 0){
				this.Socket.BeginWriteLine("500 Syntax error. Syntax:{DATA}",new SocketCallBack(this.EndSend));
				return;
			}


			/* RFC 2821 4.1.1.4 DATA
			NOTE:
				If accepted, the SMTP server returns a 354 Intermediate reply and
				considers all succeeding lines up to but not including the end of
				mail data indicator to be the message text.  When the end of text is
				successfully received and stored the SMTP-receiver sends a 250 OK
				reply.
				
				The mail data is terminated by a line containing only a period, that
				is, the character sequence "<CRLF>.<CRLF>" (see section 4.5.2).  This
				is the end of mail data indication.
					
				
				When the SMTP server accepts a message either for relaying or for
				final delivery, it inserts a trace record (also referred to
				interchangeably as a "time stamp line" or "Received" line) at the top
				of the mail data.  This trace record indicates the identity of the
				host that sent the message, the identity of the host that received
				the message (and is inserting this time stamp), and the date and time
				the message was received.  Relayed messages will have multiple time
				stamp lines.  Details for formation of these lines, including their
				syntax, is specified in section 4.4.
   
			*/


			/* RFC 2821 DATA
			NOTE:
				If there was no MAIL, or no RCPT, command, or all such commands
				were rejected, the server MAY return a "command out of sequence"
				(503) or "no valid recipients" (554) reply in response to the DATA
				command.
			*/
			if(!m_CmdValidator.MayHandle_DATA || m_BDat){
				this.Socket.BeginWriteLine("503 Bad sequence of commands",new SocketCallBack(this.EndSend));
				return;
			}

			if(m_Forward_path.Count == 0){
				this.Socket.BeginWriteLine("554 no valid recipients given",new SocketCallBack(this.EndSend));
				return;
			}

            // Get message store stream
            GetMessageStoreStream_eArgs eArgs = m_pServer.OnGetMessageStoreStream(this);
            m_pMsgStream = eArgs.StoreStream;

			// reply: 354 Start mail input
			this.Socket.WriteLine("354 Start mail input; end with <CRLF>.<CRLF>");

			//---- Construct server headers for message----------------------------------------------------------------//
			string header  = "Received: from " + Core.GetHostName(this.RemoteEndPoint.Address) + " (" + this.RemoteEndPoint.Address.ToString() + ")\r\n"; 
			header += "\tby " + this.BindInfo.HostName + " with SMTP; " + DateTime.Now.ToUniversalTime().ToString("r",System.Globalization.DateTimeFormatInfo.InvariantInfo) + "\r\n";
					    
			byte[] headers = System.Text.Encoding.ASCII.GetBytes(header);
			m_pMsgStream.Write(headers,0,headers.Length);
			//---------------------------------------------------------------------------------------------------------//

            // Begin recieving data
            this.Socket.BeginReadPeriodTerminated(m_pMsgStream,m_pServer.MaxMessageSize,null,new SocketCallBack(this.EndDataCmd));	
		}

		#endregion

		#region method EndDataCmd

		/// <summary>
		/// Is called when DATA command is finnished.
		/// </summary>
		/// <param name="result"></param>
		/// <param name="count"></param>
		/// <param name="exception"></param>
		/// <param name="tag"></param>
		private void EndDataCmd(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			try{
				switch(result)
				{
					case SocketCallBackResult.Ok:								
						// Notify Message stream owner that message storing completed ok.
                        MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream);
						if(oArg.ServerReply.ErrorReply){								
							this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend));
						}
						else{
							this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","OK"),new SocketCallBack(this.EndSend));
						}												
						break;

					case SocketCallBackResult.LengthExceeded:
                        // We must call that method to notify Message stream owner to close/dispose that stream.
                        m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream);

						this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
						break;

					case SocketCallBackResult.SocketClosed:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

						EndSession();
						break;

					case SocketCallBackResult.Exception:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

						OnError(exception);
						break;
				}

				/* RFC 2821 4.1.1.4 DATA
					NOTE:
						Receipt of the end of mail data indication requires the server to
						process the stored mail transaction information.  This processing
						consumes the information in the reverse-path buffer, the forward-path
						buffer, and the mail data buffer, and on the completion of this
						command these buffers are cleared.
				*/
				ResetState();
			}
			catch(Exception x){
				OnError(x);
			}
		}

		#endregion
		
		#endregion

		#region function BDAT

		#region method BeginBDATCmd

		private void BeginBDATCmd(string argsText)
		{
			/*RFC 3030 2
				The BDAT verb takes two arguments.The first argument indicates the length, 
                in octets, of the binary data chunk. The second optional argument indicates 
                that the data chunk	is the last.
				
				The message data is sent immediately after the trailing <CR>
				<LF> of the BDAT command line.  Once the receiver-SMTP receives the
				specified number of octets, it will return a 250 reply code.

				The optional LAST parameter on the BDAT command indicates that this
				is the last chunk of message data to be sent.  The last BDAT command
				MAY have a byte-count of zero indicating there is no additional data
				to be sent.  Any BDAT command sent after the BDAT LAST is illegal and
				MUST be replied to with a 503 "Bad sequence of commands" reply code.
				The state resulting from this error is indeterminate.  A RSET command
				MUST be sent to clear the transaction before continuing.
				
				A 250 response MUST be sent to each successful BDAT data block within
				a mail transaction.

				bdat-cmd   ::= "BDAT" SP chunk-size [ SP end-marker ] CR LF
				chunk-size ::= 1*DIGIT
				end-marker ::= "LAST"
			*/

			if(!m_CmdValidator.MayHandle_BDAT){
				this.Socket.BeginWriteLine("503 Bad sequence of commands",new SocketCallBack(this.EndSend));
				return;
			}

			string[] param = argsText.Split(new char[]{' '});
			if(param.Length > 0 && param.Length < 3){				
				if(Core.IsNumber(param[0])){
                    int countToRead = Convert.ToInt32(param[0]);

					// LAST specified
					bool lastChunk = false;
					if(param.Length == 2){
						lastChunk = true;
					}
						
				    // First BDAT command call.
					if(!m_BDat){
                        // Get message store stream
                        GetMessageStoreStream_eArgs eArgs = m_pServer.OnGetMessageStoreStream(this);
                        m_pMsgStream = eArgs.StoreStream;

                        // Add header to first bdat block only
						//---- Construct server headers for message----------------------------------------------------------------//
						string header  = "Received: from " + Core.GetHostName(this.RemoteEndPoint.Address) + " (" + this.RemoteEndPoint.Address.ToString() + ")\r\n"; 
						header += "\tby " + this.BindInfo.HostName + " with SMTP; " + DateTime.Now.ToUniversalTime().ToString("r",System.Globalization.DateTimeFormatInfo.InvariantInfo) + "\r\n";
					    
						byte[] headers = System.Text.Encoding.ASCII.GetBytes(header);
						m_pMsgStream.Write(headers,0,headers.Length);
						//---------------------------------------------------------------------------------------------------------//
					}

                    // Begin junking data, maximum allowed message size exceeded.
                    // BDAT comman is dummy, after commandline binary data is at once follwed,
                    // so server server must junk all data and then report error.
                    if((m_BDAT_ReadedCount + countToRead) > m_pServer.MaxMessageSize){
                        this.Socket.BeginReadSpecifiedLength(new JunkingStream(),countToRead,lastChunk,new SocketCallBack(this.EndBDatCmd));
                    }
                    // Begin reading data
                    else{
                        this.Socket.BeginReadSpecifiedLength(m_pMsgStream,countToRead,lastChunk,new SocketCallBack(this.EndBDatCmd));
                    }

					m_BDat = true;
				}
				else{
					this.Socket.BeginWriteLine("500 Syntax error. Syntax:{BDAT chunk-size [LAST]}",new SocketCallBack(this.EndSend));
				}
			}
			else{
				this.Socket.BeginWriteLine("500 Syntax error. Syntax:{BDAT chunk-size [LAST]}",new SocketCallBack(this.EndSend));
			}		
		}

		#endregion

		#region method EndBDatCmd

		private void EndBDatCmd(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			try{
				switch(result)
				{
					case SocketCallBackResult.Ok:
                        m_BDAT_ReadedCount += count;

						// BDAT command completed, got all data junks
						if((bool)tag){
				            // Maximum allowed message size exceeded.
                            if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){
                                m_pServer.OnMessageStoringCompleted(this,"Requested mail action aborted: exceeded storage allocation",m_pMsgStream);

                                this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                            }
                            else{
							    // Notify Message stream owner that message storing completed ok.
							    MessageStoringCompleted_eArgs oArg = m_pServer.OnMessageStoringCompleted(this,null,m_pMsgStream);
							    if(oArg.ServerReply.ErrorReply){								
								    this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("500","Error storing message"),new SocketCallBack(this.EndSend));
							    }
							    else{
								    this.Socket.BeginWriteLine(oArg.ServerReply.ToSmtpReply("250","Message(" + m_BDAT_ReadedCount + " bytes) stored ok."),new SocketCallBack(this.EndSend));
							    }
                            }

							/* RFC 2821 4.1.1.4 DATA
							NOTE:
								Receipt of the end of mail data indication requires the server to
								process the stored mail transaction information.  This processing
								consumes the information in the reverse-path buffer, the forward-path
								buffer, and the mail data buffer, and on the completion of this
								command these buffers are cleared.
							*/
							ResetState();						
						}
                        // Got BDAT data block, BDAT must continue, that wasn't last data block.
						else{
                            // Maximum allowed message size exceeded.
                            if((m_BDAT_ReadedCount) > m_pServer.MaxMessageSize){
                                this.Socket.BeginWriteLine("552 Requested mail action aborted: exceeded storage allocation",new SocketCallBack(this.EndSend));
                            }
                            else{
							    this.Socket.BeginWriteLine("250 Data block of " + count + " bytes recieved OK.",new SocketCallBack(this.EndSend));
                            }
						}
						break;

					case SocketCallBackResult.SocketClosed:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"SocketClosed",m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

						EndSession();
						return;

					case SocketCallBackResult.Exception:
                        if(m_pMsgStream != null){
                            // We must call that method to notify Message stream owner to close/dispose that stream.
                            m_pServer.OnMessageStoringCompleted(this,"Exception: " + exception.Message,m_pMsgStream);
                            m_pMsgStream = null;
                        }
                        // Stream is already closed, probably by the EndSession method, do nothing.
                        //else{
                        //}

						OnError(exception);
						return;
				}
			}
			catch(Exception x){
				OnError(x);
			}
		}

		#endregion

		#endregion

		#region method RSET

		private void RSET(string argsText)
		{
			/* RFC 2821 4.1.1
			NOTE:
				Several commands (RSET, DATA, QUIT) are specified as not permitting
				parameters.  In the absence of specific extensions offered by the
				server and accepted by the client, clients MUST NOT send such
				parameters and servers SHOULD reject commands containing them as
				having invalid syntax.
			*/

			if(argsText.Length > 0){
				this.Socket.BeginWriteLine("500 Syntax error. Syntax:{RSET}",new SocketCallBack(this.EndSend));
				return;
			}

			/* RFC 2821 4.1.1.5 RESET (RSET)
			NOTE:
				This command specifies that the current mail transaction will be
				aborted.  Any stored sender, recipients, and mail data MUST be
				discarded, and all buffers and state tables cleared.  The receiver
				MUST send a "250 OK" reply to a RSET command with no arguments.
			*/

            try{
                // Message storing aborted by RSET. 
                // This can happen if BDAT -> RSET and LAST BDAT block wasn't sent.
                if(m_pMsgStream != null){
                    // We must call that method to notify Message stream owner to close/dispose that stream.
                    m_pServer.OnMessageStoringCompleted(this,"Message storing aborted by RSET",m_pMsgStream);
                    m_pMsgStream = null;
                }
            }
            catch{
            }
			
			ResetState();

			this.Socket.BeginWriteLine("250 OK",new SocketCallBack(this.EndSend));
		}

		#endregion

		#region method VRFY

		private void VRFY()
		{
			/* RFC 821 VRFY 
			Example:
				S: VRFY Lumi
				R: 250 <NAME> <<EMAIL>>
				
				S: VRFY lum
				R: 550 String does not match anything.			 
			*/

			// ToDo: Parse user, add new event for cheking user

			this.Socket.BeginWriteLine("502 Command not implemented",new SocketCallBack(this.EndSend));
		}

		#endregion

		#region mehtod NOOP

		private void NOOP()
		{
			/* RFC 2821 4.1.1.9 NOOP (NOOP)
			NOTE:
				This command does not affect any parameters or previously entered
				commands.  It specifies no action other than that the receiver send
				an OK reply.
			*/

			this.Socket.BeginWriteLine("250 OK",new SocketCallBack(this.EndSend));
		}

		#endregion

		#region method QUIT

		private void QUIT(string argsText)
		{
			/* RFC 2821 4.1.1
			NOTE:
				Several commands (RSET, DATA, QUIT) are specified as not permitting
				parameters.  In the absence of specific extensions offered by the
				server and accepted by the client, clients MUST NOT send such
				parameters and servers SHOULD reject commands containing them as
				having invalid syntax.
			*/

			if(argsText.Length > 0){
				this.Socket.BeginWriteLine("500 Syntax error. Syntax:<QUIT>",new SocketCallBack(this.EndSend));
				return;
			}

			/* RFC 2821 4.1.1.10 QUIT (QUIT)
			NOTE:
				This command specifies that the receiver MUST send an OK reply, and
				then close the transmission channel.
			*/

			// reply: 221 - Close transmission cannel
			this.Socket.WriteLine("221 Service closing transmission channel");
		//	this.Socket.BeginSendLine("221 Service closing transmission channel",null);	
		}

		#endregion


		//---- Optional commands
		
		#region function EXPN

		private void EXPN()
		{
			/* RFC 821 EXPN 
			NOTE:
				This command asks the receiver to confirm that the argument
				identifies a mailing list, and if so, to return the
				membership of that list.  The full name of the users (if
				known) and the fully specified mailboxes are returned in a
				multiline reply.
			
			Example:
				S: EXPN lsAll
				R: 250-ivar lumi <<EMAIL>>
				R: 250-<<EMAIL>>
				R: 250 <<EMAIL>>
			*/

			this.Socket.WriteLine("502 Command not implemented");
		}

		#endregion

		#region function HELP

		private void HELP()
		{
			/* RFC 821 HELP
			NOTE:
				This command causes the receiver to send helpful information
				to the sender of the HELP command.  The command may take an
				argument (e.g., any command name) and return more specific
				information as a response.
			*/

			this.Socket.WriteLine("502 Command not implemented");
		}

		#endregion


		#region method ResetState

		private void ResetState()
		{
			//--- Reset variables
			m_BodyType = BodyType.x7_bit;
			m_Forward_path.Clear();
			m_Reverse_path  = "";
	//		m_Authenticated = false; // Keep AUTH 
			m_CmdValidator.Reset();
			m_CmdValidator.Helo_ok = true;

			m_pMsgStream = null;
            m_BDat = false;
            m_BDAT_ReadedCount = 0;
		}

		#endregion


		#region function EndSend
		
		/// <summary>
		/// Is called when asynchronous send completes.
		/// </summary>
		/// <param name="result">If true, then send was successfull.</param>
		/// <param name="count">Count sended.</param>
		/// <param name="exception">Exception happend on send. NOTE: available only is result=false.</param>
		/// <param name="tag">User data.</param>
		private void EndSend(SocketCallBackResult result,long count,Exception exception,object tag)
		{
			try{
				switch(result)
				{
					case SocketCallBackResult.Ok:
						BeginRecieveCmd();
						break;

					case SocketCallBackResult.SocketClosed:
						EndSession();
						break;

					case SocketCallBackResult.Exception:
						OnError(exception);
						break;
				}
			}
			catch(Exception x){
				OnError(x);
			}
		}

		#endregion		

        
		#region Properties Implementation
				
		/// <summary>
		/// Gets client reported EHLO/HELO name.
		/// </summary>
		public string EhloName
		{
			get{ return m_EhloName; }
		}

		/// <summary>
		/// Gets body type.
		/// </summary>
		public BodyType BodyType
		{
			get{ return m_BodyType; }
		}

		/// <summary>
		/// Gets sender.
		/// </summary>
		public string MailFrom
		{
			get{ return m_Reverse_path; }
		}

		/// <summary>
		/// Gets recipients.
		/// </summary>
		public string[] MailTo
		{
			get{
				string[] to = new string[m_Forward_path.Count];
				m_Forward_path.Values.CopyTo(to,0);

				return to; 
			}
		}

		#endregion

	}
}


<|start_filename|>module/ASC.Api/ASC.Api.Calendar/iCalParser/ParserError.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/*
 *   ICalParser is a general purpose .Net parser for iCalendar format files (RFC 2445)
 * 
 *   Copyright (C) 2004  <NAME>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

namespace ASC.Api.Calendar.iCalParser
{
    /// <summary>
    /// Basic error handling mechanism for the Parser
    /// </summary>
    public class ParserError
    {
        private readonly int linenumber;
        private readonly string message;

        public ParserError(int _linenumber, string _message)
        {
            linenumber = _linenumber;
            message = _message;
        }

        public int Linenumber
        {
            get { return linenumber; }
        }

        public string Message
        {
            get { return message; }
        }

        public override string ToString()
        {
            return "Error on line: " + linenumber + ".  " + message;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/js/asc/api/api.factory.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


;
window.ServiceFactory = (function() {
    var isInit = false,
        onlyFactory = false,
        defaultAvatar = '',
        defaultAvatarMedium = '',
        defaultAvatarSmall = '',
        formatDatetime = null,
        formatDate = null,
        formatTime = null,
        formats = { datetime: formatDatetime, date: formatDate, time: formatTime },
        monthNames = [],
        monthShortNames = [],
        dayNames = [],
        dayShortNames = [],
        nameCollections = { days: dayNames, shortdays: dayShortNames, months: monthNames, shortmonths: monthShortNames },
        portalUtcOffsetTotalMinutes = 0,
        portalUtcOffset = '',
        portalTimeZoneName = '',
        myProfile = {},
        portalSettings = {},
        portalQuotas = {},
        post = 'post',
        get = 'get',
        dlt = 'delete',
        put = 'put',
        supportedImgs = [],
        supportedDocs = [],
        supportedTypes = [],
        searchEntityTypes = [
            { id: -1, label: 'unknown' },
            { id: 0, label: 'project' },
            { id: 1, label: 'milestone' },
            { id: 2, label: 'task' },
            { id: 3, label: 'subtask' },
            { id: 4, label: 'team' },
            { id: 5, label: 'comment' },
            { id: 6, label: 'discussion' },
            { id: 7, label: 'file' },
            { id: 8, label: 'timespend' },
            { id: 9, label: 'activity' }
        ],
        folderTypes = [
            { id: 0, name: 'DEFAULT', label: 'folder-default' },
            { id: 1, name: 'COMMON', label: 'folder-common' },
            { id: 2, name: 'BUNCH', label: 'folder-bunch' },
            { id: 3, name: 'TRASH', label: 'folder-trash' },
            { id: 5, name: 'USER', label: 'folder-user' },
            { id: 6, name: 'SHARE', label: 'folder-shared' }
        ],
        // mail - 0, tel - 1, link - 2
        contactTitles = {
            mail: { name: 'mail', type: 0, title: 'Email' },
            facebook: { name: 'facebook', type: 2, title: 'FaceBook' },
            myspace: { name: 'myspace', type: 2, title: 'MySpace' },
            livejournal: { name: 'livejournal', type: 2, title: 'LiveJournal' },
            twitter: { name: 'twitter', type: 2, title: 'twitter' },
            yahoo: { name: 'yahoo', type: 2, title: 'YAHOO' },
            jabber: { name: 'jabber', type: 2, title: 'Jabber' },
            blogger: { name: 'blogger', type: 2, title: 'blogger' },
            skype: { name: 'skype', type: 2, title: 'skype' },
            msn: { name: 'msn', type: 2, title: 'msn' },
            aim: { name: 'aim', type: 2, title: 'aim' },
            icq: { name: 'icq', type: 2, title: 'icq' },
            gmail: { name: 'gmail', type: 0, title: 'Google Mail' },
            gbuzz: { name: 'gbuzz', type: 2, title: 'Google Buzz' },
            gtalk: { name: 'gtalk', type: 2, title: 'Google Talk' },
            phone: { name: 'phone', type: 1, title: 'Tel' },
            mobphone: { name: 'mobphone', type: 1, title: 'Mobile' },
            extmobphone: { name: 'extmobphone', type: 1, title: 'Mobile' },
            extmail: { name: 'extmail', type: 0, title: 'Email' }
        },
        contactTypes = {
            phone: { id: 0, title: 'Phone', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, mobile: { id: 2, title: 'Mobile' }, fax: { id: 3, title: 'Fax' }, direct: { id: 4, title: 'Direct' }, other: { id: 5, title: 'Other' } } },
            email: { id: 1, title: 'Email', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            website: { id: 2, title: 'Website', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            skype: { id: 3, title: 'Skype', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            twitter: { id: 4, title: 'Twitter', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            linkedin: { id: 5, title: 'LinkedIn', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            facebook: { id: 6, title: 'Facebook', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            address: { id: 7, title: 'Address', categories: { home: { id: 0, title: 'Home' }, postal: { id: 1, title: 'Postal' }, office: { id: 2, title: 'Office' }, billing: { id: 3, title: 'Billing' }, other: { id: 4, title: 'Other' }, work: { id: 5, title: 'Work' } } },
            livejournal: { id: 8, title: 'LiveJournal', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            myspace: { id: 9, title: 'MySpace', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            gmail: { id: 10, title: 'GMail', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            blogger: { id: 11, title: 'Blogger', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            yahoo: { id: 12, title: 'Yahoo', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            msn: { id: 13, title: 'MSN', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            icq: { id: 14, title: 'ICQ', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            jabber: { id: 15, title: 'Jabber', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } },
            aim: { id: 16, title: 'AIM', categories: { home: { id: 0, title: 'Home' }, work: { id: 1, title: 'Work' }, other: { id: 2, title: 'Other' } } }
        },
        extTypes = [
            { name: 'archive', exts: ['.zip', '.rar', '.ace', '.arc', '.arj', '.cab', '.enc', '.jar', '.lha', '.lzh', '.pak', '.pk3', '.tar', '.tgz', '.uue', '.xxe', '.zoo', '.bh', '.gz', '.ha'] },
            { name: 'image', exts: ['.bmp', '.cod', '.gif', '.ief', '.jpe', '.jpg', '.tif', '.cmx', '.ico', '.pnm', '.pbm', '.ppm', '.psd', '.rgb', '.xbm', '.xpm', '.xwd', '.png', '.ai', '.jpeg'] },
            { name: 'sound', exts: ['.mp3', '.wav', '.pcm', '.3gp', '.fla', '.cda', '.ogg', '.aiff', '.flac'] },
            { name: 'ebook', exts: ['.fb2', '.ibk', '.prc', '.epub'] },
            { name: 'html', exts: ['.htm', '.mht', '.html'] },
            { name: 'djvu', exts: ['.djvu'] },
            { name: 'svg', exts: ['.svg'] },
            { name: 'svgt', exts: ['.svgt'] },
            { name: 'doc', exts: ['.doc', '.docx'] },
            { name: 'doct', exts: ['.doct'] },
            { name: 'xls', exts: ['.xls', '.xlsx'] },
            { name: 'xlst', exts: ['.xlst'] },
            { name: 'pps', exts: ['.pps', '.ppsx'] },
            { name: 'ppt', exts: ['.ppt', '.pptx'] },
            { name: 'pptt', exts: ['.pptt'] },
            { name: 'odp', exts: ['.odp'] },
            { name: 'ods', exts: ['.ods'] },
            { name: 'odt', exts: ['.odt'] },
            { name: 'pdf', exts: ['.pdf'] },
            { name: 'rtf', exts: ['.rtf'] },
            { name: 'txt', exts: ['.txt'] },
            { name: 'iaf', exts: ['.iaf'] },
            { name: 'csv', exts: ['.csv'] },
            { name: 'xml', exts: ['.xml'] },
            { name: 'xps', exts: ['.xps'] },
            { name: 'avi', exts: ['.avi'] },
            { name: 'flv', exts: ['.flv', '.fla'] },
            { name: 'm2ts', exts: ['.m2ts'] },
            { name: 'mkv', exts: ['.mkv'] },
            { name: 'mov', exts: ['.mov'] },
            { name: 'mp4', exts: ['.mp4'] },
            { name: 'mpg', exts: ['.mpg'] },
            { name: 'vob', exts: ['.vob'] }
        ],
        profileStatuses = {
            active: { id: 1, name: 'active' },
            terminated: { id: 2, name: 'terminated' },
            leaveofabsence: { id: 4, name: 'leaveofabsence' }
        },
        activationStatuses = {
            notactivated: { id: 0, name: 'notactivated' },
            activated: { id: 1, name: 'activated' },
            pending: { id: 2, name: 'pending' }
        },
        taskStatuses = {
            notaccept: { id: 0, name: 'notaccept' },
            open: { id: 1, name: 'open' },
            closed: { id: 2, name: 'closed' },
            disable: { id: 3, name: 'disable' },
            unclassified: { id: 4, name: 'unclassified' },
            notinmilestone: { id: 5, name: 'notinmilestone' }
        },
        fileShareTypes = {
            None: '0',
            ReadWrite: '1',
            Read: '2',
            Restrict: '3'
        },
        apiAnchors = [
            apiHandler('cmt-blog', /blog\.json/, post),
            apiHandler('cmt-blog', /blog\/[\w\d-]+\.json/),
            apiHandler('cmt-topic', /forum\/topic\/[\w\d-]+\.json/),
            apiHandler('cmt-event', /event\/[\w\d-]+\.json/),
            apiHandler('cmt-event', /event\.json/, post),
            apiHandler('cmt-bookmark', /bookmark\/[\w\d-]+\.json/),
            apiHandler('cmt-bookmark', /bookmark\.json/, post),
            apiHandler('cmt-blogs', /blog\.json/, get),
            apiHandler('cmt-blogs', /blog\/@search\/.+\.json/, get),
            apiHandler('cmt-topics', /forum\/topic\/recent\.json/),
            apiHandler('cmt-topics', /forum\/@search\/.+\.json/, get),
            apiHandler('cmt-categories', /forum\.json/),
            apiHandler('cmt-events', /event\.json/, get),
            apiHandler('cmt-events', /event\/@search\/.+\.json/, get),
            apiHandler('cmt-bookmarks', /bookmark\/top\/recent\.json/, get),
            apiHandler('cmt-bookmarks', /bookmark\/@search\/.+\.json/, get),
            apiHandler('prj-task', /project\/[\w\d-]+\/task\.json/, post),
            apiHandler('prj-task', /project\/task\/[\w\d-]+\.json/),
            apiHandler('prj-task', /project\/task\/[\w\d-]+\/status\.json/),
            apiHandler('prj-task', /project\/task\/[\w\d-]+\/copy\.json/),
            apiHandler('prj-task', /project\/task\/[\w\d-]+\/milestone\.json/),
            apiHandler('prj-tasks', /project\/[\w\d-]+\/task\.json/, get),
            apiHandler('prj-tasks', /project\/[\w\d-]+\/task\/@self\.json/),
            apiHandler('prj-tasks', /project\/[\w\d-]+\/task\/filter\.json/),
            apiHandler('prj-tasks', /project\/task\/filter\.json/),
            apiHandler('prj-tasks', /project\/task\.json\?taskid/),
            apiHandler('prj-tasks', /project\/task\/status\.json/),
            apiHandler('prj-tasks', /project\/task\/milestone\.json/),
            apiHandler('prj-tasks', /project\/task\.json/, dlt),
            apiHandler('prj-simpletasks', /project\/task\/filter\/simple\.json/, get),
            apiHandler('prj-tasks', /project\/task\/@self\.json/),
            apiHandler('prj-subtask', /project\/task\/[\d]+\.json/, post),
            apiHandler('prj-subtask', /project\/task\/[\d]+\/[\d]+\/copy\.json/),
            apiHandler('prj-subtask', /project\/task\/[\d]+\/[\d]+\.json/),
            apiHandler('prj-subtask', /project\/task\/[\d]+\/[\d]+\/status\.json/),
            apiHandler('prj-milestone', /project\/milestone\/[\w\d-]+\.json/),
            apiHandler('prj-milestone', /project\/[\w\d-]+\/milestone\.json/, post),
            apiHandler('prj-milestones', /project\/[\w\d-]+\/milestone\.json/, get),
            apiHandler('prj-milestones', /project\/milestone\/[\w\d-]+\/[\w\d-]+\/[\w\d-]+\.json/),
            apiHandler('prj-milestones', /project\/milestone\/[\w\d-]+\/[\w\d-]+\.json/),
            apiHandler('prj-milestones', /project\/milestone\/late\.json/),
            apiHandler('prj-milestones', /project\/milestone\.json/),
            apiHandler('prj-milestones', /project\/milestone\/filter\.json/),
            apiHandler('prj-milestone', /project\/milestone\/[\w\d-]+\/status\.json/),
            apiHandler('prj-discussion', /project\/message\/[\w\d-]+\.json/),
            apiHandler('prj-discussion', /project\/[\w\d-]+\/message\.json/, post),
            apiHandler('prj-discussions', /project\/message\.json/),
            apiHandler('prj-discussions', /project\/[\w\d-]+\/message\.json/, get),
            apiHandler('prj-discussions', /project\/message\/filter\.json/),

            apiHandler('prj-project', /project\/[\d-]+\.json/, get),
            apiHandler('prj-project', /project\/[\d-]+\/status\.json/, put),
            apiHandler('prj-project', /project\/[\w\d-]+\/contact\.json/, post),
            apiHandler('prj-project', /project\/[\w\d-]+\/contact\.json/, dlt),
            apiHandler('prj-projects', /project[\/]*[@self|@follow]*\.json/),
            apiHandler('prj-projects', /project\/filter\.json/),
            apiHandler('prj-projects', /project\/contact\/[\w\d-]+\.json/),
            apiHandler('prj-searchentries', /project\/@search\/.+\.json/),
            apiHandler('prj-projectperson', /project\/[\w\d-]+\/team\.json/, post),
            apiHandler('prj-projectperson', /project\/[\w\d-]+\/team\.json/, dlt),
            apiHandler('prj-projectpersons', /project\/[\w\d-]+\/team\.json/, get),
            apiHandler('prj-projectpersons', /project\/[\w\d-]+\/teamExcluded\.json/, get),
            apiHandler('prj-timespend', /project\/time\/[\w\d-]+\.json/),
            apiHandler('prj-timespends', /project\/time\/times\/status\.json/, put),
            apiHandler('prj-timespends', /project\/time\/filter\.json/, get),
            apiHandler('prj-timespends', /project\/task\/[\w\d-]+\/time\.json/, get),
            apiHandler('prj-activities', /project\/activities\/filter\.json/),
            apiHandler('prj-project', /project\.json/, post),
            apiHandler('doc-folder', /files\/[@\w\d-]+\.json/),
            apiHandler('doc-folder', /files\/[\w\d-]+\/[text|html|file]+\.json/),
            apiHandler('doc-folder', /project\/[\w\d-]+\/files\.json/),
            apiHandler('doc-files', /project\/task\/[\w\d-]+\/files\.json/),
            apiHandler('doc-files', /project\/[\w\d-]+\/entityfiles\.json/),
            apiHandler('doc-files', /crm\/[\w\d-]+\/[\w\d-]+\/files\.json/, get),
            apiHandler('doc-file', /files\/file\/[\w\d-]+\.json/),
            apiHandler('doc-file', /files\/[\w\d-]+\/upload\.xml/),
            apiHandler('doc-file', /files\/[\w\d-]+\/upload\.json/),
            apiHandler('doc-session', /files\/[\w\d-]+\/upload\/create_session\.json/),
            apiHandler('doc-file', /crm\/files\/[\w\d-]+\.json/),
            apiHandler('doc-file', /crm\/[case|contact|opportunity]+\/[\w\d-]+\/files\/upload\.xml/),
            apiHandler('doc-file', /crm\/[case|contact|opportunity]+\/[\w\d-]+\/files\/upload\.json/),
            apiHandler('doc-file', /crm\/[case|contact|opportunity]+\/[\w\d-]+\/files\/text\.json/),
            apiHandler('doc-miss', /files\/fileops.json/),
            apiHandler('doc-miss', /files\/storeoriginal.json/),
            apiHandler('doc-miss', /files\/hideconfirmconvert.json/),
            apiHandler('doc-miss', /files\/displayfavorite.json/),
            apiHandler('doc-miss', /files\/displayrecent.json/),
            apiHandler('doc-miss', /files\/displaytemplates.json/),
            apiHandler('doc-check', /files\/docservice.json/),
            apiHandler('crm-addresses', /crm\/contact\/[\w\d-]+\/data\.json/, get),
            apiHandler('crm-address', /crm\/contact\/[\w\d-]+\/data\/[\w\d-]+\.json/),
            apiHandler('crm-address', /crm\/contact\/[\w\d-]+\/data\.json/, post),
            apiHandler('crm-address', /crm\/contact\/[\w\d-]+\/batch\.json/),
            apiHandler('crm-contact', /crm\/contact\/[\w\d-]+\.json/),
            apiHandler('crm-contact', /crm\/contact\/company\/[\w\d-]+\/type\.json/, post),
            apiHandler('crm-contact', /crm\/contact\/company\/[\w\d-]+\/person\.json/, post),
            apiHandler('crm-contact', /crm\/contact\/company\/[\w\d-]+\/person\.json/, dlt),
            apiHandler('crm-contact', /crm\/[case|opportunity]+\/[\w\d-]+\/contact\.json/, post),
            apiHandler('crm-contact', /crm\/[case|opportunity]+\/[\w\d-]+\/contact\/[\w\d-]+\.json/, post),
            apiHandler('crm-contact', /crm\/[case|opportunity]+\/[\w\d-]+\/contact\/[\w\d-]+\.json/),
            apiHandler('crm-contacts', /crm\/contact\/bycontactinfo\.json/, get),
            apiHandler('crm-contact', /crm\/contact\/merge\.json/),
            apiHandler('crm-socialmediaavatars', /crm\/contact\/socialmediaavatar\.json/),
            apiHandler('crm-tweets', /crm\/contact\/[\w\d-]+\/tweets\.json/),
            apiHandler('crm-twitterprofiles', /crm\/contact\/twitterprofile\.json/),
            apiHandler('crm-progressitem', /crm\/contact\/mailsmtp\/send\.json/),
            apiHandler('crm-progressitem', /crm\/contact\/mailsmtp\/status\.json/),
            apiHandler('crm-progressitem', /crm\/contact\/mailsmtp\/cancel\.json/),
            apiHandler('crm-progressitem', /crm\/[contact|person|company|opportunity|case]+\/import\/status\.json/),
            apiHandler('crm-progressitem', /crm\/contact\/export\/status\.json/),
            apiHandler('crm-progressitem', /crm\/contact\/export\/cancel\.json/),
            apiHandler('crm-progressitem', /crm\/contact\/export\/start\.json/),
            apiHandler('crm-exportitem', /crm\/export\/partial\/status\.json/),
            apiHandler('crm-exportitem', /crm\/export\/partial\/cancel\.json/),
            apiHandler('crm-exportitem', /crm\/export\/partial\/[\w\d-]+\/start\.json/),
            apiHandler('crm-fileuploadresult', /crm\/import\/uploadfake\.json/),
            apiHandler('crm-task', /crm\/task\.json/),
            apiHandler('crm-task', /crm\/task\/[\w\d-]+\.json/),
            apiHandler('crm-task', /crm\/task\/[\w\d-]+\/close\.json/),
            apiHandler('crm-task', /crm\/task\/[\w\d-]+\/reopen\.json/),
            apiHandler('crm-opportunity', /crm\/opportunity\/[\w\d-]+\.json/),
            apiHandler('crm-opportunity', /crm\/opportunity\/[\w\d-]+\/stage\/[\w\d-]+\.json/),
            apiHandler('crm-opportunity', /crm\/contact\/[\w\d-]+\/opportunity\/[\w\d-]+\.json/),
            apiHandler('crm-dealmilestone', /crm\/opportunity\/stage\/[\w\d-]+\.json/),
            apiHandler('crm-dealmilestone', /crm\/opportunity\/stage\/[\w\d-]+\/color\.json/),
            apiHandler('crm-dealmilestone', /crm\/opportunity\/stage\.json/, post),
            apiHandler('crm-dealmilestones', /crm\/opportunity\/stage\/reorder\.json/),
            apiHandler('crm-dealmilestones', /crm\/opportunity\/stage\.json/, get),
            apiHandler('crm-contactstatus', /crm\/contact\/status\/[\w\d-]+\/color\.json/),
            apiHandler('crm-contactstatus', /crm\/contact\/status\/[\w\d-]+\.json/),
            apiHandler('crm-contactstatus', /crm\/contact\/status\.json/, post),
            apiHandler('crm-contactstatuses', /crm\/contact\/status\/reorder\.json/),
            apiHandler('crm-contactstatuses', /crm\/contact\/status\.json/, get),
            apiHandler('crm-contacttypekind', /crm\/contact\/type\/[\w\d-]+\.json/),
            apiHandler('crm-contacttypekind', /crm\/contact\/type\.json/, post),
            apiHandler('crm-contacttypekinds', /crm\/contact\/type\/reorder\.json/),
            apiHandler('crm-contacttypekinds', /crm\/contact\/type\.json/, get),
            apiHandler('crm-customfield', /crm\/[contact|person|company|opportunity|case]+\/customfield\/[\w\d-]+\.json/),
            apiHandler('crm-customfield', /crm\/[contact|person|company|opportunity|case]+\/customfield\.json/),
            apiHandler('crm-customfields', /crm\/[contact|person|company|opportunity|case]+\/customfield\/definitions\.json/),
            apiHandler('crm-customfields', /crm\/[contact|person|company|opportunity|case]+\/customfield\/reorder\.json/),
            apiHandler('crm-tag', /crm\/[case|contact|opportunity]+\/tag\.json/),
            apiHandler('crm-tag', /crm\/[case|contact|opportunity]+\/taglist\.json/),
            apiHandler('crm-tag', /crm\/[case|contact|opportunity]+\/[\w\d-]+\/tag\.json/),
            apiHandler('crm-tags', /crm\/[case|contact|opportunity]+\/tag\/unused\.json/),
            apiHandler('crm-tags', /crm\/[case|contact|opportunity]+\/tag\/[\w\d-]+\.json/),
            apiHandler('crm-fulltags', /crm\/[case|contact|opportunity]+\/tag\.json/, get),
            apiHandler('crm-caseitem', /crm\/case\/[\w\d-]+\/close\.json/),
            apiHandler('crm-caseitem', /crm\/case\/[\w\d-]+\/reopen\.json/),
            apiHandler('crm-cases', /crm\/cases\.json/),
            apiHandler('crm-cases', /crm\/case\/filter\.json/),
            apiHandler('crm-cases', /crm\/case\/byprefix\.json/),
            apiHandler('crm-contacts', /crm\/contact\.json/),
            apiHandler('crm-contacts', /crm\/contact\/project\/[\w\d-]+\.json/),
            apiHandler('crm-basecontacts', /crm\/contact\/byprefix\.json/),
            apiHandler('crm-contacts', /crm\/contact\/filter\.json/),
            apiHandler('crm-simplecontacts', /crm\/contact\/simple\/filter\.json/),
            apiHandler('crm-basecontacts', /crm\/contact\/mail\.json/),
            apiHandler('crm-contacts', /crm\/contact\/company\/[\w\d-]+\/person\.json/, get),
            apiHandler('crm-contacts', /crm\/[case|opportunity]+\/[\w\d-]+\/contact\.json/, get),
            apiHandler('crm-contacts', /crm\/contact\/access\.json/),
            apiHandler('crm-contacts', /crm\/contact\/[\w\d-]+\/access\.json/, put),
            apiHandler('crm-cases', /crm\/case\/access\.json/),
            apiHandler('crm-cases', /crm\/case\/[\w\d-]+\/access\.json/),
            apiHandler('crm-opportunities', /crm\/opportunity\/access\.json/),
            apiHandler('crm-opportunities', /crm\/opportunity\/[\w\d-]+\/access\.json/),
            //ApiHandler : 'crm-customfields', re : /crm\/contact\/[\w\d-]+\/access\.json/},
            apiHandler('crm-tasks', /crm\/task\/filter\.json/),
            apiHandler('crm-opportunities', /crm\/opportunity\/filter\.json/),
            apiHandler('crm-opportunities', /crm\/opportunity\/bycontact\/[\w\d-]+\.json/),
            apiHandler('crm-opportunities', /crm\/opportunity\/byprefix\.json/),
            apiHandler('crm-taskcategory', /crm\/task\/category\/[\w\d-]+\.json/),
            apiHandler('crm-taskcategory', /crm\/task\/category\/[\w\d-]+\/icon\.json/),
            apiHandler('crm-taskcategory', /crm\/task\/category\.json/, post),
            apiHandler('crm-taskcategories', /crm\/task\/category\/reorder\.json/),
            apiHandler('crm-taskcategories', /crm\/task\/category\.json/, get),
            apiHandler('crm-historyevent', /crm\/history\.json/),
            apiHandler('crm-historyevent', /crm\/history\/[\w\d-]+.json/),
            apiHandler('crm-historyevent', /crm\/[contact|opportunity|case]+\/[\w\d-]+\/files\.json/, post),
            apiHandler('crm-historyevents', /crm\/history\/filter\.json/),
            apiHandler('crm-historycategory', /crm\/history\/category\/[\w\d-]+\.json/),
            apiHandler('crm-historycategory', /crm\/history\/category\/[\w\d-]+\/icon\.json/),
            apiHandler('crm-historycategory', /crm\/history\/category\.json/, post),
            apiHandler('crm-historycategories', /crm\/history\/category\/reorder\.json/),
            apiHandler('crm-historycategories', /crm\/history\/category\.json/, get),
            apiHandler('crm-currency', /crm\/settings\/currency\.json/),
            apiHandler('crm-currencies', /crm\/settings\/currency\.json/, get),
            apiHandler('crm-smtpsettings', /crm\/settings\/smtp\.json/),
            apiHandler('crm-rootfolder', /crm\/files\/root\.json/),
            apiHandler('crm-tasktemplatecontainer', /crm\/[contact|person|company|opportunity|case]+\/tasktemplatecontainer\.json/),
            apiHandler('crm-tasktemplatecontainer', /crm\/tasktemplatecontainer\/[\w\d-]+\.json/),
            apiHandler('crm-tasktemplate', /crm\/tasktemplatecontainer\/[\w\d-]+\/tasktemplate\.json/),
            apiHandler('crm-tasktemplate', /crm\/tasktemplatecontainer\/tasktemplate\/[\w\d-]+\.json/),
            apiHandler('crm-invoiceline', /crm\/invoiceline\.json/),
            apiHandler('crm-invoiceline', /crm\/invoice\/[\w\d-]+\.json/),
            apiHandler('crm-invoice', /crm\/invoice\.json/, post),
            apiHandler('crm-invoice', /crm\/invoice\/[\w\d-]+\.json/),
            apiHandler('crm-invoice', /crm\/invoice\/sample\.json/),
            apiHandler('crm-invoice', /crm\/invoice\/sample\.json/),
            apiHandler('crm-invoice', /crm\/invoice\/bynumber\.json/),
            apiHandler('crm-invoiceJsonData', /crm\/invoice\/jsondata\/[\w\d-]+\.json/),
            apiHandler('crm-invoices', /crm\/invoice\.json/, dlt),
            apiHandler('crm-invoicesAndItems', /crm\/invoice\/status\/[\w\d-]+\.json/),
            apiHandler('crm-invoices', /crm\/invoice\/filter\.json/),
            apiHandler('crm-invoices', /crm\/[contact|person|company|opportunity]+\/invoicelist\/[\w\d-]+\.json/),
            apiHandler('crm-invoiceItem', /crm\/invoiceitem\.json/, post),
            apiHandler('crm-invoiceItems', /crm\/invoiceitem\.json/, dlt),
            apiHandler('crm-invoiceItems', /crm\/invoiceitem\/filter\.json/),
            apiHandler('crm-invoiceTax', /crm\/invoice\/tax\/[\w\d-]+\.json/),
            apiHandler('crm-invoiceTax', /crm\/invoice\/tax\.json/, post),
            apiHandler('crm-invoiceTaxes', /crm\/invoice\/tax\.json/, get),
            apiHandler('crm-invoiceSettings', /crm\/invoice\/settings\.json/),
            apiHandler('crm-invoiceSettings', /crm\/invoice\/settings\/name\.json/),
            apiHandler('crm-invoiceSettings', /crm\/invoice\/settings\/terms\.json/),
            apiHandler('doc-file', /crm\/invoice\/[\w\d-]+\/pdf\.json/),
            apiHandler('crm-converterData', /crm\/invoice\/converter\/data\.json/),            
            apiHandler('crm-currencyRates', /crm\/currency\/rates\.json/, get),
            apiHandler('crm-currencyRate', /crm\/currency\/rates\/[\w\d-]+\.json/),
            apiHandler('crm-currencyRate', /crm\/currency\/rates\/\w{3}\/\w{3}\.json/, get),
            apiHandler('crm-currencyRate', /crm\/currency\/rates\.json/, post),            
            apiHandler('crm-voipNumbers', /crm\/voip\/numbers\/available\.json/),
            apiHandler('crm-voipNumbers', /crm\/voip\/numbers\/existing\.json/),
            apiHandler('crm-voipNumber', /crm\/voip\/numbers\.json/, post),
            apiHandler('crm-voipNumber', /crm\/voip\/numbers\/current\.json/),
            apiHandler('crm-voipCall', /crm\/voip\/call\.json/, post),
            apiHandler('crm-voipCalls', /crm\/voip\/call\.json/, get),
            apiHandler('crm-voipCall', /crm\/voip\/call\/[\w\d-]+\.json/, get),
            apiHandler('crm-voipCalls', /crm\/voip\/call\/missed\.json/, get),
            apiHandler('authentication', /authentication\.json/),
            apiHandler('settings', /settings\.json/),
            apiHandler('security', /settings\/security\.json/),
            apiHandler('access', /settings\/security\/access\.json/),
            apiHandler('administrator', /settings\/security\/administrator\.json/),
            apiHandler('quotas', /settings\/quota\.json/),
            apiHandler('profile', /people\/[\w\d-]+\.json/),
            apiHandler('isme', /people\/@self\.json/),
            apiHandler('profiles', /people\/status\/[\w\d-]+\.json/),
            apiHandler('profiles', /people\/status\/[\w\d-]+\/@search\/.+\.json/),
            apiHandler('profiles', /people\/status\/[\w\d-]+\/search\.json/),
            apiHandler('profiles', /people\.json/),
            apiHandler('profiles', /people\/@search\/.+\.json/),
            apiHandler('profiles', /people\/search\.json/),
            apiHandler('profiles', /people\/filter\.json/),
            apiHandler('profiles', /people\/type\/[\w\d-]+\.json/),
            apiHandler('profiles', /people\/invite\.json/),
            apiHandler('text', /people\/password\.json/),
            apiHandler('text', /people\/thirdparty\/linkaccount\.json/),
            apiHandler('text', /people\/thirdparty\/unlinkaccount\.json/),
            apiHandler('group', /group\/[\w\d-]+\.json/),
            apiHandler('groups', /group\.json/),
            apiHandler('crm-tasks', /crm\/contact\/task\/group\.json/),
            apiHandler('crm-tag', /crm\/[company|person]+\/[\w\d-]+\/tag\/group\.json/),
            apiHandler('crm-voipNumber', /crm\/voip\/numbers\/[\w]+\/settings.json/, put),
            apiHandler('crm-voipSettings', /crm\/voip\/numbers\/settings.json/),
            apiHandler('comment', /comment\.json/, post),
            apiHandler('comments', /comment\.json/, get),

            apiHandler('prj-settings', /project\/settings\.json/),
            apiHandler('prj-report', /project\/report\/files\.json/),
            
            apiHandler('text', /project\/comment\/[\w\d-]+\.json/, dlt),
            apiHandler('text', /community\/wiki\/comment\/[\w\d-]+\.json/, dlt),
            apiHandler('text', /community\/event\/comment\/[\w\d-]+\.json/, dlt),
            apiHandler('text', /community\/bookmark\/comment\/[\w\d-]+\.json/, dlt),
            apiHandler('text', /community\/blog\/comment\/[\w\d-]+\.json/, dlt),
            
            apiHandler('text', /project\/comment\/[\w\d-]+\.json/, put),
            apiHandler('text', /community\/wiki\/comment\/[\w\d-]+\.json/, put),
            apiHandler('text', /community\/event\/comment\/[\w\d-]+\.json/, put),
            apiHandler('text', /community\/bookmark\/comment\/[\w\d-]+\.json/, put),
            apiHandler('text', /community\/blog\/comment\/[\w\d-]+\.json/, put),
            
            apiHandler('text', /project\/message\/discussion\/preview\.json/),
            apiHandler('commentinlist', /project\/message\/preview\.json/),
            apiHandler('commentinlist', /community\/wiki\/comment\/preview\.json/),
            apiHandler('commentinlist', /community\/event\/comment\/preview\.json/),
            apiHandler('commentinlist', /community\/bookmark\/comment\/preview\.json/),
            apiHandler('commentinlist', /community\/blog\/comment\/preview\.json/),
            
            apiHandler('commentinlist', /project\/comment\.json/, post),
            apiHandler('commentinlist', /community\/wiki\/comment\.json/, post),
            apiHandler('commentinlist', /community\/event\/comment\.json/, post),
            apiHandler('commentinlist', /community\/bookmark\/comment\.json/, post),
            apiHandler('commentinlist', /community\/blog\/comment\.json/, post),
            
            
            
            apiHandler('feed-feeds', /feed\/filter\.json/),
            apiHandler('text', /crm\/[contact|opportunity|case|relationshipevent]+\/[\w\d-]+\/files\/hidden\.json/)
        ];

    function apiHandler(handler, re, method) {
        var result = { handler: handler, re: re };
        if (typeof method != "undefined") {
            result.method = method;
        }
        return result;
    }

    function isArray(o) {
        return o ? o.constructor.toString().indexOf("Array") != -1 : false;
    }

    function converText(str, toText) {
        if (toText === true) {
            var symbols = [
                ['&lt;', '<'],
                ['&gt;', '>'],
                ['&and;', '\\^'],
                ['&sim;', '~'],
                ['&amp;', '&']
            ];

            var symInd = symbols.length;
            while (symInd--) {
                str = str.replace(new RegExp(symbols[symInd][1], 'g'), symbols[symInd][0]);
            }
            return str;
        }

        var o = document.createElement('textarea');
        o.innerHTML = str;
        return o.value;
    }

    function extend(src, dsc) {
        for (var fld in dsc) {
            if (dsc.hasOwnProperty(fld)) {
                src[fld] = dsc[fld];
            }
        }
        return src;
    }

    ;

    function clone(o) {
        if (!o || typeof o !== 'object') {
            return o;
        }

        var p, v, c = typeof o.pop === 'function' ? [] : {};
        for (p in o) {
            if (o.hasOwnProperty(p)) {
                v = o[p];
                if (v && typeof v === 'object') {
                    c[p] = clone(v);
                } else {
                    c[p] = v;
                }
            }
        }
        return c;
    }

    function collection(items, hCreate, hExtend) {
        var collection = [],
            itemsInd = items ? items.length : 0;

        while (itemsInd--) {
            collection.unshift(extend(hCreate ? hCreate(items[itemsInd]) : {}, hExtend(items[itemsInd])));
        }

        return collection;
    }

    function leftPad(n, m) {
        var p = '000000000';
        n = '' + n;
        if (!m) {
            return n.length === 1 ? '0' + n : n;
        }
        return n.length === m ? n : p.substring(0, m - n.length) + n;
    }

    function getResponse(response) {
        var o = null;
        if (typeof response === 'string') {
            try {
                o = jQuery.parseJSON(converText(response));
            } catch(err) {
                o = null;
            }
            if (!o || typeof o !== 'object') {
                try {
                    o = jQuery.parseJSON(converText(jQuery.base64.decode(response)));
                } catch(err) {
                    o = null;
                }
            }
        }
        if (typeof response === 'object') {
            try {
                o = response.hasOwnProperty('response') ? response.response : response;
            } catch(err) {
                o = null;
            }
        }
        return o;
    }

    function fixUrl(url) {
        if (!url) {
            return '';
        }
        if (url.indexOf('://') === -1) {
            if (url.charAt(0) !== '/') {
                url = '/' + url;
            }
            url = [location.protocol, '//', location.hostname, location.port ? ':' + location.port : '', url].join('');
        }
        return url;
    }

    function getFileType(ext) {
        var exts = null,
            extsInd = 0,
            types = extTypes,
            typesInd = 0;

        typesInd = types.length;
        while (typesInd--) {
            exts = types[typesInd].exts;
            extsInd = exts.length;
            while (extsInd--) {
                if (exts[extsInd] == ext) {
                    return types[typesInd].name;
                }
            }
        }
        return 'unknown';
    }

    function isSupportedFileType(ext) {
        var types = supportedTypes,
            typesInd = 0;

        typesInd = types.length;
        while (typesInd--) {
            if (ext == types[typesInd]) {
                return true;
            }
        }
        return false;
    }

    function getRootFolderTypeById(id) {
        var types = folderTypes,
            typesInd = 0;

        typesInd = types.length;
        while (typesInd--) {
            if (types[typesInd].id == id) {
                return types[typesInd].label;
            }
        }
        return types.length > 0 ? types[0].label : '';
    }


    function getSearchEntityTypeById(id) {
        var types = searchEntityTypes,
            typesInd = 0;

        typesInd = types.length;
        while (typesInd--) {
            if (types[typesInd].id == id) {
                return types[typesInd].label;
            }
        }
        return types.length > 0 ? types[0].label : id;
    }

    function getTaskStatusName(id) {
        var statuses = taskStatuses,
            statusesInd = 0;

        for (statusesInd in statuses) {
            if (statuses.hasOwnProperty(statusesInd)) {
                if (statuses[statusesInd].id == id) {
                    return statuses[statusesInd].name;
                }
            }
        }
        return '';
    }

    function getContacts(items) {
        var contact = null, item = null, strcontacts = { mailboxes: [], telephones: [], links: [] };
        if (!items) {
            return strcontacts;
        }

        for (var i = 0, n = items.length; i < n; i++) {
            item = items[i];
            contact = {
                type: contactTitles.hasOwnProperty(item.type) ? contactTitles[item.type].type : -1,
                name: item.type,
                title: item.value,
                label: contactTitles.hasOwnProperty(item.type) ? contactTitles[item.type].title : item.type,
                istop: false
            };

            switch (contact.name) {
                case contactTitles.twitter.name:
                    contact.val = contact.title.indexOf('twitter.com') === -1 ? 'http://twitter.com/' + contact.title : contact.title;
                    contact.title = contact.title.indexOf('twitter.com') !== -1 ? contact.title.substring(contact.title.lastIndexOf('/')) : contact.title;
                    break;
                case contactTitles.facebook.name:
                    contact.val = contact.title.indexOf('facebook.com') === -1 ? 'http://facebook.com/' + contact.title : contact.title;
                    contact.title = contact.title.indexOf('facebook.com') !== -1 ? contact.title.substring(contact.title.lastIndexOf('/') + 1) : contact.title;
                    break;
                case contactTitles.skype.name:
                    contact.istop = true;
                    contact.val = 'skype:' + contact.title + '?call';
                case contactTitles.jabber.name:
                case contactTitles.msn.name:
                case contactTitles.aim.name:
                    break;
                case contactTitles.icq.name:
                    contact.val = 'http://www.icq.com/people/' + contact.title;
                    break;
                case contactTitles.yahoo.name:
                case contactTitles.gmail.name:
                case contactTitles.gtalk.name:
                    contact.istop = true;
                    contact.val = 'mailto:' + contact.title;
                    break;
                case contactTitles.blogger.name:
                    contact.val = contact.title.indexOf('blogger.com') === -1 ? 'http://' + contact.title + '.blogger.com/' : contact.title;
                    break;
                case contactTitles.myspace.name:
                    contact.val = contact.title.indexOf('myspace.com') === -1 ? 'http://myspace.com/' + contact.title : contact.title;
                    contact.title = contact.title.indexOf('myspace.com') !== -1 ? contact.title.substring(contact.title.lastIndexOf('/') + 1) : contact.title;
                    break;
                case contactTitles.livejournal.name:
                    contact.val = contact.title.indexOf('livejournal.com') === -1 ? 'http://' + contact.title + '.livejournal.com/' : contact.title;
                    break;
                default:
                    contact.val = contact.title;
                    break;
            }

            switch (contact.type) {
                // mails
                case 0:
                    strcontacts.mailboxes.push(contact);
                    break;
                // tels
                case 1:
                    strcontacts.telephones.push(contact);
                    break;
                // links
                case 2:
                    strcontacts.links.push(contact);
                    break;
                // other
                case -1:
                    strcontacts.links.push(contact);
                    break;
            }
        }

        return strcontacts;
    }

    var init = function(opts) {
        if (isInit === true) {
            return undefined;
        }
        isInit = true;

        opts = opts || {};
        if (opts.hasOwnProperty('portaldatetime') && opts.portaldatetime && typeof opts.portaldatetime === 'object') {
            portalUtcOffsetTotalMinutes = opts.portaldatetime.hasOwnProperty('utcoffsettotalminutes') ? opts.portaldatetime.utcoffsettotalminutes : portalUtcOffsetTotalMinutes;
            portalUtcOffset = portalUtcOffsetTotalMinutes != 0 ? (portalUtcOffsetTotalMinutes > 0 ? '+' : '-') + leftPad(Math.floor(Math.abs(portalUtcOffsetTotalMinutes) / 60)) + ':' + leftPad(Math.abs(portalUtcOffsetTotalMinutes) % 60) : portalUtcOffset;
            portalTimeZoneName = opts.portaldatetime.hasOwnProperty('displayname') ? opts.portaldatetime.displayname : portalTimeZoneName;
        }
        if (opts.hasOwnProperty('names') && opts.names && typeof opts.names === 'object') {
            monthNames = opts.names.hasOwnProperty('months') ? typeof opts.names.months === 'object' ? opts.names.months : opts.names.months.split(',') : monthNames;
            monthShortNames = opts.names.hasOwnProperty('shortmonths') ? typeof opts.names.shortmonths === 'object' ? opts.names.shortmonths : opts.names.shortmonths.split(',') : monthShortNames;
            dayNames = opts.names.hasOwnProperty('days') ? typeof opts.names.days === 'object' ? opts.names.days : opts.names.days.split(',') : dayNames;
            dayShortNames = opts.names.hasOwnProperty('shortdays') ? typeof opts.names.shortdays === 'object' ? opts.names.shortdays : opts.names.shortdays.split(',') : dayShortNames;

            nameCollections.days = dayNames;
            nameCollections.shortdays = dayShortNames;
            nameCollections.months = monthNames;
            nameCollections.shortmonths = monthShortNames;
        }

        if (opts.hasOwnProperty('avatars') && opts.avatars && typeof opts.avatars === 'object') {
            defaultAvatar = opts.avatars.hasOwnProperty('large') ? opts.avatars.large : defaultAvatar;
            defaultAvatarMedium = opts.avatars.hasOwnProperty('medium') ? opts.avatars.medium : defaultAvatarMedium;
            defaultAvatarSmall = opts.avatars.hasOwnProperty('small') ? opts.avatars.small : defaultAvatarSmall;
        }

        if (opts.hasOwnProperty('formats') && opts.formats && typeof opts.formats === 'object') {
            formatDatetime = opts.formats.hasOwnProperty('datetime') ? opts.formats.datetime : formatDatetime;
            formatDate = opts.formats.hasOwnProperty('date') ? opts.formats.date : formatDate;
            formatTime = opts.formats.hasOwnProperty('time') ? opts.formats.time : formatTime;
            if (formatTime && formatDate) {
                formatDatetime = formatTime + ' ' + formatDate;
            }

            formats.datetime = formatDatetime;
            formats.date = formatDate;
            formats.time = formatTime;
        }

        if (opts.hasOwnProperty('supportedfiles') && opts.supportedfiles && typeof opts.supportedfiles === 'object') {
            var imgs = opts.supportedfiles.hasOwnProperty('imgs') ? opts.supportedfiles.imgs || [] : [];
            supportedImgs = imgs && typeof imgs === 'string' ? imgs.split('|') : [];
            var docs = opts.supportedfiles.hasOwnProperty('docs') ? opts.supportedfiles.docs || [] : [];
            supportedDocs = docs && typeof docs === 'string' ? docs.split('|') : [];
            supportedTypes = [].concat(supportedImgs, supportedDocs);
        }

        if (opts.hasOwnProperty('responses') && opts.responses && typeof opts.responses === 'object') {
            var response = null,
                responses = opts.responses;
            for (var fld in responses) {
                response = responses[fld];
                if (response && (typeof response === 'object' || typeof response === 'string')) {
                    response = getResponse(response);
                    if (response) {
                        response = response.hasOwnProperty('response') ? response.response : response;
                        create(fld, get, response);
                    }
                }
            }
        }

        if (opts.hasOwnProperty('contacttitles') && opts.contacttitles && typeof opts.contacttitles === 'object') {
            var contacttitles = opts.contacttitles;
            for (var fld in contacttitles) {
                if (contacttitles.hasOwnProperty(fld)) {
                    if (contactTitles.hasOwnProperty(fld)) {
                        contactTitles[fld].title = contacttitles[fld];
                    }
                }
            }

        }
    };

    var fixData = function(data) {
        if (!data || typeof data !== 'object') {
            return data;
        }

        var value = null;
        for (var fld in data) {
            if (data.hasOwnProperty(fld)) {
                value = data[fld];
                switch (typeof value) {
                    case 'string':
                        switch (fld.toLowerCase()) {
                            case 'infotype':
                                if (contactTypes.hasOwnProperty(value)) {
                                    if (data.hasOwnProperty('category') && typeof data.category === 'string' && contactTypes[value].categories.hasOwnProperty(data.category)) {
                                        data.category = contactTypes[value].categories[data.category].id;
                                    }
                                    value = contactTypes[value].id;
                                }
                                break;
                        }
                        break;
                }
                data[fld] = value;
            }
        }

        return data;
    };

    var serializeDate = (function() {
        if (false && new Date(Date.parse('1970-01-01T00:00:00.000Z')).getTime() === new Date(Date.parse('1970-01-01T00:00:00.000Z')).getTime()) {
            return function(d, toLocalTime) {
                if (!d) {
                    return null;
                }
                var date = null, timestamp = d && typeof d === 'object' && d.hasOwnProperty('utc') && d.utc || d;
                var offset = d && typeof d === 'object' && d.hasOwnProperty('offset') && isFinite(+d.offset) && +d.offset || 0;
                if (typeof timestamp !== 'string') {
                    return null;
                }

                date = new Date(Date.parse(timestamp));

                if (toLocalTime !== true && date instanceof Date) {
                    date.setMinutes(date.getMinutes() - new Date().getTimezoneOffset());
                }

                return date instanceof Date ? date : null;
            };
        }
        return function(d, toUTC) {
            if (!d) {
                return null;
            }
            var date = null, timestamp = d && typeof d === 'object' && d.hasOwnProperty('utc') && d.utc || d,
                offset = d && typeof d === 'object' && d.hasOwnProperty('offset') && isFinite(+d.offset) && +d.offset || 0;

            if (typeof timestamp !== 'string') {
                return null;
            }

            offset = 0;
            if (timestamp.indexOf('Z') === -1) {
                offset = timestamp.substring(timestamp.length - 5).split(':');
                offset = (+offset[0] * 60 + +offset[1]) * (timestamp.charAt(timestamp.length - 6, 1) === '+' ? 1 : -1);
            }
            date = timestamp.split('.')[0].split('T');
            date[0] = date[0].split('-');
            date[1] = date[1].split(':');

            if (typeof(toUTC) !== "undefined" && toUTC !== true) {
                date = new Date(date[0][0], date[0][1] - 1, date[0][2], date[1][0], date[1][1], date[1][2], 0);
            } else {
                //Fix Bug 27729
                date = new Date(
                    Date.UTC(
                        +date[0][0],
                        +date[0][1] - 1,
                        +date[0][2],
                        +date[1][0],
                        +date[1][1],
                        +date[1][2],
                        0
                    )
                );
                date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
            }

            if (toUTC !== true && date instanceof Date) {
                //date.setMinutes(date.getMinutes() + new Date().getTimezoneOffset());
                //date.setMinutes(date.getMinutes() + portalUtcOffsetTotalMinutes);
                //date.setMinutes(date.getMinutes() + offset);
            }

            return date instanceof Date ? date : null;
        };
    })();

    var serializeTimestamp = function(d, safeurl) {
        var timestamp = d instanceof Date ? '' + [d.getFullYear(), leftPad((d.getMonth() + 1)), leftPad(d.getDate())].join('-') + 'T' + [leftPad(d.getHours()), leftPad(d.getMinutes()), leftPad(d.getSeconds())].join(':') : '';
        return safeurl === true ? timestamp.replace(/:/g, '-') : timestamp;

        //var timestamp = d instanceof Date ? '' + [d.getFullYear(), leftPad((d.getMonth() + 1)), leftPad(d.getDate())].join('-') + 'T' + [leftPad(d.getHours()), leftPad(d.getMinutes()), leftPad(d.getSeconds())].join(':') + '.' + leftPad(d.getMilliseconds(), 7) + portalUtcOffset : '';
        ////return safeurl === true ? timestamp.replace(/:/g, '-') : timestamp;
        //return timestamp;

        //return d instanceof Date ? '' + [d.getFullYear(), leftPad((d.getUTCMonth() + 1)), leftPad(d.getUTCDate())].join('-') + 'T' + [leftPad(d.getUTCHours()), leftPad(d.getUTCMinutes()), leftPad(d.getUTCSeconds())].join(':') + '.' + leftPad(d.getMilliseconds(), 7) + 'Z' : '';
        //return JSON.stringify(d);
    };

    function formatingDateTerm(date, term, dayshortnames, daynames, monthshortnames, monthnames) {
        switch (term) {
            case 'd':
                return date.getDate();
            case 'dd':
                return leftPad(date.getDate());
            case 'ddd':
                return dayshortnames[date.getDay()];
            case 'dddd':
                return daynames[date.getDay()];
            case 'h':
                var hours = date.getHours();
                return hours > 12 ? hours - 12 : hours === 0 ? 12 : hours;
            case 'hh':
                var hours = date.getHours();
                return leftPad(hours > 12 ? hours - 12 : hours === 0 ? 12 : hours);
                break;
            case 'H':
                return date.getHours();
            case 'HH':
                return leftPad(date.getHours());
            case 'm':
                return date.getMinutes();
            case 'mm':
                return leftPad(date.getMinutes());
            case 'M':
                return date.getMonth() + 1;
            case 'MM':
                return leftPad(date.getMonth() + 1);
            case 'MMM':
                return monthshortnames[date.getMonth()];
            case 'MMMM':
                return monthnames[date.getMonth()];
            case 's':
                return date.getSeconds();
            case 'ss':
                return leftPad(date.getSeconds());
            case 't':
                return date.getHours() < 12 ? 'A' : 'P';
            case 'tt':
                return date.getHours() < 12 ? 'AM' : 'PM';
            case 'y':
                return date.getYear() - 100;
            case 'yy':
                return (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100;
            case 'yyy':
                return (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100;
            case 'yyyy':
                return date.getFullYear();
        }
        return '';
    }

    var formattingDate = function(date, format, dayshortnames, daynames, monthshortnames, monthnames) {
        if (!(date instanceof Date) || date.getTime() < 0) {
            return '';
        }
        if (typeof format !== 'string' || format.length === 0) {
            return '';
        }

        var output = '',
            term = '',
            islit = false;
        format = format.split('');
        for (var i = 0, n = format.length; i < n; i++) {
            islit = false;
            switch (format[i]) {
                case 'd':
                case 'h':
                case 'H':
                case 'm':
                case 'M':
                case 's':
                case 't':
                case 'y':
                    term += format[i];
                    break;
                default:
                    islit = true;
            }
            if (islit) {
                output += formatingDateTerm(date, term, dayshortnames, daynames, monthshortnames, monthnames);
                output += format[i];
                term = '';
            }
        }
        if (term) {
            output += formatingDateTerm(date, term, dayshortnames, daynames, monthshortnames, monthnames);
        }
        return output;
    };

    var getDisplayTime = function(date) {
        if (date && formatTime) {
            return formattingDate(date, formatTime, dayShortNames, dayNames, monthShortNames, monthNames);
        }
        return date ? date.toLocaleTimeString() : '';
    };

    var getDisplayDate = function(date) {
        if (date && formatDate) {
            return formattingDate(date, formatDate, dayShortNames, dayNames, monthShortNames, monthNames);
        }
        return date ? date.toLocaleDateString() : '';
    };

    var getDisplayDatetime = function(date) {
        if (date && formatDatetime) {
            return formattingDate(date, formatDatetime, dayShortNames, dayNames, monthShortNames, monthNames);
        }
        return date ? date.toLocaleTimeString() + ' ' + date.toLocaleDateString() : '';
    };

    function createGroup(o) {
        if (!o) {
            return null;
        }

        var group = {
            type: 'group',
            id: o.id,
            name: o.name,
            manager: o.manager || '',
            title: o.title || o.name,
            members: o.hasOwnProperty('members') ? createPersons(o.members) : null
        };

        return group;
    }

    function createGroups(o) {
        if (!o) {
            return [];
        }

        var group = null,
            groups = [],
            items = isArray(o) ? o : [o],
            itemsInd = 0;

        itemsInd = items ? items.length : 0;
        while (itemsInd--) {
            group = createGroup(items[itemsInd]);
            group ? groups.unshift(group) : null;
        }
        return groups;
    }

    function createPerson(o) {
        if (!o) {
            return null;
        }
        if (o.hasOwnProperty('email') && o.hasOwnProperty('contacts')) {
            var email = { type: 'mail', value: o.email };
            o.contacts = o.contacts == null ? [email] : [email].concat(o.contacts);
        }

        var person = null,
            crtdate = serializeDate(o.created || o.workFrom || o.workFromDate),
            trtdate = serializeDate(o.terminated || o.terminatedDate),
            bthdate = serializeDate(o.birthday),
            displayname = o.displayName || o.firstName + ' ' + o.lastName,
            contacts = getContacts(o.contacts);

        person = {
            index: displayname.charAt(0).toLowerCase(),
            type: 'person',
            id: o.id,
            timestamp: crtdate ? crtdate.getTime() : 0,
            crtdate: crtdate,
            displayCrtdate: getDisplayDatetime(crtdate),
            displayDateCrtdate: getDisplayDate(crtdate),
            displayTimeCrtdate: getDisplayTime(crtdate),
            trtdate: trtdate,
            displayTrtdate: getDisplayDatetime(trtdate),
            displayDateTrtdate: getDisplayDate(trtdate),
            displayTimeTrtdate: getDisplayTime(trtdate),
            birthday: bthdate,
            birthdayApiString: o.birthday || '',
            userName: o.userName || '',
            firstName: o.firstName || '',
            lastName: o.lastName || '',
            displayName: displayname || '',
            email: o.email || '',
            tel: contacts.telephones.length > 0 ? contacts.telephones[0].val : '',
            contacts: contacts,
            avatar: o.avatar || o.avatarSmall || defaultAvatar,
            avatarBig: o.avatarBig,
            avatarSmall: o.avatarSmall || defaultAvatarSmall,
            groups: createGroups(o.groups || []),
            status: o.status || 0,
            activationStatus: o.activationStatus || 0,
            isActivated: activationStatuses.activated.id === (o.activationStatus || 0),
            isPending: activationStatuses.pending.id === (o.activationStatus || 0),
            isTerminated: typeof (o.isTerminated) !== "undefined" ? o.isTerminated : profileStatuses.terminated.id === (o.status || 0),
            isMe: myProfile ? myProfile.id === o.id : false,
            isManager: false,
            isPortalOwner: typeof(o.isOwner) != "undefined" ? o.isOwner : null,
            isAdmin: typeof(o.isAdmin) != "undefined" ? o.isAdmin : null,
            listAdminModules: typeof(o.listAdminModules) != "undefined" ? o.listAdminModules : [],
            isVisitor: typeof (o.isVisitor) != "undefined" ? o.isVisitor : null,
            isOutsider: typeof (o.isOutsider) != "undefined" ? o.isOutsider : null,
            sex: o.sex || '',
            location: o.location || '',
            title: o.title || '',
            notes: o.notes || '',
            culture: o.cultureName || '',
            profileUrl: o.profileUrl || '',
            isLDAP: typeof (o.isLDAP) != "undefined" ? o.isLDAP : typeof (o.isldap) != "undefined" ? o.isldap : false,
            isSSO: typeof (o.isSSO) != "undefined" ? o.isSSO : typeof (o.issso) != "undefined" ? o.issso : false
        };

        return person;
    }

    function createPersons(o) {
        if (!o) {
            return [];
        }

        var person = null,
            persons = [],
            items = isArray(o) ? o : [o],
            itemsInd = 0;

        itemsInd = items ? items.length : 0;
        while (itemsInd--) {
            person = createPerson(items[itemsInd]);
            person ? persons.unshift(person) : null;
        }
        return persons;
    }

    var sortCommentsByTree = function(comments) {
        if (comments.length === 0) {
            return comments;
        }
        var tree = clone(comments), commentParentId = null, commentsInd = 0, ind = 0;

        commentsInd = tree ? tree.length : 0;
        while (commentsInd--) {
            commentParentId = tree[commentsInd].parentId;
            if (!tree[commentsInd].comments) {
                tree[commentsInd].comments = [];
            }
            if (commentParentId === null) {
                continue;
            }

            ind = tree.length;
            while (ind--) {
                if (tree[ind].id == commentParentId) {
                    if (!tree[ind].comments) {
                        tree[ind].comments = [];
                    }
                    tree[ind].comments.unshift(tree[commentsInd]);
                    break;
                }
            }
        }

        commentsInd = tree ? tree.length : 0;
        while (commentsInd--) {
            if (tree[commentsInd].parentId !== null) {
                tree.splice(commentsInd, 1);
            }
        }

        return tree ? tree : comments;
    };

    var createComment = function(o) {
        var crtdate = serializeDate(o.created);
        uptdate = serializeDate(o.updated);
        createdBy = createPerson(o.createdBy);

        var result = {
            type: 'comment',
            id: o.id,
            inactive: o.hasOwnProperty('inactive') ? o.inactive : false,
            parentId: o.parentId === '00000000-0000-0000-0000-000000000000' ? null : o.parentId || null,
            timestamp: crtdate ? crtdate.getTime() : 0,
            crtdate: crtdate,
            displayCrtdate: getDisplayDatetime(crtdate),
            displayDateCrtdate: getDisplayDate(crtdate),
            displayTimeCrtdate: getDisplayTime(crtdate),
            displayDatetimeCrtdate: getDisplayDatetime(crtdate),
            uptdate: uptdate,
            displayUptdate: getDisplayDatetime(uptdate),
            displayDateUptdate: getDisplayDate(uptdate),
            displayTimeUptdate: getDisplayTime(uptdate),
            displayDatetimeUptdate: getDisplayDatetime(uptdate),
            createdBy: createdBy,
            updatedBy: createPerson(o.updatedBy || o.createdBy),
            isMine: myProfile && createdBy && myProfile.id == createdBy.id || false,
            comments: [],
            text: o.text || ''
        }

        if (o.hasOwnProperty('canEdit')) {
            result.canEdit = o.canEdit;
        }

        return result;
    };
    
    

    var createCommentsTree = function(o) {
        var comments = [],
            items = isArray(o) ? o : [o],
            itemsInd = 0;

        itemsInd = items ? items.length : 0;
        while (itemsInd--) {
            comments.unshift(createComment(items[itemsInd]));
        }

        return sortCommentsByTree(comments);
    };

    var createPoll = function(o) {
        if (!o) {
            return null;
        }

        var max = 0, all = 0, val = 0,
            votes = [],
            items = o.votes,
            itemsInd = 0;

        itemsInd = items ? items.length : 0;
        while (itemsInd--) {
            val = items[itemsInd].votes;
            all += val
            if (max < val) {
                max = val;
            }
        }

        itemsInd = items ? items.length : 0;
        while (itemsInd--) {
            val = items[itemsInd].votes;
            votes.unshift({
                title: items[itemsInd].name,
                count: val,
                percent: all !== 0 ? Math.round((val * 100) / all) : 0,
                leader: max === val
            });
        }

        return { votes: votes, voted: o.voted, fullCount: all };
    };

    var factories = {
        storageusage: function(response) {
            return response;
        },

        text: function(response) {
            return response;
        },

        authentication: function(response) {
            return {
                token: response.token
            };
        },

        isme: function(response) {
            var profile = createPerson(response);
            for (var fld in profile) {
                if (profile.hasOwnProperty(fld)) {
                    myProfile[fld] = profile[fld];
                }
            }
            myProfile.isMe = true;

            return myProfile;
        },

        profile: function(response) {
            return createPerson(response);
        },

        profiles: function(response) {
            return collection(response, createPerson, function(response) {
                return {};
            });
        },

        group: function(response) {
            return createGroup(response);
        },

        groups: function(response) {
            return collection(response, createGroup, function(response) {
                return {};
            });
        },

        settings: function(response) {
            portalSettings = {
                type: 'settings',
                culture: response.culture,
                timezone: response.timezone,
                trustedDomains: response.trustedDomains,
                trustedDomainsType: response.trustedDomainsType,
                utcHoursOffset: response.utcHoursOffset,
                utcOffset: response.utcOffset
            };

            return portalSettings;
        },

        quotas: function(response) {
            portalQuotas = {
                type: 'quotas',
                storageSize: response.storageSize,
                maxFileSize: response.maxFileSize,
                usedSize: response.usedSize,
                availableSize: response.availableSize,
                storageUsage: factories.storageusage(response.storageUsage),
                maxUsersCount: response.maxUsersCount,
                usersCount: response.usersCount,
                availableUsersCount: response.availableUsersCount,
                userStorageSize: response.userStorageSize,
                userUsedSize: response.userUsedSize,
                userAvailableSize: response.userAvailableSize,
                maxVisitors: response.maxVisitors,
                visitorsCount: response.visitorsCount
            };

            return portalQuotas;
        },

        comment: function(response) {
            return createComment(response);
        },
        
        comments: function(response) {
            return createCommentsTree(response);
        },
        
        commentinlist: function(response){
            return response;
        },

        searchentryitems: function(response) {
            return collection(response, null, function(response) {
                var type = getSearchEntityTypeById(response.entityType);
                switch (type) {
                    case 'file':
                        return factories.doc.file(response);
                    case 'task':
                    case 'subtask':
                        return factories.prj.subtask(response);
                    case 'discussion':
                        return factories.prj.discussion(response);
                    case 'milestone':
                        return factories.prj.milestone(response);
                    default:
                        return {
                            type: type
                        };
                }
            });
        }
    };

    /* community */
    factories.cmt = {
        item: function(response) {
            var crtdate = serializeDate(response.created),
                uptdate = serializeDate(response.updated);

            return {
                id: response.id,
                timestamp: crtdate ? crtdate.getTime() : 0,
                crtdate: crtdate,
                displayCrtdate: getDisplayDatetime(crtdate),
                displayDateCrtdate: getDisplayDate(crtdate),
                displayTimeCrtdate: getDisplayTime(crtdate),
                displayDatetimeCrtdate: getDisplayDatetime(crtdate),
                uptdate: uptdate,
                displayUptdate: getDisplayDatetime(uptdate),
                displayDateUptdate: getDisplayDate(uptdate),
                displayTimeUptdate: getDisplayTime(uptdate),
                displayDatetimeUptdate: getDisplayDatetime(uptdate),
                createdBy: createPerson(response.createdBy || response.author),
                updatedBy: createPerson(response.updatedBy || response.createdBy || response.author),
                title: response.title || '',
                text: response.preview || response.text || response.description || ''
            };
        },

        tags: function(response) {
            return response || [];
        },

        blog: function(response) {
            return extend(this.item(response), {
                type: 'blog',
                tags: factories.cmt.tags(response.tags),
                comments: null
            });
        },

        poll: function(response) {
            return extend(this.item(response), {
                type: 'poll'
                //blah-blah-blah
            });
        },

        topic: function(response) {
            var firstPost = null;
            if (response.posts && response.posts.length > 0) {
                firstPost = response.posts[0];
                response.createdBy = firstPost.createdBy;
                response.text = firstPost.text;
                response.posts = response.posts.slice(1);
            }

            return extend(this.item(response), {
                type: 'forum',
                typeCode: response.type,
                statusCode: response.status,
                tags: factories.cmt.tags(response.tags),
                threadTitle: response.threadTitle || response.threadTitile,
                posts: createCommentsTree(response.posts || [])
            });
        },

        thread: function(response) {
            return extend(this.item(response), {
                type: 'thread'
            });
        },

        category: function(response) {
            return extend(this.item(response), {
                type: 'category',
                threads: factories.cmt.threads(response.threads)
            });
        },

        event: function(response) {
            var item = this.item(response);

            return extend(item, {
                type: 'event',
                typeCode: response.type,
                poll: createPoll(response.poll),
                comments: null
            });
        },

        bookmark: function(response) {
            return extend(this.item(response), {
                type: 'bookmark',
                url: response.url,
                thumbnail: response.thumbnail,
                comments: null
            });
        },

        blogs: function(response) {
            return collection(response, this.item, function(response) {
                return factories.cmt.blog(response);
            });
        },

        polls: function(response) {
            return collection(response, this.item, function(response) {
                return factories.cmt.poll(response);
            });
        },

        topics: function(response) {
            return collection(response, this.item, function(response) {
                return factories.cmt.topic(response);
            });
        },

        threads: function(response) {
            return collection(response, this.item, function(response) {
                return factories.cmt.thread(response);
            });
        },

        categories: function(response) {
            response = response.hasOwnProperty('categories') ? response.categories : response;

            return collection(response, this.item, function(response) {
                return factories.cmt.category(response);
            });
        },

        events: function(response) {
            return collection(response, this.item, function(response) {
                return factories.cmt.event(response);
            });
        },

        bookmarks: function(response) {
            return collection(response, this.item, function(response) {
                return factories.cmt.bookmark(response);
            });
        }
    };

    /* projects */
    factories.prj = {
        item: function (response) {
            var createdBy, responsible, updatedBy, responsibles  = [];

            if (typeof response.createdBy === "object") {
                createdBy = createPerson(response.createdBy);
            } else if (typeof response.createdById === "string") {
                createdBy = UserManager.getPerson(response.createdById, createPerson);
            } else {
                createdBy = createPerson(response.author);
            }

            if (typeof response.updatedBy === "object") {
                updatedBy = createPerson(response.updatedBy);
            } else if (typeof response.updatedById === "string") {
                updatedBy = UserManager.getPerson(response.updatedById, createPerson);
            }

            if (typeof response.responsible === "object") {
                responsible = createPerson(response.responsible);
            } else if (typeof response.responsibleId === "string") {
                responsible = UserManager.getPerson(response.responsibleId, createPerson);
            }

            if (response.responsibles) {
                responsibles = createPersons(response.responsibles || response.responsible);
            } else if (response.responsibleIds) {
                responsibles = response.responsibleIds.map(function(item) {
                    return createPerson(UserManager.getUser(item) || UserManager.getRemovedProfile());
                });
            }

            var
                crtdate = serializeDate(response.created),
                uptdate = serializeDate(response.updated);

            return {
                id: response.id,
                timestamp: crtdate ? crtdate.getTime() : 0,
                crtdate: crtdate,
                displayDateCrtdate: getDisplayDate(crtdate),
                uptdate: uptdate,
                displayUptdate: getDisplayDatetime(uptdate),
                displayDateUptdate: getDisplayDate(uptdate),
                createdBy: createdBy,
                updatedBy: updatedBy,
                responsible: responsible || responsibles[0],
                responsibles: responsibles,
                canEdit: response.canEdit || false,
                isPrivate: response.isPrivate || false,
                isShared: response.isShared || false,
                isMy: createdBy && myProfile ? createdBy.id === myProfile.id : false,
                forMe: responsible && myProfile ? responsible.id === myProfile.id : false,
                title: response.title || '',
                lowTitle: (response.title || '').toLowerCase(),
                description: response.description || '',
                status: response.status
            };
        },

        task: function(response) {
            var dlndate = serializeDate(response.deadline, false),
                startdate = serializeDate(response.startDate, false),
                todaydate = new Date(),
                year = todaydate.getFullYear(),
                month = todaydate.getMonth(),
                day = todaydate.getDate();

            todaydate = new Date(year, month, day, 0, 0, 0, 0);
            var tomorrowdate = new Date(year, month, day + 1, 0, 0, 0, 0);
            var hasProjectOwner = response.hasOwnProperty('projectOwner');

            return extend(this.item(response), {
                type: 'task',
                projectId: hasProjectOwner ? response.projectOwner.id : -1,
                projectTitle: hasProjectOwner ? response.projectOwner.title : '',
                projectOwner: response.projectOwner,
                canCreateSubtask: response.canCreateSubtask,
                canCreateTimeSpend: response.canCreateTimeSpend,
                canReadFiles: response.canReadFiles,
                canEditFiles: response.canEditFiles,
                canDelete: response.canDelete,
                deadline: dlndate,
                displayDeadline: getDisplayDatetime(dlndate),
                displayDateDeadline: getDisplayDate(dlndate),
                displayTimeDeadline: getDisplayTime(dlndate),
                startDate: startdate,
                displayStartDate: getDisplayDatetime(startdate),
                displayDateStart: getDisplayDate(startdate),
                displayTimeStart: getDisplayTime(startdate),
                status: response.status > 2 ? 1 : response.status,
                statusname: getTaskStatusName(response.status > 2 ? 1 : response.status),
                priority: response.priority,
                subtasks: factories.prj.subtasks(response.subtasks),
                progress: response.hasOwnProperty('progress') ? response.progress : 0,
                milestoneId: response.milestoneId,
                milestoneTitle: response.hasOwnProperty('milestone') && response.milestone ? response.milestone.title : '',
                milestone: response.hasOwnProperty('milestone') ? factories.prj.milestone(response.milestone) : null,
                deadlineToday: dlndate ? dlndate.getTime() >= todaydate.getTime() && dlndate.getTime() < tomorrowdate.getTime() : false,
                isOpened: response.status == taskStatuses.open.id,
                isExpired: response.isExpired || false,
                links: response.hasOwnProperty('links') ? factories.prj.links(response.links) : [],
                files: response.files,
                commentsCount: response.commentsCount,
                isSubscribed: response.isSubscribed,
                project: response.project,
                timeSpend: response.timeSpend,
                comments: response.comments ? response.comments : [],
                canCreateComment: response.canCreateComment,
                customTaskStatus: response.customTaskStatus
            });
        },

        simpletask: function(response) {
            var dlndate = serializeDate(response.deadline, false),
                startdate = serializeDate(response.startDate, false),
                todaydate = new Date(),
                year = todaydate.getFullYear(),
                month = todaydate.getMonth(),
                day = todaydate.getDate();

            todaydate = new Date(year, month, day, 0, 0, 0, 0);
            var tomorrowdate = new Date(year, month, day + 1, 0, 0, 0, 0);

            return extend(this.item(response), {
                type: 'task',
                projectOwner: response.projectOwner,
                canCreateSubtask: response.canCreateSubtask,
                canCreateTimeSpend: response.canCreateTimeSpend,
                canDelete: response.canDelete,
                createdBy: response.createdBy,
                updatedBy: response.updatedBy,
                deadline: dlndate,
                displayDeadline: getDisplayDatetime(dlndate),
                displayDateDeadline: getDisplayDate(dlndate),
                startDate: startdate,
                displayStartDate: getDisplayDatetime(startdate),
                displayDateStart: getDisplayDate(startdate),
                responsibles: response.responsibles,
                status: response.status > 2 ? 1 : response.status,
                customTaskStatus: response.customTaskStatus,
                statusname: getTaskStatusName(response.status > 2 ? 1 : response.status),
                priority: response.priority,
                subtasksCount: response.subtasksCount,
                progress: response.hasOwnProperty('progress') ? response.progress : 0,
                milestoneId: response.milestoneId,
                deadlineToday: dlndate ? dlndate.getTime() >= todaydate.getTime() && dlndate.getTime() < tomorrowdate.getTime() : false,
                isOpened: response.status == taskStatuses.open.id,
                isExpired: response.isExpired || false,
                links: response.hasOwnProperty('links') ? factories.prj.links(response.links) : null
            });
        },

        milestone: function(response) {
            var dlndate = serializeDate(response.deadline, false),
                todaydate = new Date(),
                year = todaydate.getFullYear(),
                month = todaydate.getMonth(),
                day = todaydate.getDate();

            todaydate = new Date(year, month, day, 0, 0, 0, 0);
            var tomorrowdate = new Date(year, month, day + 1, 0, 0, 0, 0);

            return extend(this.item(response), {
                type: 'milestone',
                projectId: response.hasOwnProperty('projectOwner') ? response.projectOwner.id : -1,
                projectTitle: response.hasOwnProperty('projectOwner') ? response.projectOwner.title : '',
                deadline: dlndate,
                displayDeadline: getDisplayDatetime(dlndate),
                displayDateDeadline: getDisplayDate(dlndate),
                displayTimeDeadline: getDisplayTime(dlndate),
                status: response.status,
                deadlineToday: dlndate ? dlndate.getTime() >= todaydate.getTime() && dlndate.getTime() < tomorrowdate.getTime() : false,
                isKey: response.isKey,
                isNotify: response.isNotify,
                isExpired: response.isExpired || false,
                activeTaskCount: response.activeTaskCount,
                closedTaskCount: response.closedTaskCount,
                canDelete: response.canDelete
            });
        },

        discussion: function (response) {
            var crtdate = serializeDate(response.created);
            return extend(this.item(response), {
                type: 'discussion',
                projectId: response.hasOwnProperty('projectOwner') ? response.projectOwner.id : -1,
                projectTitle: response.hasOwnProperty('projectOwner') ? response.projectOwner.title : '',
                projectOwner: response.projectOwner,
                parentId: null,
                comments: response.comments ? response.comments : [],
                text: response.text || '',
                status: response.status,
                displayTimeCrtdate: getDisplayTime(crtdate),
                displayDateTimeCrtdate: getDisplayDatetime(crtdate),
                canReadFiles: response.canReadFiles,
                canEditFiles: response.canEditFiles,
                canCreateComment: response.canCreateComment,
                commentsCount: response.commentsCount,
                subscribers: response.subscribers,
                files: response.files,
                project: response.project
            });
        },

        project: function (response) {
            var createdBy;
            var responsible;

            if (typeof response.createdBy === "object") {
                createdBy = createPerson(response.createdBy);
            } else if (typeof response.createdById === "string") {
                createdBy = UserManager.getPerson(response.createdById, createPerson);
            }

            if (typeof response.responsible === "object") {
                responsible = createPerson(response.responsible);
            } else if (typeof response.responsibleId === "string") {
                responsible = UserManager.getPerson(response.responsibleId, createPerson);
            } else if (typeof response.responsible === "string") {
                responsible = UserManager.getPerson(response.responsible, createPerson);
            }

            return {
                id: response.id,
                title: response.title || '',
                description: response.description || '',
                status: response.status,

                canCreateMessage: response.hasOwnProperty('security') ? response.security.canCreateMessage : '',
                canCreateMilestone: response.hasOwnProperty('security') ? response.security.canCreateMilestone : '',
                canCreateTask: response.hasOwnProperty('security') ? response.security.canCreateTask : '',
                canCreateTimeSpend: response.hasOwnProperty('security') ? response.security.canCreateTimeSpend : '',
                canEditTeam: response.hasOwnProperty('security') ? response.security.canEditTeam : '',
                security: response.security,

                isPrivate: response.isPrivate || false,
                isInTeam: response.hasOwnProperty('security') ? response.security.isInTeam : '',
                canLinkContact: response.hasOwnProperty('security') ? response.security.canLinkContact : null,

                displayDateCrtdate: getDisplayDate(serializeDate(response.created)),
                taskCount: response.taskCount,
                taskCountTotal: response.taskCountTotal,
                milestoneCount: response.milestoneCount,
                participantCount: response.participantCount,
                discussionCount: response.discussionCount,
                documentsCount: response.documentsCount,
                responsibleId: responsible != null && responsible.id ? responsible.id : responsible,
                canEdit: response.canEdit || false,
                canDelete: response.canDelete,

                createdBy: createdBy,
                responsible: responsible,
                timeTrackingTotal: response.timeTrackingTotal,
                isFollow: response.isFollow,
                tags: response.hasOwnProperty('tags') ? response.tags : []
            };
        },

        link: function(response) {
            return {
                type: 'link',
                parentTaskId: response.parentTaskId,
                dependenceTaskId: response.dependenceTaskId,
                linkType: response.linkType
            };
        },

        projectrequest: function(response) {
            return extend(this.item(response), {
                type: 'request'
            });
        },

        activity: function(response) {
            var date = new Date(response.date);
            return extend(this.item(response), {
                type: 'activity',
                projectId: response.projectId,
                projectTitle: response.projectTitle,
                title: response.title,
                url: response.url,
                actionText: response.actionText,
                displayDatetime: getDisplayDatetime(date),
                displayDate: getDisplayDate(date),
                displayTime: getDisplayTime(date),
                user: response.user,
                entityType: response.entityType,
                entityTitle: response.entityTitle
            });
        },

        subtask: function(response) {
            return extend(this.item(response), {
                type: 'subtask',
                status: response.status,
                taskid: response.taskId
            });
        },

        subtasks: function(response) {
            return collection(response, this.item, function(response) {
                return factories.prj.subtask(response);
            });
        },

        tasks: function (response) {
            return collection(response, this.item, function(response) {
                return factories.prj.task(response);
            });
        },

        simpletasks: function(response) {
            return collection(response, this.item, function(response) {
                return factories.prj.simpletask(response);
            });
        },

        milestones: function(response) {
            return collection(response, this.item, function(response) {
                return factories.prj.milestone(response);
            });
        },

        discussions: function(response) {
            return collection(response, this.item, function(response) {
                return factories.prj.discussion(response);
            });
        },

        projects: function (response) {
            var func = function(prj) {
                return factories.prj.project(prj);
            };
            return response.map(func);
        },

        links: function(response) {
            return collection(response, null, function(response) {
                return factories.prj.link(response);
            });
        },

        projectperson: function(response) {
            var person = createPerson(response);
            person.canReadFiles = response.canReadFiles;
            person.canReadMessages = response.canReadMessages;
            person.canReadMilestones = response.canReadMilestones;
            person.canReadTasks = response.canReadTasks;
            person.canReadContacts = response.canReadContacts;
            person.isAdministrator = response.isAdministrator;
            person.isManager = response.isManager;
            person.department = response.department || "";
            person.isRemovedFromTeam = response.isRemovedFromTeam;
            return person;
        },

        projectpersons: function(response) {
            var persons = [];
            for (var i = 0; i < response.length; i++) {
                persons.push(factories.prj.projectperson(response[i]));
            }
            return persons;
        },

        searchentries: function(response) {
            return collection(response, this.item, function(response) {
                var projectOwner = response.projectOwner;
                return {
                    id: projectOwner ? projectOwner.id : response.id || -1,
                    type: 'project',
                    title: projectOwner ? projectOwner.title : response.title || '',
                    status: projectOwner ? projectOwner.status : response.status || '',
                    items: response.items ? factories.searchentryitems(response.items) : []
                };
            });
        },

        timespend: function(response) {
            var creationdate = serializeDate(response.date);
            var statusChangedDate = serializeDate(response.statusChanged);
            return extend(this.item(response), {
                type: 'timespend',
                date: creationdate,
                displayCreationDate: getDisplayDatetime(creationdate),
                displayDateCreation: getDisplayDate(creationdate),
                displayTimeCreation: getDisplayTime(creationdate),
                hours: response.hours,
                note: response.note,
                status: response.paymentStatus,
                paymentStatus: response.paymentStatus,
                statusChanged: getDisplayDate(statusChangedDate),
                canEditPaymentStatus: response.canEditPaymentStatus,
                relatedProject: response.relatedProject,
                relatedTask: response.relatedTask,
                relatedTaskTitle: response.relatedTaskTitle,
                task: factories.prj.task(response.task),
                person: response.hasOwnProperty('person') ? createPerson(response.person) : ""
            });
        },

        timespends: function(response) {
            return collection(response, this.item, function(response) {
                return factories.prj.timespend(response);
            });
        },
        activities: function(response) {
            return collection(response, this.item, function(response) {
                return factories.prj.activity(response);
            });
        },
        settings: function(response) {
            return response;
        },

        report: function(response) {
            return response;
        }
    };

    /* feed */
    factories.feed = {
        item: function(response) {
            var createdDate = serializeDate(response.CreatedDate);
            var modifiedDate = serializeDate(response.ModifiedDate);
            var aggregatedDate = serializeDate(response.AggregatedDate);

            var feed = {
                item: response.Item,
                itemId: response.ItemId,
                itemUrl: response.ItemUrl,
                id: response.Id,
                authorId: response.AuthorId,
                createdDate: createdDate,
                displayCreatedDatetime: getDisplayDatetime(createdDate),
                displayCreatedDate: getDisplayDate(createdDate),
                displayCreatedTime: getDisplayTime(createdDate),
                modifiedDate: modifiedDate,
                displayModifiedDatetime: getDisplayDatetime(modifiedDate),
                displayModifiedDate: getDisplayDate(modifiedDate),
                displayModifiedTime: getDisplayTime(modifiedDate),
                aggregatedDate: aggregatedDate,
                product: response.Product,
                module: response.Module,
                action: response.Action,
                title: response.Title,
                isToday: response.IsToday,
                isYesterday: response.IsYesterday,
                description: response.Description,
                extraLocation: response.ExtraLocation,
                extraLocationUrl: response.ExtraLocationUrl,
                additionalInfo: response.AdditionalInfo,
                additionalInfo2: response.AdditionalInfo2,
                additionalInfo3: response.AdditionalInfo3,
                additionalInfo4: response.AdditionalInfo4,
                hasPreview: response.HasPreview,
                canComment: response.CanComment,
                commentApiUrl: response.CommentApiUrl,
                groupedFeeds: response.GroupedFeeds,
                comments: getComments(response.Comments)
            };

            function getComments(comments) {
                if (!comments) {
                    return null;
                }

                var templates = [];
                for (var i = 0; i < comments.length; i++) {
                    templates.push(getComment(comments[i]));
                }
                return templates;
            }

            function getComment(comment) {
                var commentDateStr = comment.Date.slice(0, -1);
                var commentDate = serializeDate(commentDateStr);

                commentDate.setMinutes(commentDate.getMinutes() + ASC.Resources.Master.CurrentTenantTimeZone.UtcOffset);

                return {
                    id: comment.Id,
                    description: comment.Description,
                    authorId: comment.AuthorId,
                    date: commentDate,
                    formattedDate: getDisplayDatetime(commentDate)
                };
            }

            return feed;
        },

        feeds: function(response) {
            var obj = [];
            for (var i = 0; i < response.feeds.length; i++) {
                var resp = response.feeds[i];
                var feed = makeFeedItem(resp);
                feed.GroupedFeeds = [];
                for (var j = 0; j < resp.groupedFeeds.length; j++) {
                    feed.GroupedFeeds.push(makeFeedItem(resp.groupedFeeds[j]));
                }
                obj = obj.concat(feed);
            }
            var feeds = collection(obj, this.item, function(r) {
                return factories.feed.item(r);
            });

            return { feeds: feeds, readedDate: serializeDate(response.readedDate) };

            function makeFeedItem(responseItem) {
                var item = jq.parseJSON(responseItem.feed);
                item.IsToday = responseItem.isToday;
                item.IsYesterday = responseItem.isYesterday;
                item.LastModifiedBy = responseItem.lastModifiedBy;
                item.CreatedDate = responseItem.createdDate;
                item.ModifiedDate = responseItem.modifiedDate;
                item.AggregatedDate = responseItem.aggregatedDate;

                return item;
            }
        }
    };

    /* documents */
    factories.doc = {
        miss: function(response) {
            return response;
        },

        item: function(response) {
            var crtdate = serializeDate(response.created),
                uptdate = serializeDate(response.updated);

            return {
                id: response.id,
                parentId: response.parentId || response.folderId || -1,
                folderId: response.folderId || response.parentId || -1,
                access: response.access,
                sharedByMe: response.sharedByMe,
                rootFolderType: response.rootFolderType,
                rootType: getRootFolderTypeById(response.rootFolderType),
                timestamp: crtdate ? crtdate.getTime() : 0,
                crtdate: crtdate,
                displayCrtdate: getDisplayDatetime(crtdate),
                displayDateCrtdate: getDisplayDate(crtdate),
                displayTimeCrtdate: getDisplayTime(crtdate),
                uptdate: uptdate,
                displayUptdate: getDisplayDatetime(uptdate),
                displayDateUptdate: getDisplayDate(uptdate),
                displayTimeUptdate: getDisplayTime(uptdate),
                createdBy: createPerson(response.createdBy || response.author),
                updatedBy: createPerson(response.updatedBy),
                canEdit: response.canEdit || false,
                title: response.title || '',
                description: response.description || ''
            };
        },

        rootFolder: function(response) {
            if (!response || response.length <= 1) {
                return null;
            }
            var first = response[0] || {};
            return {
                type: 'folder',
                id: first.key,
                title: first.path
            };
        },

        parentFolder: function(response) {
            if (!response || response.length <= 1) {
                return null;
            }
            var last = response[response.length - 2] || null;
            return !last ? null : {
                type: 'folder',
                id: last.key,
                title: last.path,
                path: last.path
            };
        },

        files: function(response) {
            return collection(response, this.item, function(response) {
                return factories.doc.file(response);
            });
        },

        folders: function(response) {
            return collection(response, this.item, function(response) {
                return factories.doc.folder(response);
            });
        },

        file: function (response) {
            if (!response) return undefined;

            var title = response.title ? response.title : '';

            var filename = title.substring(0, title.lastIndexOf('.'));
            filename = filename ? filename : response.title;

            var extension = (title.substring(title.lastIndexOf('.')) || '').toLowerCase();

            return extend(this.item(response), {
                type: 'file',
                extension: extension,
                filename: filename,
                filetype: getFileType(extension),
                version: response.version,
                versionGroup: response.versionGroup,
                fileStatus: response.fileStatus,
                contentLength: response.contentLength,
                pureContentLength: response.pureContentLength,
                webUrl: fixUrl(response.webUrl || ''),
                viewUrl: fixUrl(response.viewUrl || ''),
                fileUrl: fixUrl(response.fileUrl || ''),
                isSupported: isSupportedFileType(extension),
                isUploaded: false
            });
        },

        folder: function(response) {
            var uploadedfilenames = response.hasOwnProperty('__filenames') ? response.__filenames : null,
                folders = factories.doc.folders(response.folders),
                files = factories.doc.files(response.files),
                pathParts = response.pathParts,
                response = response.current || response;

            if (uploadedfilenames) {
                var filesInd = 0,
                    uploadedfilename = '',
                    uploadedfilenamesInd = uploadedfilenames.length;
                while (uploadedfilenamesInd--) {
                    uploadedfilename = uploadedfilenames[uploadedfilenamesInd];
                    filesInd = files.length;
                    while (filesInd--) {
                        if (files[filesInd].title === uploadedfilename) {
                            files[filesInd].isUploaded = true;
                        }
                    }
                }
            }

            return extend(this.item(response), {
                type: 'folder',
                folders: folders,
                files: files,
                pathParts: pathParts,
                filesCount: response.filesCount,
                foldersCount: response.foldersCount,
                isShareable: response.isShareable || false,
                canAddItems: response.access == fileShareTypes.None || response.access == fileShareTypes.ReadWrite,
                rootFolder: factories.doc.rootFolder(pathParts),
                parentFolder: factories.doc.parentFolder(pathParts)
            });
        },

        session: function(response) {
            return response;
        }
    };

    /* crm */
    factories.crm = {
        item: function(response) {
            var crtdate = serializeDate(response.created),
                uptdate = serializeDate(response.updated),
                expdate = serializeDate(response.expected || response.expectedCloseDate);

            return {
                id: response.id,
                timestamp: crtdate ? crtdate.getTime() : 0,
                crtdate: crtdate,
                displayCrtdate: getDisplayDatetime(crtdate),
                displayDateCrtdate: getDisplayDate(crtdate),
                displayTimeCrtdate: getDisplayTime(crtdate),
                uptdate: uptdate,
                displayUptdate: getDisplayDatetime(uptdate),
                displayDateUptdate: getDisplayDate(uptdate),
                displayTimeUptdate: getDisplayTime(uptdate),
                expdate: expdate,
                displayExpdate: getDisplayDatetime(expdate),
                displayDateExpdate: getDisplayDate(expdate),
                displayTimeExpdate: getDisplayTime(expdate),
                createdBy: createPerson(response.createdBy || response.createBy || response.author),
                updatedBy: createPerson(response.updatedBy),
                responsible: createPerson(response.responsible),
                title: response.title || '',
                description: response.description || ''
            };
        },

        bidCurrency: function(response) {
            return response;
        },

        customfield: function(response) {
            return response;
        },

        dealmilestone: function(response) {
            return response;
        },

        category: function(response) {
            return response;
        },

        contactstatus: function(response) {
            return response;
        },

        contacttypekind: function(response) {
            return response;
        },
        historycategory: function(response) {
            return response;
        },

        entity: function(response) {
            return response;
        },

        company: function(response) {
            return response;
        },

        address: function(response) {
            var categories = ['Home', 'Postal', 'Office', 'Billing', 'Other', 'Work'],
                infoTypes = ['Phone', 'Email', 'Website', 'Skype', 'Twitter', 'LinkedIn', 'Facebook', 'Address', 'LiveJournal', 'MySpace', 'GMail', 'Blogger', 'Yahoo', 'MSN', 'ICQ', 'Jabber', 'AIM'],
                category = response.category,
                infoType = response.infoType;

            return {
                id: response.id,
                infoType: infoType,
                infoTypeName: isFinite(+infoType) && +infoType >= 0 && +infoType < infoTypes.length ? infoTypes[+infoType] : infoType,
                category: category,
                categoryName: isFinite(+category) && +category >= 0 && +category < categories.length ? categories[+category] : category,
                data: response.data,
                isPrimary: response.isPrimary
            };
        },

        addresses: function(response) {
            return collection(response, this.address, function(response) {
                return factories.crm.address(response);
            });
        },

        contactbase: function(response) {
            return extend(this.item(response), {
                type: 'contactbase',
                displayName: response.displayName,
                isCompany: response.isCompany,
                isPrivate: response.isPrivate,
                accessList: response.accessList,
                isShared: response.isShared,
                shareType: response.shareType,
                smallFotoUrl: response.smallFotoUrl,
                mediumFotoUrl: response.mediumFotoUrl,
                company: response.company ? factories.crm.company(response.company) : null,
                email: response.email ? response.email : null,
                currency: response.currency ? factories.crm.currency(response.currency) : null,
                canEdit: response.canEdit,
                canDelete: response.canDelete
            });
        },

        contact: function(response) {
            return extend(this.item(response), {
                type: 'contact',
                contactclass: response.firstName ? 'person' : 'company',
                displayName: response.displayName,
                firstName: response.firstName,
                lastName: response.lastName,
                isCompany: response.isCompany,
                isPrivate: response.isPrivate,
                isShared: response.isShared,
                shareType: response.shareType,
                smallFotoUrl: response.smallFotoUrl,
                mediumFotoUrl: response.mediumFotoUrl,
                company: response.company ? factories.crm.company(response.company) : null,
                personsCount: response.personsCount,
                customFields: factories.crm.customfields(response.customFields),
                about: response.about,
                industry: response.industry,
                currency: response.currency ? factories.crm.currency(response.currency) : null,
                accessList: response.accessList,
                addresses: response.addresses,
                commonData: response.commonData,
                haveLateTasks: response.haveLateTasks || false,
                taskCount: response.taskCount,
                contactStatus: response.contactStatus,
                canEdit: response.canEdit,
                canDelete: response.canDelete,
                tags: response.tags
            });
        },

        simplecontact: function(response) {
            return extend(this.item(response), {
                type: 'contact',
                contactclass: response.firstName ? 'person' : 'company',
                displayName: response.displayName,
                firstName: response.firstName,
                lastName: response.lastName,
                isCompany: response.isCompany,
                isPrivate: response.isPrivate,
                isShared: response.isShared,
                shareType: response.shareType,
                smallFotoUrl: response.smallFotoUrl,
                mediumFotoUrl: response.mediumFotoUrl,
                company: response.company ? factories.crm.company(response.company) : null,
                personsCount: response.personsCount,
                customFields: factories.crm.customfields(response.customFields),
                about: response.about,
                industry: response.industry,
                accessList: response.accessList,
                addresses: response.addresses,
                commonData: response.commonData,
                haveLateTasks: response.haveLateTasks || false,
                taskCount: response.taskCount,
                contactStatus: response.contactStatus,
                currency: response.currency ? factories.crm.currency(response.currency) : null,
                canEdit: response.canEdit,
                canDelete: response.canDelete,
                tags: response.tags,
                nearTask: response.nearTask || null
            });
        },

        basecontact: function(response) {
            return extend(this.item(response), {
                type: 'contact',
                contactclass: response.isCompany ? 'company' : 'person',
                displayName: response.displayName,
                email: response.email,//may be undefined if ContactBaseWithPhoneWrapper
                phone: response.phone,//may be undefined if ContactBaseWithEmailWrapper
                isCompany: response.isCompany,
                currency: response.currency ? factories.crm.currency(response.currency) : null,
                isPrivate: response.isPrivate,
                isShared: response.isShared,
                shareType: response.shareType,
                accessList: response.accessList,
                smallFotoUrl: response.smallFotoUrl,
                mediumFotoUrl: response.mediumFotoUrl,
                canEdit: response.canEdit,
                canDelete: response.canDelete
            });
        },

        socialmediaavatar: function(response) {
            return {
                type: "socialmediaavatar",
                socialNetwork: response.socialNetwork,
                imageUrl: response.imageUrl,
                identity: response.identity
            };
        },

        socialmediaavatars: function(response) {
            return collection(response, null, function(response) {
                return factories.crm.socialmediaavatar(response);
            });
        },

        tweet: function(response) {
            var postedOn = serializeDate(response.postedOn);
            return {
                type: "tweet",
                userImageUrl: response.userImageUrl,
                userName: response.userName,
                userId: response.userId,
                text: response.text,
                postedOn: postedOn,
                postedOnDisplay: getDisplayDatetime(postedOn),
                source: response.source
            };
        },

        tweets: function(response) {
            return collection(response, null, function(response) {
                return factories.crm.tweet(response);
            });
        },

        twitterprofile: function(response) {
            var postedOn = serializeDate(response.postedOn);
            return {
                type: "twitterprofile",
                userID: response.userID,
                screenName: response.screenName,
                userName: response.userName,
                smallImageUrl: response.smallImageUrl,
                description: response.description
            };
        },

        twitterprofiles: function(response) {
            return collection(response, null, function(response) {
                return factories.crm.twitterprofile(response);
            });
        },

        progressitem: function(response) {
            return response;
        },

        exportitem: function (response) {
            if (!response || jq.isEmptyObject(response)) return response;

            return {
                id: response.id,
                status: response.status,
                percentage: response.percentage,
                isCompleted: response.isCompleted,
                exception: response.error || response.errorText,
                fileId: response.fileId,
                fileUrl: response.fileUrl,
                fileName: response.fileName
            };
        },

        fileuploadresult:  function(response) {
            return response;
        },

        file: function(response) {
            return extend(this.item(response), {
                type: 'file',
                title: response.title,
                folderId: response.folderId,
                version: response.version,
                fileStatus: response.fileStatus,
                contentLength: response.contentLength,
                pureContentLength: response.pureContentLength,
                viewUrl: response.viewUrl,
                webUrl: response.webUrl,
                access: response.access,
                sharedByMe: response.sharedByMe,
                rootFolderType: response.rootFolderType,
                createdDate: serializeDate(response.created)
            });
        },

        files: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.file(response);
            });
        },

        tag: function(response) {
            return response;
        },

        task: function(response) {
            var deadLine = serializeDate(response.deadLine);
            var deadLineString = deadLine && (deadLine.getHours() == 0 && deadLine.getMinutes() == 0 && deadLine.getSeconds() == 0) ? getDisplayDate(deadLine) : getDisplayDatetime(deadLine);

            return extend(this.item(response), {
                type: 'task',
                category: factories.crm.category(response.category),
                canEdit: response.canEdit,
                canWork: response.canWork,
                contact: response.contact ? factories.crm.contactbase(response.contact) : null,
                deadLine: deadLine,
                deadLineString: deadLineString,
                entity: response.entity ? factories.crm.entity(response.entity) : null,
                isClosed: response.isClosed,
                alertValue: typeof(response.alertValue) != "undefined" ? response.alertValue : 0
            });
        },

        opportunity: function(response) {
            var expectedCloseDate = serializeDate(response.expectedCloseDate);
            var actualCloseDate = serializeDate(response.actualCloseDate);

            return extend(this.item(response), {
                type: 'opportunity',
                accessList: response.accessList,
                actualCloseDate: actualCloseDate,
                actualCloseDateString: getDisplayDate(actualCloseDate),
                bidCurrency: factories.crm.bidCurrency(response.bidCurrency),
                bidType: response.bidType,
                bidValue: response.bidValue,
                contact: response.contact ? factories.crm.contact(response.contact) : null,
                customFields: factories.crm.customfields(response.customFields),
                stage: factories.crm.dealmilestone(response.stage),
                successProbability: response.successProbability,
                expectedCloseDate: expectedCloseDate,
                expectedCloseDateString: getDisplayDate(expectedCloseDate),
                isPrivate: response.isPrivate,
                canEdit: response.canEdit,
                perPeriodValue: response.perPeriodValue
            });
        },

        taskcategory: function(response) {
            return extend(this.item(response), {
                type: 'taskcategory',
                imagePath: response.imagePath,
                relativeItemsCount: response.relativeItemsCount,
                sortOrder: response.sortOrder
            });
        },

        caseitem: function(response) {
            return extend(this.item(response), {
                type: 'case',
                accessList: response.accessList,
                isClosed: response.isClosed,
                isPrivate: response.isPrivate,
                canEdit: response.canEdit
            });
        },

        cases: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.caseitem(response);
            });
        },

        tags: function(response) {
            return response;
        },

        fulltag: function(response) {
            return {
                type: 'fulltag',
                title: response.title,
                relativeItemsCount: response.relativeItemsCount || 0,
            };
        },

        fulltags: function(response) {
            var items = [];
            for (var i = 0, n = response.length; i < n; i++) {
                items.push(factories.crm.fulltag(response[i]));
            }
            return items;
        },

        contacts: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.contact(response);
            });
        },

        simplecontacts: function(response) {
            var items = [];
            for (var i = 0; i < response.length; i++) {
                var item = factories.crm.simplecontact(response[i].contact);
                if (response[i].hasOwnProperty('task')) {
                    item.nearTask = factories.crm.task(response[i].task);
                }
                items.push(item);
            }
            return items;
        },

        basecontacts: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.basecontact(response);
            });
        },

        customfields: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.customfield(response);
            });
        },

        dealmilestones: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.dealmilestone(response);
            });
        },

        contactstatuses: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.contactstatus(response);
            });
        },

        contacttypekinds: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.contacttypekind(response);
            });
        },

        historycategories: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.historycategory(response);
            });
        },

        tasks: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.task(response);
            });
        },

        opportunities: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.opportunity(response);
            });
        },

        taskcategories: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.taskcategory(response);
            });
        },

        historyevent: function(response) {
            return extend(this.item(response), {
                type: 'event',
                createdDate: getDisplayDate(serializeDate(response.created)),
                canEdit: response.canEdit,
                category: factories.crm.category(response.category),
                contact: response.contact ? factories.crm.contact(response.contact) : null,
                content: response.content,
                entity: response.entity ? factories.crm.entity(response.entity) : null,
                files: response.files && response.files.length != 0 ? factories.crm.files(response.files) : null
            });
        },

        historyevents: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.historyevent(response);
            });
        },

        currency: function(response) {
            return {
                type: 'currency',
                abbreviation: response.abbreviation,
                cultureName: response.cultureName,
                symbol: response.symbol,
                title: response.title,
                isConvertable: response.isConvertable,
                isBasic: response.isBasic
            };
        },

        currencies: function(response) {
            return collection(response, null, function(response) {
                return factories.crm.currency(response);
            });
        },

        smtpsettings: function(response){
            return {
                type: 'smtpsettings',
                enableSSL: response.enableSSL,
                host: response.host,
                hostLogin: response.hostLogin,
                hostPassword: <PASSWORD>,
                port: response.port,
                requiredHostAuthentication: response.requiredHostAuthentication,
                senderDisplayName: response.senderDisplayName,
                senderEmailAddress: response.senderEmailAddress
            };
        },

        rootfolder: function(response) {
            return {
                id: response
            };
        },

        invoice: function(response) {
            var issueDate = serializeDate(response.issueDate),
                issueDateString = getDisplayDate(issueDate),
                dueDate = serializeDate(response.dueDate),
                dueDateString = dueDate && (dueDate.getHours() == 0 && dueDate.getMinutes() == 0 && dueDate.getSeconds() == 0)
                    ? getDisplayDate(dueDate)
                    : getDisplayDatetime(dueDate),
                crtdate = response.createOn ? serializeDate(response.createOn) : null,
                debtor = response.status.id == 2 && dueDate < new Date();

            return extend(this.item(response), {
                type: 'invoice',
                number: response.number,
                status: response.status,//int
                debtor: debtor,
                issueDate: issueDate,
                issueDateString: issueDateString,
                dueDate: dueDate,
                dueDateString: dueDateString,
                templateType: response.templateType,
                contact: response.contact ? factories.crm.basecontact(response.contact) : null,
                consignee: response.consignee ? factories.crm.basecontact(response.consignee) : null,
                entity: response.entity ? factories.crm.entity(response.entity) : null,
                language: response.language,
                currency: response.currency ? factories.crm.currency(response.currency) : null,
                cost: response.cost,
                purchaseOrderNumber: response.purchaseOrderNumber,
                terms: response.terms,
                description: response.description,
                fileId: response.fileID,
                crtdate: crtdate,
                displayCrtdate: getDisplayDatetime(crtdate),
                displayDateCrtdate: getDisplayDate(crtdate),
                displayTimeCrtdate: getDisplayTime(crtdate),
                invoiceLines: response.invoiceLines && response.invoiceLines.length != 0 ? factories.crm.invoiceLines(response.invoiceLines) : null,
                canEdit: response.canEdit,
                canDelete: response.canDelete
            });
        },

        invoices: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.invoice(response);
            });
        },

        invoiceJsonData: function(response) {
            return jq.parseJSON(response || null);
        },

        invoiceLines: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.invoiceLine(response);
            });
        },

        invoiceLine: function(response) {
            return {
                type: 'invoiceLine',
                id: response.id,
                invoiceID: response.invoiceID,
                invoiceItemID: response.invoiceItemID,
                invoiceTax1ID: response.invoiceTax1ID,
                invoiceTax2ID: response.invoiceTax2ID,
                sortOrder: response.sortOrder,
                description: response.description,
                quantity: response.quantity,
                price: response.price,
                discount: response.discount,
                canEdit: response.canEdit
            };
        },

        invoiceItems: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.invoiceItem(response);
            });
        },

        invoiceItem: function(response) {
            return {
                type: 'invoiceItem',
                id: response.id,
                title: response.title,
                stockKeepingUnit: response.stockKeepingUnit,
                description: response.description,
                price: response.price,
                currency: response.currency,
                stockQuantity: response.stockQuantity,
                trackInvenory: response.trackInvenory,
                invoiceTax1: response.invoiceTax1 ? factories.crm.invoiceTax(response.invoiceTax1) : null,
                invoiceTax2: response.invoiceTax2 ? factories.crm.invoiceTax(response.invoiceTax2) : null,
                sortOrder: response.sortOrder,
                canEdit: response.canEdit,
                canDelete: response.canDelete
            };
        },

        invoicesAndItems: function(response) {
            return {
                invoices: response.key && response.key.length != 0 ? factories.crm.invoices(response.key) : null,
                invoiceItems: response.value && response.value.length != 0 ? factories.crm.invoiceItems(response.value) : null
            };
        },

        invoiceTaxes: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.invoiceTax(response);
            });
        },

        invoiceTax: function(response) {
            return {
                type: 'invoiceTax',
                id: response.id,
                name: response.name,
                description: response.description,
                rate: response.rate,
                canEdit: response.canEdit,
                canDelete: response.canDelete
            };
        },

        invoiceSettings: function(response) {
            return {
                type: 'invoiceSettings',
                autogenerated: response.autogenerated,
                prefix: response.prefix,
                number: response.number,
                terms: response.terms
            };
        },

        currencyRates: function(response) {
            return collection(response, this.item, function(response) {
                return factories.crm.currencyRate(response);
            });
        },

        currencyRate: function(response) {
            return {
                type: 'currencyRate',
                id: response.id,
                fromCurrency: response.fromCurrency,
                toCurrency: response.toCurrency,
                rate: response.rate
            };
        },

        voipNumbers: function(response) {
            return collection(response, null, function(response) {
                return factories.crm.voipNumber(response);
            });
        },

        voipNumber: function(response) {
            return {
                id: response.id,
                number: response.number,
                alias: response.alias,
                settings: response.settings
            };
        },

        voipSettings: function(response) {
            return response;
        },

        voipCalls: function(response) {
            return collection(response, null, function(response) {
                return factories.crm.voipCall(response);
            });
        },

        voipCall: function (response) {
            var serializedDate = serializeDate(response.dialDate);

            return {
                id: response.id,
                from: response.from,
                to: response.to,
                status: response.status,
                answeredBy: createPerson(response.answeredBy),
                dateObj: serializedDate,
                datetime: getDisplayDatetime(serializedDate),
                time: getDisplayTime(serializedDate),
                dialDuration: response.dialDuration,
                cost: response.cost,
                recordUrl: response.recordUrl,
                recordDuration: response.recordDuration,
                contact: response.hasOwnProperty('contact') && response.contact ? factories.crm.contact(response.contact) : null,
                history: response.history
            };
        },

        converterData: function(response) {
            return {
                type: 'converterData',
                storageUrl: response.storageUrl,
                revisionId: response.revisionId,
                urlToFile: response.urlToFile,
                invoiceId: response.invoiceId,
                fileId: response.fileId
            };
        },
    };

    var create = function(apiurl, method, response, responses) {
        if (typeof response === 'undefined') {
            return null;
        }

        responses = responses || [response];
        method = typeof method === 'string' ? method.toLowerCase() : '';
        var apiAnchorsInd = apiAnchors.length;
        while (apiAnchorsInd--) {
            if (apiAnchors[apiAnchorsInd].re.test(apiurl)) {
                //console.log(apiurl, ' # ', apiAnchors[apiAnchorsInd].handler);
                if (!apiAnchors[apiAnchorsInd].hasOwnProperty('method')) {
                    break;
                }
                if (apiAnchors[apiAnchorsInd].method === method) {
                    break;
                }
            }
        }

        var handlername = apiAnchorsInd !== -1 ? apiAnchors[apiAnchorsInd].handler : apiurl,
            namespaces = handlername.split('-');

        if (namespaces.length > 1) {
            if (factories.hasOwnProperty(namespaces[0]) && typeof factories[namespaces[0]][namespaces[1]] === 'function') {
                return factories[namespaces[0]][namespaces[1]].apply(factories[namespaces[0]], [response, responses]);
            }
        }

        if (typeof factories[handlername] === 'function') {
            return factories[handlername].apply(factories, [response, responses]);
        }

        return onlyFactory === true ? null : response;
    };

    return {
        profile: myProfile,
        dateFormats: formats,
        contactTypes: contactTypes,
        nameCollections: nameCollections,

        init: init,

        create: create,

        fixData: fixData,
        formattingDate: formattingDate,
        serializeDate: serializeDate,
        serializeTimestamp: serializeTimestamp,
        getDisplayTime: getDisplayTime,
        getDisplayDate: getDisplayDate,
        getDisplayDatetime: getDisplayDatetime
    };
})();

<|start_filename|>common/ASC.Data.Storage/Configuration/StorageSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Web.Optimization;

using ASC.Common.Caching;
using ASC.Core;
using ASC.Core.Common.Configuration;
using ASC.Core.Common.Settings;

namespace ASC.Data.Storage.Configuration
{
    [Serializable]
    [DataContract]
    public abstract class BaseStorageSettings<T> : BaseSettings<T> where T : class, ISettings, new()
    {
        [DataMember(Name = "Module")]
        public string Module { get; set; }

        [DataMember(Name = "Props")]
        public Dictionary<string, string> Props { get; set; }

        public override ISettings GetDefault()
        {
            return new T();
        }

        static BaseStorageSettings()
        {
            AscCache.Notify.Subscribe<Consumer>((i, a) =>
            {
                if (a == CacheNotifyAction.Remove)
                {
                    var settings = StorageSettings.Load();
                    if (i.Name == settings.Module)
                    {
                        settings.Clear();
                    }

                    var cdnSettings = CdnStorageSettings.Load();
                    if (i.Name == cdnSettings.Module)
                    {
                        cdnSettings.Clear();
                    }
                }
            });
        }

        public override bool Save()
        {
            StorageFactory.ClearCache();
            dataStoreConsumer = null;
            return base.Save();
        }

        public virtual void Clear()
        {
            Module = null;
            Props = null;
            Save();
        }

        private DataStoreConsumer dataStoreConsumer;
        public DataStoreConsumer DataStoreConsumer
        {
            get
            {
                if (string.IsNullOrEmpty(Module) || Props == null) return dataStoreConsumer = new DataStoreConsumer();

                var consumer = ConsumerFactory.GetByName<DataStoreConsumer>(Module);

                if (!consumer.IsSet) return dataStoreConsumer = new DataStoreConsumer();

                dataStoreConsumer = (DataStoreConsumer)consumer.Clone();

                foreach (var prop in Props)
                {
                    dataStoreConsumer[prop.Key] = prop.Value;
                }

                return dataStoreConsumer;
            }
        }

        private IDataStore dataStore;
        public IDataStore DataStore
        {
            get
            {
                if (dataStore != null) return dataStore;

                if (DataStoreConsumer.HandlerType == null) return null;

                return dataStore = ((IDataStore)
                    Activator.CreateInstance(DataStoreConsumer.HandlerType, CoreContext.TenantManager.GetCurrentTenant().TenantId.ToString()))
                    .Configure(DataStoreConsumer);
            }
        }

        public virtual Func<DataStoreConsumer, DataStoreConsumer> Switch { get { return d => d; } }
    }

    [Serializable]
    [DataContract]
    public class StorageSettings : BaseStorageSettings<StorageSettings>
    {
        public override Guid ID
        {
            get { return new Guid("F13EAF2D-FA53-44F1-A6D6-A5AEDA46FA2B"); }
        }
    }

    [Serializable]
    [DataContract]
    public class CdnStorageSettings : BaseStorageSettings<CdnStorageSettings>
    {
        public override Guid ID
        {
            get { return new Guid("0E9AE034-F398-42FE-B5EE-F86D954E9FB2"); }
        }

        public override Func<DataStoreConsumer, DataStoreConsumer> Switch { get { return d => d.Cdn; } }

        public override void Clear()
        {
            base.Clear();
            BundleTable.Bundles.Clear();
        }
    }

}


<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/js/talk.connectiomanager.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC = window.ASC || {};

window.ASC.TMTalk = window.ASC.TMTalk || {};

window.ASC.TMTalk.connectionManager = (function () {
  var
    isInit = false,
    isLoaded = false,
    isConnected = false,
    JID = '',
    servicePath = '',
    clientInactivity = 30,
    wait = 30,
    hold = 2,
    resourcePriority = '0',
    idPrefix = 'tmtalk',
    statusTitle = 'Talk',
    messageId = Math.round(Math.random() * 10000) + 100000,
    messageIds = {},
    lazyMessages = [],
    requestRoomInfo = {},
    connectionManager = null,
    onlineStatusId = 1,
    offlineStatusId = 0,
    newStatus = null,
    reconnectionAttempts = 5,
    reconnectTimeout = 2000,
    reconnectCount = 0;
    statuses = [
      {id : 0, name : 'Offline', show : 'offline', title : 'Offline', isCurrent : true, className : 'offline'},
      {id : 1, name : 'Online', show : 'online', title : 'Online', isCurrent : false, className : 'online'},
      {id : 2, name : 'Away', show : 'away', title : 'Away', isCurrent : false, className : 'away'},
      {id : 3, name : 'Not Available', show : 'xa', title : 'Not Available', isCurrent : false, className : 'xa'}
    ],
    customEvents = {
      // before attempt to connect to server
      initConnection : 'oninitconnection',
      // attempt to connect to server
      connecting : 'onconnecting',
      // before attempt to disconnect from the server
      disconnecting : 'ondisconnecting',
      // after conected
      connected : 'onconnected',
      // after disconnected
      disconnected : 'ondisconnected',
      // connection failed
      connectingFailed : 'onconnectingfailed',
      // change status
      updateStatus : 'onupdatestatus',
      // join to conference
      enteringRoom : 'onenteringroom',
      // create conference
      creatingRoom : 'oncreatingroom',
      // leave conference
      exitingRoom : 'onexitingroom',
      // remove conference (only owner)
      destroyingRoom : 'ondestroyingroom',
      // kicked occupant
      kickingOccupant : 'onkickingoccupant',
      // Retrieves Private Data
      retrievesData : 'onretrievesdata',
      // Retrieves Command
      retrievesCommand : 'onretrievescommand',
      // Retrieves Features
      retrievesFeatures : 'onretrievesfeatures',
      // Retrieves DiscoItems
      retrievesDiscoItems : 'onretrievesdiscoitems'
    },
    eventManager = new CustomEvent(customEvents);
  var getMessageId = function () {
    messageId++;
    return idPrefix + messageId.toString(16);
  };

  var getXHR = (function () {
    if (window.XMLHttpRequest) {
      return function () {
        try {
          xhr = new XMLHttpRequest();
          if (xhr.overrideMimeType) {
            xhr.overrideMimeType("text/xml");
          }
          return xhr;
        } catch (err) {
          return null;
        }
      };
    }
    return function () {
      try {
        return new ActiveXObject('Msxml2.XMLHTTP');
      } catch (err1) {
        try {
          return new ActiveXObject('Microsoft.XMLHTTP');
        } catch (err2) {
          return null;      
        }
      }
    };
  })();

  var conflict;
  var init = function (servicepath, jid, priority, inactivity) {
    if (isInit === true) {
      return undefined;
    }
    this.conflict = false;
    isInit = true;
    // TODO
    if (typeof jid === 'string') {
        JID = jid;
    }
    if (typeof priority === 'string') {
      resourcePriority = priority;
    }
    if (typeof inactivity === 'string' && isFinite(+inactivity)) {
      clientInactivity = +inactivity;
    }
    if (typeof servicepath === 'string') {
      servicePath = servicepath;
      connectionManager = new Strophe.Connection(servicePath);
    }

    if (ASC.TMTalk.TalkResource.hasOwnProperty('statusTitles') && typeof ASC.TMTalk.TalkResource.StatusTitles === 'object') {
      var
        status = null,
        statusesInd = statuses.length;
      while (statusesInd--) {
        status = statuses[statusesInd];
        if (ASC.TMTalk.TalkResource.StatusTitles.hasOwnProperty(status.show)) {
            statuses[statusesInd].title = ASC.TMTalk.TalkResource.StatusTitles[status.show];
        }
      }
    }
  };

  var bind = function (eventName, handler, params) {
    return eventManager.bind(eventName, handler, params);
  };

  var unbind = function (handlerId) {
    return eventManager.unbind(handlerId);
  };

  var addIqHandler = function (ns, handler) {
    if (typeof ns === 'string' && typeof handler === 'function') {
      connectionManager.addHandler(handler, ns, 'iq', null, null, null);
    }
  };

  var sendIqMessage = function (iq) {
    if (connectionManager !== null && typeof iq === 'object') {
      connectionManager.send(iq);
    }
  };

  var changeStatus = function (statusId, show, title, priority) {
    var pres = $pres({from : connectionManager.jid});
    if (statusId !== onlineStatusId) {
      pres.c('show').t(show).up();
    }
    connectionManager.send(
      pres
        .c('status').t(title).up()
        .c('priority').t(priority).up()
        .c('c', {xmlns : Strophe.NS.CAPS, ver : '2.3', node : Strophe.NS.CAPS})
        .tree()
    );
  };

  var connect = function (password, authtoken) {
    if (isInit === false) {
      throw 'uninit connectionManager';
    }
    if (typeof password === 'string' && password) {
      eventManager.call(customEvents.initConnection);
      connectionManager.connect(JID, password, onConnect, clientInactivity, wait, hold);
      return undefined;
    }
    if (typeof authtoken === 'string' && authtoken) {
      eventManager.call(customEvents.initConnection);
      connectionManager.connect1(JID, authtoken, onConnect, clientInactivity, wait, hold);

      return undefined;
    }
    JabberClient.GetAuthToken(function (response) {
        if (response && typeof response.value === 'string' && response.value) {
            ASC.TMTalk.connectionManager.connect(null, response.value);
        } else {
            eventManager.call(customEvents.connecting);
            setTimeout(function () {
                ASC.TMTalk.connectionManager.status(Strophe.Status.CONNECTING);
            }, reconnectTimeout);
        }
    });
  };

  var disconnect = function () {
    if (isConnected) {
      connectionManager.disconnect();
    }
  };

  var terminate = function () {
      if (isConnected) {
          var body = $build("body", {rid : connectionManager.rid++, sid : connectionManager.sid, xmlns: Strophe.NS.HTTPBIND, type : "terminate"});
          if (connectionManager.authenticated) {
              body.c("presence", {xmlns : Strophe.NS.CLIENT, type : "unavailable"});
          }
          var data = Strophe.serialize(body.tree());
          try {
              if (window.opener) {
                  window.opener.ASC.Controls.JabberClient.terminate(data, connectionManager.service);
              } else {
                  var xhr = getXHR();
                  xhr.onreadystatechange = function () {};
                  xhr.open("POST", connectionManager.service, true);
                  xhr.send(data);
              }
          } catch (e) {
              console.error(e.message);
          }
      }
  };

  var connected = function () {
    return isConnected;
  };

  var setStatus = function (status) {
    if (typeof status !== 'undefined') {
      status = isFinite(+status) ? +status : status;
      newStatus = null;
      var statusInd = 0;
      statusInd = statuses.length;
      while (statusInd--) {
        if ((statuses[statusInd].id === status || statuses[statusInd].name === status)) {
          newStatus = statuses[statusInd];
          break;
        }
      }
      if (newStatus === null) {
        return undefined;
      }

      if (!isConnected && newStatus.id !== offlineStatusId) {
        connect();
        return undefined;
      }
      if (isConnected && newStatus.id === offlineStatusId) {
        disconnect();
        return undefined;
      }

      if (newStatus.id !== offlineStatusId) {
        changeStatus(newStatus.id, newStatus.show, statusTitle, resourcePriority);
      }
      statusInd = statuses.length;
      var wasOffline = false;
      while (statusInd--) {
        if (statuses[statusInd].isCurrent && statuses[statusInd].id === offlineStatusId) {
          wasOffline = true;
        }
        statuses[statusInd].isCurrent = statuses[statusInd].id === newStatus.id;
      }
      eventManager.call(customEvents.updateStatus, window, [newStatus, wasOffline]);
      newStatus = null;
      return undefined;
    }
    var statusInd = statuses.length;
    while (statusInd--) {
      if (statuses[statusInd].isCurrent) {
        return statuses[statusInd];
      }
    }
    return null;
  };

  var onConnect = function (status) {
    switch (status) {
      case Strophe.Status.DISCONNECTING :
        eventManager.call(customEvents.disconnecting);
        break;
      case Strophe.Status.DISCONNECTED :
        isLoaded = false;
        isConnected = false;
        setStatus(offlineStatusId);
        ASC.TMTalk.mucManager.closeRooms();
        ASC.TMTalk.contactsManager.clearOnlineContacts();
        eventManager.call(customEvents.disconnected);
        break;
      case Strophe.Status.CONNECTING :
        eventManager.call(customEvents.connecting);
        break;
      case Strophe.Status.CONNECTED :
        connectionManager.addHandler(handleIq, null, 'iq', null, null, null);
        connectionManager.addHandler(handleMessage, null, 'message',  null, null, null);
        connectionManager.addHandler(handlePresence, null, 'presence', null, null, null);

        connectionManager.addHandler(handleIqVcard, Strophe.NS.VCARD, 'iq', null, null, null);
        connectionManager.addHandler(handleIqRoster, Strophe.NS.ROSTER, 'iq', null, null, null);
        connectionManager.addHandler(handleIqVersion, Strophe.NS.VERSION, 'iq', null, null, null);
        connectionManager.addHandler(handleIqHistory, Strophe.NS.HISTORY, 'iq', null, null, null);
        connectionManager.addHandler(handleIqPrivate, Strophe.NS.PRIVATE, 'iq', null, null, null);
        connectionManager.addHandler(handleIqCommands, Strophe.NS.COMMANDS, 'iq', null, null, null);
        connectionManager.addHandler(handleIqMucOwner, Strophe.NS.MUC_OWNER, 'iq', null, null, null);
        connectionManager.addHandler(handleIqDiscoInfo, Strophe.NS.DISCO_INFO, 'iq', null, null, null);
        connectionManager.addHandler(handlerIqDiscoItems, Strophe.NS.DISCO_ITEMS, 'iq', null, null, null);

        connectionManager.send($iq({id : getMessageId(), from : connectionManager.jid, type : 'get'}).c('query', {xmlns : Strophe.NS.ROSTER}).tree());
        connectionManager.send($iq({id : getMessageId(), from : connectionManager.jid, to : connectionManager.domain, type : 'get'}).c('query', {xmlns : Strophe.NS.DISCO_INFO}).tree());

        isConnected = true;
        setStatus(newStatus.id);
        eventManager.call(customEvents.connected);
        break;
      case Strophe.Status.CONNFAIL :
        eventManager.call(customEvents.connectingFailed);
        break;
    }
  };

  // strophe callback functions.
  // return only true.
  var handlePresence = function (presence) {
    //console.log('handlePresence', presence);
    var x = presence.getElementsByTagName('x');
    if (x.length === 0) {
      x = Strophe.getElementsByTagName(presence, 'x');
    }
    if (x.length > 0 && x[0].getAttribute('xmlns') === Strophe.NS.MUC_USER) {
      // message from conference
      var
        items = null,
        statuses = null,
        destroynodes = null,
        type = presence.getAttribute('type');

      destroynodes = presence.getElementsByTagName('destroy');
      if (destroynodes.length === 0) {
        destroynodes = Strophe.getElementsByTagName(presence, 'destroy');
      }

      items = presence.getElementsByTagName('item');
      if (items.length === 0) {
        items = Strophe.getElementsByTagName(presence, 'item');
      }

      statuses = presence.getElementsByTagName('status');
      if (statuses.length === 0) {
        statuses = Strophe.getElementsByTagName(presence, 'status');
      }

      if (destroynodes.length > 0) {
        eventManager.call(customEvents.destroyingRoom, window, [presence]);
      }

      // get the presence's status
      // 201 need processed before 110
      var statusesInd = statuses.length;
      while (statusesInd--) {
        if (statuses[statusesInd].getAttribute('code') === '201') {
          eventManager.call(customEvents.creatingRoom, window, [presence]);
          break;
        }
      }
      statusesInd = statuses.length;
      while (statusesInd--) {
        if (statuses[statusesInd].getAttribute('code') === '110') {
          eventManager.call(customEvents.enteringRoom, window, [presence]);
          break;
        }
      }
      statusesInd = statuses.length;
      while (statusesInd--) {
        if (statuses[statusesInd].getAttribute('code') === '307') {
          eventManager.call(customEvents.kickingOccupant, window, [presence]);
          break;
        }
      }

      if (items.length > 0 && destroynodes.length === 0) {
        if (type === 'unavailable') {
          if (ASC.TMTalk.mucManager.isMe(presence.getAttribute('from'))) {
            eventManager.call(customEvents.exitingRoom, window, [presence]);
          } else {
            ASC.TMTalk.mucManager.leftContact(presence);
          }
        } else {
          ASC.TMTalk.mucManager.comeContact(presence);
        }
      }
      return true;
    }
    // message from contact
    if (presence.getAttribute('type') === 'unavailable') {
      ASC.TMTalk.contactsManager.leftContact(presence);
    } else {
      ASC.TMTalk.contactsManager.comeContact(presence);
    }
    return true;
  };

  var handleOfflineMessages = function (messages) {
    if (isLoaded === false) {
      return true;
    }
    var
      type = null,
      body = null,
      delay = null,
      message = null,
      messagesInd = 0;
    messagesInd = messages.length;
    while (messagesInd--) {
      message = messages[messagesInd];
      type = message.getAttribute('type');
      switch (type) {
        case 'chat' :
          delay = message.getElementsByTagName('delay');
          if (delay.length === 0) {
            delay = Strophe.getElementsByTagName(message, 'delay');
          }
          delay = delay.length > 0 ? delay[0] : null;

          body = message.getElementsByTagName('body');
          if (body.length === 0) {
            body = Strophe.getElementsByTagName(message, 'body');
          }
          body = body.length > 0 ? body[0] : null;

          if (delay === null || body === null) {
            messages.splice(messagesInd, 1);
          }
          break;
      }
    }
    ASC.TMTalk.messagesManager.recvOfflineMessagesFromChat(messages);
    return true;
  };

  var handleMessage = function (message) {
    var
      id = message.getAttribute('id'),
      from = message.getAttribute('from');

    // message[id] unique test
    if (id && from) {
      if (!messageIds.hasOwnProperty(from)) {
        messageIds[from] = {};
      }
      /*if (messageIds[from].hasOwnProperty(id)) {
        return true;
      }*/
      messageIds[from][id] = true;
    }

    // lazy messages
    if (isLoaded === false) {
      lazyMessages.push(message);
      return true;
    }

    //console.log('handleMessage', message);
    var type = message.getAttribute('type');
    type = typeof type === 'string' ? type.toLowerCase() : null;
    switch (type) {
      case 'headline' :
        ASC.TMTalk.messagesManager.recvMessageFromChat(message);
        break;
      case 'chat' :
        var composing = null;
        composing = message.getElementsByTagName('composing');
        if (composing.length === 0) {
          composing = Strophe.getElementsByTagName(message, 'composing');
        }
        composing = composing.length > 0 ? composing[0] : null;
        if (composing !== null) {
          ASC.TMTalk.messagesManager.composingMessageFromChat(message);
        }

        var paused = null;
        paused = message.getElementsByTagName('paused');
        if (paused.length === 0) {
          paused = Strophe.getElementsByTagName(message, 'paused');
        }
        if (paused.length === 0) {
          paused = message.getElementsByTagName('active');
          if (paused.length === 0) {
            paused = Strophe.getElementsByTagName(message, 'active');
          }
        }
        paused = paused.length > 0 ? paused[0] : null;
        if (paused !== null) {
          ASC.TMTalk.messagesManager.pausedMessageFromChat(message);
        }

        var delay = null;
        delay = message.getElementsByTagName('delay');
        if (delay.length === 0) {
          delay = Strophe.getElementsByTagName(message, 'delay');
        }
        delay = delay.length > 0 ? delay[0] : null;

        var body = null;
        body = message.getElementsByTagName('body');
        if (body.length === 0) {
          body = Strophe.getElementsByTagName(message, 'body');
        }
        body = body.length > 0 ? body[0] : null;
        if (body !== null) {
          ASC.TMTalk.messagesManager.recvMessageFromChat(message, delay !== null);
        }

        var event = null;
        event = message.getElementsByTagName('x');
        if (event.length === 0) {
          event = Strophe.getElementsByTagName(message, 'x');
        }
        event = event.length > 0 ? event[0] : null;
        if (event !== null && event.getAttribute('xmlns') !== 'jabber:x:event') {
          event === null;
        }

        if (event !== null && composing === null && paused === null && body === null) {
          ASC.TMTalk.messagesManager.pausedMessageFromChat(message);
        }
        break;
      case 'groupchat' :
        var
          from = message.getAttribute('from'),
          nodes = null;
        nodes = message.getElementsByTagName('subject');
        if (nodes.length === 0) {
          nodes = Strophe.getElementsByTagName(message, 'subject');
        }
        if (from && nodes.length > 0) {
          from = from.substring(0, from.indexOf('/')).toLowerCase();
          if (from.length > 0) {
            ASC.TMTalk.mucManager.updateSubject(from, nodes.length > 0 ? ASC.TMTalk.dom.getContent(nodes[0]) : '');
          }
          break;
        }
        ASC.TMTalk.messagesManager.recvMessageFromConference(message);
        break;
      default :
        // recv invite
        var invite = null;
        invite = message.getElementsByTagName('invite');
        if (invite.length === 0) {
          invite = Strophe.getElementsByTagName(message, 'invite');
        }
        invite = invite.length > 0 ? invite[0] : null;
        if (invite !== null) {
          var
            inviterjid = invite.getAttribute('from'),
            roomjid = message.getAttribute('from'),
            reason = '',
            nodes = null;
          nodes = invite.getElementsByTagName('reason');
          if (nodes.length === 0) {
            nodes = Strophe.getElementsByTagName(invite, 'reason');
          }
          reason = nodes.length > 0 ? ASC.TMTalk.dom.getContent(nodes[0]) : '';
          if (roomjid && inviterjid) {
            ASC.TMTalk.mucManager.recvInvite(roomjid, inviterjid, reason);
          }
          break;
        }

        // get decline
        var decline = null;
        decline = message.getElementsByTagName('invite');
        if (decline.length === 0) {
          decline = Strophe.getElementsByTagName(message, 'invite');
        }
        decline = decline.length > 0 ? decline[0] : null;
        if (decline !== null && decline.getAttribute('from') === connectionManager.jid) {
          var
            deviatorjid = message.getAttribute('from'),
            reason = '',
            nodes = null;
          nodes = invite.getElementsByTagName('reason');
          if (nodes.length === 0) {
            nodes = Strophe.getElementsByTagName(invite, 'reason');
          }
          reason = nodes.length > 0 ? ASC.TMTalk.dom.getContent(nodes[0]) : '';
          if (deviatorjid) {
            //console.log(deviatorjid, ' decline invite');
          }
          break;
        }

        // get multicastmessage
        var addresses = null;
        addresses = message.getElementsByTagName('addresses');
        if (addresses.length === 0) {
          addresses = Strophe.getElementsByTagName(message, 'addresses');
        }
        addresses = addresses.length > 0 ? addresses[0] : null;
        if (addresses !== null) {
          var body = null;
          body = message.getElementsByTagName('body');
          if (body.length === 0) {
            body = Strophe.getElementsByTagName(message, 'body');
          }
          body = body.length > 0 ? body[0] : null;
          if (body !== null) {
            ASC.TMTalk.messagesManager.recvMulticastMessage(message);
          }
        }

        var
          from = message.getAttribute('from'),
          nodes = null;
        nodes = message.getElementsByTagName('subject');
        if (nodes.length === 0) {
          nodes = Strophe.getElementsByTagName(message, 'subject');
        }
        if (from && nodes.length > 0) {
          ASC.TMTalk.mucManager.updateSubject(from, nodes.length > 0 ? ASC.TMTalk.dom.getContent(nodes[0]) : '');
        }
    }
    return true;
  };

  var handleIq = function (iq) {
    //console.log('handleIq', iq);
    return true;
  };

  var handleIqVersion = function (iq) {
    //console.log('handleIqVersion', iq);
    switch (iq.getAttribute('type').toLowerCase()) {
      case 'get' :
        connectionManager.send(
          $iq({id : iq.getAttribute('id'), from : iq.getAttribute('to'), to : iq.getAttribute('from'), type : 'result'})
            .c('query', {xmlns : Strophe.NS.VERSION})
            .c('name').t('Talk').up()
            .c('version').t(' ').up()
            .c('os').t(navigator.userAgent)
            .tree()
        );
        break;
    }
    return true;
  };

  var handleIqMucOwner = function (iq) {
    //console.log('handleIqMucOwner', iq);
    switch (iq.getAttribute('type').toLowerCase()) {
      case 'get' :
        break;
      case 'result' :
        var
          from = iq.getAttribute('from'),
          fields = null;
        fields = iq.getElementsByTagName('field');
        if (fields.length === 0) {
          fields = Strophe.getElementsByTagName(iq, 'field');
        }
        if (fields.length > 0) {
          ASC.TMTalk.mucManager.sendConfigurationForm(from, fields);
        }
        break;
    }
    return true;
  };

  var handleIqDiscoInfo = function (iq) {
    //console.log('handleIqDiscoInfo', iq);
    switch (iq.getAttribute('type').toLowerCase()) {
      case 'get' :
        connectionManager.send(
          $iq({id : iq.getAttribute('id'), from : iq.getAttribute('to'), to : iq.getAttribute('from'), type : 'result'})
            .c('query', {xmlns : Strophe.NS.DISCO_INFO})
            .c('feature', {'var' : Strophe.NS.VERSION}).up()
            .c('feature', {'var' : Strophe.NS.CONFERENCE}).up()
            .c('feature', {'var' : Strophe.NS.CHATSTATES}).up()
            .c('feature', {'var' : Strophe.NS.DISCO_INFO}).up()
            .c('feature', {'var' : Strophe.NS.DISCO_ITEMS}).up()
            .c('feature', {'var' : Strophe.NS.MUC}).up()
            .c('feature', {'var' : Strophe.NS.MUC_USER}).up()
            .tree()
        );
        break;
      case 'result' :
        var
          features = null,
          from = iq.getAttribute('from');

        features = iq.getElementsByTagName('feature');
        if (features.length === 0) {
          features = Strophe.getElementsByTagName(iq, 'feature');
        }
        if (from) {
          eventManager.call(customEvents.retrievesFeatures, window, [from, features]);
        }
        break;
    }
    return true;
  };

  var handlerIqDiscoItems = function (iq) {
    //console.log('handlerIqDiscoItems', iq);
    switch (iq.getAttribute('type').toLowerCase()) {
      case 'get' :
        connectionManager.send(
          $iq({id : iq.getAttribute('id'), type : 'result', to : iq.getAttribute('from')})
            .c('query', {xmlns : Strophe.NS.DISCO_ITEMS})
            .tree()
        );
        break;
      case 'result' :
        var
          item = null,
          items = null,
          itemsInd = 0,
          roomjid = '',
          isDiscoItemsRequest = true,
          from = iq.getAttribute('from');

        items = iq.getElementsByTagName('item');
        if (items.length === 0) {
          items = Strophe.getElementsByTagName(iq, 'item');
        }
        isDiscoItemsRequest = true;
        itemsInd = items.length;
        while (itemsInd--) {
          item = items[itemsInd];
          roomjid = item.getAttribute('jid');
          for (var fld in requestRoomInfo) {
            if (requestRoomInfo.hasOwnProperty(fld)) {
              if (fld === roomjid) {
                delete requestRoomInfo[fld];
                ASC.TMTalk.mucManager.getRoomInfo(roomjid, item);
                isDiscoItemsRequest = false;
              }
            }
          }
        }
        if (isDiscoItemsRequest && from) {
          eventManager.call(customEvents.retrievesDiscoItems, window, [from, items]);
        }
        break;
    }
    return true;
  };

  var handleIqVcard = function (iq) {
    //console.log('handleIqVcard', iq);
    if (iq.getAttribute('type').toLowerCase() === 'result') {
      if (iq.getAttribute('from') === connectionManager.jid) {
        isLoaded = true;
        if (lazyMessages.length > 0) {
          //for (var i = 0, n = lazyMessages.length; i < n; i++) {
          //  handleMessage(lazyMessages[i]);
          //}
          handleOfflineMessages(lazyMessages);
          lazyMessages = [];
        }
      }
      ASC.TMTalk.contactsManager.updateCard(iq);
    }
    return true;
  };

  var handleIqRoster = function (iq) {
    //console.log('handleIqRoster', iq);
    if (iq.getAttribute('type').toLowerCase() === 'result') {
      var items = iq.getElementsByTagName('item');
      if (items.length === 0) {
        items = Strophe.getElementsByTagName(iq, 'item');
      }
      ASC.TMTalk.contactsManager.fillContacts(items);
      connectionManager.send(
        $iq({id : getMessageId(), from : connectionManager.jid, to : connectionManager.jid, type : 'get'})
          .c('vCard', {xmlns : Strophe.NS.VCARD})
          .tree()
      );
    }
    try {
        var opener = window.opener;
        if (opener && opener.SmallChat) {
            opener.SmallChat.openContacts();
        }
    } catch (e) {
        console.error(e.message);
    }

    return true;
  };

  var handleIqHistory = function (iq) {
    //console.log('handleIqHistory', iq);
    if (iq.getAttribute('type').toLowerCase() === 'result') {
      var query = null;
      var query = iq.getElementsByTagName('query');
      if (query.length === 0) {
        query = Strophe.getElementsByTagName(iq, 'query');
      }
      query = query.length > 0 ? query[0] : null;
      if (query === null) {
        return undefined;
      }
      if (query.getAttribute('count') || query.getAttribute('text')) {
          var startIndex = query.getAttribute('startindex');

          ASC.TMTalk.messagesManager.loadHistory(iq, ASC.TMTalk.Config.fullText && startIndex == null || parseInt(startIndex) === 0, query.getAttribute('text'));
      }
      if (query.getAttribute('from') && query.getAttribute('to')) {
        ASC.TMTalk.messagesManager.loadHistoryByFilter(iq, query.getAttribute('from'), query.getAttribute('to'));
      }
    }
    return true;
  };

  var handleIqPrivate = function (iq) {
    //console.log('handleIqPrivate', iq);
    if (iq.getAttribute('type').toLowerCase() === 'result') {
      var storages = iq.getElementsByTagName('tmtalk');
      if (storages.length === 0) {
        storages = Strophe.getElementsByTagName(iq, 'tmtalk');
      }
      if (storages.length > 0) {
        eventManager.call(customEvents.retrievesData, window, [storages]);
      }
    }
    return true;
  };

  var handleIqCommands = function (iq) {
    //console.log('handleIqCommands', iq);
    switch (iq.getAttribute('type').toLowerCase()) {
      case 'set' :
        var
          from = iq.getAttribute('from'),
          node = null,
          commands = null
          commandsInd = 0;
        commands = Strophe.getElementsByTagName(iq, 'command');
        if (commands.length === 0) {
          commands = Strophe.getElementsByTagName(iq, 'command');
        }

        commandsInd = commands.length;
        while (commandsInd--) {
          node = commands[commandsInd].getAttribute('node');
          if (node) {
            eventManager.call(customEvents.retrievesCommand, window, [from, node]);
          }
        }
        break;
    }
    return true;
  };

  var creatingRoom = function (jid) {
    connectionManager.send(
      $pres({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'set'})
        .c('query', {xmlns : Strophe.NS.MUC_USER})
        .tree()
    );
  };

  var enteringRoom = function (jid) {
    connectionManager.send(
      $pres({from : connectionManager.jid, to : jid})
        .c('priority').t(resourcePriority)
        .tree()
    );
  };

  var exitingRoom = function (jid) {
    connectionManager.send(
      $pres({from : connectionManager.jid, to : jid, type : 'unavailable'})
        .tree()
      );
  };
  var savePushEndpoint = function (username, endpoint, browser) {

      connectionManager.send(
          $iq({ username: username, endpoint: endpoint, browser: browser, type: 'notification' })
          .c('query', { xmlns: Strophe.NS.MUC_ADMIN })
          .tree()
      );
  };
  var kickingOccupant = function (jid, nick, reason) {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'set'})
        .c('query', {xmlns : Strophe.NS.MUC_ADMIN})
        .c('item', {nick : nick, role : 'none'})
        .c('reason').t(reason)
        .tree()
    );
  };

  var destroyingRoom = function (jid, reason) {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'set'})
        .c('query', {xmlns : Strophe.NS.MUC_OWNER})
        .c('destroy', {jid : jid})
        .c('reason').t(reason)
        .tree()
    );
  };

  var getConfigurationForm = function (jid) {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'set'})
        .c('query', {xmlns : Strophe.NS.MUC_OWNER})
        .tree()
    );
  };

  var sendConfigurationForm = function (jid, fields) {
    var
      iq = null,
      field = null,
      fieldsInd = 0;
    iq =  $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'set'})
            .c('query', {xmlns : Strophe.NS.MUC_OWNER})
            .c('x', {xmlns : Strophe.NS.DATA, type : 'submit'});
    fieldsInd = fields.length;
    while (fieldsInd--) {
      field = fields[fieldsInd];
      iq.c('field', {'var' : field.name}).c('value').t(field.value).up().up();
    }
    connectionManager.send(iq.tree());
  };

  var sendMailingLists = function (xmlns, items) {
    var
      iq = null,
      item = null,
      itemsInd = items.length;

    iq =  $iq({id : getMessageId(), from : connectionManager.jid, type : 'set'})
            .c('query', {xmlns : Strophe.NS.PRIVATE})
              .c('tmtalk', {xmlns : xmlns});
    while (itemsInd--) {
      item = items[itemsInd];
      if (item.jid !== null) {
        iq.c('item', {jid : item.jid}).c('list').t(item.listname).up().up();
      } else {
        iq.c('item').c('list').t(item.listname).up().up();
      }
    }
    connectionManager.send(iq.tree());
  };

  var sendInvite = function (discoitem, roomjid, contactjid, reason) {
    connectionManager.send(
      $msg({id : getMessageId(), from : connectionManager.jid, to : roomjid})
        .c('x', {xmlns : Strophe.NS.MUC_USER})
        .c('invite', {to : contactjid})
        .c('reason').t(reason)
        .tree()
    );
  };

  var composingMessage = function (jid) {
    connectionManager.send(
      $msg({ id: getMessageId(), from: connectionManager.jid, to: jid, type: 'chat' })
        .c('composing', {xmlns : Strophe.NS.CHATSTATES})
        .tree()
    );
  };

  var pausedMessage = function (jid) {
    connectionManager.send(
      $msg({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'chat'})
        .c('paused', {xmlns : Strophe.NS.CHATSTATES})
        .tree()
    );
  };

  var sendMulticastMessage = function (domain, jids, body) {
    var
      msg = null,
      jidsInd = jids.length;
    msg = $msg({id : getMessageId(), from : connectionManager.jid, to : domain})
            .c('addresses', {xmlns : Strophe.NS.ADDRESS});
    while (jidsInd--) {
      msg.c('address', {type : jidsInd === 0 ? 'to' : 'cc', jid : jids[jidsInd]}).up();
    }
    msg.up().c('body').t(body);
    connectionManager.send(msg.tree());
  };

  var sendMessage = function (jid, body, type) {
    var userName = escape(ASC.TMTalk.contactsManager.getContactName());
    connectionManager.send(
      $msg({ id: getMessageId(), from: connectionManager.jid, to: jid, username: userName, type: type })
        .c('active', {xmlns : Strophe.NS.CHATSTATES}).up()
        .c('body').t(body).up()
        .tree()
    );
  };

  var getRoomInfo = function (jid) {
    var discoitemJid = jid.substring(jid.indexOf('@') + 1);
    requestRoomInfo[jid] = {
      jid           : jid,
      discoitemJid  : discoitemJid
    };
    getDiscoItems(discoitemJid);
  };

  var sendCommand = function () {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : connectionManager.jid, type : 'set'})
        .c('command', {xmlns : Strophe.NS.COMMANDS, node : 'tm:open-chat'})
        .tree()
    );
  };

  var retrievesData = function (xmlns) {
    connectionManager.send(
      $iq({id : getMessageId(), type : 'get'})
       .c('query', {xmlns : Strophe.NS.PRIVATE})
          .c('tmtalk', {xmlns : xmlns})
          .tree()
    );
  };

  var getMessagesByDate = function (jid, from, to) {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'get'})
        .c('query', {xmlns : Strophe.NS.HISTORY, from : from, to : to})
        .tree()
    );
  };

  var getMessagesByNumber = function (jid, count) {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'get'})
        .c('query', {xmlns : Strophe.NS.HISTORY, count : count})
        .tree()
    );
  };
  var getMessagesByRange = function(jid, startindex, count, text) {
      connectionManager.send(
          $iq({ id: getMessageId(), from: connectionManager.jid, to: jid, type: 'get' })
          .c('query', { xmlns: Strophe.NS.HISTORY, count: count, startindex: startindex, text: Encoder.htmlEncode(text) })
          .tree()
      );
  };
    
  var clearUnreadMessage = function (jid, to) {
      connectionManager.send(
          $iq({ id: getMessageId(), from: connectionManager.jid, to: to, type: 'get' })
          .c('query', { xmlns: 'urn:xmpp:chat-markers:0'})
          .tree()
      );
  };

  var searchMessage = function (jid, text) {
      connectionManager.send(
        $iq({ id: getMessageId(), from: connectionManager.jid, to: jid, type: 'get' })
          .c('query', { xmlns: Strophe.NS.HISTORY, text: Encoder.htmlEncode(text) })
          .tree()
      );
  };

  var setSubject = function (jid, subject) {
    connectionManager.send(
      $msg({id : getMessageId(), to : jid, type : 'groupchat'})
        .c('subject').t(subject).up()
        .tree()
    );
  };

  var getDiscoInfo = function (jid) {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'get'})
        .c('query', {xmlns : Strophe.NS.DISCO_INFO})
        .tree()
    );
  };

  var getDiscoItems = function (jid) {
    connectionManager.send(
      $iq({id : getMessageId(), from : connectionManager.jid, to : jid, type : 'get'})
        .c('query', {xmlns : Strophe.NS.DISCO_ITEMS})
        .tree()
    );
  };

  var getJid = function () {
    return Strophe.getBareJidFromJid(connectionManager.jid);
  };
  var getJID = function () {
      return JID;
  };
  var getDomain = function () {
    return connectionManager.domain;
  };

  var getUsername = function () {
    return Strophe.getNodeFromJid(connectionManager.jid);
  }

  return {
    init    : init,

    conflict: conflict,

    bind          : bind,
    unbind        : unbind,
    addIqHandler  : addIqHandler,
    sendIqMessage : sendIqMessage,

    status      : setStatus,
    connect     : connect,
    disconnect  : disconnect,
    terminate   : terminate,
    connected   : connected,

    events          : customEvents,
    statuses        : statuses,
    onlineStatusId  : onlineStatusId,
    offlineStatusId : offlineStatusId,

    creatingRoom          : creatingRoom,
    enteringRoom          : enteringRoom,
    exitingRoom           : exitingRoom,
    destroyingRoom        : destroyingRoom,
    getConfigurationForm  : getConfigurationForm,
    sendConfigurationForm : sendConfigurationForm,

    sendMailingLists  : sendMailingLists,

    kickingOccupant : kickingOccupant,

    sendInvite            : sendInvite,
    composingMessage      : composingMessage,
    pausedMessage         : pausedMessage,
    sendMulticastMessage  : sendMulticastMessage,
    sendMessage           : sendMessage,
    getRoomInfo           : getRoomInfo,
    sendCommand           : sendCommand,

    retrievesData : retrievesData,

    getMessagesByDate   : getMessagesByDate,
    getMessagesByNumber : getMessagesByNumber,
    getMessagesByRange: getMessagesByRange,
    clearUnreadMessage: clearUnreadMessage,

    searchMessage: searchMessage,

    setSubject  : setSubject,

    getDiscoInfo  : getDiscoInfo,
    getDiscoItems : getDiscoItems,

    getJid        : getJid,
    getDomain     : getDomain,
    getUsername: getUsername,

    getJID: getJID,

    savePushEndpoint: savePushEndpoint

  };
})();


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/Authorize/js/recaptchacontroller.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


;
var RecaptchaController = new function () {
    this.InitRecaptcha = function (datahl) {
        if (!datahl || typeof  datahl !== "string") {
            datahl = "en";
        }

        var script = document.createElement("script");
        script.type = "text/javascript";
        script.async = false;
        script.src = "https://www.recaptcha.net/recaptcha/api.js?hl=" + datahl;

        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(script, s);
    };
};

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/UserProfileEditControl.ascx.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Web.Core;
using ASC.Web.Core.Users;
using ASC.Web.Core.Utility;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

using Newtonsoft.Json;

using LdapMapping = ASC.ActiveDirectory.Base.Settings.LdapSettings.MappingFields;

namespace ASC.Web.Studio.UserControls.Users.UserProfile
{
    public partial class UserProfileEditControl : UserControl
    {
        protected class RoleUser
        {
            public string Class { get; set; }
            public string Title { get; set; }
        }

        #region Protected Fields

        protected bool IsPageEditProfileFlag;
        protected bool CurrentUserIsPeopleAdmin;
        protected bool CurrentUserIsMailAdmin;
        protected bool IsPersonal;
        protected bool IsTrial;
        protected string HelpLink;
        protected List<LdapMapping> LdapFields;

        protected UserInfo Profile;

        protected bool ProfileIsMe;
        protected bool ProfileIsOwner;
        protected bool ProfileIsAdmin;
        protected bool ProfileIsAnyModuleAdmin;
        protected bool ProfileIsVisitor;
        protected bool ProfileIsLdap;
        protected bool ProfileIsSso;
        protected bool ProfileHasAvatar;
        protected string ProfilePath;

        protected RoleUser ProfileRole;

        protected string FirstName;
        protected string LastName;
        protected string Email;
        protected string Phone;
        protected string Position;
        protected string Place;
        protected string Login;
        protected string Comment;
        protected string ProfileGender;
        protected string PhotoPath = UserPhotoManager.GetDefaultPhotoAbsoluteWebPath();
        protected string WorkFromDate = TenantUtil.DateTimeNow().ToString(DateTimeExtension.DateFormatPattern);
        protected string BirthDate;

        protected GroupInfo[] Departments;
        protected List<MyContact> SocContacts;
        protected List<MyContact> OtherContacts;

        protected string UserTypeSelectorClass;
        protected string UserTypeSelectorGuestItemClass;
        protected string UserTypeSelectorUserItemClass;

        protected int UserPasswordMinLength;
        protected bool UserPasswordUpperCase;
        protected bool UserPasswordDigits;
        protected bool UserPasswordSpecSymbols;

        protected string PageTitle = Resource.CreateNewProfile;
        protected string ButtonText = Resource.AddButton;

        #endregion

        #region Properies

        public static string Location
        {
            get { return "~/UserControls/Users/UserProfile/UserProfileEditControl.ascx"; }
        }

        protected string TariffPageLink { get; set; }

        protected bool IsFreeTariff { get; set; }

        #endregion

        #region events

        protected void Page_Load(object sender, EventArgs e)
        {
            TariffPageLink = TenantExtra.GetTariffPageLink();
            IsFreeTariff = TenantExtra.GetTenantQuota().Free;
            IsPageEditProfileFlag = (Request["action"] == "edit");
            CurrentUserIsPeopleAdmin = WebItemSecurity.IsProductAdministrator(WebItemManager.PeopleProductID, SecurityContext.CurrentAccount.ID);
            CurrentUserIsMailAdmin = WebItemSecurity.IsProductAdministrator(WebItemManager.MailProductID, SecurityContext.CurrentAccount.ID);
            IsPersonal = CoreContext.Configuration.Personal;
            IsTrial = TenantExtra.GetTenantQuota().Trial;
            HelpLink = CommonLinkUtility.GetHelpLink();
            LdapFields = ActiveDirectory.Base.Settings.LdapSettings.GetImportedFields;

            var profileHelper = new ProfileHelper(Request["user"]);

            InitProfile(profileHelper);

            CheckPermission();

            RegisterBodyScript();

            if (!IsPersonal)
            {
                InitUserTypeSelector();
            }

            InitPasswordSettings();

            if (IsPageEditProfileFlag)
            {
                PageTitle = Profile.DisplayUserName(false) + " - " + Resource.EditUserDialogTitle;
                ButtonText = Resource.SaveButton;

                InitProfileFields(profileHelper);

                RegisterStartupScript();
            }

            var photoControl = (LoadPhotoControl)LoadControl(LoadPhotoControl.Location);
            photoControl.User = IsPageEditProfileFlag ? Profile : null;
            loadPhotoWindow.Controls.Add(photoControl);

            Page.Title = HeaderStringHelper.GetPageTitle(PageTitle);
        }

        #endregion

        #region Private Methods

        private void InitProfile(ProfileHelper profileHelper)
        {
            Profile = profileHelper.UserInfo;

            ProfileIsMe = Profile.IsMe();
            ProfileIsOwner = Profile.IsOwner();
            ProfileIsAdmin = Profile.IsAdmin();

            ProfileIsAnyModuleAdmin = Profile.GetListAdminModules().Any();

            ProfileIsVisitor = Profile.IsVisitor();
            ProfileIsLdap = Profile.IsLDAP();
            ProfileIsSso = Profile.IsSSO();

            ProfileHasAvatar = Profile.HasAvatar();

            ProfilePath = CommonLinkUtility.GetUserProfile(Profile.ID);

            ProfileRole = GetRole();
        }

        private RoleUser GetRole()
        {
            if (ProfileIsOwner)
            {
                return new RoleUser
                {
                    Class = "owner",
                    Title = Resource.Owner
                };
            }
            if (ProfileIsAdmin || ProfileIsAnyModuleAdmin)
            {
                return new RoleUser
                {
                    Class = "admin",
                    Title = Resource.Administrator
                };
            }
            if (ProfileIsVisitor)
            {
                return new RoleUser
                {
                    Class = "guest",
                    Title = CustomNamingPeople.Substitute<Resource>("Guest").HtmlEncode()
                };
            }
            return null;
        }

        private void CheckPermission()
        {
            if (IsPageEditProfileFlag)
            {
                if (CurrentUserIsPeopleAdmin)
                {
                    if (ProfileIsOwner && !ProfileIsMe)
                        Response.Redirect("~/Products/People/", true);
                }
                else
                {
                    if (!ProfileIsMe)
                        Response.Redirect("~/Products/People/", true);
                }
            }
            else
            {
                if (!CurrentUserIsPeopleAdmin)
                    Response.Redirect("~/Products/People/", true);
            }
        }

        private void RegisterBodyScript()
        {
            Page.RegisterBodyScripts("~/js/third-party/xregexp.js", "~/UserControls/Users/UserProfile/js/userprofileeditcontrol.js")
                .RegisterStyle("~/UserControls/Users/UserProfile/css/profileeditcontrol_style.less");
        }

        public bool CanAddVisitor()
        {
            return CoreContext.Configuration.Standalone || TenantStatisticsProvider.GetVisitorsCount() < TenantExtra.GetTenantQuota().ActiveUsers * Constants.CoefficientOfVisitors;
        }

        private void InitUserTypeSelector()
        {
            var canAddUser = TenantStatisticsProvider.GetUsersCount() < TenantExtra.GetTenantQuota().ActiveUsers;

            var canEditType = SecurityContext.CheckPermissions(Constants.Action_AddRemoveUser) &&
                              (!(ProfileIsAdmin || ProfileIsAnyModuleAdmin) || !IsPageEditProfileFlag);

            var isVisitorType = (ProfileIsMe && !IsPageEditProfileFlag) ? Request["type"] == "guest" : ProfileIsVisitor;

            if (canAddUser)
            {
                UserTypeSelectorUserItemClass = isVisitorType ? "" : "active";
            }
            else
            {
                UserTypeSelectorUserItemClass = "disabled";
            }
            if (CanAddVisitor())
            {
                UserTypeSelectorGuestItemClass = isVisitorType ? "active" : "";
            }
            else
            {
                UserTypeSelectorGuestItemClass = "disabled";
            }
            if (canEditType)
            {
                UserTypeSelectorClass = "";
            }
            else
            {
                UserTypeSelectorClass = "disabled";
            }

            if (IsPageEditProfileFlag)
            {
                if (isVisitorType)
                {
                    UserTypeSelectorGuestItemClass = "active";
                }
                else
                {
                    UserTypeSelectorUserItemClass = "active";
                }
            }

        }

        private void InitPasswordSettings()
        {
            var passwordSettings = PasswordSettings.Load();

            UserPasswordMinLength = passwordSettings.MinLength;
            UserPasswordDigits = passwordSettings.Digits;
            UserPasswordSpecSymbols = passwordSettings.SpecSymbols;
            UserPasswordUpperCase = passwordSettings.UpperCase;
        }

        private void InitProfileFields(ProfileHelper profileHelper)
        {
            FirstName = Profile.FirstName.HtmlEncode();
            LastName = Profile.LastName.HtmlEncode();
            Email = Profile.Email.HtmlEncode();
            Phone = Profile.MobilePhone.HtmlEncode();
            Position = Profile.Title.HtmlEncode();
            Place = Profile.Location.HtmlEncode();
            Login = Profile.UserName.HtmlEncode();
            Comment = Profile.Notes.HtmlEncode();
            ProfileGender = Profile.Sex.HasValue ? Profile.Sex.Value ? "1" : "0" : "-1";
            PhotoPath = UserPhotoManager.GetMaxPhotoURL(Profile.ID);
            WorkFromDate = Profile.WorkFromDate.HasValue ? Profile.WorkFromDate.Value.ToShortDateString() : "";
            BirthDate = Profile.BirthDate.HasValue ? Profile.BirthDate.Value.ToShortDateString() : "";
            Departments = CoreContext.UserManager.GetUserGroups(Profile.ID);

            SocContacts = profileHelper.Contacts;

            OtherContacts = new List<MyContact>();
            OtherContacts.AddRange(profileHelper.Emails);
            OtherContacts.AddRange(profileHelper.Messengers);
            OtherContacts.AddRange(profileHelper.Phones);
        }

        private void RegisterStartupScript()
        {
            var script =
                    String.Format(
                        @"<script type='text/javascript'>
                                    var departmentsList = {0},
                                        socContacts = {1},
                                        otherContacts = {2},
                                        userId = {3},
                                        userSex = {4};
                        </script>",
                        JsonConvert.SerializeObject(Departments.Select(item => new
                        {
                            id = item.ID,
                            title = item.Name.HtmlEncode()
                        })),
                        JsonConvert.SerializeObject(SocContacts),
                        JsonConvert.SerializeObject(OtherContacts),
                        JsonConvert.SerializeObject(Profile.ID),
                        JsonConvert.SerializeObject(Profile.Sex));

            Page.ClientScript.RegisterStartupScript(GetType(), Guid.NewGuid().ToString(), script);
        }

        #endregion

        #region Protected Methods

        protected bool IsLdapField(LdapMapping field)
        {
            return ProfileIsLdap && LdapFields.Contains(field);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SMTP/SMTP_t_Mailbox.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SMTP
{
    #region usings

    using System;
    using MIME;

    #endregion

    /// <summary>
    /// This class represents SMTP "Mailbox" address. Defined in RFC 5321 4.1.2.
    /// </summary>
    /// <example>
    /// <code>
    /// RFC 5321 4.1.2.
    ///     Mailbox    = Local-part "@" ( Domain / address-literal )
    ///     Local-part = Dot-string / Quoted-string
    ///                  ; MAY be case-sensitive
    /// </code>
    /// </example>
    public class SMTP_t_Mailbox
    {
        #region Members

        private readonly string m_Domain;
        private readonly string m_LocalPart;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="localPart">Local part of mailbox.</param>
        /// <param name="domain">Domain of mailbox.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>localPart</b> or <b>domain</b> is null reference.</exception>
        public SMTP_t_Mailbox(string localPart, string domain)
        {
            if (localPart == null)
            {
                throw new ArgumentNullException("localPart");
            }
            if (domain == null)
            {
                throw new ArgumentNullException("domain");
            }

            m_LocalPart = localPart;
            m_Domain = domain;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets domain of mailbox.
        /// </summary>
        /// <remarks>If domain is <b>address-literal</b>, surrounding bracets will be removed.</remarks>
        public string Domain
        {
            get { return m_Domain; }
        }

        /// <summary>
        /// Gets local-part of mailbox.
        /// </summary>
        /// <remarks>If local-part is <b>Quoted-string</b>, quotes will not returned.</remarks>
        public string LocalPart
        {
            get { return m_LocalPart; }
        }

        #endregion

        /*
        /// <summary>
        /// Parses SMTP mailbox from the specified string.
        /// </summary>
        /// <param name="value">Mailbox string.</param>
        /// <returns>Returns parsed SMTP mailbox.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        public static SMTP_t_Mailbox Parse(string value)
        {
            if(value == null){
                throw new ArgumentNullException("value");
            }

            return Parse(new ABNF_Reader(value));
        }

        /// <summary>
        /// Parses SMTP mailbox from the specified reader.
        /// </summary>
        /// <param name="reader">Source reader.</param>
        /// <returns>Returns parsed SMTP mailbox.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>reader</b> is null reference.</exception>
        public static SMTP_t_Mailbox Parse(ABNF_Reader reader)
        {
            if(reader == null){
                throw new ArgumentNullException("reader");
            }

            // TODO:

            return null;
        }
        */

        #region Methods

        /// <summary>
        /// Returns mailbox as string.
        /// </summary>
        /// <returns>Returns mailbox as string.</returns>
        public override string ToString()
        {
            if (MIME_Reader.IsDotAtom(m_LocalPart))
            {
                return m_LocalPart + "@" + (Net_Utils.IsIPAddress(m_Domain) ? "[" + m_Domain + "]" : m_Domain);
            }
            else
            {
                return TextUtils.QuoteString(m_LocalPart) + "@" +
                       (Net_Utils.IsIPAddress(m_Domain) ? "[" + m_Domain + "]" : m_Domain);
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Statistics/VisitorsChart/js/tooltip.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function () {
  if (typeof window.ASC === 'undefined') {
    window.ASC = {};
  }
  if (typeof window.ASC.Common === 'undefined') {
    window.ASC.Common = {};
  }

  window.ASC.Common.toolTip = (function () {
    var
      wrapperId = '',
      wrapperClassName = 'tooltip-wrapper',
      wrapperHandler = null;

    var uniqueId = function (prefix) {
      return (typeof prefix != 'undefined' ? prefix + '-' : '') + Math.floor(Math.random() * 1000000);
    };

    var create = function () {
      if (!wrapperHandler) {
        wrapperId = uniqueId('tooltipWrapper');
        wrapperHandler = document.createElement('div');
        wrapperHandler.id = wrapperId;
        wrapperHandler.className = wrapperClassName;
        wrapperHandler.style.display = 'none';
        wrapperHandler.style.left = '0';
        wrapperHandler.style.top = '0';
        wrapperHandler.style.position = 'absolute';
        document.body.appendChild(wrapperHandler);
      }
      return wrapperHandler;
    };

    var show = function (content, handler) {
      create();
      wrapperHandler.innerHTML = content;
      wrapperHandler.style.display = 'block';

      if (typeof handler === 'function') {
        handler.call(wrapperHandler);
      }
    };

    var hide = function () {
      if (wrapperHandler && typeof wrapperHandler === 'object') {
        wrapperHandler.style.display = 'none';
      }
    };

    return {
      show  : show,
      hide  : hide
    }
  })();
})();


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/WikiUC/EditFile.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI.WebControls;

using ASC.Core.Tenants;
using ASC.Data.Storage;
using ASC.Web.Community.Modules.Wiki.Resources;
using ASC.Web.UserControls.Wiki.Data;
using ASC.Web.UserControls.Wiki.Handlers;

using IO = System.IO;

namespace ASC.Web.UserControls.Wiki.UC
{
    public partial class EditFile : BaseUserControl
    {
        public string FileName
        {
            get
            {
                return ViewState["FileName"] == null ? string.Empty : ViewState["FileName"].ToString();
            }
            set { ViewState["FileName"] = value; }
        }

        private File _fileInfo;

        protected File CurrentFile
        {
            get
            {
                if (_fileInfo == null)
                {
                    if (string.IsNullOrEmpty(FileName))
                        return null;

                    _fileInfo = Wiki.GetFile(FileName);
                }
                return _fileInfo;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (Page.IsPostBack) return;
            if (CurrentFile != null && !string.IsNullOrEmpty(CurrentFile.FileName))
            {
                RisePublishVersionInfo(CurrentFile);
            }
        }

        protected string GetUploadFileName()
        {
            return CurrentFile == null ? string.Empty : CurrentFile.UploadFileName;
        }

        protected string GetFileLink()
        {
            var file = Wiki.GetFile(FileName);
            if (file == null)
            {
                RisePageEmptyEvent();
                return string.Empty; // "nonefile.png";
            }

            var ext = file.FileLocation.Split('.')[file.FileLocation.Split('.').Length - 1];
            if (!string.IsNullOrEmpty(ext) && !WikiFileHandler.ImageExtentions.Contains(ext.ToLower()))
            {
                return string.Format(@"<a class=""linkMedium"" href=""{0}"" title=""{1}"">{2}</a>",
                                     ResolveUrl(string.Format(ImageHandlerUrlFormat, FileName)),
                                     file.FileName,
                                     WikiUCResource.wikiFileDownloadCaption);
            }

            return string.Format(@"<img src=""{0}"" style=""max-width:300px; max-height:200px"" />",
                                 ResolveUrl(string.Format(ImageHandlerUrlFormat, FileName)));
        }

        private static string GetFileLocation(string fileName)
        {
            var letter = (byte)fileName[0];

            var secondFolder = letter.ToString("x");
            var firstFolder = secondFolder.Substring(0, 1);

            var fileLocation = IO.Path.Combine(firstFolder, secondFolder);
            fileLocation = IO.Path.Combine(fileLocation, EncodeSafeName(fileName)); //TODO: encode nameprep here

            return fileLocation;
        }

        private static string EncodeSafeName(string fileName)
        {
            return fileName;
        }

        public static void DeleteTempContent(string fileName, string configLocation, WikiSection section, int tenantId, HttpContext context)
        {
            var storage = StorageFactory.GetStorage(tenantId.ToString(), section.DataStorage.ModuleName);
            storage.Delete(section.DataStorage.TempDomain, fileName);
        }

        public static void DeleteContent(string fileName, string configLocation, WikiSection section, int tenantId, HttpContext context)
        {
            var storage = StorageFactory.GetStorage(tenantId.ToString(), section.DataStorage.ModuleName);
            storage.Delete(section.DataStorage.DefaultDomain, fileName);
        }

        public static SaveResult MoveContentFromTemp(Guid userId, string fromFileName, string toFileName, string configLocation, WikiSection section, int tenantId, HttpContext context, string rootFile, out string _fileName)
        {
            var storage = StorageFactory.GetStorage(tenantId.ToString(), section.DataStorage.ModuleName);

            var fileName = toFileName;
            var fileLocation = GetFileLocation(fileName);
            var file = new File
            {
                FileName = fileName,
                UploadFileName = fileName,
                UserID = userId,
                FileLocation = fileLocation,
                FileSize = (int)storage.GetFileSize(section.DataStorage.TempDomain, fromFileName),
            };

            var wiki = new WikiEngine();
            wiki.SaveFile(file);

            storage.Move(section.DataStorage.TempDomain, fromFileName, section.DataStorage.DefaultDomain, fileLocation);
            _fileName = file.FileName;

            return SaveResult.Ok;
        }

        public static SaveResult DirectFileSave(Guid userId, FileUpload fuFile, string rootFile, WikiSection section, string configLocation, int tenantId, HttpContext context)
        {
            if (!fuFile.HasFile)
                return SaveResult.FileEmpty;

            var wikiEngine = new WikiEngine();
            File file = null;

            try
            {
                file = wikiEngine.CreateOrUpdateFile(new File { FileName = fuFile.FileName, FileSize = fuFile.FileBytes.Length });
                FileContentSave(file.FileLocation, fuFile.FileBytes, section, configLocation, tenantId, context);
            }
            catch (TenantQuotaException)
            {
                if (file != null)
                    wikiEngine.RemoveFile(file.FileName);
                return SaveResult.FileSizeExceeded;
            }

            return SaveResult.Ok;
        }

        private static void FileContentSave(string location, byte[] fileContent, WikiSection section, string configLocation, int tenantId, HttpContext context)
        {
            var storage = StorageFactory.GetStorage(tenantId.ToString(), section.DataStorage.ModuleName);
            FileContentSave(storage, location, fileContent, section);
        }

        private static void FileContentSave(string location, byte[] fileContent, WikiSection section, int tenantId)
        {
            var storage = StorageFactory.GetStorage(tenantId.ToString(), section.DataStorage.ModuleName);
            FileContentSave(storage, location, fileContent, section);
        }

        private static void FileContentSave(IDataStore storage, string location, byte[] fileContent, WikiSection section)
        {
            using (var ms = new IO.MemoryStream(fileContent))
            {
                storage.Save(section.DataStorage.DefaultDomain, location, ms);
            }
        }

        public SaveResult Save(Guid userId)
        {
            string fileName;
            return Save(userId, out fileName);
        }

        public SaveResult Save(Guid userId, out string fileName)
        {
            fileName = string.Empty;
            if (!fuFile.HasFile)
                return SaveResult.FileEmpty;

            var file = CurrentFile ?? new File { FileName = fuFile.FileName, UploadFileName = fuFile.FileName };

            file.FileSize = fuFile.FileBytes.Length;

            file = Wiki.CreateOrUpdateFile(file);

            try
            {
                FileContentSave(file.FileLocation, fuFile.FileBytes, WikiSection.Section, TenantId);
            }
            catch (TenantQuotaException)
            {
                Wiki.RemoveFile(file.FileName);
                return SaveResult.FileSizeExceeded;
            }

            _fileInfo = file;

            RisePublishVersionInfo(file);
            fileName = file.FileName;

            return SaveResult.Ok;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/UserControls/Common/Settings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

namespace ASC.Web.UserControls.Forum.Common
{
    public class Settings
    {
        public ForumManager ForumManager { get; private set; }

        public LinkProvider LinkProvider { get; private set; }

        public Guid ID { get; private set; }

        public Guid ModuleID { get; private set; }

        public Guid ImageItemID { get; private set; }

        public int TopicCountOnPage { get; private set; }

        public int PostCountOnPage { get; private set; }

        public string UserControlsVirtualPath { get; private set; }

        public string FileStoreModuleID { get; private set; }

        public string ThreadParamName { get; private set; }

        public string TopicParamName { get; private set; }

        public string TagParamName { get; private set; }

        public string ActionParamName { get; private set; }
        public string PostParamName { get; private set; }

        public string NewPostPageVirtualPath { get; private set; }
        public string NewPostPageAbsolutePath { get { return GetAbsolutePathWithParams(NewPostPageVirtualPath); } }

        public string SearchPageVirtualPath { get; private set; }
        public string SearchPageAbsolutePath { get { return GetAbsolutePathWithParams(SearchPageVirtualPath); } }

        public string StartPageVirtualPath { get; private set; }
        public string StartPageAbsolutePath { get { return GetAbsolutePathWithParams(StartPageVirtualPath); } }

        public string TopicPageVirtualPath { get; private set; }
        public string TopicPageAbsolutePath { get { return GetAbsolutePathWithParams(TopicPageVirtualPath); } }

        public string EditTopicPageVirtualPath { get; private set; }
        public string EditTopicPageAbsolutePath { get { return GetAbsolutePathWithParams(EditTopicPageVirtualPath); } }

        public string PostPageVirtualPath { get; private set; }
        public string PostPageAbsolutePath { get { return GetAbsolutePathWithParams(PostPageVirtualPath); } }

        public Settings()
        {
            ID = Guid.NewGuid();
            TopicCountOnPage = 20;
            PostCountOnPage = 20;

            ThreadParamName = "f";
            TopicParamName = "t";
            TagParamName = "tag";
            ActionParamName = "a";
            PostParamName = "m";

            ModuleID = new Guid("853B6EB9-73EE-438d-9B09-8FFEEDF36234");
            ImageItemID = new Guid("853B6EB9-73EE-438d-9B09-8FFEEDF36234");
            UserControlsVirtualPath = "~/Products/Community/Modules/Forum/UserControls";
            StartPageVirtualPath = "~/Products/Community/Modules/Forum/Default.aspx";
            TopicPageVirtualPath = "~/Products/Community/Modules/Forum/Topics.aspx";
            PostPageVirtualPath = "~/Products/Community/Modules/Forum/Posts.aspx";
            SearchPageVirtualPath = "~/Products/Community/Modules/Forum/Search.aspx";
            NewPostPageVirtualPath = "~/Products/Community/Modules/Forum/NewPost.aspx";
            EditTopicPageVirtualPath = "~/Products/Community/Modules/Forum/EditTopic.aspx";
            FileStoreModuleID = "forum";

            LinkProvider = new LinkProvider(this);
            //registry
            ForumManager = new ForumManager(this);
        }

        private static string GetAbsolutePathWithParams(string virtualPath)
        {
            if (!string.IsNullOrEmpty(virtualPath))
            {
                if (virtualPath.IndexOf("?") != -1)
                    return VirtualPathUtility.ToAbsolute(virtualPath.Split('?')[0]) + "?" + virtualPath.Split('?')[1];

                return VirtualPathUtility.ToAbsolute(virtualPath) + "?";
            }

            return string.Empty;
        }

        internal string[] GetAllPageAdditionalParams()
        {
            var result = new List<string>();

            result.AddRange(GetPageAdditionalParams(PostPageVirtualPath));
            result.AddRange(GetPageAdditionalParams(TopicPageVirtualPath));
            result.AddRange(GetPageAdditionalParams(SearchPageVirtualPath));
            result.AddRange(GetPageAdditionalParams(SearchPageVirtualPath));
            result.AddRange(GetPageAdditionalParams(NewPostPageVirtualPath));
            result.AddRange(GetPageAdditionalParams(EditTopicPageVirtualPath));

            return result.ToArray();
        }

        private static string[] GetPageAdditionalParams(string url)
        {
            if (string.IsNullOrEmpty(url) || url.IndexOf("?") == -1) return new string[0];

            var query = url.Split('?')[1];
            if (!string.IsNullOrEmpty(query))
            {
                var result = new List<string>();
                foreach (var param in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    result.Add(param.Split('=')[0]);
                }

                return result.ToArray();
            }

            return new string[0];
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/AuthorizationKeys/AuthorizationKeys.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Common.Configuration;
using ASC.Data.Storage;
using ASC.FederatedLogin.LoginProviders;
using ASC.MessagingSystem;
using ASC.Web.Core.Sms;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    [ManagementControl(ManagementType.ThirdPartyAuthorization, Location)]
    [AjaxNamespace("AuthorizationKeys")]
    public partial class AuthorizationKeys : UserControl
    {
        public const string Location = "~/UserControls/Management/AuthorizationKeys/AuthorizationKeys.ascx";

        private List<AuthService> _authServiceList;

        protected string TariffPageLink { get; set; }

        public List<AuthService> AuthServiceList
        {
            get { return _authServiceList ?? (_authServiceList = GetAuthServices().ToList()); }
        }

        protected string HelpLink { get; set; }

        protected string SupportLink { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            TariffPageLink = TenantExtra.GetTariffPageLink();
            AjaxPro.Utility.RegisterTypeForAjax(GetType(), Page);
            Page.RegisterBodyScripts("~/UserControls/Management/AuthorizationKeys/js/authorizationkeys.js");
            Page.ClientScript.RegisterClientScriptBlock(GetType(), "authorizationkeys_style", "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + WebPath.GetPath("UserControls/Management/AuthorizationKeys/css/authorizationkeys.css") + "\">", false);

            HelpLink = CommonLinkUtility.GetHelpLink();

            SupportLink = GetFeedbackAndSupportUrl();
        }

        private static string GetFeedbackAndSupportUrl()
        {
            var settings = AdditionalWhiteLabelSettings.Instance;

            if (!settings.FeedbackAndSupportEnabled || String.IsNullOrEmpty(settings.FeedbackAndSupportUrl))
                return string.Empty;

            return CommonLinkUtility.GetRegionalUrl(settings.FeedbackAndSupportUrl, CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
        }

        private static IEnumerable<AuthService> GetAuthServices()
        {
            return ConsumerFactory.Consumers
                .Where(consumer => consumer.ManagedKeys.Any())
                .Select(ToAuthService)
                .OrderBy(services => services.Order);
        }

        private static AuthService ToAuthService(Consumer consumer)
        {
            return new AuthService(consumer);
        }

        protected bool SaveAvailable
        {
            get { return CoreContext.Configuration.Standalone || CoreContext.TenantManager.GetTenantQuota(CoreContext.TenantManager.GetCurrentTenant().TenantId).ThirdParty; }
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public bool SaveAuthKeys(string name, List<AuthKey> props)
        {
            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

            if (!SetupInfo.IsVisibleSettings(ManagementType.ThirdPartyAuthorization.ToString())
                || !SaveAvailable)
                throw new BillingException(Resource.ErrorNotAllowedOption, "ThirdPartyAuthorization");

            var changed = false;
            var consumer = ConsumerFactory.GetByName(name);

            var validateKeyProvider = (IValidateKeysProvider)ConsumerFactory.Consumers.FirstOrDefault(r => r.Name == consumer.Name && r is IValidateKeysProvider);
            if (validateKeyProvider != null)
            {
                RemoveOldNumberFromTwilio(validateKeyProvider);
                ClearUrlShortenerInstance(validateKeyProvider);
            }

            if (props.All(r => string.IsNullOrEmpty(r.Value)))
            {
                consumer.Clear();
                changed = true;
            }
            else
            {
                foreach (var authKey in props.Where(authKey => consumer[authKey.Name] != authKey.Value))
                {
                    consumer[authKey.Name] = authKey.Value;
                    changed = true;
                }
            }

            //TODO: Consumer implementation required (Bug 50606)
            var allPropsIsEmpty = consumer.GetType() == typeof(SmscProvider)
                ? consumer.ManagedKeys.All(key => string.IsNullOrEmpty(consumer[key]))
                : consumer.All(r => string.IsNullOrEmpty(r.Value));

            if (validateKeyProvider != null && !validateKeyProvider.ValidateKeys() && !allPropsIsEmpty)
            {
                consumer.Clear();
                throw new ArgumentException(Resource.ErrorBadKeys);
            }

            if (changed)
                MessageService.Send(HttpContext.Current.Request, MessageAction.AuthorizationKeysSetting);

            return changed;
        }

        private static void RemoveOldNumberFromTwilio(IValidateKeysProvider provider)
        {
            try
            {
                var twilioLoginProvider = provider as TwilioProvider;
                if (twilioLoginProvider != null)
                {
                    twilioLoginProvider.ClearOldNumbers();
                }
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC").Error(e);
            }
        }

        private static void ClearUrlShortenerInstance(IValidateKeysProvider provider)
        {
            try
            {
                var twilioLoginProvider = provider as BitlyLoginProvider;
                if (twilioLoginProvider != null)
                {
                    Web.Core.Utility.UrlShortener.Instance = null;
                }
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC").Error(e);
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Settings/Smtp/SmtpSettingsWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

namespace ASC.Api.Settings.Smtp
{
    [DataContract(Name = "quota", Namespace = "")]
    public class SmtpSettingsWrapper
    {
        [DataMember]
        public string Host { get; set; }

        [DataMember]
        public int? Port { get; set; }

        [DataMember]
        public string SenderAddress { get; set; }

        [DataMember]
        public string SenderDisplayName { get; set; }

        [DataMember]
        public string CredentialsUserName { get; set; }

        [DataMember]
        public string CredentialsUserPassword { get; set; }

        [DataMember]
        public bool EnableSSL { get; set; }

        [DataMember]
        public bool EnableAuth { get; set; }

        public static SmtpSettingsWrapper GetSample()
        {
            return new SmtpSettingsWrapper
            {
                Host = "mail.example.com",
                Port = 25,
                CredentialsUserName = "<EMAIL>",
                CredentialsUserPassword = <PASSWORD>}",
                EnableAuth = true,
                EnableSSL = false,
                SenderAddress = "<EMAIL>",
                SenderDisplayName = "Postman"
            };
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Users/UserPhotoManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;

using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Threading.Workers;
using ASC.Core;
using ASC.Data.Storage;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Core.Users
{
    internal class ResizeWorkerItem
    {
        private readonly Guid _userId;
        private readonly byte[] _data;
        private readonly long _maxFileSize;
        private readonly Size _size;
        private readonly IDataStore _dataStore;
        private readonly UserPhotoThumbnailSettings _settings;


        public ResizeWorkerItem(Guid userId, byte[] data, long maxFileSize, Size size, IDataStore dataStore, UserPhotoThumbnailSettings settings)
        {
            _userId = userId;
            _data = data;
            _maxFileSize = maxFileSize;
            _size = size;
            _dataStore = dataStore;
            _settings = settings;
        }

        public Size Size
        {
            get { return _size; }
        }

        public IDataStore DataStore
        {
            get { return _dataStore; }
        }

        public long MaxFileSize
        {
            get { return _maxFileSize; }
        }

        public byte[] Data
        {
            get { return _data; }
        }

        public Guid UserId
        {
            get { return _userId; }
        }

        public UserPhotoThumbnailSettings Settings
        {
            get { return _settings; }
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof(ResizeWorkerItem)) return false;
            return Equals((ResizeWorkerItem)obj);
        }

        public bool Equals(ResizeWorkerItem other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other.UserId.Equals(UserId) && other.MaxFileSize == MaxFileSize && other.Size.Equals(Size);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                int result = UserId.GetHashCode();
                result = (result * 397) ^ MaxFileSize.GetHashCode();
                result = (result * 397) ^ Size.GetHashCode();
                return result;
            }
        }
    }

    public class UserPhotoManagerCacheItem
    {
        public Guid UserID { get; set; }
        public Size Size { get; set; }
        public string FileName { get; set; }
    }

    public class UserPhotoManager
    {
        private static readonly IDictionary<Guid, IDictionary<Size, string>> Photofiles = new Dictionary<Guid, IDictionary<Size, string>>();
        private static readonly ICacheNotify CacheNotify;

        static UserPhotoManager()
        {
            try
            {
                CacheNotify = AscCache.Notify;

                CacheNotify.Subscribe<UserPhotoManagerCacheItem>((data, action) =>
                {
                    if (action == CacheNotifyAction.InsertOrUpdate)
                    {
                        lock (Photofiles)
                        {
                            if (!Photofiles.ContainsKey(data.UserID))
                            {
                                Photofiles[data.UserID] = new ConcurrentDictionary<Size, string>();
                            }

                            Photofiles[data.UserID][data.Size] = data.FileName;
                        }
                    }
                    if (action == CacheNotifyAction.Remove)
                    {
                        try
                        {
                            lock (Photofiles)
                            {
                                Photofiles.Remove(data.UserID);
                            }
                            var storage = GetDataStore();
                            storage.DeleteFiles("", data.UserID.ToString() + "*.*", false);
                            SetCacheLoadedForTenant(false);
                        }
                        catch { }
                    }
                });
            }
            catch (Exception)
            {

            }
        }


        public static string GetDefaultPhotoAbsoluteWebPath()
        {
            return WebImageSupplier.GetAbsoluteWebPath(_defaultAvatar);
        }


        public static string GetRetinaPhotoURL(Guid userID)
        {
            return GetSizedPhotoAbsoluteWebPath(userID, RetinaFotoSize);
        }

        public static string GetMaxPhotoURL(Guid userID)
        {
            return GetSizedPhotoAbsoluteWebPath(userID, MaxFotoSize);
        }

        public static string GetBigPhotoURL(Guid userID)
        {
            return GetSizedPhotoAbsoluteWebPath(userID, BigFotoSize);
        }

        public static string GetMediumPhotoURL(Guid userID)
        {
            return GetSizedPhotoAbsoluteWebPath(userID, MediumFotoSize);
        }

        public static string GetSmallPhotoURL(Guid userID)
        {
            return GetSizedPhotoAbsoluteWebPath(userID, SmallFotoSize);
        }


        public static string GetSizedPhotoUrl(Guid userId, int width, int height)
        {
            return GetSizedPhotoAbsoluteWebPath(userId, new Size(width, height));
        }


        public static string GetDefaultSmallPhotoURL()
        {
            return GetDefaultPhotoAbsoluteWebPath(SmallFotoSize);
        }

        public static string GetDefaultMediumPhotoURL()
        {
            return GetDefaultPhotoAbsoluteWebPath(MediumFotoSize);
        }

        public static string GetDefaultBigPhotoURL()
        {
            return GetDefaultPhotoAbsoluteWebPath(BigFotoSize);
        }

        public static string GetDefaultMaxPhotoURL()
        {
            return GetDefaultPhotoAbsoluteWebPath(MaxFotoSize);
        }

        public static string GetDefaultRetinaPhotoURL()
        {
            return GetDefaultPhotoAbsoluteWebPath(RetinaFotoSize);
        }



        public static Size OriginalFotoSize
        {
            get { return new Size(1280, 1280); }
        }

        public static Size RetinaFotoSize
        {
            get { return new Size(360, 360); }
        }

        public static Size MaxFotoSize
        {
            get { return new Size(200, 200); }
        }

        public static Size BigFotoSize
        {
            get { return new Size(82, 82); }
        }

        public static Size MediumFotoSize
        {
            get { return new Size(48, 48); }
        }

        public static Size SmallFotoSize
        {
            get { return new Size(32, 32); }
        }

        private static readonly string _defaultRetinaAvatar = "default_user_photo_size_360-360.png";
        private static readonly string _defaultAvatar = "default_user_photo_size_200-200.png";
        private static readonly string _defaultSmallAvatar = "default_user_photo_size_32-32.png";
        private static readonly string _defaultMediumAvatar = "default_user_photo_size_48-48.png";
        private static readonly string _defaultBigAvatar = "default_user_photo_size_82-82.png";
        private static readonly string _tempDomainName = "temp";


        public static bool UserHasAvatar(Guid userID)
        {
            var path = GetPhotoAbsoluteWebPath(userID);
            var fileName = Path.GetFileName(path);
            return fileName != _defaultAvatar;
        }

        public static string GetPhotoAbsoluteWebPath(Guid userID)
        {
            var path = SearchInCache(userID, Size.Empty);
            if (!string.IsNullOrEmpty(path)) return path;

            try
            {
                var data = CoreContext.UserManager.GetUserPhoto(userID);
                string photoUrl;
                string fileName;
                if (data == null || data.Length == 0)
                {
                    photoUrl = GetDefaultPhotoAbsoluteWebPath();
                    fileName = "default";
                }
                else
                {
                    photoUrl = SaveOrUpdatePhoto(userID, data, -1, new Size(-1, -1), false, out fileName);
                }
                AddToCache(userID, Size.Empty, fileName);

                return photoUrl;
            }
            catch
            {
            }
            return GetDefaultPhotoAbsoluteWebPath();
        }

        internal static Size GetPhotoSize(Guid userID)
        {
            var virtualPath = GetPhotoAbsoluteWebPath(userID);
            if (virtualPath == null) return Size.Empty;

            try
            {
                var sizePart = virtualPath.Substring(virtualPath.LastIndexOf('_'));
                sizePart = sizePart.Trim('_');
                sizePart = sizePart.Remove(sizePart.LastIndexOf('.'));
                return new Size(Int32.Parse(sizePart.Split('-')[0]), Int32.Parse(sizePart.Split('-')[1]));
            }
            catch
            {
                return Size.Empty;
            }
        }

        private static string GetSizedPhotoAbsoluteWebPath(Guid userID, Size size)
        {
            var res = SearchInCache(userID, size);
            if (!string.IsNullOrEmpty(res)) return res;

            try
            {
                var data = CoreContext.UserManager.GetUserPhoto(userID);

                if (data == null || data.Length == 0)
                {
                    //empty photo. cache default
                    var photoUrl = GetDefaultPhotoAbsoluteWebPath(size);

                    AddToCache(userID, size, "default");
                    return photoUrl;
                }

                //Enqueue for sizing
                SizePhoto(userID, data, -1, size);
            }
            catch { }

            return GetDefaultPhotoAbsoluteWebPath(size);
        }

        private static string GetDefaultPhotoAbsoluteWebPath(Size size)
        {
            if (size == RetinaFotoSize) return WebImageSupplier.GetAbsoluteWebPath(_defaultRetinaAvatar);
            if (size == MaxFotoSize) return WebImageSupplier.GetAbsoluteWebPath(_defaultAvatar);
            if (size == BigFotoSize) return WebImageSupplier.GetAbsoluteWebPath(_defaultBigAvatar);
            if (size == SmallFotoSize) return WebImageSupplier.GetAbsoluteWebPath(_defaultSmallAvatar);
            if (size == MediumFotoSize) return WebImageSupplier.GetAbsoluteWebPath(_defaultMediumAvatar);
            return GetDefaultPhotoAbsoluteWebPath();
        }

        //Regex for parsing filenames into groups with id's
        private static readonly Regex ParseFile =
                new Regex(@"^(?'module'\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1}){0,1}" +
                    @"(?'user'\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1}){1}" +
                    @"_(?'kind'orig|size){1}_(?'size'(?'width'[0-9]{1,5})-{1}(?'height'[0-9]{1,5})){0,1}\..*", RegexOptions.Compiled);

        private static readonly HashSet<int> TenantDiskCache = new HashSet<int>();
        private static readonly object DiskCacheLoaderLock = new object();

        private static bool IsCacheLoadedForTenant()
        {
            return TenantDiskCache.Contains(TenantProvider.CurrentTenantID);
        }

        private static bool SetCacheLoadedForTenant(bool isLoaded)
        {
            return isLoaded ? TenantDiskCache.Add(TenantProvider.CurrentTenantID) : TenantDiskCache.Remove(TenantProvider.CurrentTenantID);
        }


        private static string SearchInCache(Guid userId, Size size)
        {
            if (!IsCacheLoadedForTenant())
                LoadDiskCache();

            string fileName;
            lock (Photofiles)
            {
                if (!Photofiles.ContainsKey(userId)) return null;
                if (size != Size.Empty && !Photofiles[userId].ContainsKey(size)) return null;

                if (size != Size.Empty)
                    fileName = Photofiles[userId][size];
                else
                    fileName = Photofiles[userId]
                                .Select(x => x.Value)
                                .FirstOrDefault(x => !String.IsNullOrEmpty(x) && x.Contains("_orig_"));
            }
            if (fileName != null && fileName.StartsWith("default")) return GetDefaultPhotoAbsoluteWebPath(size);

            if (!string.IsNullOrEmpty(fileName))
            {
                var store = GetDataStore();
                return store.GetUri(fileName).ToString();
            }

            return null;
        }


        private static void LoadDiskCache()
        {
            lock (DiskCacheLoaderLock)
            {
                if (!IsCacheLoadedForTenant())
                {
                    try
                    {
                        var listFileNames = GetDataStore().ListFilesRelative("", "", "*.*", false);
                        foreach (var fileName in listFileNames)
                        {
                            //Try parse fileName
                            if (fileName != null)
                            {
                                var match = ParseFile.Match(fileName);
                                if (match.Success && match.Groups["user"].Success)
                                {
                                    var parsedUserId = new Guid(match.Groups["user"].Value);
                                    var size = Size.Empty;
                                    if (match.Groups["width"].Success && match.Groups["height"].Success)
                                    {
                                        //Parse size
                                        size = new Size(int.Parse(match.Groups["width"].Value), int.Parse(match.Groups["height"].Value));
                                    }
                                    AddToCache(parsedUserId, size, fileName);
                                }
                            }
                        }
                        SetCacheLoadedForTenant(true);
                    }
                    catch (Exception err)
                    {
                        LogManager.GetLogger("ASC.Web.Photo").Error(err);
                    }
                }
            }
        }

        private static void ClearCache(Guid userID)
        {
            if (CacheNotify != null)
            {
                CacheNotify.Publish(new UserPhotoManagerCacheItem { UserID = userID }, CacheNotifyAction.Remove);
            }
        }

        private static void AddToCache(Guid userId, Size size, string fileName)
        {
            if (CacheNotify != null)
            {
                CacheNotify.Publish(new UserPhotoManagerCacheItem { UserID = userId, Size = size, FileName = fileName }, CacheNotifyAction.InsertOrUpdate);
            }
        }

        public static void ResetThumbnailSettings(Guid userId)
        {
            var thumbSettings = new UserPhotoThumbnailSettings().GetDefault() as UserPhotoThumbnailSettings;
            thumbSettings.SaveForUser(userId);
        }

        public static string SaveOrUpdatePhoto(Guid userID, byte[] data)
        {
            string fileName;
            return SaveOrUpdatePhoto(userID, data, -1, OriginalFotoSize, true, out fileName);
        }

        public static void RemovePhoto(Guid idUser)
        {
            CoreContext.UserManager.SaveUserPhoto(idUser, null);
            ClearCache(idUser);
        }

        public static void SyncPhoto(Guid userID, byte[] data)
        {
            data = TryParseImage(data, -1, OriginalFotoSize, out _, out int width, out int height);
            CoreContext.UserManager.SaveUserPhoto(userID, data);
            SetUserPhotoThumbnailSettings(userID, width, height);
            ClearCache(userID);
        }

        private static string SaveOrUpdatePhoto(Guid userID, byte[] data, long maxFileSize, Size size, bool saveInCoreContext, out string fileName)
        {
            ImageFormat imgFormat;
            int width;
            int height;
            data = TryParseImage(data, maxFileSize, size, out imgFormat, out width, out height);

            var widening = CommonPhotoManager.GetImgFormatName(imgFormat);
            fileName = string.Format("{0}_orig_{1}-{2}.{3}", userID, width, height, widening);

            if (saveInCoreContext)
            {
                CoreContext.UserManager.SaveUserPhoto(userID, data);
                SetUserPhotoThumbnailSettings(userID, width, height);
                ClearCache(userID);
            }

            var store = GetDataStore();

            var photoUrl = GetDefaultPhotoAbsoluteWebPath();
            if (data != null && data.Length > 0)
            {
                using (var stream = new MemoryStream(data))
                {
                    photoUrl = store.Save(fileName, stream).ToString();
                }
                //Queue resizing
                SizePhoto(userID, data, -1, SmallFotoSize, true);
                SizePhoto(userID, data, -1, MediumFotoSize, true);
                SizePhoto(userID, data, -1, BigFotoSize, true);
                SizePhoto(userID, data, -1, MaxFotoSize, true);
                SizePhoto(userID, data, -1, RetinaFotoSize, true);
            }
            return photoUrl;
        }

        private static void SetUserPhotoThumbnailSettings(Guid userId, int width, int height)
        {
            var settings = UserPhotoThumbnailSettings.LoadForUser(userId);

            if (!settings.IsDefault) return;

            var max = Math.Max(Math.Max(width, height), SmallFotoSize.Width);
            var min = Math.Max(Math.Min(width, height), SmallFotoSize.Width);

            var pos = (max - min) / 2;

            settings = new UserPhotoThumbnailSettings(
                width >= height ? new Point(pos, 0) : new Point(0, pos),
                new Size(min, min));

            settings.SaveForUser(userId);
        }

        private static byte[] TryParseImage(byte[] data, long maxFileSize, Size maxsize, out ImageFormat imgFormat, out int width, out int height)
        {
            if (data == null || data.Length <= 0) throw new UnknownImageFormatException();
            if (maxFileSize != -1 && data.Length > maxFileSize) throw new ImageSizeLimitException();

            data = ImageHelper.RotateImageByExifOrientationData(data);

            try
            {
                using (var stream = new MemoryStream(data))
                using (var img = new Bitmap(stream))
                {
                    imgFormat = img.RawFormat;
                    width = img.Width;
                    height = img.Height;
                    var maxWidth = maxsize.Width;
                    var maxHeight = maxsize.Height;

                    if ((maxHeight != -1 && img.Height > maxHeight) || (maxWidth != -1 && img.Width > maxWidth))
                    {
                        #region calulate height and width

                        if (width > maxWidth && height > maxHeight)
                        {

                            if (width > height)
                            {
                                height = (int)((double)height * (double)maxWidth / (double)width + 0.5);
                                width = maxWidth;
                            }
                            else
                            {
                                width = (int)((double)width * (double)maxHeight / (double)height + 0.5);
                                height = maxHeight;
                            }
                        }

                        if (width > maxWidth && height <= maxHeight)
                        {
                            height = (int)((double)height * (double)maxWidth / (double)width + 0.5);
                            width = maxWidth;
                        }

                        if (width <= maxWidth && height > maxHeight)
                        {
                            width = (int)((double)width * (double)maxHeight / (double)height + 0.5);
                            height = maxHeight;
                        }

                        #endregion

                        using (var b = new Bitmap(width, height))
                        using (var gTemp = Graphics.FromImage(b))
                        {
                            gTemp.InterpolationMode = InterpolationMode.HighQualityBicubic;
                            gTemp.PixelOffsetMode = PixelOffsetMode.HighQuality;
                            gTemp.SmoothingMode = SmoothingMode.HighQuality;
                            gTemp.DrawImage(img, 0, 0, width, height);

                            data = CommonPhotoManager.SaveToBytes(b);
                        }
                    }
                    return data;
                }
            }
            catch (OutOfMemoryException)
            {
                throw new ImageSizeLimitException();
            }
            catch (ArgumentException error)
            {
                throw new UnknownImageFormatException(error);
            }
        }

        //note: using auto stop queue
        private static readonly WorkerQueue<ResizeWorkerItem> ResizeQueue = new WorkerQueue<ResizeWorkerItem>(2, TimeSpan.FromSeconds(30), 1, true);//TODO: configure

        private static string SizePhoto(Guid userID, byte[] data, long maxFileSize, Size size)
        {
            return SizePhoto(userID, data, maxFileSize, size, false);
        }

        private static string SizePhoto(Guid userID, byte[] data, long maxFileSize, Size size, bool now)
        {
            if (data == null || data.Length <= 0) throw new UnknownImageFormatException();
            if (maxFileSize != -1 && data.Length > maxFileSize) throw new ImageWeightLimitException();

            var resizeTask = new ResizeWorkerItem(userID, data, maxFileSize, size, GetDataStore(), UserPhotoThumbnailSettings.LoadForUser(userID));

            if (now)
            {
                //Resize synchronously
                ResizeImage(resizeTask);
                return GetSizedPhotoAbsoluteWebPath(userID, size);
            }
            else
            {
                if (!ResizeQueue.GetItems().Contains(resizeTask))
                {
                    //Add
                    ResizeQueue.Add(resizeTask);
                    if (!ResizeQueue.IsStarted)
                    {
                        ResizeQueue.Start(ResizeImage);
                    }
                }
                return GetDefaultPhotoAbsoluteWebPath(size);
                //NOTE: return default photo here. Since task will update cache
            }
        }

        private static void ResizeImage(ResizeWorkerItem item)
        {
            try
            {
                var data = item.Data;
                using (var stream = new MemoryStream(data))
                using (var img = Image.FromStream(stream))
                {
                    var imgFormat = img.RawFormat;
                    if (item.Size != img.Size)
                    {
                        using (var img2 = item.Settings.IsDefault ?
                            CommonPhotoManager.DoThumbnail(img, item.Size, true, true, true) :
                            UserPhotoThumbnailManager.GetBitmap(img, item.Size, item.Settings))
                        {
                            data = CommonPhotoManager.SaveToBytes(img2);
                        }
                    }
                    else
                    {
                        data = CommonPhotoManager.SaveToBytes(img);
                    }

                    var widening = CommonPhotoManager.GetImgFormatName(imgFormat);
                    var fileName = string.Format("{0}_size_{1}-{2}.{3}", item.UserId, item.Size.Width, item.Size.Height, widening);

                    using (var stream2 = new MemoryStream(data))
                    {
                        item.DataStore.Save(fileName, stream2).ToString();

                        AddToCache(item.UserId, item.Size, fileName);
                    }
                }
            }
            catch (ArgumentException error)
            {
                throw new UnknownImageFormatException(error);
            }
        }

        public static string GetTempPhotoAbsoluteWebPath(string fileName)
        {
            return GetDataStore().GetUri(_tempDomainName, fileName).ToString();
        }

        public static string SaveTempPhoto(byte[] data, long maxFileSize, int maxWidth, int maxHeight)
        {
            ImageFormat imgFormat;
            int width;
            int height;
            data = TryParseImage(data, maxFileSize, new Size(maxWidth, maxHeight), out imgFormat, out width, out height);

            var fileName = Guid.NewGuid() + "." + CommonPhotoManager.GetImgFormatName(imgFormat);

            var store = GetDataStore();
            using (var stream = new MemoryStream(data))
            {
                return store.Save(_tempDomainName, fileName, stream).ToString();
            }
        }

        public static byte[] GetTempPhotoData(string fileName)
        {
            using (var s = GetDataStore().GetReadStream(_tempDomainName, fileName))
            {
                var data = new MemoryStream();
                var buffer = new Byte[1024 * 10];
                while (true)
                {
                    var count = s.Read(buffer, 0, buffer.Length);
                    if (count == 0) break;
                    data.Write(buffer, 0, count);
                }
                return data.ToArray();
            }
        }

        public static string GetSizedTempPhotoAbsoluteWebPath(string fileName, int newWidth, int newHeight)
        {
            var store = GetDataStore();
            if (store.IsFile(_tempDomainName, fileName))
            {
                using (var s = store.GetReadStream(_tempDomainName, fileName))
                using (var img = Image.FromStream(s))
                {
                    var imgFormat = img.RawFormat;
                    byte[] data;

                    if (img.Width != newWidth || img.Height != newHeight)
                    {
                        using (var img2 = CommonPhotoManager.DoThumbnail(img, new Size(newWidth, newHeight), true, true, true))
                        {
                            data = CommonPhotoManager.SaveToBytes(img2);
                        }
                    }
                    else
                    {
                        data = CommonPhotoManager.SaveToBytes(img);
                    }
                    var widening = CommonPhotoManager.GetImgFormatName(imgFormat);
                    var index = fileName.LastIndexOf('.');
                    var fileNameWithoutExt = (index != -1) ? fileName.Substring(0, index) : fileName;

                    var trueFileName = fileNameWithoutExt + "_size_" + newWidth.ToString() + "-" + newHeight.ToString() + "." + widening;
                    using (var stream = new MemoryStream(data))
                    {
                        return store.Save(_tempDomainName, trueFileName, stream).ToString();
                    }
                }
            }
            return GetDefaultPhotoAbsoluteWebPath(new Size(newWidth, newHeight));
        }

        public static void RemoveTempPhoto(string fileName)
        {
            var index = fileName.LastIndexOf('.');
            var fileNameWithoutExt = (index != -1) ? fileName.Substring(0, index) : fileName;
            try
            {
                var store = GetDataStore();
                store.DeleteFiles(_tempDomainName, "", fileNameWithoutExt + "*.*", false);
            }
            catch { };
        }


        public static Bitmap GetPhotoBitmap(Guid userID)
        {
            try
            {
                var data = CoreContext.UserManager.GetUserPhoto(userID);
                if (data != null)
                {
                    using (var s = new MemoryStream(data))
                    {
                        return new Bitmap(s);
                    }
                }
            }
            catch { }
            return null;
        }

        public static string SaveThumbnail(Guid userID, Image img, ImageFormat format)
        {
            var moduleID = Guid.Empty;
            var widening = CommonPhotoManager.GetImgFormatName(format);
            var size = img.Size;
            var fileName = string.Format("{0}{1}_size_{2}-{3}.{4}", (moduleID == Guid.Empty ? "" : moduleID.ToString()), userID, img.Width, img.Height, widening);

            var store = GetDataStore();
            string photoUrl;
            using (var s = new MemoryStream(CommonPhotoManager.SaveToBytes(img)))
            {
                img.Dispose();
                photoUrl = store.Save(fileName, s).ToString();
            }

            AddToCache(userID, size, fileName);
            return photoUrl;
        }

        public static byte[] GetUserPhotoData(Guid userId, Size size)
        {
            try
            {
                var pattern = string.Format("{0}_size_{1}-{2}.*", userId, size.Width, size.Height);

                var fileName = GetDataStore().ListFilesRelative("", "", pattern, false).FirstOrDefault();

                if (string.IsNullOrEmpty(fileName)) return null;

                using (var s = GetDataStore().GetReadStream("", fileName))
                {
                    var data = new MemoryStream();
                    var buffer = new Byte[1024 * 10];
                    while (true)
                    {
                        var count = s.Read(buffer, 0, buffer.Length);
                        if (count == 0) break;
                        data.Write(buffer, 0, count);
                    }
                    return data.ToArray();
                }
            }
            catch (Exception err)
            {
                LogManager.GetLogger("ASC.Web.Photo").Error(err);
                return null;
            }
        }

        private static IDataStore GetDataStore()
        {
            return StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(), "userPhotos");
        }
    }

    #region Exception Classes

    public class UnknownImageFormatException : Exception
    {
        public UnknownImageFormatException() : base("unknown image file type") { }

        public UnknownImageFormatException(Exception inner) : base("unknown image file type", inner) { }
    }

    public class ImageWeightLimitException : Exception
    {
        public ImageWeightLimitException() : base("image width is too large") { }
    }

    public class ImageSizeLimitException : Exception
    {
        public ImageSizeLimitException() : base("image size is too large") { }
    }

    #endregion


    /// <summary>
    /// Helper class for manipulating images.
    /// </summary>
    public static class ImageHelper
    {
        /// <summary>
        /// Rotate the given image byte array according to Exif Orientation data
        /// </summary>
        /// <param name="data">source image byte array</param>
        /// <param name="updateExifData">set it to TRUE to update image Exif data after rotation (default is TRUE)</param>
        /// <returns>The rotated image byte array. If no rotation occurred, source data will be returned.</returns>
        public static byte[] RotateImageByExifOrientationData(byte[] data, bool updateExifData = true)
        {
            try
            {
                using (var stream = new MemoryStream(data))
                using (var img = new Bitmap(stream))
                {
                    var fType = RotateImageByExifOrientationData(img, updateExifData);
                    if (fType != RotateFlipType.RotateNoneFlipNone)
                    {
                        var converter = new ImageConverter();
                        data = (byte[])converter.ConvertTo(img, typeof(byte[]));
                    }
                }
            }
            catch (Exception err)
            {
                LogManager.GetLogger("ASC.Web.Photo").Error(err);
            }

            return data;
        }

        /// <summary>
        /// Rotate the given image file according to Exif Orientation data
        /// </summary>
        /// <param name="sourceFilePath">path of source file</param>
        /// <param name="targetFilePath">path of target file</param>
        /// <param name="targetFormat">target format</param>
        /// <param name="updateExifData">set it to TRUE to update image Exif data after rotation (default is TRUE)</param>
        /// <returns>The RotateFlipType value corresponding to the applied rotation. If no rotation occurred, RotateFlipType.RotateNoneFlipNone will be returned.</returns>
        public static RotateFlipType RotateImageByExifOrientationData(string sourceFilePath, string targetFilePath, ImageFormat targetFormat, bool updateExifData = true)
        {
            // Rotate the image according to EXIF data
            var bmp = new Bitmap(sourceFilePath);
            var fType = RotateImageByExifOrientationData(bmp, updateExifData);
            if (fType != RotateFlipType.RotateNoneFlipNone)
            {
                bmp.Save(targetFilePath, targetFormat);
            }
            return fType;
        }

        /// <summary>
        /// Rotate the given bitmap according to Exif Orientation data
        /// </summary>
        /// <param name="img">source image</param>
        /// <param name="updateExifData">set it to TRUE to update image Exif data after rotation (default is TRUE)</param>
        /// <returns>The RotateFlipType value corresponding to the applied rotation. If no rotation occurred, RotateFlipType.RotateNoneFlipNone will be returned.</returns>
        public static RotateFlipType RotateImageByExifOrientationData(Image img, bool updateExifData = true)
        {
            const int orientationId = 0x0112;
            var fType = RotateFlipType.RotateNoneFlipNone;
            if (img.PropertyIdList.Contains(orientationId))
            {
                var pItem = img.GetPropertyItem(orientationId);
                fType = GetRotateFlipTypeByExifOrientationData(pItem.Value[0]);
                if (fType != RotateFlipType.RotateNoneFlipNone)
                {
                    img.RotateFlip(fType);
                    if (updateExifData) img.RemovePropertyItem(orientationId); // Remove Exif orientation tag
                }
            }
            return fType;
        }

        /// <summary>
        /// Return the proper System.Drawing.RotateFlipType according to given orientation EXIF metadata
        /// </summary>
        /// <param name="orientation">Exif "Orientation"</param>
        /// <returns>the corresponding System.Drawing.RotateFlipType enum value</returns>
        public static RotateFlipType GetRotateFlipTypeByExifOrientationData(int orientation)
        {
            switch (orientation)
            {
                case 1:
                    return RotateFlipType.RotateNoneFlipNone;
                case 2:
                    return RotateFlipType.RotateNoneFlipX;
                case 3:
                    return RotateFlipType.Rotate180FlipNone;
                case 4:
                    return RotateFlipType.Rotate180FlipX;
                case 5:
                    return RotateFlipType.Rotate90FlipX;
                case 6:
                    return RotateFlipType.Rotate90FlipNone;
                case 7:
                    return RotateFlipType.Rotate270FlipX;
                case 8:
                    return RotateFlipType.Rotate270FlipNone;
                default:
                    return RotateFlipType.RotateNoneFlipNone;
            }
        }
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/AuditModuleSpecifics.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Data.Backup.Tasks.Data;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal class AuditModuleSpecifics : ModuleSpecificsBase
    {
        private readonly TableInfo[] _tables = new[]
            {
                new TableInfo("audit_events", "tenant_id", "id") {UserIDColumns = new[] {"user_id"}},
                new TableInfo("login_events", "tenant_id", "id") {UserIDColumns = new[] {"user_id"}}
            };

        public override string ConnectionStringName
        {
            get { return "core"; }
        }

        public override ModuleName ModuleName
        {
            get { return ModuleName.Audit; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return _tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return Enumerable.Empty<RelationInfo>(); }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/InvoiceLineDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;

using ASC.Collections;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.CRM.Core.Entities;

using Newtonsoft.Json;

namespace ASC.CRM.Core.Dao
{
    public class CachedInvoiceLineDao : InvoiceLineDao
    {
        private readonly HttpRequestDictionary<InvoiceLine> _invoiceLineCache = new HttpRequestDictionary<InvoiceLine>("crm_invoice_line");

        public CachedInvoiceLineDao(int tenantID)
            : base(tenantID)
        {
        }

        public override InvoiceLine GetByID(int invoiceLineID)
        {
            return _invoiceLineCache.Get(invoiceLineID.ToString(CultureInfo.InvariantCulture), () => GetByIDBase(invoiceLineID));
        }

        private InvoiceLine GetByIDBase(int invoiceLineID)
        {
            return base.GetByID(invoiceLineID);
        }

        public override int SaveOrUpdateInvoiceLine(InvoiceLine invoiceLine)
        {
            if (invoiceLine != null && invoiceLine.ID > 0)
                ResetCache(invoiceLine.ID);

            return base.SaveOrUpdateInvoiceLine(invoiceLine);
        }

        public override void DeleteInvoiceLine(int invoiceLineID)
        {
            ResetCache(invoiceLineID);

            base.DeleteInvoiceLine(invoiceLineID);
        }

        private void ResetCache(int invoiceLineID)
        {
            _invoiceLineCache.Reset(invoiceLineID.ToString(CultureInfo.InvariantCulture));
        }
    }

    public class InvoiceLineDao : AbstractDao
    {
        public InvoiceLineDao(int tenantID)
            : base(tenantID)
        {
        }


        public static string GetJson(InvoiceItem invoiceItem)
        {
            return invoiceItem == null ?
                    string.Empty :
                    JsonConvert.SerializeObject(new
                    {
                        id = invoiceItem.ID,
                        title = invoiceItem.Title,
                        description = invoiceItem.Description
                    });
        }
        public static string GetJson(InvoiceTax invoiceTax)
        {
            return invoiceTax == null ?
                    string.Empty :
                    JsonConvert.SerializeObject(new
                    {
                        id = invoiceTax.ID,
                        name = invoiceTax.Name,
                        rate = invoiceTax.Rate,
                        description = invoiceTax.Description
                    });
        }

        #region Get

        public virtual List<InvoiceLine> GetAll()
        {
            return Db.ExecuteList(GetInvoiceLineSqlQuery(null)).ConvertAll(ToInvoiceLine);
        }

        public virtual List<InvoiceLine> GetByID(int[] ids)
        {
            return Db.ExecuteList(GetInvoiceLineSqlQuery(Exp.In("id", ids))).ConvertAll(ToInvoiceLine);
        }

        public virtual InvoiceLine GetByID(int id)
        {
            var invoiceLines = Db.ExecuteList(GetInvoiceLineSqlQuery(Exp.Eq("id", id))).ConvertAll(ToInvoiceLine);

            return invoiceLines.Count > 0 ? invoiceLines[0] : null;
        }

        public List<InvoiceLine> GetInvoiceLines(int invoiceID)
        {
            return Db.ExecuteList(GetInvoiceLineSqlQuery(Exp.Eq("invoice_id", invoiceID)).OrderBy("sort_order", true)).ConvertAll(ToInvoiceLine);
        }

        public List<InvoiceLine> GetInvoicesLines(int[] invoiceIDs)
        {
            return Db.ExecuteList(GetInvoiceLineSqlQuery(Exp.In("invoice_id", invoiceIDs)).OrderBy("sort_order", true)).ConvertAll(ToInvoiceLine);
        }

        #endregion


        #region SaveOrUpdate

        public virtual int SaveOrUpdateInvoiceLine(InvoiceLine invoiceLine)
        {
            _cache.Remove(new Regex(TenantID.ToString(CultureInfo.InvariantCulture) + "invoice.*"));

            return SaveOrUpdateInvoiceLineInDb(invoiceLine);
        }

        private int SaveOrUpdateInvoiceLineInDb(InvoiceLine invoiceLine)
        {
            if (invoiceLine.InvoiceID <= 0 || invoiceLine.InvoiceItemID <= 0)
                throw new ArgumentException();

            if (String.IsNullOrEmpty(invoiceLine.Description))
            {
                invoiceLine.Description = String.Empty;
            }

            if (Db.ExecuteScalar<int>(Query("crm_invoice_line").SelectCount().Where(Exp.Eq("id", invoiceLine.ID))) == 0)
            {
                invoiceLine.ID = Db.ExecuteScalar<int>(
                               Insert("crm_invoice_line")
                              .InColumnValue("id", 0)
                              .InColumnValue("invoice_id", invoiceLine.InvoiceID)
                              .InColumnValue("invoice_item_id", invoiceLine.InvoiceItemID)
                              .InColumnValue("invoice_tax1_id", invoiceLine.InvoiceTax1ID)
                              .InColumnValue("invoice_tax2_id", invoiceLine.InvoiceTax2ID)
                              .InColumnValue("sort_order", invoiceLine.SortOrder)
                              .InColumnValue("description", invoiceLine.Description)
                              .InColumnValue("quantity", invoiceLine.Quantity)
                              .InColumnValue("price", invoiceLine.Price)
                              .InColumnValue("discount", invoiceLine.Discount)
                              .Identity(1, 0, true));
            }
            else
            {

                Db.ExecuteNonQuery(
                    Update("crm_invoice_line")
                        .Set("invoice_id", invoiceLine.InvoiceID)
                        .Set("invoice_item_id", invoiceLine.InvoiceItemID)
                        .Set("invoice_tax1_id", invoiceLine.InvoiceTax1ID)
                        .Set("invoice_tax2_id", invoiceLine.InvoiceTax2ID)
                        .Set("sort_order", invoiceLine.SortOrder)
                        .Set("description", invoiceLine.Description)
                        .Set("quantity", invoiceLine.Quantity)
                        .Set("price", invoiceLine.Price)
                        .Set("discount", invoiceLine.Discount)
                        .Where(Exp.Eq("id", invoiceLine.ID)));
            }
            return invoiceLine.ID;
        }

        #endregion


        #region Delete

        public virtual void DeleteInvoiceLine(int invoiceLineID)
        {
            var invoiceLine = GetByID(invoiceLineID);

            if (invoiceLine == null) return;

            Db.ExecuteNonQuery(Delete("crm_invoice_line").Where("id", invoiceLineID));

            /*_cache.Remove(_invoiceItemCacheKey);
            _cache.Insert(_invoiceLineCacheKey, String.Empty);*/
        }

        public void DeleteInvoiceLines(int invoiceID)
        {
            Db.ExecuteNonQuery(Delete("crm_invoice_line").Where(Exp.Eq("invoice_id", invoiceID)));

            /*_cache.Remove(_invoiceItemCacheKey);
            _cache.Insert(_invoiceLineCacheKey, String.Empty);*/
        }

        public Boolean CanDelete(int invoiceLineID)
        {
            return CanDeleteInDb(invoiceLineID);
        }

        public Boolean CanDeleteInDb(int invoiceLineID)
        {

            var invoiceID = Db.ExecuteScalar<int>(Query("crm_invoice_line").Select("invoice_id")
                                 .Where(Exp.Eq("id", invoiceLineID)));

            if (invoiceID == 0) return false;

            var count = Db.ExecuteScalar<int>(Query("crm_invoice_line").SelectCount()
                                    .Where(Exp.Eq("invoice_id", invoiceID)));

            return count > 1;
        }

        #endregion


        #region Private Methods

        private static InvoiceLine ToInvoiceLine(object[] row)
        {
            return new InvoiceLine
            {
                ID = Convert.ToInt32(row[0]),
                InvoiceID = Convert.ToInt32(row[1]),
                InvoiceItemID = Convert.ToInt32(row[2]),
                InvoiceTax1ID = Convert.ToInt32(row[3]),
                InvoiceTax2ID = Convert.ToInt32(row[4]),
                SortOrder = Convert.ToInt32(row[5]),
                Description = Convert.ToString(row[6]),
                Quantity = Convert.ToDecimal(row[7]),
                Price = Convert.ToDecimal(row[8]),
                Discount = Convert.ToDecimal(row[9])
            };
        }

        private SqlQuery GetInvoiceLineSqlQuery(Exp where)
        {
            var sqlQuery = Query("crm_invoice_line")
                .Select(
                    "id",
                    "invoice_id",
                    "invoice_item_id",
                    "invoice_tax1_id",
                    "invoice_tax2_id",
                    "sort_order",
                    "description",
                    "quantity",
                    "price",
                    "discount");

            if (where != null)
            {
                sqlQuery.Where(where);
            }

            return sqlQuery;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/js/filterhandler.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function() {
    function onRenderProfiles(evt, params, data) {
        jq('#peopleFilter').advansedFilter({
            nonetrigger: true,
            hintDefaultDisable: true,
            sorters: [
                        { id: params.sortby, dsc: params.sortorder }
                     ],
            filters: [
                    {
                        id: 'text',
                        params: { value: params.query }
                    },
                    {
                        id: 'selected-group',
                        params: params.groupId ? { id: params.groupId} : null
                    },
                    {
                        id: 'selected-employee-status-active',
                        params: params.employeestatus ? { value: params.employeestatus } : null
                    },
                    {
                        id: 'selected-employee-status-disabled',
                        params: params.employeestatus ? { value: params.employeestatus } : null
                    },
                    {
                        id: 'selected-activation-status-active',
                        params: params.activationstatus ? { value: params.activationstatus } : null
                    },
                    {
                        id: 'selected-activation-status-pending',
                        params: params.activationstatus ? { value: params.activationstatus } : null
                    },
                    {
                        id: 'selected-type-admin',
                        params: params.type ? { value: params.type } : null
                    },
                    {
                        id: 'selected-type-user',
                        params: params.type ? { value: params.type} : null
                    },
                    {
                        id: 'selected-type-visitor',
                        params: params.type ? { value: params.type} : null
                    }
                  ]
        });
        if (params.groupId || params.employeestatus || params.activationstatus || params.type) {
            jq('#peopleFilter').addClass("has-filters");
        }
    }

    jq(window).bind('people-render-profiles', onRenderProfiles);
})();


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Statistics/VisitorsChart/VisitorsChart.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;
using System.Web.UI;

using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Statistics
{
    [ManagementControl(ManagementType.Statistic, Location)]
    public partial class VisitorsChart : UserControl
    {
        public const string Location = "~/UserControls/Statistics/VisitorsChart/VisitorsChart.ascx";

        protected void Page_Load(object sender, EventArgs e)
        {
            AjaxPro.Utility.RegisterTypeForAjax(GetType());

            Page.RegisterStyle("~/UserControls/Statistics/VisitorsChart/css/visitorschart_style.less")
                .RegisterBodyScripts("~/UserControls/Statistics/VisitorsChart/js/excanvas.min.js",
                "~/UserControls/Statistics/VisitorsChart/js/jquery.flot.js",
                "~/UserControls/Statistics/VisitorsChart/js/tooltip.js",
                "~/UserControls/Statistics/VisitorsChart/js/visitorschart.js");

            var jsResources = new StringBuilder();
            jsResources.Append("jq(document).ready(function(){");
            jsResources.Append("if(typeof window.ASC==='undefined')window.ASC={};");
            jsResources.Append("if(typeof window.ASC.Resources==='undefined')window.ASC.Resources={};");
            jsResources.Append("window.ASC.Resources.chartDateFormat='" + Resource.ChartDateFormat + "';");
            jsResources.Append("window.ASC.Resources.chartMonthNames='" + Resource.ChartMonthNames + "';");
            jsResources.Append("window.ASC.Resources.hitLabel='" + Resource.VisitorsChartHitLabel + "';");
            jsResources.Append("window.ASC.Resources.hostLabel='" + Resource.VisitorsChartHostLabel + "';");
            jsResources.Append("window.ASC.Resources.visitsLabel='" + Resource.VisitorsChartVisitsLabel + "';");
            jsResources.Append("});");

            Page.RegisterInlineScript(jsResources.ToString());
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/CustomNavigation/js/customnavigation.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


CustomNavigationManager = new function () {

    var renderItem = function (item) {
        var container = jq("#customNavigationItems tr.display-none").clone().removeClass("display-none");
        container.find(".item-img img").attr("src", item.smallImg);
        container.find(".item-label div").text(item.label);
        container.find(".item-action a").attr("id", item.id);

        var exist = jq("#" + item.id);

        if (exist.length) {
            exist.parents("tr:first").replaceWith(container);
        } else {
            container.appendTo("#customNavigationItems");
        }

        jq("#addBtn").parent().addClass("middle-button-container");

        exist = jq("#topNavCustomItem_" + item.id);

        if (!item.showInMenu) {
            exist.remove();
            return;
        }

        var topNavItemLi = jq("<li/>").attr("id", "topNavCustomItem_" + item.id);
        var topNavItemA = jq("<a/>").attr("href", item.url).attr("target", "_blank").addClass("dropdown-item menu-products-item").text(item.label);
        var topNavItemSpan = jq("<span/>").addClass("dropdown-item-icon").attr("style", "background: url('" + item.smallImg + "')");

        topNavItemSpan.prependTo(topNavItemA);
        topNavItemLi.append(topNavItemA);

        if (exist.length) {
            exist.replaceWith(topNavItemLi);
        } else {
            topNavItemLi.appendTo("#studio_productListPopupPanel .custom-nav-items ul");
        }
    };

    var bindUploader = function (uploader, img, size) {
        return new AjaxUpload(uploader, {
            action: "ajaxupload.ashx?type=ASC.Web.Studio.UserControls.CustomNavigation.LogoUploader,ASC.Web.Studio",
            autoSubmit: false,
            data: { size: size },
            onChange: function () {
                var fileUploader = this,
                    file = fileUploader._input.files[0],
                    reader = new FileReader();

                reader.onload = function (event) {
                    var dataUri = event.target.result,
                        image = new Image();

                    if (dataUri.indexOf("data:image") == -1) {
                        toastr.error(jq("#notImageError").text());
                        return;
                    }

                    image.onload = function () {
                        if (image.width == size && image.height == size) {
                            LoadingBanner.showLoaderBtn("#studio_customNavigation");
                            fileUploader.submit();
                        } else {
                            toastr.error(jq("#sizeError").text());
                        }
                    };

                    image.src = reader.result;
                };

                reader.onerror = function (event) {
                    console.error("The file can not be read! error code " + event.target.error.code);
                };

                reader.readAsDataURL(file);
            },
            onComplete: function (file, response) {
                var result = eval("(" + response + ")");
                if (result.Success) {
                    img.attr("src", result.Message);
                } else {
                    toastr.error(result.Message);
                }
                LoadingBanner.hideLoaderBtn("#studio_customNavigation");
            }
        });
    };

    var getItemData = function() {
        var item = {};
        var valid = true;

        item.id = jq("#itemId").val().trim();

        var obj = jq("#labelText");
        var value = obj.val().trim();
        item.label = value;
        value ? obj.removeClass("with-error") : (obj.addClass("with-error") && (valid = false));

        obj = jq("#urlText");
        value = obj.val().trim();
        item.url = value;

        if (value) {
            obj.removeClass("with-error");
            var urlpattern = /^(ftp|http|https):\/\//;
            if (!urlpattern.test(value)) {
                var trimpattern = /^\/+/g;
                item.url = "http://" + value.replace(trimpattern, "");
            }
        } else {
            obj.addClass("with-error");
            valid = false;
        }

        item.showInMenu = jq("#showInMenuCbx").is(":checked");

        item.showOnHomePage = jq("#showOnHomePageCbx").is(":checked");
        
        item.smallImg = jq("#smallImg").attr("src").trim();

        item.bigImg = jq("#bigImg").attr("src").trim();

        return valid ? item : null;
    };

    var setItemData = function (item) {
        jq("#itemId").val(item.id);
        jq("#labelText").val(item.label).removeClass("with-error");
        jq("#urlText").val(item.url).removeClass("with-error");
        jq("#showInMenuCbx").prop("checked", item.showInMenu);
        jq("#showOnHomePageCbx").prop("checked", item.showOnHomePage);
        jq("#smallImg").attr("src", item.smallImg);
        jq("#bigImg").attr("src", item.bigImg);
    };

    this.Init = function () {

        jq("#addBtn").click(function () {
            Teamlab.getCustomNavigationItemSample({},
            {
                before: function () {
                    LoadingBanner.showLoaderBtn("#studio_customNavigation");
                },
                after: function () {
                    LoadingBanner.hideLoaderBtn("#studio_customNavigation");
                },
                success: function (params, response) {
                    setItemData(response);
                    var dialog = jq("#customNavigationItemDialog").removeClass("settings-mode");
                    window.StudioBlockUIManager.blockUI(dialog, 400);
                },
                error: function (params, errors) {
                    LoadingBanner.showMesInfoBtn("#studio_customNavigation", errors[0], "error");
                }
            });
        });

        jq("#customNavigationItems").on("click", ".item-action a", function () {
            Teamlab.getCustomNavigationItem({}, jq(this).attr("id"),
            {
                before: function () {
                    LoadingBanner.showLoaderBtn("#studio_customNavigation");
                },
                after: function () {
                    LoadingBanner.hideLoaderBtn("#studio_customNavigation");
                },
                success: function (params, response) {
                    if (!response.id) return;

                    setItemData(response);
                    var dialog = jq("#customNavigationItemDialog").addClass("settings-mode");
                    window.StudioBlockUIManager.blockUI(dialog, 400);
                },
                error: function (params, errors) {
                    LoadingBanner.showMesInfoBtn("#studio_customNavigation", errors[0], "error");
                }
            });
        });

        jq("#customNavigationItemDialog .cancel-btn").click(function () {
            PopupKeyUpActionProvider.CloseDialog();
        });

        jq("#saveBtn").click(function () {
            var data = getItemData();

            if (!data) return;

            Teamlab.createCustomNavigationItem({}, { item: data },
            {
                before: function () {
                    LoadingBanner.showLoaderBtn("#customNavigationItemDialog");
                },
                after: function () {
                    LoadingBanner.hideLoaderBtn("#customNavigationItemDialog");
                },
                success: function (params, response) {
                    renderItem(response);
                    PopupKeyUpActionProvider.CloseDialog();
                    toastr.success(ASC.Resources.Master.ResourceJS.SuccessfullySaveSettingsMessage);
                },
                error: function (params, errors) {
                    LoadingBanner.showMesInfoBtn("#customNavigationItemDialog", errors[0], "error");
                }
            });
        });

        jq("#removeBtn").click(function () {
            var id = jq("#customNavigationItemDialog #itemId").val();

            Teamlab.deleteCustomNavigationItem({}, id,
            {
                before: function () {
                    LoadingBanner.showLoaderBtn("#customNavigationItemDialog");
                },
                after: function () {
                    LoadingBanner.hideLoaderBtn("#customNavigationItemDialog");
                },
                success: function () {
                    jq("#" + id).parents("tr:first").remove();
                    jq("#topNavCustomItem_" + id).remove();

                    if (!jq("#customNavigationItems tr:visible").length)
                        jq("#addBtn").parent().removeClass("middle-button-container");

                    PopupKeyUpActionProvider.CloseDialog();
                },
                error: function (params, errors) {
                    LoadingBanner.showMesInfoBtn("#customNavigationItemDialog", errors[0], "error");
                }
            });
        });

        bindUploader(jq("#smallUploader"), jq("#smallImg"), 16);

        bindUploader(jq("#bigUploader"), jq("#bigImg"), 100);
    };
};

jq(document).ready(function () {
    CustomNavigationManager.Init();
});

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/js/tariffnotify.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


jq(function () {
    jq("#tariffNotifyClose").click(function () {
        jq("#tariffNotifyPanel").remove();

        TariffNotifyController.HideNotify({},
            function (result) {
                if (result.error != null) {
                    toastr.error(result.error.Message);
                    return;
                }
            });
        return true;
    });
});

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/Base/ComposeEngineBase.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Web;

using ASC.Common.Logging;
using ASC.Core.Notify.Signalr;
using ASC.Mail.Core.Dao.Expressions.Attachment;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Core.Dao.Expressions.Message;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Data.Contracts.Base;
using ASC.Mail.Data.Search;
using ASC.Mail.Data.Storage;
using ASC.Mail.Enums;
using ASC.Mail.Extensions;
using ASC.Mail.Utils;

using MailMessage = ASC.Mail.Data.Contracts.MailMessageData;

namespace ASC.Mail.Core.Engine
{
    public class ComposeEngineBase
    {
        public ILog Log { get; set; }
        public static SignalrServiceClient _signalrServiceClient;
        public readonly bool _isAutoreply;
        public readonly bool _sslCertificatePermit;
        public const string EMPTY_HTML_BODY = "<div dir=\"ltr\"><br></div>"; // GMail style

        public int Tenant { get; private set; }
        public string User { get; private set; }

        public class DeliveryFailureMessageTranslates
        {
            public string DaemonEmail { get; set; }
            public string SubjectLabel { get; set; }
            public string AutomaticMessageLabel { get; set; }
            public string MessageIdentificator { get; set; }
            public string RecipientsLabel { get; set; }
            public string RecommendationsLabel { get; set; }
            public string TryAgainButtonLabel { get; set; }
            public string FaqInformationLabel { get; set; }
            public string ReasonLabel { get; set; }

            public DeliveryFailureMessageTranslates(string daemonEmail,
                string subjectLabel,
                string automaticMessageLabel,
                string messageIdentificator,
                string recipientsLabel,
                string recommendationsLabel,
                string tryAgainButtonLabel,
                string faqInformationLabel,
                string reasonLabel
                )
            {
                DaemonEmail = daemonEmail;
                SubjectLabel = subjectLabel;
                AutomaticMessageLabel = automaticMessageLabel;
                MessageIdentificator = messageIdentificator;
                RecipientsLabel = recipientsLabel;
                RecommendationsLabel = recommendationsLabel;
                TryAgainButtonLabel = tryAgainButtonLabel;
                FaqInformationLabel = faqInformationLabel;
                ReasonLabel = reasonLabel;
            }

            public static DeliveryFailureMessageTranslates Defauilt
            {
                get
                {
                    return new DeliveryFailureMessageTranslates("<EMAIL>",
                        "Message Delivery Failure",
                        "This message was created automatically by mail delivery software.",
                        "Delivery failed for message with subject \"{subject}\" from {date}.",
                        "Message could not be delivered to recipient(s)",
                        "Please, check your message recipients addresses and message format. " +
                        "If you are sure your message is correct, check all the {account_name} account settings, " +
                        "and, if everything is correct, sign in to the mail service you use and confirm any " +
                        "verification questions, in case there are some. After then try again.",
                        "Change your message",
                        "In case the error persists, please read the {url_begin}FAQ section{url_end} " +
                        "to learn more about the problem.",
                        "Reason");
                }
            }
        }

        public DeliveryFailureMessageTranslates DaemonLabels { get; internal set; }

        public ComposeEngineBase(int tenant, string user, DeliveryFailureMessageTranslates daemonLabels = null, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.ComposeEngineBase");

            DaemonLabels = daemonLabels ?? DeliveryFailureMessageTranslates.Defauilt;

            _sslCertificatePermit = Defines.SslCertificatesErrorPermit;

            if (_signalrServiceClient != null) return;
            _signalrServiceClient = new SignalrServiceClient("mail");
        }

        #region .Public

        public virtual MailMessage Save(
            int id,
            string from,
            List<string> to,
            List<string> cc,
            List<string> bcc,
            string mimeReplyToId,
            bool importance,
            string subject,
            List<int> tags,
            string body,
            List<MailAttachmentData> attachments,
            string calendarIcs,
            DeliveryFailureMessageTranslates translates = null)
        {
            var mailAddress = new MailAddress(from);

            var engine = new EngineFactory(Tenant, User);

            var accounts = engine.AccountEngine.GetAccountInfoList().ToAccountData();

            var account = accounts.FirstOrDefault(a => a.Email.ToLower().Equals(mailAddress.Address));

            if (account == null)
                throw new ArgumentException("Mailbox not found");

            if (account.IsGroup)
                throw new InvalidOperationException("Saving emails from a group address is forbidden");

            var mbox = engine.MailboxEngine.GetMailboxData(
                new СoncreteUserMailboxExp(account.MailboxId, Tenant, User));

            if (mbox == null)
                throw new ArgumentException("No such mailbox");

            string mimeMessageId, streamId;

            var previousMailboxId = mbox.MailBoxId;

            if (id > 0)
            {
                var message = engine.MessageEngine.GetMessage(id, new MailMessage.Options
                {
                    LoadImages = false,
                    LoadBody = true,
                    NeedProxyHttp = Defines.NeedProxyHttp,
                    NeedSanitizer = false
                });

                if (message.Folder != FolderType.Draft)
                {
                    throw new InvalidOperationException("Saving emails is permitted only in the Drafts folder");
                }

                if (message.HtmlBody.Length > Defines.MaximumMessageBodySize)
                {
                    throw new InvalidOperationException("Message body exceeded limit (" + Defines.MaximumMessageBodySize / 1024 + " KB)");
                }

                mimeMessageId = message.MimeMessageId;

                streamId = message.StreamId;

                previousMailboxId = message.MailboxId;
            }
            else
            {
                mimeMessageId = MailUtil.CreateMessageId();
                streamId = MailUtil.CreateStreamId();
            }

            var fromAddress = MailUtil.CreateFullEmail(mbox.Name, mbox.EMail.Address);

            var compose = new MailDraftData(id, mbox, fromAddress, to, cc, bcc, subject, mimeMessageId, mimeReplyToId, importance,
                    tags, body, streamId, attachments, calendarIcs)
            { PreviousMailboxId = previousMailboxId };

            DaemonLabels = translates ?? DeliveryFailureMessageTranslates.Defauilt;

            return Save(compose);
        }

        public MailMessage Save(MailComposeBase compose)
        {
            var embededAttachmentsForSaving = FixHtmlBodyWithEmbeddedAttachments(compose);

            var message = compose.ToMailMessage();

            var engine = new EngineFactory(compose.Mailbox.TenantId, compose.Mailbox.UserId);

            var addIndex = compose.Id == 0;

            var attachmentsToRestore = message.Attachments.Where(att => att.streamId != message.StreamId || att.isTemp).ToList();

            var needRestoreAttachments = attachmentsToRestore.Any();

            if (needRestoreAttachments)
            {
                message.Attachments.ForEach(
                    attachment =>
                        engine.AttachmentEngine.StoreAttachmentCopy(compose.Mailbox.TenantId, compose.Mailbox.UserId,
                            attachment, compose.StreamId));
            }

            MessageEngine.StoreMailBody(compose.Mailbox, message, Log);

            long usedQuota;

            using (var daoFactory = new DaoFactory())
            {
                var db = daoFactory.DbManager;

                using (var tx = db.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    compose.Id = engine.MessageEngine.MailSave(daoFactory, compose.Mailbox, message, compose.Id, message.Folder, message.Folder, null,
                        string.Empty, string.Empty, false, out usedQuota);

                    message.Id = compose.Id;

                    if (compose.AccountChanged)
                    {
                        engine.ChainEngine.UpdateChain(daoFactory, message.ChainId, message.Folder, null, compose.PreviousMailboxId,
                            compose.Mailbox.TenantId, compose.Mailbox.UserId);
                    }

                    var daoMailInfo = daoFactory.CreateMailInfoDao(compose.Mailbox.TenantId, compose.Mailbox.UserId);

                    if (compose.Id > 0 && needRestoreAttachments)
                    {
                        var daoAttachment = daoFactory.CreateAttachmentDao(compose.Mailbox.TenantId, compose.Mailbox.UserId);
                        var existingAttachments = daoAttachment.GetAttachments(
                            new ConcreteMessageAttachmentsExp(compose.Id, compose.Mailbox.TenantId, compose.Mailbox.UserId));

                        foreach (var attachment in message.Attachments)
                        {
                            if (existingAttachments.Any(x => x.Id == attachment.fileId ||
                            (x.Stream == attachment.streamId && x.StoredName == attachment.storedName)))
                            {
                                continue;
                            }

                            var attach = attachment.ToAttachmnet(compose.Id);
                            attach.Id = 0;

                            var newId = daoAttachment.SaveAttachment(attach);
                            attachment.fileId = newId;
                        }

                        if (message.Attachments.Any())
                        {
                            var count = daoAttachment.GetAttachmentsCount(
                                new ConcreteMessageAttachmentsExp(compose.Id, compose.Mailbox.TenantId, compose.Mailbox.UserId));

                            daoMailInfo.SetFieldValue(
                                SimpleMessagesExp.CreateBuilder(compose.Mailbox.TenantId, compose.Mailbox.UserId)
                                    .SetMessageId(compose.Id)
                                    .Build(),
                                MailTable.Columns.AttachCount,
                                count);
                        }
                    }

                    if (compose.Id > 0 && embededAttachmentsForSaving.Any())
                    {
                        var daoAttachment = daoFactory.CreateAttachmentDao(compose.Mailbox.TenantId, compose.Mailbox.UserId);

                        foreach (var attachment in embededAttachmentsForSaving)
                        {
                            var newId = daoAttachment.SaveAttachment(attachment.ToAttachmnet(compose.Id));
                            attachment.fileId = newId;
                        }

                        if (message.Attachments.Any())
                        {
                            var count = daoAttachment.GetAttachmentsCount(
                                new ConcreteMessageAttachmentsExp(compose.Id, compose.Mailbox.TenantId, compose.Mailbox.UserId));

                            daoMailInfo.SetFieldValue(
                                SimpleMessagesExp.CreateBuilder(compose.Mailbox.TenantId, compose.Mailbox.UserId)
                                    .SetMessageId(compose.Id)
                                    .Build(),
                                MailTable.Columns.AttachCount,
                                count);
                        }
                    }

                    engine.ChainEngine.UpdateChain(daoFactory, message.ChainId, message.Folder, null, compose.Mailbox.MailBoxId, compose.Mailbox.TenantId,
                        compose.Mailbox.UserId);

                    if (compose.AccountChanged)
                    {
                        var daoCrmLink = daoFactory.CreateCrmLinkDao(compose.Mailbox.TenantId, compose.Mailbox.UserId);

                        daoCrmLink.UpdateCrmLinkedMailboxId(message.ChainId, compose.PreviousMailboxId,
                            compose.Mailbox.MailBoxId);
                    }

                    tx.Commit();

                }
            }

            if (usedQuota > 0)
            {
                engine.QuotaEngine.QuotaUsedDelete(usedQuota);
            }

            if (addIndex)
            {
                engine.IndexEngine.Add(message.ToMailWrapper(compose.Mailbox.TenantId, new Guid(compose.Mailbox.UserId)));
            }
            else
            {
                engine.IndexEngine.Update(new List<MailWrapper>
                {
                    message.ToMailWrapper(compose.Mailbox.TenantId,
                        new Guid(compose.Mailbox.UserId))
                });
            }

            try
            {
                var tempStorage = MailDataStore.GetDataStore(compose.Mailbox.TenantId);

                tempStorage.DeleteDirectory("attachments_temp", compose.Mailbox.UserId + "/" + compose.StreamId + "/");
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("Clearing temp storage failed with exception: {0}", ex.ToString());
            }

            return message;
        }

        public MailMessage GetTemplate()
        {
            var template = new MailMessage
            {
                Attachments = new List<MailAttachmentData>(),
                Bcc = "",
                Cc = "",
                Subject = "",
                From = "",
                HtmlBody = "",
                Important = false,
                ReplyTo = "",
                MimeMessageId = "",
                MimeReplyToId = "",
                To = "",
                StreamId = MailUtil.CreateStreamId()
            };

            return template;
        }

        #endregion

        #region .Private

        private List<MailAttachmentData> FixHtmlBodyWithEmbeddedAttachments(MailComposeBase compose)
        {
            var embededAttachmentsForSaving = new List<MailAttachmentData>();

            var embeddedLinks = compose.GetEmbeddedAttachmentLinks();
            if (!embeddedLinks.Any())
                return embededAttachmentsForSaving;

            var fckStorage = StorageManager.GetDataStoreForCkImages(compose.Mailbox.TenantId);
            var attachmentStorage = StorageManager.GetDataStoreForAttachments(compose.Mailbox.TenantId);
            var currentMailFckeditorUrl = fckStorage.GetUri(StorageManager.CKEDITOR_IMAGES_DOMAIN, "").ToString();
            var currentUserStorageUrl = MailStoragePathCombiner.GetUserMailsDirectory(compose.Mailbox.UserId);

            var engine = new EngineFactory(compose.Mailbox.TenantId, compose.Mailbox.UserId);

            StorageManager storage = null;
            foreach (var embeddedLink in embeddedLinks)
            {
                try
                {
                    var isFckImage = embeddedLink.StartsWith(currentMailFckeditorUrl);
                    var prefixLength = isFckImage
                        ? currentMailFckeditorUrl.Length
                        : embeddedLink.IndexOf(currentUserStorageUrl, StringComparison.Ordinal) +
                          currentUserStorageUrl.Length + 1;
                    var fileLink = HttpUtility.UrlDecode(embeddedLink.Substring(prefixLength));
                    var fileName = Path.GetFileName(fileLink);
                    var attach = new MailAttachmentData
                    {
                        fileName = fileName,
                        storedName = fileName,
                        contentId = embeddedLink.GetMd5(),
                        storedFileUrl = fileLink,
                        streamId = compose.StreamId,
                        user = compose.Mailbox.UserId,
                        tenant = compose.Mailbox.TenantId,
                        mailboxId = compose.Mailbox.MailBoxId
                    };

                    var savedAttachment =
                        engine.AttachmentEngine.GetAttachment(
                            new ConcreteContentAttachmentExp(compose.Id, attach.contentId));

                    var savedAttachmentId = savedAttachment == null ? 0 : savedAttachment.fileId;

                    var attachmentWasSaved = savedAttachmentId != 0;
                    var currentImgStorage = isFckImage ? fckStorage : attachmentStorage;
                    var domain = isFckImage ? StorageManager.CKEDITOR_IMAGES_DOMAIN : compose.Mailbox.UserId;

                    if (compose.Id == 0 || !attachmentWasSaved)
                    {
                        attach.data = StorageManager.LoadDataStoreItemData(domain, fileLink, currentImgStorage);

                        if (storage == null)
                        {
                            storage = new StorageManager(compose.Mailbox.TenantId, compose.Mailbox.UserId);
                        }

                        storage.StoreAttachmentWithoutQuota(attach);

                        embededAttachmentsForSaving.Add(attach);
                    }

                    if (attachmentWasSaved)
                    {
                        attach = engine.AttachmentEngine.GetAttachment(
                            new ConcreteUserAttachmentExp(savedAttachmentId, compose.Mailbox.TenantId, compose.Mailbox.UserId));

                        var path = MailStoragePathCombiner.GerStoredFilePath(attach);
                        currentImgStorage = attachmentStorage;
                        attach.storedFileUrl =
                            MailStoragePathCombiner.GetStoredUrl(currentImgStorage.GetUri(path));
                    }

                    compose.HtmlBody = compose.HtmlBody.Replace(embeddedLink, attach.storedFileUrl);

                }
                catch (Exception ex)
                {
                    Log.ErrorFormat("ChangeEmbededAttachmentLinksForStoring() failed with exception: {0}", ex.ToString());
                }
            }

            return embededAttachmentsForSaving;
        }

        #endregion
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/Batch/ApiBatchRequest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Net.Mime;
using System.Text;

namespace ASC.Api.Batch
{
    public class ApiBatchRequest
    {
        public ApiBatchRequest()
        {
            //Defaults
            BodyContentType = new ContentType("application/x-www-form-urlencoded") { CharSet = Encoding.UTF8.WebName }.ToString();
            Method = "GET";
        }

        public int Order { get; set; }

        public string[] After { get; set; }
        public string[] Before { get; set; }

        public string RelativeUrl { get; set; }

        public string Name { get; set; }

        private string _method;
        public string Method
        {
            get { return string.IsNullOrEmpty(_method) ? "GET" : _method; }
            set { _method = value; }
        }

        public string Body { get; set; }

        public string BodyContentType { get; set; }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Calendars/ITodo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Web.Core.Calendars
{

    public class TodoContext : ICloneable
    {
        #region ICloneable Members

        public object Clone()
        {
            return this.MemberwiseClone();
        }

        #endregion
    }

    public interface ITodo : IiCalFormatView
    {
        string Id { get; }
        string Uid { get; }
        string CalendarId { get; }
        string Name { get; }
        string Description { get; }
        Guid OwnerId { get; }
        DateTime UtcStartDate { get; }
        DateTime Completed { get; }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/vCard/PhoneNumber.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Mime.vCard
{
    /// <summary>
    /// vCard phone number implementation.
    /// </summary>
    public class PhoneNumber
    {
        #region Members

        private readonly Item m_pItem;
        private string m_Number = "";
        private PhoneNumberType_enum m_Type = PhoneNumberType_enum.Voice;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="item">Owner vCard item.</param>
        /// <param name="type">Phone number type. Note: This value can be flagged value !</param>
        /// <param name="number">Phone number.</param>
        internal PhoneNumber(Item item, PhoneNumberType_enum type, string number)
        {
            m_pItem = item;
            m_Type = type;
            m_Number = number;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets underlaying vCrad item.
        /// </summary>
        public Item Item
        {
            get { return m_pItem; }
        }

        /// <summary>
        /// Gets or sets phone number.
        /// </summary>
        public string Number
        {
            get { return m_Number; }

            set
            {
                m_Number = value;
                Changed();
            }
        }

        /// <summary>
        /// Gets or sets phone number type. Note: This property can be flagged value !
        /// </summary>
        public PhoneNumberType_enum NumberType
        {
            get { return m_Type; }

            set
            {
                m_Type = value;
                Changed();
            }
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Parses phone from vCard TEL structure string.
        /// </summary>
        /// <param name="item">vCard TEL item.</param>
        internal static PhoneNumber Parse(Item item)
        {
            PhoneNumberType_enum type = PhoneNumberType_enum.NotSpecified;
            if (item.ParametersString.ToUpper().IndexOf("PREF") != -1)
            {
                type |= PhoneNumberType_enum.Preferred;
            }
            if (item.ParametersString.ToUpper().IndexOf("HOME") != -1)
            {
                type |= PhoneNumberType_enum.Home;
            }
            if (item.ParametersString.ToUpper().IndexOf("MSG") != -1)
            {
                type |= PhoneNumberType_enum.Msg;
            }
            if (item.ParametersString.ToUpper().IndexOf("WORK") != -1)
            {
                type |= PhoneNumberType_enum.Work;
            }
            if (item.ParametersString.ToUpper().IndexOf("VOICE") != -1)
            {
                type |= PhoneNumberType_enum.Voice;
            }
            if (item.ParametersString.ToUpper().IndexOf("FAX") != -1)
            {
                type |= PhoneNumberType_enum.Fax;
            }
            if (item.ParametersString.ToUpper().IndexOf("CELL") != -1)
            {
                type |= PhoneNumberType_enum.Cellular;
            }
            if (item.ParametersString.ToUpper().IndexOf("VIDEO") != -1)
            {
                type |= PhoneNumberType_enum.Video;
            }
            if (item.ParametersString.ToUpper().IndexOf("PAGER") != -1)
            {
                type |= PhoneNumberType_enum.Pager;
            }
            if (item.ParametersString.ToUpper().IndexOf("BBS") != -1)
            {
                type |= PhoneNumberType_enum.BBS;
            }
            if (item.ParametersString.ToUpper().IndexOf("MODEM") != -1)
            {
                type |= PhoneNumberType_enum.Modem;
            }
            if (item.ParametersString.ToUpper().IndexOf("CAR") != -1)
            {
                type |= PhoneNumberType_enum.Car;
            }
            if (item.ParametersString.ToUpper().IndexOf("ISDN") != -1)
            {
                type |= PhoneNumberType_enum.ISDN;
            }
            if (item.ParametersString.ToUpper().IndexOf("PCS") != -1)
            {
                type |= PhoneNumberType_enum.PCS;
            }

            return new PhoneNumber(item, type, item.Value);
        }

        /// <summary>
        /// Converts PhoneNumberType_enum to vCard item parameters string.
        /// </summary>
        /// <param name="type">Value to convert.</param>
        /// <returns></returns>
        internal static string PhoneTypeToString(PhoneNumberType_enum type)
        {
            string retVal = "";
            if ((type & PhoneNumberType_enum.BBS) != 0)
            {
                retVal += "BBS,";
            }
            if ((type & PhoneNumberType_enum.Car) != 0)
            {
                retVal += "CAR,";
            }
            if ((type & PhoneNumberType_enum.Cellular) != 0)
            {
                retVal += "CELL,";
            }
            if ((type & PhoneNumberType_enum.Fax) != 0)
            {
                retVal += "FAX,";
            }
            if ((type & PhoneNumberType_enum.Home) != 0)
            {
                retVal += "HOME,";
            }
            if ((type & PhoneNumberType_enum.ISDN) != 0)
            {
                retVal += "ISDN,";
            }
            if ((type & PhoneNumberType_enum.Modem) != 0)
            {
                retVal += "MODEM,";
            }
            if ((type & PhoneNumberType_enum.Msg) != 0)
            {
                retVal += "MSG,";
            }
            if ((type & PhoneNumberType_enum.Pager) != 0)
            {
                retVal += "PAGER,";
            }
            if ((type & PhoneNumberType_enum.PCS) != 0)
            {
                retVal += "PCS,";
            }
            if ((type & PhoneNumberType_enum.Preferred) != 0)
            {
                retVal += "PREF,";
            }
            if ((type & PhoneNumberType_enum.Video) != 0)
            {
                retVal += "VIDEO,";
            }
            if ((type & PhoneNumberType_enum.Voice) != 0)
            {
                retVal += "VOICE,";
            }
            if ((type & PhoneNumberType_enum.Work) != 0)
            {
                retVal += "WORK,";
            }
            if (retVal.EndsWith(","))
            {
                retVal = retVal.Substring(0, retVal.Length - 1);
            }

            return retVal;
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// This method is called when some property has changed, wee need to update underlaying vCard item.
        /// </summary>
        private void Changed()
        {
            m_pItem.ParametersString = PhoneTypeToString(m_Type);
            m_pItem.Value = m_Number;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Resources/MailApiResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Mail.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class MailApiResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal MailApiResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Mail.Resources.MailApiResource", typeof(MailApiResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Some input parameters are invalid..
        /// </summary>
        public static string AttachmentsBadInputParamsError {
            get {
                return ResourceManager.GetString("AttachmentsBadInputParamsError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Access to the document is denied..
        /// </summary>
        public static string AttachmentsDocumentAccessDeniedError {
            get {
                return ResourceManager.GetString("AttachmentsDocumentAccessDeniedError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Document could not be found or does not exist on the chosen storage..
        /// </summary>
        public static string AttachmentsDocumentNotFoundError {
            get {
                return ResourceManager.GetString("AttachmentsDocumentNotFoundError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Empty files are not supported..
        /// </summary>
        public static string AttachmentsEmptyFileNotSupportedError {
            get {
                return ResourceManager.GetString("AttachmentsEmptyFileNotSupportedError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message could not be found..
        /// </summary>
        public static string AttachmentsMessageNotFoundError {
            get {
                return ResourceManager.GetString("AttachmentsMessageNotFoundError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Total size of all attachments exceeds limit..
        /// </summary>
        public static string AttachmentsTotalLimitError {
            get {
                return ResourceManager.GetString("AttachmentsTotalLimitError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Some unexpected error has occurred. Please try again later..
        /// </summary>
        public static string AttachmentsUnknownError {
            get {
                return ResourceManager.GetString("AttachmentsUnknownError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creating link.
        /// </summary>
        public static string CreatingLinkHeader {
            get {
                return ResourceManager.GetString("CreatingLinkHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This message was created automatically by mail delivery software..
        /// </summary>
        public static string DeliveryFailureAutomaticMessage {
            get {
                return ResourceManager.GetString("DeliveryFailureAutomaticMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Change your message.
        /// </summary>
        public static string DeliveryFailureBtn {
            get {
                return ResourceManager.GetString("DeliveryFailureBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to In case the error persists, please read the {url_begin}FAQ section{url_end} to learn more about the problem..
        /// </summary>
        public static string DeliveryFailureFAQInformation {
            get {
                return ResourceManager.GetString("DeliveryFailureFAQInformation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delivery failed for message with subject &quot;{subject}&quot; from {date}..
        /// </summary>
        public static string DeliveryFailureMessageIdentificator {
            get {
                return ResourceManager.GetString("DeliveryFailureMessageIdentificator", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reason.
        /// </summary>
        public static string DeliveryFailureReason {
            get {
                return ResourceManager.GetString("DeliveryFailureReason", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message could not be delivered to recipient(s).
        /// </summary>
        public static string DeliveryFailureRecipients {
            get {
                return ResourceManager.GetString("DeliveryFailureRecipients", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, check your message recipients addresses and message format.  If you are sure your message is correct, check all the {account_name} account settings, and, if everything is correct, sign in to the mail service you use and confirm any verification questions, in case there are some. After then try again..
        /// </summary>
        public static string DeliveryFailureRecommendations {
            get {
                return ResourceManager.GetString("DeliveryFailureRecommendations", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message delivery failure.
        /// </summary>
        public static string DeliveryFailureSubject {
            get {
                return ResourceManager.GetString("DeliveryFailureSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This field cannot be empty.
        /// </summary>
        public static string ErrorEmptyField {
            get {
                return ResourceManager.GetString("ErrorEmptyField", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect email address in %1 field.
        /// </summary>
        public static string ErrorIncorrectEmailAddress {
            get {
                return ResourceManager.GetString("ErrorIncorrectEmailAddress", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tag %1 already exists.
        /// </summary>
        public static string ErrorTagNameAlreadyExists {
            get {
                return ResourceManager.GetString("ErrorTagNameAlreadyExists", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tag name cannot be empty.
        /// </summary>
        public static string ErrorTagNameCantBeEmpty {
            get {
                return ResourceManager.GetString("ErrorTagNameCantBeEmpty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folder name cannot be empty.
        /// </summary>
        public static string ErrorUserFoldeNameCantBeEmpty {
            get {
                return ResourceManager.GetString("ErrorUserFoldeNameCantBeEmpty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folder %1 already exists.
        /// </summary>
        public static string ErrorUserFolderNameAlreadyExists {
            get {
                return ResourceManager.GetString("ErrorUserFolderNameAlreadyExists", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bcc.
        /// </summary>
        public static string FieldNameBcc {
            get {
                return ResourceManager.GetString("FieldNameBcc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cc.
        /// </summary>
        public static string FieldNameCc {
            get {
                return ResourceManager.GetString("FieldNameCc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to From.
        /// </summary>
        public static string FieldNameFrom {
            get {
                return ResourceManager.GetString("FieldNameFrom", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To.
        /// </summary>
        public static string FieldNameTo {
            get {
                return ResourceManager.GetString("FieldNameTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Finished.
        /// </summary>
        public static string FinishedHeader {
            get {
                return ResourceManager.GetString("FinishedHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Get attachments.
        /// </summary>
        public static string GetAttachmentsHeader {
            get {
                return ResourceManager.GetString("GetAttachmentsHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to IMAP server connection timeout exceeded..
        /// </summary>
        public static string ImapConnectionTimeoutError {
            get {
                return ResourceManager.GetString("ImapConnectionTimeoutError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to IMAP response:.
        /// </summary>
        public static string ImapResponse {
            get {
                return ResourceManager.GetString("ImapResponse", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to POP3 server connection timeout exceeded..
        /// </summary>
        public static string Pop3ConnectionTimeoutError {
            get {
                return ResourceManager.GetString("Pop3ConnectionTimeoutError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to POP3 response:.
        /// </summary>
        public static string Pop3Response {
            get {
                return ResourceManager.GetString("Pop3Response", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Getting the archive ready.
        /// </summary>
        public static string PreparationArchiveHeader {
            get {
                return ResourceManager.GetString("PreparationArchiveHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Setup tenant and user.
        /// </summary>
        public static string SetupTenantAndUserHeader {
            get {
                return ResourceManager.GetString("SetupTenantAndUserHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to SMTP server connection timeout exceeded..
        /// </summary>
        public static string SmtpConnectionTimeoutError {
            get {
                return ResourceManager.GetString("SmtpConnectionTimeoutError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to SMTP response:.
        /// </summary>
        public static string SmtRresponse {
            get {
                return ResourceManager.GetString("SmtRresponse", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Zipping attachments.
        /// </summary>
        public static string ZippingAttachmentsHeader {
            get {
                return ResourceManager.GetString("ZippingAttachmentsHeader", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Utility/AjaxResponse.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Web.Studio.Utility
{
    public class AjaxResponse
    {
        public string status { get; set; }
        public string message { get; set; }
        public string rs1 { get; set; }
        public string rs2 { get; set; }
        public string rs3 { get; set; }
        public string rs4 { get; set; }
        public string rs5 { get; set; }
        public string rs6 { get; set; }
        public string rs7 { get; set; }
        public string rs8 { get; set; }
        public string rs9 { get; set; }
        public string rs10 { get; set; }
        public string rs11 { get; set; }
        public string rs12 { get; set; }
        public string rs13 { get; set; }
        public string rs14 { get; set; }
        public string rs15 { get; set; }
        public string rs16 { get; set; }
        public string rs17 { get; set; }
        public string rs18 { get; set; }
        public string rs19 { get; set; }
        public string rs20 { get; set; }
        public AjaxResponse()
        {
            status = "";
            message = "";
            rs1 = "";
            rs2 = "";
            rs3 = "";
            rs4 = "";
            rs5 = "";
            rs6 = "";
            rs7 = "";
            rs8 = "";
            rs9 = "";
            rs10 = "";
            rs11 = "";
            rs12 = "";
            rs13 = "";
            rs14 = "";
            rs15 = "";
            rs16 = "";
            rs17 = "";
            rs18 = "";
            rs19 = "";
            rs20 = "";
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Api.Exceptions;
using ASC.Api.Interfaces;
using ASC.Api.Utils;
using ASC.Common.Logging;

using Autofac;

namespace ASC.Api.Impl
{

    public class ApiManager : IApiManager
    {
        private readonly IApiMethodInvoker _invoker;
        private readonly List<IApiParamInspector> _paramInspectors;
        private readonly IEnumerable<IApiMethodCall> _methods;

        public IApiConfiguration Config { get; set; }

        public IApiArgumentBuilder ArgumentBuilder { get; set; }

        public ILog Log { get; set; }

        #region IApiManager Members

        public ApiManager(IComponentContext container, IApiMethodInvoker invoker)
        {
            _invoker = invoker;
            _paramInspectors = container.Resolve<IEnumerable<IApiParamInspector>>().ToList();
            _methods = container.Resolve<IEnumerable<IApiMethodCall>>();

        }

        public object InvokeMethod(IApiMethodCall methodToCall, ApiContext apicontext, object instance)
        {
            if (apicontext == null) throw new ArgumentNullException("apicontext");

            if (methodToCall != null)
            {
                var context = apicontext.RequestContext;

                Log.DebugFormat("Method to call={0}", methodToCall);

                //try convert params
                var callArg = ArgumentBuilder.BuildCallingArguments(context, methodToCall);
                if (_paramInspectors.Any())
                {
                    callArg = _paramInspectors.Aggregate(callArg,
                        (current, apiParamInspector) =>
                            apiParamInspector.InspectParams(current));
                }

                Log.DebugFormat("Arguments count: {0}", callArg == null ? "empty" : callArg.Count().ToString());


                try
                {
                    //Pre call filter
                    methodToCall.Filters.ToList().ForEach(x => x.PreMethodCall(methodToCall, apicontext, callArg));
                    if (apicontext.RequestContext.HttpContext.Response.StatusCode / 100 != 2)
                    {
                        return new HttpException(apicontext.RequestContext.HttpContext.Response.StatusCode,
                            apicontext.RequestContext.HttpContext.Response.StatusDescription);
                    }

                    object result = _invoker.InvokeMethod(methodToCall, instance, callArg, apicontext);
                    //Post call filter
                    methodToCall.Filters.ToList().ForEach(x => x.PostMethodCall(methodToCall, apicontext, result));
                    return result;
                }
                catch (Exception e)
                {
                    methodToCall.Filters.ToList().ForEach(x => x.ErrorMethodCall(methodToCall, apicontext, e));
                    throw;
                }
            }
            throw new ApiBadHttpMethodException();
        }

        public IApiMethodCall GetMethod(string routeUrl, string httpMethod)
        {
            var basePath = StringUtils.TrimExtension(routeUrl, Config.GetBasePath().Length);
            return _methods.SingleOrDefault(x => x.FullPath == basePath && x.HttpMethod.Equals(httpMethod, StringComparison.OrdinalIgnoreCase));
        }


        #endregion

    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Documents/FileOperationWraper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Web.Files.Classes;
using ASC.Web.Files.Services.WCFService.FileOperations;
using ASC.Web.Studio.Utility;

namespace ASC.Api.Documents
{
    /// <summary>
    /// </summary>
    [DataContract(Name = "operation_result", Namespace = "")]
    public class FileOperationWraper
    {
        /// <summary>
        /// </summary>
        [DataMember(Name = "id", IsRequired = false)]
        public string Id { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "operation", IsRequired = false)]
        public FileOperationType OperationType { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "progress", IsRequired = false)]
        public int Progress { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "error", IsRequired = false)]
        public string Error { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "processed", IsRequired = false)]
        public string Processed { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "finished", IsRequired = false)]
        public bool Finished { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "url", IsRequired = false)]
        public string Url { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "files", IsRequired = true, EmitDefaultValue = true)]
        public List<FileWrapper> Files { get; set; }

        /// <summary>
        /// </summary>
        [DataMember(Name = "folders", IsRequired = true, EmitDefaultValue = true)]
        public List<FolderWrapper> Folders { get; set; }

        /// <summary>
        /// </summary>
        public FileOperationWraper()
        {
        }

        /// <summary>
        /// </summary>
        /// <param name="o"></param>
        public FileOperationWraper(FileOperationResult o)
        {
            Id = o.Id;
            OperationType = o.OperationType;
            Progress = o.Progress;
            Error = o.Error;
            Processed = o.Processed;
            Finished = o.Finished;

            if (!string.IsNullOrEmpty(o.Result) && OperationType != FileOperationType.Delete)
            {
                var arr = o.Result.Split(':');
                var folders = arr.Where(s => s.StartsWith("folder_")).Select(s => s.Substring(7));
                if (folders.Any())
                {
                    using (var folderDao = Global.DaoFactory.GetFolderDao())
                    {
                        Folders = folderDao.GetFolders(folders.ToArray()).Select(r => new FolderWrapper(r)).ToList();
                    }
                }
                var files = arr.Where(s => s.StartsWith("file_")).Select(s => s.Substring(5));
                if (files.Any())
                {
                    using (var fileDao = Global.DaoFactory.GetFileDao())
                    {
                        Files = fileDao.GetFiles(files.ToArray()).Select(r => new FileWrapper(r)).ToList();
                    }
                }

                if (OperationType == FileOperationType.Download)
                {
                    Url = CommonLinkUtility.GetFullAbsolutePath(o.Result);
                }
            }
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public static FileOperationWraper GetSample()
        {
            return new FileOperationWraper
            {
                Id = Guid.NewGuid().ToString(),
                OperationType = FileOperationType.Move,
                Progress = 100,
                //Source = "folder_1,file_1",
                //Result = "folder_1,file_1",
                Error = "",
                Processed = "1",
                Files = new List<FileWrapper> { FileWrapper.GetSample() },
                Folders = new List<FolderWrapper> { FolderWrapper.GetSample() }
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/Wrappers/BaseTypeWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ASC.Web.Files.Services.WCFService
{
    [CollectionDataContract(Name = "{0}List", ItemName = "entry", Namespace = "")]
    public class ItemList<TItem> : List<TItem>
    {
        public ItemList()
            : base()
        {
        }

        public ItemList(IEnumerable<TItem> items)
            : base(items)
        {
        }
    }

    [CollectionDataContract(Name = "{1}Hash", ItemName = "entry", KeyName = "key", ValueName = "value", Namespace = "")]
    public class ItemDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public ItemDictionary()
            : base()
        {
        }

        public ItemDictionary(IDictionary<TKey, TValue> items)
            : base(items)
        {
        }
    }
}

<|start_filename|>common/ASC.Common/Web/RouteCallInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

namespace ASC.Common.Web
{
    public class RouteCallInfo
    {
        public int? Tid { get; set; }
        public string Url { get; set; }
        public string AttachmentUrl { get; set; }
        public bool IsNewRequest { get; set; }

        public string Method { get; set; }

        public Dictionary<string, object> Params { get; set; }

        public bool CleanupHtml { get; set; }

        public RouteCallInfo()
        {
            CleanupHtml = true;//Default
        }

        public override string ToString()
        {
            return string.Format("{0} {1} T:{2},{3}", Method.ToUpper(), Url, Tid, string.Join(",", Params.Select(x => string.Format("{0}={1}", x.Key, x.Value)).ToArray()));
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Client/Bundling/IStaticBundle.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

using ASC.Web.Core.Client.HttpHandlers;

namespace ASC.Web.Core.Client.Bundling
{
    public interface IStaticBundle
    {
        ScriptBundleData GetStaticJavaScript();
        StyleBundleData GetStaticStyleSheet();
    }

    public class BundleData
    {
        private readonly HashSet<string> source;
        internal string CategoryName { get; private set; }
        internal string FileName { get; set; }
        internal readonly Func<string, bool, string> GetLink;

        private readonly string sourceType;
        private readonly string ext;

        protected BundleData(string fileName, string categoryName)
        {
            source = new HashSet<string>();
            CategoryName = GetCategory(categoryName);
            FileName = fileName;
        }

        protected BundleData(string sourceType, string ext, Func<string, bool, string> getLink, string fileName, string categoryName) : this(fileName, categoryName)
        {
            this.sourceType = sourceType;
            this.ext = ext;
            GetLink = getLink;
        }

        public BundleData AddSource(Func<string, string> converter, params string[] src)
        {
            foreach (var s in src)
            {
                source.Add(converter(s));
            }

            return this;
        }

        public IEnumerable<string> GetSource()
        {
            return source;
        }

        public string GetStorageVirtualPath(string resetCacheKey)
        {
            return string.Format("{0}/{1}/{2}-{3}{4}", CategoryName, sourceType, FileName, GetHash(resetCacheKey), ext);
        }

        public string GetBundleVirtualPath(string bundleVPath, string resetCacheKey)
        {
            return string.Format("~{0}{1}-{2}{3}", bundleVPath, CategoryName, GetHash(resetCacheKey), ext);
        }

        internal virtual BundleHelper.ASCBundle CreateAscBundle(string virtualPath)
        {
            return null;
        }

        private static string GetCategory(string category)
        {
            if (!string.IsNullOrEmpty(category)) return category;

            category = "common";
            if (HttpContext.Current != null && HttpContext.Current.Request.Url != null && !string.IsNullOrEmpty(HttpContext.Current.Request.Url.AbsolutePath))
            {
                var matches = Regex.Match(HttpContext.Current.Request.Url.AbsolutePath, "(products|addons)/(\\w+)/?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                if (matches.Success && 2 < matches.Groups.Count && matches.Groups[2].Success)
                {
                    category = matches.Groups[2].Value;
                }
            }
            return category;
        }

        private string GetHash(string resetCacheKey)
        {
            return HttpServerUtility.UrlTokenEncode(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(string.Join(",", source) + resetCacheKey)));
        }
    }

    public class ScriptBundleData : BundleData
    {
        public ScriptBundleData(string fileName, string categoryName) : base("javascript", ".js", BundleHelper.GetJavascriptLink, fileName, categoryName) { }

        internal override BundleHelper.ASCBundle CreateAscBundle(string virtualPath)
        {
            return new BundleHelper.ASCJsBundle(virtualPath);
        }

        public ScriptBundleData AddSource(Func<string, string> converter, ClientScriptTemplate clientScriptTemplate)
        {
            AddSource(converter, clientScriptTemplate.GetLinks());
            return this;
        }
    }

    public class StyleBundleData : BundleData
    {
        public StyleBundleData(string fileName, string categoryName) : base("css", ".css", BundleHelper.GetCssLink, fileName, categoryName) { }

        internal override BundleHelper.ASCBundle CreateAscBundle(string virtualPath)
        {
            return new BundleHelper.ASCStyleBundle(virtualPath);
        }
    }
}


<|start_filename|>common/ASC.Data.Backup/Service/BackupWorker.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;

using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Threading.Progress;
using ASC.Core;
using ASC.Core.Common.Contracts;
using ASC.Core.Tenants;
using ASC.Data.Backup.Storage;
using ASC.Data.Backup.Tasks;
using ASC.Data.Backup.Tasks.Modules;
using ASC.Data.Backup.Utils;

namespace ASC.Data.Backup.Service
{
    internal static class BackupWorker
    {
        private static readonly ILog Log = LogManager.GetLogger("ASC");
        private static ProgressQueue tasks;
        private static ProgressQueue schedulerTasks;
        internal static string TempFolder;
        private static string currentRegion;
        private static Dictionary<string, string> configPaths;
        private static int limit;
        private static string upgradesPath;

        public static void Start(BackupConfigurationSection config)
        {
            TempFolder = TempPath.GetTempPath();

            limit = config.Limit;
            upgradesPath = config.UpgradesPath;
            currentRegion = config.WebConfigs.CurrentRegion;
            configPaths = config.WebConfigs.Cast<WebConfigElement>().ToDictionary(el => el.Region, el => PathHelper.ToRootedConfigPath(el.Path));
            configPaths[currentRegion] = PathHelper.ToRootedConfigPath(config.WebConfigs.CurrentPath);

            var invalidConfigPath = configPaths.Values.FirstOrDefault(path => !File.Exists(path));
            if (invalidConfigPath != null)
            {
                Log.WarnFormat("Configuration file {0} not found", invalidConfigPath);
            }

            tasks = new ProgressQueue(config.Service.WorkerCount, TimeSpan.FromMinutes(15), false);
            schedulerTasks = new ProgressQueue(config.Scheduler.WorkerCount, TimeSpan.FromMinutes(15), false);
        }

        public static void Stop()
        {
            if (tasks != null)
            {
                tasks.Terminate();
                tasks = null;
            }
            if (schedulerTasks != null)
            {
                schedulerTasks.Terminate();
                schedulerTasks = null;
            }
        }

        public static BackupProgress StartBackup(StartBackupRequest request)
        {
            lock (tasks.SynchRoot)
            {
                var item = tasks.GetItems().OfType<BackupProgressItem>().FirstOrDefault(t => t.TenantId == request.TenantId);
                if (item != null && item.IsCompleted)
                {
                    tasks.Remove(item);
                    item = null;
                }
                if (item == null)
                {
                    item = new BackupProgressItem(false, request.TenantId, request.UserId, request.StorageType, request.StorageBasePath) { BackupMail = request.BackupMail, StorageParams = request.StorageParams };
                    tasks.Add(item);
                }
                return ToBackupProgress(item);
            }
        }

        public static void StartScheduledBackup(Schedule schedule)
        {
            lock (schedulerTasks.SynchRoot)
            {
                var item = schedulerTasks.GetItems().OfType<BackupProgressItem>().FirstOrDefault(t => t.TenantId == schedule.TenantId);
                if (item != null && item.IsCompleted)
                {
                    schedulerTasks.Remove(item);
                    item = null;
                }
                if (item == null)
                {
                    item = new BackupProgressItem(true, schedule.TenantId, Guid.Empty, schedule.StorageType, schedule.StorageBasePath) { BackupMail = schedule.BackupMail, StorageParams = schedule.StorageParams };
                    schedulerTasks.Add(item);
                }
            }
        }

        public static BackupProgress GetBackupProgress(int tenantId)
        {
            lock (tasks.SynchRoot)
            {
                return ToBackupProgress(tasks.GetItems().OfType<BackupProgressItem>().FirstOrDefault(t => t.TenantId == tenantId));
            }
        }

        public static void ResetBackupError(int tenantId)
        {
            lock (tasks.SynchRoot)
            {
                var progress = tasks.GetItems().OfType<BackupProgressItem>().FirstOrDefault(t => t.TenantId == tenantId);
                if (progress != null)
                {
                    progress.Error = null;
                }
            }
        }

        public static void ResetRestoreError(int tenantId)
        {
            lock (tasks.SynchRoot)
            {
                var progress = tasks.GetItems().OfType<RestoreProgressItem>().FirstOrDefault(t => t.TenantId == tenantId);
                if (progress != null)
                {
                    progress.Error = null;
                }
            }
        }

        public static BackupProgress StartRestore(StartRestoreRequest request)
        {
            lock (tasks.SynchRoot)
            {
                var item = tasks.GetItems().OfType<RestoreProgressItem>().FirstOrDefault(t => t.TenantId == request.TenantId);
                if (item != null && item.IsCompleted)
                {
                    tasks.Remove(item);
                    item = null;
                }
                if (item == null)
                {
                    item = new RestoreProgressItem(request.TenantId, request.StorageType, request.FilePathOrId, request.NotifyAfterCompletion) { StorageParams = request.StorageParams };
                    tasks.Add(item);
                }
                return ToBackupProgress(item);
            }
        }

        public static BackupProgress GetRestoreProgress(int tenantId)
        {
            lock (tasks.SynchRoot)
            {
                return ToBackupProgress(tasks.GetItems().OfType<RestoreProgressItem>().FirstOrDefault(t => t.TenantId == tenantId));
            }
        }

        public static BackupProgress StartTransfer(int tenantId, string targetRegion, bool transferMail, bool notify)
        {
            lock (tasks.SynchRoot)
            {
                var item = tasks.GetItems().OfType<TransferProgressItem>().FirstOrDefault(t => t.TenantId == tenantId);
                if (item != null && item.IsCompleted)
                {
                    tasks.Remove(item);
                    item = null;
                }
                if (item == null)
                {
                    item = new TransferProgressItem(tenantId, targetRegion, transferMail, notify);
                    tasks.Add(item);
                }
                return ToBackupProgress(item);
            }
        }

        public static BackupProgress GetTransferProgress(int tenantId)
        {
            lock (tasks.SynchRoot)
            {
                return ToBackupProgress(tasks.GetItems().OfType<TransferProgressItem>().FirstOrDefault(t => t.TenantId == tenantId));
            }
        }

        private static BackupProgress ToBackupProgress(IProgressItem progressItem)
        {
            if (progressItem == null)
            {
                return null;
            }

            var progress = new BackupProgress
            {
                IsCompleted = progressItem.IsCompleted,
                Progress = (int)progressItem.Percentage,
                Error = progressItem.Error != null ? ((Exception)progressItem.Error).Message : null
            };

            var backupProgressItem = progressItem as BackupProgressItem;
            if (backupProgressItem != null)
            {
                progress.Link = backupProgressItem.Link;
            }
            else
            {
                var transferProgressItem = progressItem as TransferProgressItem;
                if (transferProgressItem != null)
                {
                    progress.Link = transferProgressItem.Link;
                }
            }

            return progress;
        }

        private static string GetBackupHash(string path)
        {
            using (var sha256 = SHA256.Create())
            using (var fileStream = File.OpenRead(path))
            {
                fileStream.Position = 0;
                var hash = sha256.ComputeHash(fileStream);
                return BitConverter.ToString(hash).Replace("-", string.Empty);
            }
        }

        private class BackupProgressItem : IProgressItem
        {
            private const string ArchiveFormat = "tar.gz";
            private bool IsScheduled { get; set; }
            public int TenantId { get; private set; }
            private Guid UserId { get; set; }
            private BackupStorageType StorageType { get; set; }
            private string StorageBasePath { get; set; }
            public bool BackupMail { get; set; }

            public Dictionary<string, string> StorageParams { get; set; }

            public string Link { get; private set; }

            public object Id { get; set; }
            public object Status { get; set; }
            public object Error { get; set; }
            public double Percentage { get; set; }
            public bool IsCompleted { get; set; }

            public BackupProgressItem(bool isScheduled, int tenantId, Guid userId, BackupStorageType storageType, string storageBasePath)
            {
                Id = Guid.NewGuid();
                IsScheduled = isScheduled;
                TenantId = tenantId;
                UserId = userId;
                StorageType = storageType;
                StorageBasePath = storageBasePath;
            }

            public void RunJob()
            {
                if (ThreadPriority.BelowNormal < Thread.CurrentThread.Priority)
                {
                    Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
                }

                var dateTime = CoreContext.Configuration.Standalone ? DateTime.Now : DateTime.UtcNow;
                var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", CoreContext.TenantManager.GetTenant(TenantId).TenantAlias, dateTime, ArchiveFormat);
                var tempFile = Path.Combine(TempFolder, backupName);
                var storagePath = tempFile;
                try
                {
                    var backupTask = new BackupPortalTask(Log, TenantId, configPaths[currentRegion], tempFile, limit);
                    if (!BackupMail)
                    {
                        backupTask.IgnoreModule(ModuleName.Mail);
                    }
                    backupTask.ProgressChanged += (sender, args) => Percentage = 0.9 * args.Progress;
                    backupTask.RunJob();

                    var backupStorage = BackupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams);
                    if (backupStorage != null)
                    {
                        storagePath = backupStorage.Upload(StorageBasePath, tempFile, UserId);
                        Link = backupStorage.GetPublicLink(storagePath);
                    }

                    var repo = BackupStorageFactory.GetBackupRepository();
                    repo.SaveBackupRecord(
                        new BackupRecord
                        {
                            Id = (Guid)Id,
                            TenantId = TenantId,
                            IsScheduled = IsScheduled,
                            FileName = Path.GetFileName(tempFile),
                            StorageType = StorageType,
                            StorageBasePath = StorageBasePath,
                            StoragePath = storagePath,
                            CreatedOn = DateTime.UtcNow,
                            ExpiresOn = StorageType == BackupStorageType.DataStore ? DateTime.UtcNow.AddDays(1) : DateTime.MinValue,
                            StorageParams = StorageParams,
                            Hash = GetBackupHash(tempFile)
                        });

                    Percentage = 100;

                    if (UserId != Guid.Empty && !IsScheduled)
                    {
                        NotifyHelper.SendAboutBackupCompleted(TenantId, UserId, Link);
                    }

                    IsCompleted = true;
                }
                catch (Exception error)
                {
                    Log.ErrorFormat("RunJob - Params: {0}, Error = {1}", new { Id = Id, Tenant = TenantId, File = tempFile, BasePath = StorageBasePath, }, error);
                    Error = error;
                    IsCompleted = true;
                }
                finally
                {
                    try
                    {
                        if (!(storagePath == tempFile && StorageType == BackupStorageType.Local))
                        {
                            File.Delete(tempFile);
                        }
                    }
                    catch (Exception error)
                    {
                        Log.Error("can't delete file: {0}", error);
                    }
                }
            }

            public object Clone()
            {
                return MemberwiseClone();
            }
        }

        private class RestoreProgressItem : IProgressItem
        {
            public int TenantId { get; private set; }
            public BackupStorageType StorageType { get; set; }
            public string StoragePath { get; set; }
            public bool Notify { get; set; }

            public Dictionary<string, string> StorageParams { get; set; }

            public object Id { get; set; }
            public object Status { get; set; }
            public object Error { get; set; }
            public double Percentage { get; set; }
            public bool IsCompleted { get; set; }

            public RestoreProgressItem(int tenantId, BackupStorageType storageType, string storagePath, bool notify)
            {
                Id = Guid.NewGuid();
                TenantId = tenantId;
                StorageType = storageType;
                StoragePath = storagePath;
                Notify = notify;
            }

            public void RunJob()
            {
                Tenant tenant = null;
                var tempFile = PathHelper.GetTempFileName(TempFolder);
                try
                {
                    NotifyHelper.SendAboutRestoreStarted(TenantId, Notify);

                    var storage = BackupStorageFactory.GetBackupStorage(StorageType, TenantId, StorageParams);
                    storage.Download(StoragePath, tempFile);

                    if (!CoreContext.Configuration.Standalone)
                    {
                        var backupHash = GetBackupHash(tempFile);
                        var repo = BackupStorageFactory.GetBackupRepository();
                        var record = repo.GetBackupRecord(backupHash, TenantId);
                        if (record == null)
                        {
                            throw new Exception(BackupResource.BackupNotFound);
                        }
                    }

                    Percentage = 10;

                    tenant = CoreContext.TenantManager.GetTenant(TenantId);
                    tenant.SetStatus(TenantStatus.Restoring);
                    CoreContext.TenantManager.SaveTenant(tenant);

                    var columnMapper = new ColumnMapper();
                    columnMapper.SetMapping("tenants_tenants", "alias", tenant.TenantAlias, ((Guid)Id).ToString("N"));
                    columnMapper.Commit();

                    var restoreTask = new RestorePortalTask(Log, TenantId, configPaths[currentRegion], tempFile, columnMapper, upgradesPath);
                    restoreTask.ProgressChanged += (sender, args) => Percentage = (10d + 0.65 * args.Progress);
                    restoreTask.RunJob();

                    Tenant restoredTenant = null;

                    if (restoreTask.Dump)
                    {
                        AscCache.OnClearCache();
                        if (Notify)
                        {
                            var tenants = CoreContext.TenantManager.GetTenants();
                            foreach (var t in tenants)
                            {
                                NotifyHelper.SendAboutRestoreCompleted(t.TenantId, Notify);
                            }
                        }
                    }
                    else
                    {
                        CoreContext.TenantManager.RemoveTenant(tenant.TenantId);

                        restoredTenant = CoreContext.TenantManager.GetTenant(columnMapper.GetTenantMapping());
                        restoredTenant.SetStatus(TenantStatus.Active);
                        restoredTenant.TenantAlias = tenant.TenantAlias;
                        restoredTenant.PaymentId = string.Empty;
                        if (string.IsNullOrEmpty(restoredTenant.MappedDomain) && !string.IsNullOrEmpty(tenant.MappedDomain))
                        {
                            restoredTenant.MappedDomain = tenant.MappedDomain;
                        }
                        CoreContext.TenantManager.SaveTenant(restoredTenant);

                        // sleep until tenants cache expires
                        Thread.Sleep(TimeSpan.FromMinutes(2));

                        NotifyHelper.SendAboutRestoreCompleted(restoredTenant.TenantId, Notify);
                    }

                    Percentage = 75;

                    File.Delete(tempFile);

                    Percentage = 100;
                }
                catch (Exception error)
                {
                    Log.Error(error);
                    Error = error;

                    if (tenant != null)
                    {
                        tenant.SetStatus(TenantStatus.Active);
                        CoreContext.TenantManager.SaveTenant(tenant);
                    }
                }
                finally
                {
                    if (File.Exists(tempFile))
                    {
                        File.Delete(tempFile);
                    }
                    IsCompleted = true;
                }
            }

            public object Clone()
            {
                return MemberwiseClone();
            }
        }

        private class TransferProgressItem : IProgressItem
        {
            public int TenantId { get; private set; }
            public string TargetRegion { get; set; }
            public bool TransferMail { get; set; }
            public bool Notify { get; set; }

            public string Link { get; set; }

            public object Id { get; set; }
            public object Status { get; set; }
            public object Error { get; set; }
            public double Percentage { get; set; }
            public bool IsCompleted { get; set; }

            public TransferProgressItem(int tenantId, string targetRegion, bool transferMail, bool notify)
            {
                Id = Guid.NewGuid();
                TenantId = tenantId;
                TargetRegion = targetRegion;
                TransferMail = transferMail;
                Notify = notify;
            }

            public void RunJob()
            {
                var tempFile = PathHelper.GetTempFileName(TempFolder);
                var alias = CoreContext.TenantManager.GetTenant(TenantId).TenantAlias;
                try
                {
                    NotifyHelper.SendAboutTransferStart(TenantId, TargetRegion, Notify);

                    var transferProgressItem = new TransferPortalTask(Log, TenantId, configPaths[currentRegion], configPaths[TargetRegion], limit) { BackupDirectory = TempFolder };
                    transferProgressItem.ProgressChanged += (sender, args) => Percentage = args.Progress;
                    if (!TransferMail)
                    {
                        transferProgressItem.IgnoreModule(ModuleName.Mail);
                    }
                    transferProgressItem.RunJob();

                    Link = GetLink(alias, false);
                    NotifyHelper.SendAboutTransferComplete(TenantId, TargetRegion, Link, !Notify, transferProgressItem.ToTenantId);
                }
                catch (Exception error)
                {
                    Log.Error(error);
                    Error = error;

                    Link = GetLink(alias, true);
                    NotifyHelper.SendAboutTransferError(TenantId, TargetRegion, Link, !Notify);
                }
                finally
                {
                    if (File.Exists(tempFile))
                    {
                        File.Delete(tempFile);
                    }
                    IsCompleted = true;
                }
            }

            private string GetLink(string alias, bool isErrorLink)
            {
                return "https://" + alias + "." + ConfigurationProvider.Open(configPaths[isErrorLink ? currentRegion : TargetRegion]).AppSettings.Settings["core.base-domain"].Value;
            }

            public object Clone()
            {
                return MemberwiseClone();
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Configuration/SearchHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.CRM.Core.Dao;
using ASC.Web.Core.ModuleManagement.Common;
using ASC.Web.Core.Utility;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.CRM.Controls.Common;
using ASC.Web.CRM.Core;
using ASC.Web.CRM.Resources;

using Autofac;

namespace ASC.Web.CRM.Configuration
{
    public class SearchHandler : BaseSearchHandlerEx
    {
        public override Guid ProductID
        {
            get { return ProductEntryPoint.ID; }
        }

        public override Guid ModuleID
        {
            get { return ProductID; }
        }

        public override ImageOptions Logo
        {
            get { return new ImageOptions { ImageFileName = "search_in_module.png", PartID = ProductID }; }
        }

        public override string SearchName
        {
            get { return CRMContactResource.Search; }
        }

        public override IItemControl Control
        {
            get { return new ResultsView(); }
        }

        public override SearchResultItem[] Search(string searchText)
        {
            using (var scope = DIHelper.Resolve())
            {
                return scope.Resolve<DaoFactory>().SearchDao.Search(searchText);
            }
        }
    }
}

<|start_filename|>common/ASC.Data.Backup.Restore/MainForm.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace ASC.Data.Backup.Restore
{
    public partial class MainForm : Form
    {
        private bool progress = false;


        public MainForm()
        {
            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

            InitializeComponent();

            labelStatus.Text = string.Empty;
            buttonCancel.Click += (s, e) => Application.Exit();
            this.FormClosing += (s, e) => e.Cancel = progress;
            try
            {
                var config = ConfigurationManager.AppSettings["coreConfig"];
                config = Path.GetFullPath(!string.IsNullOrEmpty(config) ? config : "TeamLabSvc.exe.config");
                if (File.Exists(config)) textBoxCoreConfig.Text = config;

                config = ConfigurationManager.AppSettings["webConfig"];
                config = Path.GetFullPath(!string.IsNullOrEmpty(config) ? config : "..\\WebStudio\\Web.Config");
                if (File.Exists(config))
                {
                    textBoxWebConfig.Text = config;
                }
                else
                {
                    config = Path.GetFullPath("..\\..\\WebStudio\\Web.Config");
                    if (File.Exists(config)) textBoxWebConfig.Text = config;
                }
            }
            catch { }
        }

        private void buttonConfig_Click(object sender, EventArgs e)
        {
            var dialog = openFileDialogCoreConfig;
            var textBox = textBoxCoreConfig;
            if (sender == buttonWebConfig)
            {
                dialog = openFileDialogWebConfig;
                textBox = textBoxWebConfig;
            }
            if (sender == buttonBackup)
            {
                dialog = openFileDialogBackup;
                textBox = textBoxBackup;
            }
            
            var fileName = textBox.Text;
            if (!string.IsNullOrEmpty(fileName))
            {
                if (File.Exists(fileName)) dialog.FileName = fileName;
                if (Directory.Exists(fileName)) dialog.InitialDirectory = fileName;
            }
            
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                textBox.Text = dialog.FileName;
            }
        }

        private void textBox_TextChanged(object sender, EventArgs e)
        {
            buttonRestore.Enabled = 0 < textBoxCoreConfig.TextLength && 0 < textBoxWebConfig.TextLength && 0 < textBoxBackup.TextLength;
        }


        private void buttonRestore_Click(object sender, EventArgs e)
        {
            var backuper = new BackupManager(textBoxBackup.Text, textBoxCoreConfig.Text, textBoxWebConfig.Text);
            backuper.AddBackupProvider(new Restarter());
            backuper.ProgressChanged += backuper_ProgressChanged;

            try
            {
                progress = true;
                labelStatus.Text = string.Empty;
                buttonRestore.Enabled = buttonCancel.Enabled = false;

                backuper.Load();

                labelStatus.Text = "Complete";
            }
            catch (Exception error)
            {
                labelStatus.Text = "Error: " + error.Message.Replace("\r\n", " ");
            }
            finally
            {
                progress = false;
                progressBar.Value = 0;
                buttonRestore.Enabled = buttonCancel.Enabled = true;
            }
        }

        private void backuper_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (IsDisposed) return;
            if (InvokeRequired)
            {
                BeginInvoke(new EventHandler<ProgressChangedEventArgs>(backuper_ProgressChanged), sender, e);
            }
            else
            {
                labelStatus.Text = e.Status;
                progressBar.Value = (int)e.Progress;
                Application.DoEvents();
            }
        }

        private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            var name = new AssemblyName(args.Name);
            if (name.Name == "ASC.Data.Backup")
            {
                var assemblyPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Backup");
                assemblyPath = Path.Combine(assemblyPath, name.Name + ".dll");
                if (File.Exists(assemblyPath))
                {
                    return Assembly.LoadFrom(assemblyPath);
                }
            }
            return null;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTP_Address.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    #region usings

    using System;
    using System.Net;

    #endregion

    /// <summary>
    /// This class implements RTP session address.
    /// </summary>
    public class RTP_Address
    {
        #region Members

        private readonly int m_ControlPort;
        private readonly int m_DataPort;
        private readonly IPAddress m_pIP;
        private readonly IPEndPoint m_pRtcpEP;
        private readonly IPEndPoint m_pRtpEP;
        private readonly int m_TTL;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this is multicast RTP address.
        /// </summary>
        public bool IsMulticast
        {
            get { return Net_Utils.IsMulticastAddress(m_pIP); }
        }

        /// <summary>
        /// Gets IP address.
        /// </summary>
        public IPAddress IP
        {
            get { return m_pIP; }
        }

        /// <summary>
        /// Gets RTP data port.
        /// </summary>
        public int DataPort
        {
            get { return m_DataPort; }
        }

        /// <summary>
        /// Gets RTCP control port.
        /// </summary>
        public int ControlPort
        {
            get { return m_ControlPort; }
        }

        /// <summary>
        /// Gets mulicast TTL(time to live) value.
        /// </summary>
        public int TTL
        {
            get { return m_TTL; }
        }

        /// <summary>
        /// Gets RTP end point.
        /// </summary>
        public IPEndPoint RtpEP
        {
            get { return m_pRtpEP; }
        }

        /// <summary>
        /// Gets RTPCP end point.
        /// </summary>
        public IPEndPoint RtcpEP
        {
            get { return m_pRtcpEP; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Unicast constructor.
        /// </summary>
        /// <param name="ip">Unicast IP address.</param>
        /// <param name="dataPort">RTP data port.</param>
        /// <param name="controlPort">RTP control port. Usualy this is <b>dataPort</b> + 1.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>ip</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid values.</exception>
        public RTP_Address(IPAddress ip, int dataPort, int controlPort)
        {
            if (ip == null)
            {
                throw new ArgumentNullException("ip");
            }
            if (dataPort < IPEndPoint.MinPort || dataPort > IPEndPoint.MaxPort)
            {
                throw new ArgumentException("Argument 'dataPort' value must be between '" + IPEndPoint.MinPort +
                                            "' and '" + IPEndPoint.MaxPort + "'.");
            }
            if (controlPort < IPEndPoint.MinPort || controlPort > IPEndPoint.MaxPort)
            {
                throw new ArgumentException("Argument 'controlPort' value must be between '" +
                                            IPEndPoint.MinPort + "' and '" + IPEndPoint.MaxPort + "'.");
            }
            if (dataPort == controlPort)
            {
                throw new ArgumentException("Arguments 'dataPort' and 'controlPort' values must be different.");
            }

            m_pIP = ip;
            m_DataPort = dataPort;
            m_ControlPort = controlPort;

            m_pRtpEP = new IPEndPoint(ip, dataPort);
            m_pRtcpEP = new IPEndPoint(ip, controlPort);
        }

        /// <summary>
        /// Multicast constructor.
        /// </summary>
        /// <param name="ip">Multicast IP address.</param>
        /// <param name="dataPort">RTP data port.</param>
        /// <param name="controlPort">RTP control port. Usualy this is <b>dataPort</b> + 1.</param>
        /// <param name="ttl">RTP control port. Usualy this is <b>dataPort</b> + 1.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>ip</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid values.</exception>
        public RTP_Address(IPAddress ip, int dataPort, int controlPort, int ttl)
        {
            if (ip == null)
            {
                throw new ArgumentNullException("ip");
            }
            if (!Net_Utils.IsMulticastAddress(ip))
            {
                throw new ArgumentException("Argument 'ip' is not multicast ip address.");
            }
            if (dataPort < IPEndPoint.MinPort || dataPort > IPEndPoint.MaxPort)
            {
                throw new ArgumentException("Argument 'dataPort' value must be between '" + IPEndPoint.MinPort +
                                            "' and '" + IPEndPoint.MaxPort + "'.");
            }
            if (controlPort < IPEndPoint.MinPort || controlPort > IPEndPoint.MaxPort)
            {
                throw new ArgumentException("Argument 'controlPort' value must be between '" +
                                            IPEndPoint.MinPort + "' and '" + IPEndPoint.MaxPort + "'.");
            }
            if (dataPort == controlPort)
            {
                throw new ArgumentException("Arguments 'dataPort' and 'controlPort' values must be different.");
            }
            if (ttl < 0 || ttl > 255)
            {
                throw new ArgumentException("Argument 'ttl' value must be between '0' and '255'.");
            }

            m_pIP = ip;
            m_DataPort = dataPort;
            m_ControlPort = controlPort;
            m_TTL = ttl;

            m_pRtpEP = new IPEndPoint(ip, dataPort);
            m_pRtcpEP = new IPEndPoint(ip, controlPort);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Determines whether the specified Object is equal to the current Object.
        /// </summary>
        /// <param name="obj">The Object to compare with the current Object.</param>
        /// <returns>True if the specified Object is equal to the current Object; otherwise, false.</returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (obj is RTP_Address)
            {
                RTP_Address a = (RTP_Address) obj;
                if (!a.IP.Equals(IP))
                {
                    return false;
                }
                if (a.DataPort != DataPort)
                {
                    return false;
                }
                if (a.ControlPort != ControlPort)
                {
                    return false;
                }
            }
            else
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Gets this hash code.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Common/Threading/Workers/WorkItem.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Common.Threading.Workers
{
    public class WorkItem<T> : IDisposable
    {
        private bool disposed;

        internal DateTime Added { get; set; }
        internal int ErrorCount { get; set; }
        internal bool IsProcessed { get; set; }

        public T Item { get; set; }
        public bool IsCompleted { get; set; }


        public WorkItem(T item)
        {
            Item = item;
            Added = DateTime.Now;
            IsProcessed = false;
        }

        ~WorkItem()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    var disposable = Item as IDisposable;
                    if (disposable != null)
                    {
                        disposable.Dispose();
                    }
                }
                disposed = true;
            }
        }
    }
}

<|start_filename|>common/ASC.ActiveDirectory/ComplexOperations/LdapLocalization.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Resources;

namespace ASC.ActiveDirectory.ComplexOperations
{
    public class LdapLocalization
    {
        private readonly ResourceManager _resourceManager;
        private readonly ResourceManager _notifyResourceManager;

        public LdapLocalization(ResourceManager resourceManager = null, ResourceManager notifyResourceManager = null)
        {
            _resourceManager = resourceManager;
            _notifyResourceManager = notifyResourceManager;
        }

        public string FirstName
        {
            get
            {
                const string def_key = "FirstName";
                const string def_val = "First Name";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LastName
        {
            get
            {
                const string def_key = "LastName";
                const string def_val = "Last Name";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsModifyLdapUsers
        {
            get
            {
                const string def_key = "LdapSettingsModifyLdapUsers";
                const string def_val = "Modifying LDAP users on ordinary portal users";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsTenantQuotaSettled
        {
            get
            {
                const string def_key = "LdapSettingsTenantQuotaSettled";
                const string def_val = "The current pricing plan user limit has been reached";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorCantCreateUsers
        {
            get
            {
                const string def_key = "LdapSettingsErrorCantCreateUsers";
                const string def_val = "Users could not be created, the received data are incorrect.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsInternalServerError
        {
            get
            {
                const string def_key = "LdapSettingsInternalServerError";
                const string def_val = "Server internal error.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusGettingUsersFromLdap
        {
            get
            {
                const string def_key = "LdapSettingsStatusGettingUsersFromLdap";
                const string def_val = "Retrieving the user list from the LDAP server";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusGivingRights
        {
            get
            {
                const string def_key = "LdapSettingsStatusGivingRights";
                const string def_val = "Setting user {0} as {1} admin";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorUsersNotFound
        {
            get
            {
                const string def_key = "LdapSettingsErrorUsersNotFound";
                const string def_val = "No users could be found.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusRemovingOldRights
        {
            get
            {
                const string def_key = "LdapSettingsStatusRemovingOldRights";
                const string def_val = "Removing outdated access rights that have been loaded via LDAP earlier";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusRemovingOldUsers
        {
            get
            {
                const string def_key = "LdapSettingsStatusRemovingOldUsers";
                const string def_val = "Removing outdated user profiles that have been loaded via LDAP earlier";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusSavingUserPhoto
        {
            get
            {
                const string def_key = "LdapSettingsStatusSavingUserPhoto";
                const string def_val = "Saving photo";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusSavingUsers
        {
            get
            {
                const string def_key = "LdapSettingsStatusSavingUsers";
                const string def_val = "Saving users";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusSyncingUsers
        {
            get
            {
                const string def_key = "LdapSettingsStatusSyncingUsers";
                const string def_val = "Syncing users";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusRemovingOldGroups
        {
            get
            {
                const string def_key = "LdapSettingsStatusRemovingOldGroups";
                const string def_val = "Removing outdated groups that have been loaded via LDAP earlier";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusGettingGroupsFromLdap
        {
            get
            {
                const string def_key = "LdapSettingsStatusGettingGroupsFromLdap";
                const string def_val = "Retrieving the group list from the LDAP server";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorGroupsNotFound
        {
            get
            {
                const string def_key = "LdapSettingsErrorGroupsNotFound";
                const string def_val = "No groups could be found.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusSavingGroups
        {
            get
            {
                const string def_key = "LdapSettingsStatusSavingGroups";
                const string def_val = "Saving groups";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorCantGetLdapSettings
        {
            get
            {
                const string def_key = "LdapSettingsErrorCantGetLdapSettings";
                const string def_val = "The server could not get settings.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusCheckingLdapSettings
        {
            get
            {
                const string def_key = "LdapSettingsStatusCheckingLdapSettings";
                const string def_val = "Checking LDAP support settings";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusLoadingBaseInfo
        {
            get
            {
                const string def_key = "LdapSettingsStatusLoadingBaseInfo";
                const string def_val = "Loading LDAP base info";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusCertificateVerification
        {
            get
            {
                const string def_key = "LdapSettingsStatusCertificateVerification";
                const string def_val = "Certificate verification";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongServerOrPort
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongServerOrPort";
                const string def_val =
                    "Unable to connect to LDAP server. Please check if the server address and port number are correct.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongUserDn
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongUserDN";
                const string def_val = "Incorrect User DN.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorIncorrectLdapFilter
        {
            get
            {
                const string def_key = "LdapSettingsErrorIncorrectLdapFilter";
                const string def_val = "Invalid User Filter value.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorLostRights
        {
            get
            {
                const string def_key = "LdapSettingsErrorLostRights";
                const string def_val = "You attempted to take away admin rights from yourself. Your admin rights was unaffected.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorRemovedYourself
        {
            get
            {
                const string def_key = "LdapSettingsErrorRemovedYourself";
                const string def_val = "Your account has been unlinked from LDAP. You may need to set a password for your account because you won't be able to login using LDAP password.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongLoginAttribute
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongLoginAttribute";
                const string def_val = "Could not get Login Attribute for one or several users.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongGroupDn
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongGroupDN";
                const string def_val = "Incorrect Group DN.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongGroupFilter
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongGroupFilter";
                const string def_val = "Could not get Group Attribute for one or several groups.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongGroupAttribute
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongGroupAttribute";
                const string def_val = "Could not get User Attribute for one or several users.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongUserAttribute
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongUserAttribute";
                const string def_val = "Could not get User Attribute for one or several users.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorWrongGroupNameAttribute
        {
            get
            {
                const string def_key = "LdapSettingsErrorWrongGroupNameAttribute";
                const string def_val = "Could not obtain Group Name Attribute for one or several groups.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorCredentialsNotValid
        {
            get
            {
                const string def_key = "LdapSettingsErrorCredentialsNotValid";
                const string def_val = "Incorrect login or password.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsConnectError
        {
            get
            {
                const string def_key = "LdapSettingsConnectError";
                const string def_val =
                    "A more secure authentication type is required. Please use encripted connection or enable plain authentication on the server.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStrongAuthRequired
        {
            get
            {
                const string def_key = "LdapSettingsStrongAuthRequired";
                const string def_val =
                    "A more secure authentication type is required. Please use encripted connection or enable plain authentication on the server.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsWrongSidAttribute
        {
            get
            {
                const string def_key = "LdapSettingsWrongSidAttribute";
                const string def_val =
                    "Unique ID for user/group objects could not be obtained. By default the system will try to match one of the following identifiers: entryUUID, nsuniqueid, GUID, objectSid. If none of the attributes corresponds to your LDAP server, please specify the necessary attribute in the ldap.unique.id setting of the web.appsettings.config file.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsTlsNotSupported
        {
            get
            {
                const string def_key = "LdapSettingsTlsNotSupported";
                const string def_val = "StartTLS not supported for current LDAP server.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorDomainNotFound
        {
            get
            {
                const string def_key = "LdapSettingsErrorDomainNotFound";
                const string def_val = "LDAP domain not found.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorUnknownError
        {
            get
            {
                const string def_key = "LdapSettingsErrorUnknownError";
                const string def_val = "Unknown error.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusSavingSettings
        {
            get
            {
                const string def_key = "LdapSettingsStatusSavingSettings";
                const string def_val = "Saving settings";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsErrorCantSaveLdapSettings
        {
            get
            {
                const string def_key = "LdapSettingsErrorCantSaveLdapSettings";
                const string def_val = "The server could not save settings.";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string ErrorEmailEmpty
        {
            get
            {
                const string def_key = "ErrorEmailEmpty";
                const string def_val = "Email field is empty";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string ErrorAccessDenied
        {
            get
            {
                const string def_key = "ErrorAccessDenied";
                const string def_val = "No permissions to perform this action";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusAddingGroupUser
        {
            get
            {
                const string def_key = "LdapSettingsStatusAddingGroupUser";
                const string def_val = "adding user";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusRemovingGroupUser
        {
            get
            {
                const string def_key = "LdapSettingsStatusRemovingGroupUser";
                const string def_val = "removing user";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusUpdatingAccessRights
        {
            get
            {
                const string def_key = "LdapSettingsStatusUpdatingAccessRights";
                const string def_val = "Updating users access rights";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusUpdatingUserPhotos
        {
            get
            {
                const string def_key = "LdapSettingsStatusUpdatingUserPhotos";
                const string def_val = "Updating user photos";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string LdapSettingsStatusDisconnecting
        {
            get
            {
                const string def_key = "LdapSettingsStatusDisconnecting";
                const string def_val = "LDAP disconnecting";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        public string NotifyButtonJoin
        {
            get
            {
                const string def_key = "ButtonAccessYourPortal";
                const string def_val = "Click here to join the portal";

                return GetValueOrDefault(def_key, def_val);
            }
        }

        private string GetValueOrDefault(string key, string defaultValue)
        {
            try
            {
                var val = _resourceManager != null ? _resourceManager.GetString(key) : null;
                if (val == null && _notifyResourceManager != null)
                {
                    val = _notifyResourceManager.GetString(key);
                }

                return val != null ? val : defaultValue;
            }
            catch
            {
                //
            }

            return defaultValue;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/Core/Business/Subscriptions/BookmarkSubscriptionConstants.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

namespace ASC.Bookmarking.Business.Subscriptions
{
    public static class BookmarkSubscriptionConstants
    {
        public const string BookmarkTitle = "BookmarkTitle";

        public const string BookmarkUrl = "BookmarkUrl";

        public const string UserURL = "UserURL";

        public const string Date = "Date";

        public const string BookmarkDescription = "BookmarkDescription";

        public const string CommentBody = "CommentBody";

    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/ThirdPartyBanner/ThirdPartyBanner.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.FederatedLogin.LoginProviders;
using ASC.VoipService.Dao;
using ASC.Web.Core;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Common.ThirdPartyBanner
{
    [AjaxNamespace("ThirdPartyBanner")]
    public partial class ThirdPartyBanner : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Common/ThirdPartyBanner/ThirdPartyBanner.ascx"; }
        }

        public static bool Display
        {
            get { return SetupInfo.ThirdPartyBannerEnabled && SecurityContext.CheckPermissions(SecutiryConstants.EditPortalSettings) && GetBanner.Any(); }
        }

        protected Tuple<string, string> CurrentBanner;

        protected void Page_Load(object sender, EventArgs e)
        {
            AjaxPro.Utility.RegisterTypeForAjax(GetType());

            Page.RegisterStyle("~/UserControls/Common/ThirdPartyBanner/css/thirdpartybanner.css");

            var tmp = GetBanner;
            var i = new Random().Next(0, tmp.Count());
            CurrentBanner = GetBanner.ToArray()[i];
        }

        private static IEnumerable<Tuple<string, string>> GetBanner
        {
            get
            {
                if (CoreContext.Configuration.Personal
                    || CoreContext.Configuration.CustomMode
                    || HttpContext.Current.Request.DesktopApp())
                {
                    yield break;
                }

                var currentProductId = CommonLinkUtility.GetProductID();

                if ((currentProductId == WebItemManager.DocumentsProductID
                     || currentProductId == WebItemManager.PeopleProductID)
                    && !ThirdPartyBannerSettings.CheckClosed("bitly")
                    && !BitlyLoginProvider.Enabled)
                {
                    yield return new Tuple<string, string>("bitly", UserControlsCommonResource.BannerBitly);
                }

                if ((currentProductId == WebItemManager.CRMProductID
                     || currentProductId == WebItemManager.PeopleProductID)
                    && !ThirdPartyBannerSettings.CheckClosed("social")
                    &&
                    (!TwitterLoginProvider.Instance.IsEnabled ||
                    !FacebookLoginProvider.Instance.IsEnabled ||
                    !LinkedInLoginProvider.Instance.IsEnabled ||
                    !GoogleLoginProvider.Instance.IsEnabled))
                {
                    yield return new Tuple<string, string>("social", UserControlsCommonResource.BannerSocial);
                }

                if (currentProductId == WebItemManager.DocumentsProductID
                    && !ThirdPartyBannerSettings.CheckClosed("storage")
                    && (!BoxLoginProvider.Instance.IsEnabled
                        || !DropboxLoginProvider.Instance.IsEnabled
                        || !OneDriveLoginProvider.Instance.IsEnabled))
                {
                    yield return new Tuple<string, string>("storage", UserControlsCommonResource.BannerStorage);
                }

                if (currentProductId == WebItemManager.CRMProductID
                    && !VoipDao.ConfigSettingsExist
                    && VoipDao.Consumer.CanSet)
                {
                    if (!ThirdPartyBannerSettings.CheckClosed("twilio2"))
                        yield return new Tuple<string, string>("twilio2", UserControlsCommonResource.BannerTwilio2);
                }
            }
        }

        [AjaxMethod]
        public void CloseBanner(string banner)
        {
            ThirdPartyBannerSettings.Close(banner);
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SNTP/Client/SNTP_Client.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Text;

namespace LumiSoft.Net.SNTP.Client
{
    /// <summary>
    /// This class implments Simple Network Time Protocol (SNTP) protocol. Defined in RFC 2030. 
    /// </summary>
    public class SNTP_Client
    {
        /// <summary>
        /// Gets UTC time from NTP server.
        /// </summary>
        /// <param name="server">NTP server.</param>
        /// <param name="port">NTP port. Default NTP port is 123.</param>
        /// <returns>Returns UTC time.</returns>
        public static DateTime GetTime(string server,int port)
        {
            /* RFC 2030 4.
                Below is a description of the NTP/SNTP Version 4 message format,
                which follows the IP and UDP headers. This format is identical to
                that described in RFC-1305, with the exception of the contents of the
                reference identifier field. The header fields are defined as follows:

                                     1                   2                   3
                 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |LI | VN  |Mode |    Stratum    |     Poll      |   Precision   |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                          Root Delay                           |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                       Root Dispersion                         |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                     Reference Identifier                      |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                                                               |
                |                   Reference Timestamp (64)                    |
                |                                                               |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                                                               |
                |                   Originate Timestamp (64)                    |
                |                                                               |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                                                               |
                |                    Receive Timestamp (64)                     |
                |                                                               |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                                                               |
                |                    Transmit Timestamp (64)                    |
                |                                                               |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                 Key Identifier (optional) (32)                |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                |                                                               |
                |                                                               |
                |                 Message Digest (optional) (128)               |
                |                                                               |
                |                                                               |
                +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             
                2030 5. For unicast request we need to fill version and mode only.
                
            */
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/js/forum.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var ForumManager = new function() {
    this.All = "All";
    this.QuestionEmptyMessage = "Enter question";
    this.SubjectEmptyMessage = "Enter topic title";
    this.ApproveTopicButton = "Aloow";
    this.OpenTopicButton = "Open";
    this.CloseTopicButton = "Close";
    this.StickyTopicButton = "Stick";
    this.ClearStickyTopicButton = "Unstick";
    this.DeleteTopicButton = "Remove";
    this.EditTopicButton = "Edit";
    this.ConfirmMessage = "Are you sure?";
    this.NameEmptyString = "Enter title";
    this.SaveButton = "Save";
    this.CancelButton = "Cancel";
    this.ModuleID = '853B6EB9-73EE-438d-9B09-8FFEEDF36234';
    this.SettingsID = '';
    this.TextEmptyMessage = "Enter a message";
    this.forumEditor = null;

    this.SendMessage = function() {
        if (jq("#createPostBth").hasClass("disable"))
            return;

        var subject = '';

        if (jq('#forum_postType').val() != 0)
            subject = jq.trim(jq('#forum_subject').val());

        if (subject == '' && jq('#forum_postType').val() != 0) {
            if (jq('#forum_postType').val() == 2) {
                AddRequiredErrorText(jq("input[name$='poll_question']"), this.QuestionEmptyMessage);
                ShowRequiredError(jq("input[name$='poll_question']"));
            }
            else {
                AddRequiredErrorText(jq("input[name$='forum_subject']"), this.SubjectEmptyMessage);
                ShowRequiredError(jq("input[name$='forum_subject']"));
            }

            jq('#forum_subject').focus();
            return;
        }

        if (jq('#forum_postType').val() != 0)
            jq('#forum_subject').val(subject);

        var html = ForumManager.forumEditor.getData();
        if (jq.trim(html) == "") {
            toastr.error(this.TextEmptyMessage);
            return;
        }

        if (jq('#forum_topSubscription').length > 0) {
            if (jq('#forum_topSubscription').is(':checked'))
                jq('#forum_topSubscriptionState').val('1');
            else
                jq('#forum_topSubscriptionState').val('0');
        }

        this.BlockButtons();

        __doPostBack('', '');
    };

    this.CancelPost = function(itemID) {
        AjaxPro.onLoading = function(b) { };
        PostCreator.CancelPost(this.SettingsID, itemID, function(result) {
            window.open(result.value, '_self');
        });
    };

    this.CancelForum = function(itemID) {
        window.location.href = "Default.aspx";
    };

    this.BlockButtons = function() {
        LoadingBanner.showLoaderBtn("#post_container");
    };

    this.UnblockButtons = function() {
        LoadingBanner.hideLoaderBtn("#post_container");
    };

    this.ShowInfoMessage = function(text) {
        jq('#' + ForumContainer_PanelInfoID).html(text);
        jq('#' + ForumContainer_PanelInfoID).show();
    };

    this.PreviewEditor = function () {
        if (jq("#btnPreview").hasClass("disable")) return;
        jq('#forum_previewBoxFCK').show();
        jq('#forum_message_previewfck').html(ForumManager.forumEditor.getData());
        jq.scrollTo(jq('#forum_previewBoxFCK').position().top, { speed: 500 });
    };

    this.HidePreview = function() {
        jq('#forum_previewBoxFCK').hide();
        var scroll_to = jq('#post_container').position();
        jq.scrollTo(scroll_to.top, { speed: 500 });
    }

    this.SaveEditTopic = function() {
        var subject = jq.trim(jq('#forum_subject').val());

        if (subject == '') {
            if (jq('#forum_topicType').val() == 1)
                jq('#forum_errorMessage').html('<div class="errorBox">' + this.QuestionEmptyMessage + '</div>');
            else
                jq('#forum_errorMessage').html('<div class="errorBox">' + this.SubjectEmptyMessage + '</div>');
            jq('#forum_subject').focus();
            jq('#forum_errorMessage').scrollTo();
            return;
        }

        jq('#forum_subject').val(subject);
        document.forms[0].submit();
    };

    //---------------Tags--------------------------    

    this.SaveSearchTags = function(elementId, tagValue, tagHelp) {
        if (tagValue == '' || tagHelp == '')
            return;

        var valuesStr = jq("#" + elementId).val();

        var values = JSON.parse(valuesStr);

        values.push([tagValue, tagHelp]);

        jq("#" + elementId).val(JSON.stringify(values));
    };

    //----------------------------------------------------------  

    this.ApproveTopic = function(idTopic) {
        AjaxPro.onLoading = function(b) {
            if (b)
                jq('#forum_topic_' + idTopic).block();
            else
                jq('#forum_topic_' + idTopic).unblock();
        }
        jq('#forum_mf').hide();

        TopicManager.DoApprovedTopic(idTopic, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1')
                jq('#forum_topic_' + res.rs2).removeClass('tintDangerous');
            else {
                jq('#forum_topic_' + res.rs2).attr('class', 'errorBox');
                jq('#forum_topic_' + res.rs2).html(res.rs3);
            }
        });
    };


    this.CloseTopic = function(idTopic) {
        AjaxPro.onLoading = function(b) {
            if (b)
                jq('#forum_topic_' + idTopic).block();
            else
                jq('#forum_topic_' + idTopic).unblock();

        }
        jq('#forum_mf').hide();

        TopicManager.DoCloseTopic(idTopic, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                toastr.success(res.rs3);
                location.reload();
            }
            else {
                toastr.error(res.rs3);
            }
        });

    };

    this.StickyTopic = function(idTopic) {
        AjaxPro.onLoading = function(b) {
            if (b)
                jq('#forum_topic_' + idTopic).block();
            else
                jq('#forum_topic_' + idTopic).unblock();
        }
        jq('#forum_mf').hide();

        TopicManager.DoStickyTopic(idTopic, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                toastr.success(res.rs3);
                location.reload();
            }
            else {
                toastr.error(res.rs3);
            }
        });
    };

    this.DeleteTopic = function(idTopic) {
        if (!confirm(this.ConfirmMessage))
            return;

        AjaxPro.onLoading = function(b) {
            if (b)
                jq('#forum_topic_' + idTopic).block();
            else
                jq('#forum_topic_' + idTopic).unblock();
        }
        jq('#forum_mf').hide();

        TopicManager.DoDeleteTopic(idTopic, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                toastr.success(res.rs3);
                if (jq(".forums-row").length > 1) {
                    jq('#forum_topic_' + res.rs2).remove();
                } else {
                    location.reload();
                }
            }
            else {
                toastr.error(res.rs3);
            }
        });

    };
    this.CloseTopicPost = function(idTopic) {

        TopicManager.DoCloseTopic(idTopic, this.SettingsID, function(result) {
            var res = result.value;
            //console.log(res);
            jq("#forumsActionsMenuPanel").hide();
            if (res.rs1 == '1') {
                location.reload();
            }
            else {
                jq('#post_errorMessage').html('<div class="errorBox">' + res.rs3 + '</div>');
                setTimeout("jq('#post_errorMessage').html('');", 3000);
            }
        });

    };
    this.StickyTopicPost = function(idTopic) {
        TopicManager.DoStickyTopic(idTopic, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#StickyTopic').html(res.rs4);
            }
            else {
                jq('#errorMessageTopic').html('<div class="errorBox">' + res.rs3 + '</div>');
            }
        });
    };

    this.DeleteTopicPost = function(idTopic) {
        if (!confirm(this.ConfirmMessage))
            return;

        TopicManager.DoDeleteTopic(idTopic, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                window.location.href = "topics.aspx?f=" + res.rs4;
            }
            else {
                jq('#errorMessageTopic').html('<div class="errorBox">' + res.rs3 + '</div>');
            }
        });

    };

    this.ModeratorFunctionState = 0;

    this.ShowTopicModeratorFunctions = function(idTopic, mask, status, editURL) {
        if (mask == 0)
            return;

        if (jq('#forum_mf').length == 0)
            jq('#container').append('<div style="display:none;" id="forum_mf"></div>');

        var sb = '';
        // 1 - aprroved
        // 2 - delete
        // 3 - stiky
        // 4 - close
        // 5 - move
        // 6 - edit
        if (mask & 1)
            sb += '<div class="clearFix describe-text" style="margin:5px 0px;"><a href="javascript:ForumManager.ApproveTopic(\'' + idTopic + '\')">' + this.ApproveTopicButton + '</a></div>';
        if (mask & 8) {
            //1 - close / open
            sb += '<div class="clearFix" style="margin:5px 0px;">';
            if (status & 1)
                sb += '<a class = "link" href="javascript:ForumManager.CloseTopic(\'' + idTopic + '\')">' + this.OpenTopicButton + '</a>';
            else
                sb += '<a class = "link" href="javascript:ForumManager.CloseTopic(\'' + idTopic + '\')">' + this.CloseTopicButton + '</a>';

            sb += '</div>';
        }
        if (mask & 4) {
            //2 - sticky / clearsticky
            sb += '<div class="clearFix describe-text" style="margin:5px 0px;">';
            if (status & 2)
                sb += '<a class = "link" href="javascript:ForumManager.StickyTopic(\'' + idTopic + '\')">' + this.ClearStickyTopicButton + '</a>';
            else
                sb += '<a class = "link" href="javascript:ForumManager.StickyTopic(\'' + idTopic + '\')">' + this.StickyTopicButton + '</a>';

            sb += '</div>';
        }

        if (mask & 2) {
            //delete
            sb += '<div class="clearFix describe-text" style="margin:5px 0px;">';
            sb += '<a class = "link" href="javascript:ForumManager.DeleteTopic(\'' + idTopic + '\')">' + this.DeleteTopicButton + '</a>';
            sb += '</div>';
        }
        if (mask & 16) {
            //sb+='<div class="clearFix" style="height:2px;"></div>';     
            //sb+='<a class="button.blue" style="width:110px;" href="javascript:showMoveTopic(\''+id+'\',\''+alMask+'\',\''+status+'\')">'+moveTopicButton+'</a>';
        }
        if (mask & 32) {
            sb += '<div class="clearFix describe-text" style="margin:5px 0px;">';
            sb += '<a class = "link" href="' + editURL + '">' + this.EditTopicButton + '</a>';
            sb += '</div>';
        }
        jq('#forum_mf').html(sb);

        var pos = jq('#forum_mf_' + idTopic).offset();
        var top = pos.top + jq('#forum_mf_' + idTopic).outerHeight() - 1;
        jq('#forum_mf').attr('style', 'display:none;');

        jq('#forum_mf').css({
            'left': pos.left + "px",
            'top': +top + 'px',
            'display': 'block',
            'position': 'absolute',
            'width': '100px',
            'padding': '10px'
        });

        jq('#forum_mf').attr('class', 'tintLight cornerAll borderBase');

        jq('body').click(function(event) {

            var elt = (event.target) ? event.target : event.srcElement;
            var isHide = true;
            if (jq(elt).is('[id^="forum_mf"]') || jq(elt).is('[id^="forum_mf"]'))
                isHide = false;

            if (isHide)
                jq(elt).parents().each(function() {
                    if (jq(this).is('[id^="forum_mf"]') || jq(this).is('[id^="forum_mf"]')) {
                        isHide = false;
                        return false;
                    }
                });

            if (isHide) {
                jq('#forum_mf').hide();
            }
        });
    };

    this.ShowModeratorFunctions = function(idTopic, mask, status, editURL) {
        if (mask == 0)
            return;

        var sb = '';
        var $combox = jq('#forumsActions');
        
        if($combox.html()!="")
            return;

        if (mask & 1)
            sb += '<li><a class = "dropdown-item" href="javascript:ForumManager.ApproveTopic(\'' + idTopic + '\')">' + this.ApproveTopicButton + '</a></li>';
        
        if (mask & 32) {
            sb += '<li><a class = "dropdown-item" href="' + editURL + '">' + this.EditTopicButton + '</a>';
        }

        if (mask & 8) {
            //1 - close / open
            if (status & 1)
                sb += '<li><a class = "dropdown-item" id="OpenCloseTopic" href="javascript:ForumManager.CloseTopicPost(\'' + idTopic + '\')">' + this.OpenTopicButton + '</a></li>';
            else
                sb += '<li><a class = "dropdown-item" id="OpenCloseTopic" href="javascript:ForumManager.CloseTopicPost(\'' + idTopic + '\')">' + this.CloseTopicButton + '</a></li>';

        }
        if (mask & 4) {
            //2 - sticky / clearsticky
            if (status & 2)
                sb += '<li><a class = "dropdown-item" id="StickyTopic" href="javascript:ForumManager.StickyTopicPost(\'' + idTopic + '\')">' + this.ClearStickyTopicButton + '</a></li>';
            else
                sb += '<li><a class = "dropdown-item" id="StickyTopic" href="javascript:ForumManager.StickyTopicPost(\'' + idTopic + '\')">' + this.StickyTopicButton + '</a></li>';

        }

        if (mask & 2) {
            //delete
            sb += '<li><a class = "dropdown-item" href="javascript:ForumManager.DeleteTopicPost(\'' + idTopic + '\')">' + this.DeleteTopicButton + '</a></li>';
        }
        $combox.html(sb);
    };

    //----------- -------------------------------------

    this.ApprovePost = function(idPost) {
        AjaxPro.onLoading = function(b) {
            if (b)
                jq('#forum_post_' + idPost).block();
            else
                jq('#forum_post_' + idPost).unblock();
        }
        PostManager.DoApprovedPost(idPost, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#forum_message_' + res.rs2).removeClass("tintDangerous");
                jq('#forum_btap_' + res.rs2).remove();
                return;
            }
            else {
                jq('#forum_post_' + res.rs2).attr('class', "errorBox").css("padding", "10px 0 10px 35px");
                jq('#forum_post_' + res.rs2).html(res.rs3);
            }
        });
    };

    this.DeletePost = function(idPost) {
        if (!confirm(this.ConfirmMessage))
            return;

        AjaxPro.onLoading = function(b) {
            if (b)
                jq('#forum_post_' + idPost).block();
            else
                jq('#forum_post_' + idPost).unblock();
        }
        PostManager.DoDeletePost(idPost, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#forum_post_' + res.rs2).remove();
                toastr.success(res.rs3);
                disableLastPostDelete();
            }
            else {
                toastr.error(res.rs3);
            }
        });


    };

    this.DeleteAttachment = function(idAttachment, idPost) {
        if (!confirm(this.ConfirmMessage))
            return;

        AjaxPro.onLoading = function(b) {
            if (b)
                jq('#forum_attach_' + idAttachment).block();
            else
                jq('#forum_attach_' + idAttachment).unblock();
        };
        
        PostManager.DoDeleteAttachment(idAttachment, idPost, this.SettingsID, function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#forum_attach_' + res.rs2).remove();
                toastr.success(res.rs3);
            }
            else {
                toastr.error(res.rs3);
            }
        });
    };
}

function disableLastPostDelete() {
    try {
        var postsCount = jq('div[id^="forum_post_"]').length;
        if (postsCount == 1) {
            var postID = jq('div[id^="forum_post_"]').attr('id').split('forum_post_')[1];

            jq('#PostDeleteLink' + postID).hide();
            jq('#PostDeleteSplitter' + postID).hide();
        }
    } catch (err) { }
}

jq(document).ready(function() {
    disableLastPostDelete();
});


jQuery.extend({
    /*
    var result = $.format("Hello, {0}.", "world");
    //result -> "Hello, world."
    */
    format: function jQuery_dotnet_string_format(text) {
        //check if there are two arguments in the arguments list
        if (arguments.length <= 1) {
            //if there are not 2 or more arguments there's nothing to replace
            //just return the text
            return text;
        }
        //decrement to move to the second argument in the array
        var tokenCount = arguments.length - 2;
        for (var token = 0; token <= tokenCount; ++token) {
            //iterate through the tokens and replace their placeholders from the text in order
            text = text.replace(new RegExp("\\{" + token + "\\}", "gi"), arguments[token + 1]);
        }
        return text;
    }
}
);

function getURLParam(strParamName) {

        strParamName = strParamName.toLowerCase();

        var strReturn = "";
        var strHref = window.location.href.toLowerCase();
        var bFound = false;

        var cmpstring = strParamName + "=";
        var cmplen = cmpstring.length;

        if (strHref.indexOf("?") > -1) {
            var strQueryString = strHref.substr(strHref.indexOf("?") + 1);
            var aQueryString = strQueryString.split("&");
            for (var iParam = 0; iParam < aQueryString.length; iParam++) {
                if (aQueryString[iParam].substr(0, cmplen) == cmpstring) {
                    var aParam = aQueryString[iParam].split("=");
                    strReturn = aParam[1];
                    bFound = true;
                    break;
                }

            }
        }
        if (bFound == false) return null;

        if (strReturn.indexOf("#") > -1)
            return strReturn.split("#")[0];

        return strReturn;
}

function changeCountOfRows (val) {
    var forum = getURLParam("f");
    var search = getURLParam("search");
    var href = window.location.href.split("?")[0]+"?";
    if(forum!=null)
        href += "&f=" + forum;
    if(search!=null)
        href += "&search=" + search;
    window.location.href = href + "&size=" + val;
}

function changePostCountOfRows (val) {
    var post = getURLParam("t");
    var search = getURLParam("search");
    var href = window.location.href.split("?")[0]+"?";
    if(post!=null)
        href += "&t=" + post;
    if(search!=null)
        href += "&search=" + search;        
    window.location.href = href + "&size=" + val;
}

function resizeContent() {
    var windowWidth = jq(window).width() - 24 * 2,
        newWidth = windowWidth,
        mainBlockWidth = parseInt(jq(".mainPageLayout").css("min-width"));
    if (windowWidth < mainBlockWidth) {
        newWidth = mainBlockWidth;
    }
    jq(".forum_mesBox").each(
        function() {
            jq(this).css("max-width", newWidth - jq(".mainPageTableSidePanel").width() - 24 * 2 - 180 + "px"); // 180 - width of the author block
        }
    );
};

jq(document).ready(function() {
    jq.dropdownToggle({
        dropdownID: "forumsActionsMenuPanel",
        switcherSelector: ".forumsHeaderBlock .menu-small",
        addLeft: -11,
        showFunction: function(switcherObj, dropdownItem) {
            jq('.forumsHeaderBlock .menu-small.active').removeClass('active');
            if (dropdownItem.is(":hidden")) {
                switcherObj.addClass('active');
            }
        },
        hideFunction: function() {
            jq('.forumsHeaderBlock .menu-small.active').removeClass('active');
        }
    });
    resizeContent();
    jq(window).resize(function () {
        resizeContent();
    });
    
    var textInput = jq("#forum_subject");
    if (textInput.length)
        textInput.focus();
});


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Masters/ClientScripts/ClientSettingsResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Web;

using ASC.Core;
using ASC.Core.Users;
using ASC.FederatedLogin.LoginProviders;
using ASC.Mail;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Mail.Masters.ClientScripts
{
    public class MasterSettingsResources : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Mail.Master"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            return new List<KeyValuePair<string, object>>(1)
            {
                RegisterObject(new
                {
                    file_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_21.png"),
                    file_archive_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_archive_21.png"),
                    file_avi_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_avi_21.png"),
                    file_cal_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_cal_21.png"),
                    file_csv_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_csv_21.png"),
                    file_djvu_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_djvu_21.png"),
                    file_doc_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_doc_21.png"),
                    file_doct_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_doct_21.png"),
                    file_docx_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_docx_21.png"),
                    file_dvd_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_dvd_21.png"),
                    file_ebook_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_ebook_21.png"),
                    file_flv_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_flv_21.png"),
                    file_gdoc_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_gdoc_21.png"),
                    file_gsheet_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_gsheet_21.png"),
                    file_gslides_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_gslides_21.png"),
                    file_html_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_html_21.png"),
                    file_iaf_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_iaf_21.png"),
                    file_image_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_image_21.png"),
                    file_m2ts_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_m2ts_21.png"),
                    file_mkv_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_mkv_21.png"),
                    file_mov_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_mov_21.png"),
                    file_mp4_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_mp4_21.png"),
                    file_mpg_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_mpg_21.png"),
                    file_odp_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_odp_21.png"),
                    file_ods_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_ods_21.png"),
                    file_odt_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_odt_21.png"),
                    file_pdf_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_pdf_21.png"),
                    file_pps_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_pps_21.png"),
                    file_ppsx_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_ppsx_21.png"),
                    file_ppt_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_ppt_21.png"),
                    file_pptt_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_pptt_21.png"),
                    file_pptx_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_pptx_21.png"),
                    file_rtf_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_rtf_21.png"),
                    file_sound_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_sound_21.png"),
                    file_svg_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_svg_21.png"),
                    file_txt_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_txt_21.png"),
                    file_xls_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xls_21.png"),
                    file_xlst_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xlst_21.png"),
                    file_xlsx_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xlsx_21.png"),
                    file_xml_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xml_21.png"),
                    file_xps_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xps_21.png"),
                    file_docm_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_docm_21.png"),
                    file_dot_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_dot_21.png"),
                    file_dotm_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_dotm_21.png"),
                    file_dotx_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_dotx_21.png"),
                    file_pot_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_pot_21.png"),
                    file_potm_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_potm_21.png"),
                    file_potx_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_potx_21.png"),
                    file_ppsm_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_ppsm_21.png"),
                    file_pptm_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_pptm_21.png"),
                    file_soundunk_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_soundunk_21.png"),
                    file_video_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_video_21.png"),
                    file_videounk_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_videounk_21.png"),
                    file_xlsm_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xlsm_21.png"),
                    file_xlt_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xlt_21.png"),
                    file_xltm_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xltm_21.png"),
                    file_xltx_21 = CommonLinkUtility.GetFullAbsolutePath("~/UserControls/Common/ckeditor/plugins/filetype/images/file_xltx_21.png"),
                    IsTurnOnAttachmentsGroupOperations = Defines.IsAttachmentsGroupOperationsAvailable,
                    IsTurnOnOAuth = GoogleLoginProvider.Instance.IsEnabled && Convert.ToBoolean(ConfigurationManagerExtension.AppSettings["mail.google-oauth"] ?? "true"),
                    OAuthLocation = VirtualPathUtility.ToAbsolute(OAuth.Location),
                    userDisplayFormat = (int) UserFormatter.GetUserDisplayDefaultOrder()
        })
            };
        }

        protected override string GetCacheHash()
        {
            /* return user last mod time + culture */
            return SecurityContext.CurrentAccount.ID.ToString()
                       + CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).LastModified.ToString(CultureInfo.InvariantCulture)
                       + CoreContext.TenantManager.GetCurrentTenant().LastModified.ToString(CultureInfo.InvariantCulture);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Code/BaseUserControl.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Web.UserControls.Wiki.Data;
using ASC.Web.UserControls.Wiki.Handlers;

namespace ASC.Web.UserControls.Wiki
{
    public class VersionEventArgs : EventArgs
    {
        public Guid UserID { get; set; }
        public DateTime Date { get; set; }
        public int Version { get; set; }
    }


    public class BaseUserControl : System.Web.UI.UserControl
    {
        public static readonly string[] reservedPrefixes = new string[] { Constants.WikiCategoryKeyCaption, Constants.WikiInternalKeyCaption };

        private string _mainWikiClassName = "wiki";
        public delegate void PageEmptyHamdler(object sender, EventArgs e);
        public event PageEmptyHamdler PageEmpty;

        public delegate void PublishVersionInfoHandler(object sender, VersionEventArgs e);
        public event PublishVersionInfoHandler PublishVersionInfo;

        public delegate void WikiPageLoadedHandler(bool isNew, IWikiObjectOwner owner);
        public event WikiPageLoadedHandler WikiPageLoaded;

        protected WikiEngine Wiki
        {
            get { return new WikiEngine(); }
        }


        public void RiseWikiPageLoaded(IWikiObjectOwner owner)
        {
            RiseWikiPageLoaded(false, owner);
        }

        public void RiseWikiPageLoaded(bool isNew, IWikiObjectOwner owner)
        {
            if (WikiPageLoaded != null)
            {
                WikiPageLoaded(isNew, owner);
            }
        }

        public string MainWikiClassName
        {
            get { return _mainWikiClassName; }
            set { _mainWikiClassName = value; }
        }


        protected void RisePageEmptyEvent()
        {
            if (PageEmpty != null)
            {
                PageEmpty(this, new EventArgs());
            }
        }

        protected string PathFromFCKEditor
        {
            get { return WikiSection.Section.FckeditorInfo.PathFrom.ToLower(); }
        }

        protected string BaseFCKRelPath
        {
            get { return WikiSection.Section.FckeditorInfo.BaseRelPath; }
        }

        protected void RisePublishVersionInfo(IVersioned container)
        {
            if (!this.Visible)
                return;

            if (PublishVersionInfo != null)
            {
                PublishVersionInfo(this, new VersionEventArgs()
                {
                    UserID = container.UserID,
                    Date = container.Date,
                    Version = container.Version
                });
            }
        }


        public int TenantId
        {
            get
            {
                if (ViewState["TenantId"] == null)
                    return 0;
                try
                {
                    return Convert.ToInt32(ViewState["TenantId"]);
                }
                catch (System.Exception) { }

                return 0;
            }
            set
            {
                ViewState["TenantId"] = value;
            }
        }


        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            Page.RegisterBodyScripts("~/Products/Community/Modules/Wiki/scripts/editpage.js")
                .RegisterStyle("~/Products/Community/Modules/Wiki/content/main.css");
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }

        protected override void OnUnload(EventArgs e)
        {
            base.OnUnload(e);
        }


        private string _imageHandlerUrlFormat = WikiSection.Section.ImageHangler.UrlFormat;
        public string ImageHandlerUrlFormat
        {
            get { return _imageHandlerUrlFormat; }
            set { _imageHandlerUrlFormat = value; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Utils/SocketManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Core.Notify.Signalr;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Files.Utils
{
    public class SocketManager
    {
        private readonly SignalrServiceClient _signalrServiceClient;

        public SocketManager()
        {
            _signalrServiceClient = new SignalrServiceClient("files");
        }

        public void FilesChangeEditors(object fileId, bool finish = false)
        {
            _signalrServiceClient.FilesChangeEditors(TenantProvider.CurrentTenantID, fileId.ToString(), finish);
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Notify/EmailSenderSink.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core.Notify.Senders;
using ASC.Core.Tenants;
using ASC.Notify.Messages;
using ASC.Notify.Sinks;

namespace ASC.Core.Notify
{
    class EmailSenderSink : Sink
    {
        private static readonly string senderName = ASC.Core.Configuration.Constants.NotifyEMailSenderSysName;
        private readonly INotifySender sender;


        public EmailSenderSink(INotifySender sender)
        {
            if (sender == null) throw new ArgumentNullException("sender");

            this.sender = sender;
        }


        public override SendResponse ProcessMessage(INoticeMessage message)
        {
            if (message.Recipient.Addresses == null || message.Recipient.Addresses.Length == 0)
            {
                return new SendResponse(message, senderName, SendResult.IncorrectRecipient);
            }

            var responce = new SendResponse(message, senderName, default(SendResult));
            try
            {
                var m = CreateNotifyMessage(message);
                var result = sender.Send(m);

                switch (result)
                {
                    case NoticeSendResult.TryOnceAgain:
                        responce.Result = SendResult.Inprogress;
                        break;
                    case NoticeSendResult.MessageIncorrect:
                        responce.Result = SendResult.IncorrectRecipient;
                        break;
                    case NoticeSendResult.SendingImpossible:
                        responce.Result = SendResult.Impossible;
                        break;
                    default:
                        responce.Result = SendResult.OK;
                        break;
                }
                return responce;
            }
            catch (Exception e)
            {
                return new SendResponse(message, senderName, e);
            }
        }


        private NotifyMessage CreateNotifyMessage(INoticeMessage message)
        {
            var m = new NotifyMessage
            {
                Subject = message.Subject.Trim(' ', '\t', '\n', '\r'),
                ContentType = message.ContentType,
                Content = message.Body,
                Sender = senderName,
                CreationDate = DateTime.UtcNow,
            };

            var tenant = CoreContext.TenantManager.GetCurrentTenant(false);
            m.Tenant = tenant == null ? Tenant.DEFAULT_TENANT : tenant.TenantId;

            var from = MailAddressUtils.Create(CoreContext.Configuration.SmtpSettings.SenderAddress, CoreContext.Configuration.SmtpSettings.SenderDisplayName);
            var fromTag = message.Arguments.FirstOrDefault(x => x.Tag.Equals("MessageFrom"));
            if ((CoreContext.Configuration.SmtpSettings.IsDefaultSettings || string.IsNullOrEmpty(CoreContext.Configuration.SmtpSettings.SenderDisplayName)) &&
                fromTag != null && fromTag.Value != null)
            {
                try
                {
                    from = MailAddressUtils.Create(from.Address, fromTag.Value.ToString());
                }
                catch { }
            }
            m.From = from.ToString();

            var to = new List<string>();
            foreach (var address in message.Recipient.Addresses)
            {
                to.Add(MailAddressUtils.Create(address, message.Recipient.Name).ToString());
            }
            m.To = string.Join("|", to.ToArray());

            var replyTag = message.Arguments.FirstOrDefault(x => x.Tag == "replyto");
            if (replyTag != null && replyTag.Value is string)
            {
                try
                {
                    m.ReplyTo = MailAddressUtils.Create((string)replyTag.Value).ToString();
                }
                catch (Exception e)
                {
                    LogManager.GetLogger("ASC.Notify").Error("Error creating reply to tag for: " + replyTag.Value, e);
                }
            }

            var priority = message.Arguments.FirstOrDefault(a => a.Tag == "Priority");
            if (priority != null)
            {
                m.Priority = Convert.ToInt32(priority.Value);
            }

            var attachmentTag = message.Arguments.FirstOrDefault(x => x.Tag == "EmbeddedAttachments");
            if (attachmentTag != null && attachmentTag.Value != null)
            {
                m.EmbeddedAttachments = attachmentTag.Value as NotifyMessageAttachment[];
            }

            var autoSubmittedTag = message.Arguments.FirstOrDefault(x => x.Tag == "AutoSubmitted");
            if (autoSubmittedTag != null && autoSubmittedTag.Value is string)
            {
                try
                {
                    m.AutoSubmitted = autoSubmittedTag.Value.ToString();
                }
                catch (Exception e)
                {
                    LogManager.GetLogger("ASC.Notify").Error("Error creating AutoSubmitted tag for: " + autoSubmittedTag.Value, e);
                }
            }

            return m;
        }
    }
}

<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Classes/ShellExe.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using log4net;
using System;
using System.Diagnostics;

namespace ASC.HealthCheck.Classes
{
    public class ShellExe
    {
        private readonly ILog log = LogManager.GetLogger(typeof(ShellExe));
        private const int MonoWaitTimeout = 15000;

        public Process RunBinFile(string command, string arguments)
        {
            try
            {
                var process = new Process
                {
                    StartInfo =
                    {
                        FileName = command,
                        Arguments = arguments,
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true
                    }
                };
                process.Start();
                process.WaitForInputIdle();
                process.WaitForExit(MonoWaitTimeout);
                if (process.HasExited == false)
                {
                    if (process.Responding)
                    {
                        process.CloseMainWindow();
                    }
                    else
                    {
                        process.Kill();
                    }
                }
                return process;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error while executing command \"{0}\" : {1}", command + " " + arguments, ex);
                throw;
            }
        }

        public string ExecuteCommand(string programName, params string[] parameters)
        {
            try
            {
                var startInfo = new ProcessStartInfo
                {
                    FileName = programName,
                    Arguments = string.Join(" ", parameters),
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true
                };

                using (var proc = Process.Start(startInfo))
                {
                    proc.WaitForExit(MonoWaitTimeout);
                    var error = proc.StandardError.ReadToEnd();
                    return !string.IsNullOrEmpty(error) ? error : proc.StandardOutput.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error while executing command \"{0}\" : {1}", programName + " " + parameters, ex);
                throw;
            }
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Projects/ProjectApi.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Api.Attributes;
using ASC.Api.Documents;
using ASC.Api.Impl;
using ASC.Api.Interfaces;
using ASC.Api.Projects.Calendars;
using ASC.Api.Utils;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Core.Calendars;
using ASC.Web.Projects;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Api.Projects
{
    ///<summary>
    ///Projects access
    ///</summary>
    public partial class ProjectApi : ProjectApiBase, IApiEntryPoint
    {
        private readonly DocumentsApi documentsApi;

        ///<summary>
        ///Api name entry
        ///</summary>
        public string Name
        {
            get { return "project"; }
        }

        public TaskFilter CreateFilter(EntityType entityType)
        {
            var filter = new TaskFilter
            {
                SortOrder = !Context.SortDescending,
                SearchText = Context.FilterValue,
                Offset = Context.StartIndex,
                Max = Context.Count
            };

            if (!string.IsNullOrEmpty(Context.SortBy))
            {
                var type = entityType.ToString();
                var sortColumns = filter.SortColumns.ContainsKey(type) ? filter.SortColumns[type] : null;
                if (sortColumns != null && sortColumns.Any())
                    filter.SortBy = sortColumns.ContainsKey(Context.SortBy) ? Context.SortBy : sortColumns.First().Key;
            }

            Context.SetDataFiltered().SetDataPaginated().SetDataSorted();

            return filter;
        }

        ///<summary>
        ///Constructor
        ///</summary>
        ///<param name="context"></param>
        ///<param name="documentsApi">Docs api</param>
        public ProjectApi(ApiContext context, DocumentsApi documentsApi)
        {
            this.documentsApi = documentsApi;

            Context = context;
        }

        private void SetTotalCount(int count)
        {
            Context.SetTotalCount(count);
        }

        private long StartIndex
        {
            get { return Context.StartIndex; }
        }

        private long Count
        {
            get { return Context.Count; }
        }

        private static HttpRequest Request
        {
            get { return HttpContext.Current.Request; }
        }


        internal static List<BaseCalendar> GetUserCalendars(Guid userId)
        {
            using (var scope = DIHelper.Resolve())
            {
                var engineFactory = scope.Resolve<EngineFactory>();

                var cals = new List<BaseCalendar>();
                var engine = engineFactory.ProjectEngine;
                var projects = engine.GetByParticipant(userId);

                if (projects != null)
                {
                    var team = engine.GetTeam(projects.Select(r => r.ID).ToList());

                    foreach (var project in projects)
                    {
                        var p = project;

                        var sharingOptions = new SharingOptions();
                        foreach (var participant in team.Where(r => r.ProjectID == p.ID))
                        {
                            sharingOptions.PublicItems.Add(new SharingOptions.PublicItem
                            {
                                Id = participant.ID,
                                IsGroup = false
                            });
                        }

                        var index = project.ID % CalendarColors.BaseColors.Count;
                        cals.Add(new ProjectCalendar(
                            project,
                            CalendarColors.BaseColors[index].BackgroudColor,
                            CalendarColors.BaseColors[index].TextColor,
                            sharingOptions, false));
                    }
                }

                var folowingProjects = engine.GetFollowing(userId);
                if (folowingProjects != null)
                {
                    var team = engine.GetTeam(folowingProjects.Select(r => r.ID).ToList());

                    foreach (var project in folowingProjects)
                    {
                        var p = project;

                        if (projects != null && projects.Any(proj => proj.ID == p.ID)) continue;

                        var sharingOptions = new SharingOptions();
                        sharingOptions.PublicItems.Add(new SharingOptions.PublicItem { Id = userId, IsGroup = false });
                        foreach (var participant in team.Where(r => r.ProjectID == p.ID))
                        {
                            sharingOptions.PublicItems.Add(new SharingOptions.PublicItem
                            {
                                Id = participant.ID,
                                IsGroup = false
                            });
                        }

                        var index = p.ID % CalendarColors.BaseColors.Count;
                        cals.Add(new ProjectCalendar(
                            p,
                            CalendarColors.BaseColors[index].BackgroudColor,
                            CalendarColors.BaseColors[index].TextColor,
                            sharingOptions, true));
                    }
                }

                return cals;
            }
        }

        [Update(@"settings")]
        public ProjectsCommonSettings UpdateSettings(bool? everebodyCanCreate,
            bool? hideEntitiesInPausedProjects,
            StartModuleType? startModule,
            object folderId)
        {
            if (everebodyCanCreate.HasValue || hideEntitiesInPausedProjects.HasValue)
            {
                if (!ProjectSecurity.CurrentUserAdministrator) ProjectSecurity.CreateSecurityException();

                var settings = ProjectsCommonSettings.Load();

                if (everebodyCanCreate.HasValue)
                {
                    settings.EverebodyCanCreate = everebodyCanCreate.Value;
                }

                if (hideEntitiesInPausedProjects.HasValue)
                {
                    settings.HideEntitiesInPausedProjects = hideEntitiesInPausedProjects.Value;
                }

                settings.Save();
                return settings;
            }

            if (startModule.HasValue || folderId != null)
            {
                if (!ProjectSecurity.IsProjectsEnabled(CurrentUserId)) ProjectSecurity.CreateSecurityException();
                var settings = ProjectsCommonSettings.LoadForCurrentUser();
                if (startModule.HasValue)
                {
                    settings.StartModuleType = startModule.Value;
                }

                if (folderId != null)
                {
                    settings.FolderId = folderId;
                }

                settings.SaveForCurrentUser();
                return settings;
            }

            return null;
        }

        [Read(@"settings")]
        public ProjectsCommonSettings GetSettings()
        {
            var commonSettings = ProjectsCommonSettings.Load();
            var userSettings = ProjectsCommonSettings.LoadForCurrentUser();

            return new ProjectsCommonSettings
            {
                EverebodyCanCreate = commonSettings.EverebodyCanCreate,
                HideEntitiesInPausedProjects = commonSettings.HideEntitiesInPausedProjects,
                StartModuleType = userSettings.StartModuleType,
                FolderId = userSettings.FolderId,
            };
        }


        [Create(@"status")]
        public CustomTaskStatus CreateStatus(CustomTaskStatus status)
        {
            return EngineFactory.StatusEngine.Create(status);
        }

        [Update(@"status")]
        public CustomTaskStatus UpdateStatus(CustomTaskStatus newStatus)
        {
            if (newStatus.IsDefault && !EngineFactory.StatusEngine.Get().Any(r => r.IsDefault && r.StatusType == newStatus.StatusType))
            {
                return CreateStatus(newStatus);
            }

            var status = EngineFactory.StatusEngine.Get().FirstOrDefault(r => r.Id == newStatus.Id).NotFoundIfNull();

            status.Title = Update.IfNotEmptyAndNotEquals(status.Title, newStatus.Title);
            status.Description = Update.IfNotEmptyAndNotEquals(status.Description, newStatus.Description);
            status.Color = Update.IfNotEmptyAndNotEquals(status.Color, newStatus.Color);
            status.Image = Update.IfNotEmptyAndNotEquals(status.Image, newStatus.Image);
            status.ImageType = Update.IfNotEmptyAndNotEquals(status.ImageType, newStatus.ImageType);
            status.Order = Update.IfNotEmptyAndNotEquals(status.Order, newStatus.Order);
            status.StatusType = Update.IfNotEmptyAndNotEquals(status.StatusType, newStatus.StatusType);
            status.Available = Update.IfNotEmptyAndNotEquals(status.Available, newStatus.Available);

            EngineFactory.StatusEngine.Update(status);

            return status;
        }

        [Update(@"statuses")]
        public List<CustomTaskStatus> UpdateStatuses(List<CustomTaskStatus> statuses)
        {
            foreach (var status in statuses)
            {
                UpdateStatus(status);
            }

            return statuses;
        }

        [Read(@"status")]
        public List<CustomTaskStatus> GetStatuses()
        {
            return EngineFactory.StatusEngine.GetWithDefaults();
        }

        [Delete(@"status/{id}")]
        public CustomTaskStatus DeleteStatus(int id)
        {
            var status = EngineFactory.StatusEngine.Get().FirstOrDefault(r => r.Id == id).NotFoundIfNull();
            EngineFactory.StatusEngine.Delete(status.Id);
            return status;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/userfolders/panel.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.userFoldersPanel = (function($) {
    var container,
        userFolderContainer,
        selectedId,
        isInit = false,
        idPrefix = "uf_panel_",
        idRoot = "#",
        stateId = "jstreeUserFoldersPanel",
        stateReady = false;

    var init = function() {
        if (isInit === true) return;

        isInit = true;

        userFolderContainer = $("#userFolderContainer");

        container = userFolderContainer.find(".userFolders");

        container
            .on("loading.jstree",
                function(e) {
                    $(e.currentTarget).find(".jstree-anchor").text(ASC.Mail.Resources.MailResource.LoadingLabel);
                })
            .on("loaded.jstree", 
                function () {
                    $("#userFoldersManage").show();
                    resize();
                })
            .on("state_ready.jstree",
                function () {
                    stateReady = true;

                    if (!TMMail.pageIs('userfolder') && getSelected()) {
                        unmarkAll();
                    }

                    container.on("select_node.jstree", onSelectNode);
                })
            .on("after_open.jstree after_close.jstree refresh.jstree refresh_node.jstree create_node.jstree delete_node.jstree", resize)
            .jstree({
                "plugins": ["wholerow", "state", "counters"],
                'core': {
                    "animation": 0,
                    "check_callback": true,
                    "multiple": false,
                    "force_text": true,
                    'data': loadTree,
                    "keyboard": {
                        "f2":  false
                    }
                },
                "state": { "key": stateId }
            });

        createFolderLink = $("#userFoldersManage .link")
            .unbind("click")
            .bind("click", createFolder);

        userFoldersManager.bind(userFoldersManager.events.OnCreate, onCreated);
        userFoldersManager.bind(userFoldersManager.events.OnUpdate, onEdited);
        userFoldersManager.bind(userFoldersManager.events.OnDelete, onDeleted);
        userFoldersManager.bind(userFoldersManager.events.OnUnreadChanged, onUnreadChanged);

        setupDroppable();

        selectedId = TMMail.extractUserFolderIdFromAnchor();
    };

    function resize() {
        TMMail.resizeUserFolders();
        markSelectedPath();
    }

    function onSelectNode(e, data) {
        var href = "#userfolder={0}".format(data.node.id.replace(idPrefix, ""));
        ASC.Controls.AnchorController.move(href);
        markSelectedPath();
    }

    function markSelectedPath() {
        var selectedNode = userFolderContainer.find('[aria-selected="true"]'),
            selectedNodes = getSelected(),
            parentNodes = (selectedNodes === undefined) ? false : selectedNodes.parents;

        clearMarkedPath();

        selectedNode.addClass('node-selected');

        if (parentNodes) {
            for (var i = 0; i < parentNodes.length - 1; i++) {
                $('#' + parentNodes[i]).addClass('parent-selected');
            }
        }
    }

    function clearMarkedPath() {
        userFolderContainer.find('li').removeClass('node-selected').removeClass('parent-selected');
    }

    function createFolder() {
        var ref = container.jstree(true),
            sel = ref.get_selected();

        var parentFolder = {
            id: 0,
            name: ""
        };

        if (sel.length) {
            sel = sel[0];
            var node = ref.get_node(sel);

            parentFolder.id = node.id.replace(idPrefix, "");
            parentFolder.name = node.text;
        }

        var newFolder = {
            name: "",
            parent: parentFolder.id
        };

        var options = {
            disableSelector: userFoldersManager.getList().length === 0
                ? true
                : false
        };

        userFoldersManager.create(newFolder, parentFolder, options);

        return true;
    }

    function getFolderByPosition(x, y) {
        var w = $(window);
        var baseElm = $(document.elementFromPoint(x - w.scrollLeft(), y - w.scrollTop()));

        if (!baseElm) return undefined;

        var isUserFolder = baseElm.closest(".userFolders").length > 0;
        var folderId = null;

        if (baseElm.attr("folderid")) {
            folderId = baseElm.attr("folderid");
        } else {
            var aElm = baseElm.closest("a");

            if (aElm && aElm.attr("folderid")) {
                folderId = aElm.attr("folderid");
            } else {
                var liElm = baseElm.closest("li");

                if (liElm && liElm.attr("folderid"))
                    folderId = liElm.attr("folderid");
            }
        }

        if (!folderId)
            return undefined;

        folderId = +folderId;

        return isUserFolder
            ? {
                folderType: TMMail.sysfolders.userfolder.id,
                userFolderId: folderId
            }
            : {
                folderType: folderId,
                userFolderId: null
            };
    }

    function setupDroppable() {
        userFolderContainer.droppable({
            drop: function (event, ui) {
                var folder = getFolderByPosition(ui.offset.left, ui.offset.top);

                if (!folder) return;

                var curFolderType = +MailFilter.getFolder();
                var curUserFolderId = +MailFilter.getUserFolder() || null;

                if (curFolderType === folder.folderType && curUserFolderId === folder.userFolderId) {
                    return;
                }

                mailBox.moveTo(folder.folderType, folder.userFolderId);
            },
            tolerance: "pointer"
        });
    }

    function loadTree(node, cb) {
        userFoldersManager.loadTree(node.id === idRoot ? 0 : node.id.replace(idPrefix, ""))
            .then(function(params, data) {
                var result = data.map(function (v) {
                    return {
                            id: idPrefix + v.id,
                            parent: v.parent === 0 ? idRoot : idPrefix + v.parent,
                            text: v.name,
                            icon: "",
                            state: {
                                opened: false,
                                disabled: false,
                                selected: selectedId && selectedId == v.id ? true : false
                            },
                            li_attr: { folderid: v.id, unread_messages: v.unread_count, unread_chains: v.unread_chain_count },
                            a_attr: { folderid: v.id, href: "#userfolder={0}".format(v.id) },
                            children: v.folder_count > 0 ? true : false
                        };
                    });

                    cb(result);
                },
                function(params, errors) {
                    console.error("loadTree Error", errors, arguments);
                });
    }

    function markFolder(id) {
        var ref = container.jstree(true);
        var nodeId = idPrefix + id;

        if (stateReady)
            container.unbind("select_node.jstree");

        unmarkAll();

        ref.select_node(nodeId);

        MailFilter.setFolder(TMMail.sysfolders.userfolder.id);
        MailFilter.setUserFolder(id);

        selectedId = id;

        if (stateReady)
            container.bind("select_node.jstree", onSelectNode);
    }

    function unmarkAll() {
        container.jstree("deselect_all");
        clearMarkedPath();
    }

    function refresh() {
        console.log("userFoldersPanel -> refresh");
        container.jstree("refresh");
        resize();
    }

    function getSelected() {
        return container.jstree('get_selected', true)[0];
    }

    function onCreated(e, folder) {
        console.log("userFoldersPanel -> onCreated", folder);

        var ref = container.jstree(true);

        var parentId = folder.parent === 0 ? idRoot : idPrefix + folder.parent;

        var res = ref.create_node(parentId, {
            id: idPrefix + folder.id,
            parent: parentId,
            text: folder.name,
            icon: "",
            state: {
                opened: false,
                disabled: false,
                selected: false
            },
            li_attr: { folderid: folder.id, unread_messages: folder.unread_count, unread_chains: folder.unread_chain_count },
            a_attr: { folderid: folder.id, href: "#userfolder={0}".format(folder.id) },
            children: false
        });

        if (!res) {
            refresh();
        }
    }

    function onEdited(e, newFolder, oldFolder) {
        console.log("userFoldersPanel -> onEdited", newFolder, oldFolder);

        var ref = container.jstree(true);

        var id = idPrefix + newFolder.id;

        ref.set_text(id, newFolder.name);

        var oldParentId = oldFolder.parent === 0 ? idRoot : idPrefix + oldFolder.parent;
        var newParentId = newFolder.parent === 0 ? idRoot : idPrefix + newFolder.parent;

        if (oldParentId !== newParentId) {
            if (newParentId !== idRoot && ref.is_loaded(newParentId)) {
                var res = ref.move_node(id,
                    newParentId,
                    "last");

                if (!res) {
                    refresh();
                }
            } else {
                refresh();
            }
        }
    }

    function onDeleted(e, folder) {
        console.log("userFoldersPanel -> onDeleted", folder);

        var ref = container.jstree(true);

        var id = idPrefix + folder.id;

        var res = ref.delete_node(id);

        if (!res) {
            refresh();
        }
    }

    function onUnreadChanged(e, folder) {
        console.log("userFoldersPanel -> OnUnreadChanged", folder);

        var ref = container.jstree(true);

        var id = idPrefix + folder.id;

        var node = ref.get_node(id);

        if (!node) return;

        node.li_attr.unread_messages = folder.unread_count;
        node.li_attr.unread_chains = folder.unread_chain_count;

        ref.redraw_node(node.id);

        resize();

        TMMail.setPageHeaderFolderName(TMMail.sysfolders.userfolder.id);
    }

    function decrementUnreadCount() {
        var node = getSelected();
        if (!node) return;

        var oldUserFolder = window.userFoldersManager.get(node.li_attr.folderid);

        node.li_attr.unread_messages--;
        node.li_attr.unread_chains--;

        if (oldUserFolder) {
            oldUserFolder.unread_count = node.li_attr.unread_messages;
            oldUserFolder.unread_chain_count = node.li_attr.unread_chains;
        }

        var ref = container.jstree(true);
        ref.redraw_node(node.id);

        if (node.li_attr.unread_messages === 0 || node.li_attr.unread_chains === 0)
            resize();
    }

    return {
        init: init,
        markFolder: markFolder,
        unmarkAll: unmarkAll,
        refresh: refresh,
        getSelected: getSelected,
        decrementUnreadCount: decrementUnreadCount
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/ManagerDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.Linq;
using ASC.CRM.Core.Entities;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Users;
using ASC.Files.Core;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Configuration;
using ASC.Web.Files.Api;
using ASC.Web.Studio.Helpers;
using ASC.Web.Studio.Utility;
using log4net;

#endregion

namespace ASC.CRM.Core.Dao
{

    public class ManagerDao : AbstractDao
    {

        #region Constructor

        public ManagerDao(int tenantID, String storageKey)
            : base(tenantID, storageKey)
        {


        }

        #endregion

        #region Methods

        public void Add(Guid managerID)
        {
            DbManager.ExecuteNonQuery(Insert("crm_manager").InColumnValue("id", managerID));

        }

        public void Remove(Guid managerID)
        {

            DbManager.ExecuteNonQuery(Delete("crm_manager").Where(Exp.Eq("id", managerID)));

        }

        public List<UserInfo> GetAll(bool includeAdmins)
        {

            var managers = DbManager.ExecuteList(Query("crm_manager").Select("id")).ConvertAll(row=> ASC.Core.CoreContext.UserManager.GetUsers(ToGuid(row[0])));
           
            if (includeAdmins)
              return managers.Union(ASC.Core.CoreContext.UserManager.GetUsersByGroup(Constants.GroupAdmin.ID)).Distinct().ToList();

            return managers;
        }

        #endregion

    }

}

<|start_filename|>module/ASC.Api/ASC.Api/Collections/Extensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region usings

using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;

#endregion

namespace ASC.Api.Collections
{
    public static class Extensions
    {
        public static ItemList<T> ToItemList<T>(this IEnumerable<T> enumerable)
        {
            return new ItemList<T>(enumerable);
        }

        public static SmartList<T> ToSmartList<T>(this IEnumerable<T> enumerable)
        {
            return SmartListFactory.Create(enumerable);
        }

        public static ItemDictionary<TKey, TValue> ToItemDictionary<TKey, TValue>(
            this IDictionary<TKey, TValue> enumerable)
        {
            return new ItemDictionary<TKey, TValue>(enumerable);
        }

        public static NameValueCollection ToNameValueCollection(
            this IEnumerable<KeyValuePair<string, object>> enumerable)
        {
            var collection = new NameValueCollection();
            foreach (var keyValuePair in enumerable.Where(keyValuePair => keyValuePair.Value is string))
            {
                collection.Add(keyValuePair.Key, (string)keyValuePair.Value);
            }
            return collection;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/MailDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Expressions.Message;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Enums;
using ASC.Mail.Utils;

namespace ASC.Mail.Core.Dao
{
    public class MailDao : BaseDao, IMailDao
    {
        protected static ITable table = new MailTableFactory().Create<MailTable>();

        protected string CurrentUserId { get; private set; }

        public MailDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public int Save(Entities.Mail mail)
        {
            var query = new SqlInsert(MailTable.TABLE_NAME, true)
                .InColumnValue(MailTable.Columns.Id, mail.Id)
                .InColumnValue(MailTable.Columns.MailboxId, mail.MailboxId)
                .InColumnValue(MailTable.Columns.Tenant, mail.Tenant)
                .InColumnValue(MailTable.Columns.User, mail.User)
                .InColumnValue(MailTable.Columns.Address, mail.Address)
                .InColumnValue(MailTable.Columns.Uidl, mail.Uidl)
                .InColumnValue(MailTable.Columns.Md5, mail.Md5)
                .InColumnValue(MailTable.Columns.From, MailUtil.NormalizeStringForMySql(mail.From))
                .InColumnValue(MailTable.Columns.To, MailUtil.NormalizeStringForMySql(mail.To))
                .InColumnValue(MailTable.Columns.Reply, mail.Reply)
                .InColumnValue(MailTable.Columns.Subject, MailUtil.NormalizeStringForMySql(mail.Subject))
                .InColumnValue(MailTable.Columns.Cc, MailUtil.NormalizeStringForMySql(mail.Cc))
                .InColumnValue(MailTable.Columns.Bcc, MailUtil.NormalizeStringForMySql(mail.Bcc))
                .InColumnValue(MailTable.Columns.Importance, mail.Importance)
                .InColumnValue(MailTable.Columns.DateReceived, mail.DateReceived)
                .InColumnValue(MailTable.Columns.DateSent, mail.DateSent)
                .InColumnValue(MailTable.Columns.Size, mail.Size)
                .InColumnValue(MailTable.Columns.AttachCount, mail.AttachCount)
                .InColumnValue(MailTable.Columns.Unread, mail.Unread)
                .InColumnValue(MailTable.Columns.IsAnswered, mail.IsAnswered)
                .InColumnValue(MailTable.Columns.IsForwarded, mail.IsForwarded)
                .InColumnValue(MailTable.Columns.Stream, mail.Stream)
                .InColumnValue(MailTable.Columns.Folder, (int)mail.Folder)
                .InColumnValue(MailTable.Columns.FolderRestore, (int)mail.FolderRestore)
                .InColumnValue(MailTable.Columns.Spam, mail.Spam)
                .InColumnValue(MailTable.Columns.MimeMessageId, mail.MimeMessageId)
                .InColumnValue(MailTable.Columns.MimeInReplyTo, mail.MimeInReplyTo)
                .InColumnValue(MailTable.Columns.ChainId, mail.ChainId)
                .InColumnValue(MailTable.Columns.Introduction, MailUtil.NormalizeStringForMySql(mail.Introduction))
                .InColumnValue(MailTable.Columns.ChainDate, mail.DateSent)
                .InColumnValue(MailTable.Columns.IsTextBodyOnly, mail.IsTextBodyOnly)
                .Identity(0, 0, true);

            if (mail.HasParseError)
                query.InColumnValue(MailTable.Columns.HasParseError, mail.HasParseError);

            if (!string.IsNullOrEmpty(mail.CalendarUid))
                query.InColumnValue(MailTable.Columns.CalendarUid, mail.CalendarUid);

            return Db.ExecuteScalar<int>(query);
        }

        public Entities.Mail GetMail(IMessageExp exp)
        {
            var query = Query()
                .Where(exp.GetExpression());

            return Db.ExecuteList(query)
                .ConvertAll(ToMail)
                .SingleOrDefault();
        }

        public Entities.Mail GetNextMail(IMessageExp exp)
        {
            var query = Query()
                .Where(exp.GetExpression())
                .OrderBy(MailTable.Columns.Id, true)
                .SetMaxResults(1);

            var mail = Db.ExecuteList(query)
                .ConvertAll(ToMail)
                .SingleOrDefault();

            return mail;
        }

        public List<string> GetExistingUidls(int mailboxId, List<string> uidlList)
        {
            var query = new SqlQuery(MailTable.TABLE_NAME)
                .Select(MailTable.Columns.Uidl)
                .Where(MailTable.Columns.MailboxId, mailboxId)
                .Where(Exp.In(MailTable.Columns.Uidl, uidlList));

            var existingUidls = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToString(r[0]))
                .ToList();

            return existingUidls;
        }

        private const string SET_LAST_MODIFIED = MailTable.Columns.LastModified + " = UTC_TIMESTAMP()";

        public int SetMessagesChanged(List<int> ids)
        {
            var update = new SqlUpdate(MailTable.TABLE_NAME)
                .Set(SET_LAST_MODIFIED)
                .Where(Exp.In(MailTable.Columns.Id, ids));

            var result = Db.ExecuteNonQuery(update);

            return result;
        }

        protected Entities.Mail ToMail(object[] r)
        {
            var mail = new Entities.Mail
            {
                Id = Convert.ToInt32(r[0]),
                MailboxId = Convert.ToInt32(r[1]),
                User = Convert.ToString(r[2]),
                Tenant = Convert.ToInt32(r[3]),
                Address = Convert.ToString(r[4]),
                Uidl = Convert.ToString(r[5]),
                Md5 = Convert.ToString(r[6]),
                From = Convert.ToString(r[7]),
                To = Convert.ToString(r[8]),
                Reply = Convert.ToString(r[9]),
                Cc = Convert.ToString(r[10]),
                Bcc = Convert.ToString(r[11]),
                Subject = Convert.ToString(r[12]),
                Introduction = Convert.ToString(r[13]),
                Importance = Convert.ToBoolean(r[14]),
                DateReceived = Convert.ToDateTime(r[15]),
                DateSent = Convert.ToDateTime(r[16]),
                Size = Convert.ToInt32(r[17]),
                AttachCount = Convert.ToInt32(r[18]),
                Unread = Convert.ToBoolean(r[19]),
                IsAnswered = Convert.ToBoolean(r[20]),
                IsForwarded = Convert.ToBoolean(r[21]),
                Stream = Convert.ToString(r[22]),
                Folder = (FolderType)Convert.ToInt32(r[23]),
                FolderRestore = (FolderType)Convert.ToInt32(r[24]),
                Spam = Convert.ToBoolean(r[25]),
                IsRemoved = Convert.ToBoolean(r[26]),
                TimeModified = Convert.ToDateTime(r[27]),
                MimeMessageId = Convert.ToString(r[28]),
                MimeInReplyTo = Convert.ToString(r[29]),
                ChainId = Convert.ToString(r[30]),
                ChainDate = Convert.ToDateTime(r[31]),
                IsTextBodyOnly = Convert.ToBoolean(r[32]),
                HasParseError = Convert.ToBoolean(r[33]),
                CalendarUid = Convert.ToString(r[34])
            };

            return mail;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/tags/modal.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.tagsModal = (function($) {
    var isInit = false,
        wnd;

    function init() {
        if (isInit)
            return;

        isInit = true;

        wnd = $('#tagWnd');

        wnd.find('.tag.color .outer .inner').unbind('click').bind('click', function(e) {
            if ($('.tag.color .outer .inner').attr('disabled')) {
                return false;
            }

            tagsColorsPopup.show(this, changeWndTagColor);
            e.stopPropagation();
            return false;
        });

        wnd.find('.buttons .del').unbind('click').bind('click', function() {
            if ($('.buttons .del').attr('disabled')) {
                return false;
            }
            hide();
            deleteTag();
            return false;
        });

        wnd.find('.buttons .cancel').unbind('click').bind('click', function() {
            if ($('.buttons .cancel').attr('disabled')) {
                return false;
            }
            hide();
            return false;
        });

        tagsManager.bind(tagsManager.events.OnDelete, onTagsChange);
        tagsManager.bind(tagsManager.events.OnCreate, onTagsChange);
        tagsManager.bind(tagsManager.events.OnUpdate, onTagsChange);
        tagsManager.bind(tagsManager.events.OnError, onTagsError);
    }

    function onTagsChange() {
        hide();
    }

    function prepareOptions(opts) {
        if (!opts || typeof opts !== "object") {
            opts = {};
        }

        var options = {};

        options.onSuccess = !opts.hasOwnProperty("onSuccess") || typeof (opts.onSuccess) !== "function"
            ? function() { console.log("tag default success callback", arguments); }
            : opts.onSuccess;

        options.onError = !opts.hasOwnProperty("onError") || typeof (opts.onError) !== "function"
            ? function () { console.log("tag default error callback", arguments); }
            : opts.onError;

        return options;
    }

    function showCreate(opts) {
        var options = prepareOptions(opts);
        return show({ id: 0, name: '', addresses: {}, style: tagsManager.getVacantStyle() }, 'new', options);
    }

    function showEdit(tag, opts) {
        var options = prepareOptions(opts);
        return show(tag, 'edit', options);
    }

    function showDelete(tag, opts) {
        var options = prepareOptions(opts);
        return show(tag, 'delete', options);
    }

    function show(tag, type, options) {
        init();

        var headerText;

        if (type === 'delete') {
            wnd.find('.del').show();
            wnd.find('.save').hide();
            var text = MailScriptResource.DeleteTagShure;
            wnd.find('#deleteTagShure').text(text.replace(/%1/g, tag.name));
            headerText = wnd.attr('deletetag');
        } else {
            wnd.find('.del').hide();
            wnd.find('.save').show();

            if (type === 'new') {
                headerText = wnd.attr('newtag');
            } else {
                headerText = wnd.attr('savetag');
            }

            if (!tag.addresses.length)
                wnd.find('#mail_EmailsContainer').hide();
        }

        changeWndTagColor(undefined, tag.style);

        wnd.find('div.containerHeaderBlock:first td:first').html(headerText);
        wnd.find('#mail_CreateTag_Name input').val(tag.name);
        wnd.find('#mail_EmailsContainer').empty();
        wnd.attr('tagid', tag.id);

        var saveBtn = wnd.find('.buttons .save');

        saveBtn.unbind('click')
            .bind('click',
                function() {
                    if (saveBtn.attr('disabled') || saveBtn.hasClass('disable')) {
                        return false;
                    }

                    if (wnd.find('#mail_tag_email').val()) {
                        wnd.find("#mail_CreateTag_Email .plusmail").trigger("click");
                        return false;
                    }

                    TMMail.setRequiredError('mail_CreateTag_Email', false);
                    TMMail.setRequiredError('mail_CreateTag_Name', false);

                    tag = getTagFromWnd();
                    if (tag.name.length === 0) {
                        TMMail.setRequiredHint('mail_CreateTag_Name', MailScriptResource.ErrorEmptyField);
                        TMMail.setRequiredError('mail_CreateTag_Name', true);

                        wnd.find('#mail_tag_name').focus();
                        return false;
                    }

                    showLoader(MailScriptResource.TagCreation);

                    if ('new' === type) {
                        tagsManager.createTag(tag)
                            .then(function(tag) {
                                    hide();
                                    options.onSuccess(tag);
                                },
                                options.onError);
                    } else {
                        var currentValue = tagsManager.getTag(tag.id);
                        tag.lettersCount = currentValue.lettersCount;

                        tagsManager.updateTag(tag)
                            .then(function(tag) {
                                    hide();
                                    options.onSuccess(tag);
                                },
                                options.onError);
                    }

                    return true;
                });

        wnd.find('input.addemail')
            .EmailsSelector("init",
            {
                isInPopup: true,
                items: tag.addresses,
                container: wnd.find("#mail_EmailsContainer")
            });

        StudioBlockUIManager.blockUI(wnd, 350, { bindEvents: false });

        wnd = $('#tagWnd');

        TMMail.setRequiredError('mail_CreateTag_Email', false);
        TMMail.setRequiredError('mail_CreateTag_Name', false);

        window.PopupKeyUpActionProvider.EnterAction = "jq('#tagWnd .containerBodyBlock .buttons .save').click();";
    }

    function showLoader(message) {
        wnd.find('.progressContainer').show();
        wnd.find('.progressContainer .loader').show().html(message || '');
        wnd.find('.save #mail_tag_name').attr('disabled', 'true');
        wnd.find('.save .tag.color .outer .inner').attr('disabled', 'true').css('cursor', 'default');
        wnd.find('.save .tag.color').css('cursor', 'default');
        wnd.find('.linked_addresses.save #mail_tag_email').attr('disabled', 'true');
        wnd.find('.linked_addresses a.plusmail').attr('disabled', 'true').css('cursor', 'default');
        wnd.find('.removeTagAddress').attr('disabled', 'true').css('cursor', 'default');
        wnd.find('.buttons .save').attr('disabled', 'true').removeClass("disable").addClass("disable");
        wnd.find('.buttons .cancel').attr('disabled', 'true').removeClass("disable").addClass("disable");
    }

    function hideLoader() {
        wnd.find('.progressContainer').hide();
        wnd.find('.save #mail_tag_name').removeAttr('disabled');
        wnd.find('.save .tag.color .outer .inner').removeAttr('disabled').css('cursor', 'pointer');
        wnd.find('.save .tag.color').css('cursor', 'pointer');
        wnd.find('.linked_addresses.save #mail_tag_email').removeAttr('disabled');
        wnd.find('.linked_addresses a.plusmail').removeAttr("disabled").css('cursor', 'pointer');
        wnd.find('.removeTagAddress').removeAttr("disabled").css('cursor', 'pointer');
        wnd.find('.buttons .save').removeAttr('disabled').removeClass("disable");
        wnd.find('.buttons .cancel').removeAttr('disabled').removeClass("disable");
    }

    function changeWndTagColor(obj, newStyle) {
        wnd.find('a.square').removeClass().addClass('square tag' + newStyle);
        wnd.find('.tag.color .inner').removeClass().addClass('inner tag' + newStyle);
        wnd.find('.tag.color .inner').attr('colorstyle', newStyle);
    }

    function deleteTag() {
        var tag = getTagFromWnd();
        tagsManager.deleteTag(tag.id);
    }

    function hide(error) {
        wnd.find('.buttons .save').unbind('click');

        if (typeof error === 'object') {
            onTagsError(null, error);
            return;
        } else {
            hideLoader();
        }

        tagsColorsPopup.hide();

        if (wnd.is(':visible')) {
            $.unblockUI();
        }
    }

    function getTagFromWnd() {
        var id = wnd.attr('tagid'),
            style = wnd.find('.tag.color .inner').attr('colorstyle'),
            name = $.trim(wnd.find('#mail_tag_name').val()),
            addresses = wnd.find('input.addemail').EmailsSelector("get");

        return {
            id: id,
            name: name,
            style: style,
            addresses: jq.map(addresses, function(a) {
                return a.email;
            })
        };
    }

    function onTagsError(e, error) {
        setErrorMessage(error.message + (error.comment ? ': ' + error.comment : ''));
        wnd.find('.removeTagAddress').removeAttr("disabled").css('cursor', 'pointer');
    }

    function setErrorMessage(errorMessage) {
        hideLoader();
        window.toastr.error(errorMessage);
    }

    return {
        init: init,
        hide: hide,
        showCreate: showCreate,
        showDelete: showDelete,
        showEdit: showEdit
    };
})(jQuery);

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/OperationEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using ASC.Common.Threading;
using ASC.Core;
using ASC.Mail.Core.Engine.Operations;
using ASC.Mail.Core.Engine.Operations.Base;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Web.Studio.Utility;

using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Mail.Core.Engine
{
    public class OperationEngine
    {
        private readonly DistributedTaskQueue _mailOperations;

        public DistributedTaskQueue MailOperations
        {
            get { return _mailOperations; }
        }

        public OperationEngine()
        {
            _mailOperations = new DistributedTaskQueue("mailOperations", Defines.MailOperationsLimit);
        }

        public MailOperationStatus RemoveMailbox(MailBoxData mailbox,
            Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var operations = MailOperations.GetTasks()
                .Where(o =>
                {
                    var oTenant = o.GetProperty<int>(MailOperation.TENANT);
                    var oUser = o.GetProperty<string>(MailOperation.OWNER);
                    var oType = o.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
                    return oTenant == tenant.TenantId &&
                           oUser == user.ID.ToString() &&
                           oType == MailOperationType.RemoveMailbox;
                })
                .ToList();

            var sameOperation = operations.FirstOrDefault(o =>
            {
                var oSource = o.GetProperty<string>(MailOperation.SOURCE);
                return oSource == mailbox.MailBoxId.ToString();
            });

            if (sameOperation != null)
            {
                return GetMailOperationStatus(sameOperation.Id, translateMailOperationStatus);
            }

            var runningOperation = operations.FirstOrDefault(o => o.Status <= DistributedTaskStatus.Running);

            if (runningOperation != null)
                throw new MailOperationAlreadyRunningException("Remove mailbox operation already running.");

            var op = new MailRemoveMailboxOperation(tenant, user, mailbox);

            return QueueTask(op, translateMailOperationStatus);
        }

        public MailOperationStatus DownloadAllAttachments(int messageId,
            Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var operations = MailOperations.GetTasks()
                .Where(o =>
                {
                    var oTenant = o.GetProperty<int>(MailOperation.TENANT);
                    var oUser = o.GetProperty<string>(MailOperation.OWNER);
                    var oType = o.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
                    return oTenant == tenant.TenantId &&
                           oUser == user.ID.ToString() &&
                           oType == MailOperationType.DownloadAllAttachments;
                })
                .ToList();

            var sameOperation = operations.FirstOrDefault(o =>
            {
                var oSource = o.GetProperty<string>(MailOperation.SOURCE);
                return oSource == messageId.ToString();
            });

            if (sameOperation != null)
            {
                return GetMailOperationStatus(sameOperation.Id, translateMailOperationStatus);
            }

            var runningOperation = operations.FirstOrDefault(o => o.Status <= DistributedTaskStatus.Running);

            if (runningOperation != null)
                throw new MailOperationAlreadyRunningException("Download all attachments operation already running.");

            var op = new MailDownloadAllAttachmentsOperation(tenant, user, messageId);

            return QueueTask(op, translateMailOperationStatus);
        }

        public MailOperationStatus RecalculateFolders(Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var operations = MailOperations.GetTasks()
                .Where(o =>
                {
                    var oTenant = o.GetProperty<int>(MailOperation.TENANT);
                    var oUser = o.GetProperty<string>(MailOperation.OWNER);
                    var oType = o.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
                    return oTenant == tenant.TenantId &&
                           oUser == user.ID.ToString() &&
                           oType == MailOperationType.RecalculateFolders;
                });

            var runningOperation = operations.FirstOrDefault(o => o.Status <= DistributedTaskStatus.Running);

            if (runningOperation != null)
                return GetMailOperationStatus(runningOperation.Id, translateMailOperationStatus);

            var op = new MailRecalculateFoldersOperation(tenant, user);

            return QueueTask(op, translateMailOperationStatus);
        }

        public MailOperationStatus CheckDomainDns(string domainName, ServerDns dns,
            Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var operations = MailOperations.GetTasks()
                .Where(o =>
                {
                    var oTenant = o.GetProperty<int>(MailOperation.TENANT);
                    var oUser = o.GetProperty<string>(MailOperation.OWNER);
                    var oType = o.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
                    var oSource = o.GetProperty<string>(MailOperation.SOURCE);
                    return oTenant == tenant.TenantId &&
                           oUser == user.ID.ToString() &&
                           oType == MailOperationType.CheckDomainDns &&
                           oSource == domainName;
                });

            var runningOperation = operations.FirstOrDefault(o => o.Status <= DistributedTaskStatus.Running);

            if (runningOperation != null)
                return GetMailOperationStatus(runningOperation.Id, translateMailOperationStatus);

            var op = new MailCheckMailserverDomainsDnsOperation(tenant, user, domainName, dns);

            return QueueTask(op, translateMailOperationStatus);
        }

        public MailOperationStatus RemoveUserFolder(uint userFolderId,
            Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var operations = MailOperations.GetTasks()
                .Where(o =>
                {
                    var oTenant = o.GetProperty<int>(MailOperation.TENANT);
                    var oUser = o.GetProperty<string>(MailOperation.OWNER);
                    var oType = o.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
                    return oTenant == tenant.TenantId &&
                           oUser == user.ID.ToString() &&
                           oType == MailOperationType.RemoveUserFolder;
                })
                .ToList();

            var sameOperation = operations.FirstOrDefault(o =>
            {
                var oSource = o.GetProperty<string>(MailOperation.SOURCE);
                return oSource == userFolderId.ToString();
            });

            if (sameOperation != null)
            {
                return GetMailOperationStatus(sameOperation.Id, translateMailOperationStatus);
            }

            var runningOperation = operations.FirstOrDefault(o => o.Status <= DistributedTaskStatus.Running);

            if (runningOperation != null)
                throw new MailOperationAlreadyRunningException("Remove user folder operation already running.");

            var op = new MailRemoveUserFolderOperation(tenant, user, userFolderId);

            return QueueTask(op, translateMailOperationStatus);
        }

        public MailOperationStatus ApplyFilter(int filterId,
            Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var operations = MailOperations.GetTasks()
                .Where(o =>
                {
                    var oTenant = o.GetProperty<int>(MailOperation.TENANT);
                    var oUser = o.GetProperty<string>(MailOperation.OWNER);
                    var oType = o.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
                    return oTenant == tenant.TenantId &&
                           oUser == user.ID.ToString() &&
                           oType == MailOperationType.ApplyFilter;
                })
                .ToList();

            var sameOperation = operations.FirstOrDefault(o =>
            {
                var oSource = o.GetProperty<string>(MailOperation.SOURCE);
                return oSource == filterId.ToString();
            });

            if (sameOperation != null)
            {
                return GetMailOperationStatus(sameOperation.Id, translateMailOperationStatus);
            }

            var runningOperation = operations.FirstOrDefault(o => o.Status <= DistributedTaskStatus.Running);

            if (runningOperation != null)
                throw new MailOperationAlreadyRunningException("Apply filter operation already running.");

            var op = new ApplyFilterOperation(tenant, user, filterId);

            return QueueTask(op, translateMailOperationStatus);
        }

        public MailOperationStatus ApplyFilters(List<int> ids,
            Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var op = new ApplyFiltersOperation(tenant, user, ids);

            return QueueTask(op, translateMailOperationStatus);
        }
        public MailOperationStatus QueueTask(MailOperation op, Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var task = op.GetDistributedTask();
            MailOperations.QueueTask(op.RunJob, task);
            return GetMailOperationStatus(task.Id, translateMailOperationStatus);
        }

        public List<MailOperationStatus> GetMailOperations(Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var operations = MailOperations.GetTasks().Where(
                    o =>
                        o.GetProperty<int>(MailOperation.TENANT) == TenantProvider.CurrentTenantID &&
                        o.GetProperty<string>(MailOperation.OWNER) == SecurityContext.CurrentAccount.ID.ToString());

            var list = new List<MailOperationStatus>();

            foreach (var o in operations)
            {
                if (string.IsNullOrEmpty(o.Id))
                    continue;

                list.Add(GetMailOperationStatus(o.Id, translateMailOperationStatus));
            }

            return list;
        }

        public MailOperationStatus GetMailOperationStatus(string operationId, Func<DistributedTask, string> translateMailOperationStatus = null)
        {
            var defaultResult = new MailOperationStatus
            {
                Id = null,
                Completed = true,
                Percents = 100,
                Status = "",
                Error = "",
                Source = "",
                OperationType = -1
            };

            if (string.IsNullOrEmpty(operationId))
                return defaultResult;

            var operations = MailOperations.GetTasks().ToList();

            foreach (var o in operations)
            {
                if (!string.IsNullOrEmpty(o.InstanseId) &&
                    Process.GetProcesses().Any(p => p.Id == int.Parse(o.InstanseId)))
                    continue;

                o.SetProperty(MailOperation.PROGRESS, 100);
                MailOperations.RemoveTask(o.Id);
            }

            var operation = operations
                .FirstOrDefault(
                    o =>
                        o.GetProperty<int>(MailOperation.TENANT) == TenantProvider.CurrentTenantID &&
                        o.GetProperty<string>(MailOperation.OWNER) == SecurityContext.CurrentAccount.ID.ToString() &&
                        o.Id.Equals(operationId));

            if (operation == null)
                return defaultResult;

            if (DistributedTaskStatus.Running < operation.Status)
            {
                operation.SetProperty(MailOperation.PROGRESS, 100);
                MailOperations.RemoveTask(operation.Id);
            }

            var operationTypeIndex = (int)operation.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);

            var result = new MailOperationStatus
            {
                Id = operation.Id,
                Completed = operation.GetProperty<bool>(MailOperation.FINISHED),
                Percents = operation.GetProperty<int>(MailOperation.PROGRESS),
                Status = translateMailOperationStatus != null
                    ? translateMailOperationStatus(operation)
                    : operation.GetProperty<string>(MailOperation.STATUS),
                Error = operation.GetProperty<string>(MailOperation.ERROR),
                Source = operation.GetProperty<string>(MailOperation.SOURCE),
                OperationType = operationTypeIndex,
                Operation = Enum.GetName(typeof(MailOperationType), operationTypeIndex)
            };

            return result;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/Wrappers/AceWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Files.Core;
using ASC.Files.Core.Security;
using ASC.Web.Files.Resources;

namespace ASC.Web.Files.Services.WCFService
{
    [DataContract(Name = "ace_collection", Namespace = "")]
    public class AceCollection
    {
        [DataMember(Name = "entries", Order = 1)]
        public ItemList<string> Entries { get; set; }

        [DataMember(Name = "aces", Order = 2)]
        public ItemList<AceWrapper> Aces { get; set; }

        [DataMember(Name = "message", Order = 3, IsRequired = false)]
        public string Message { get; set; }
    }

    [DataContract(Name = "ace_wrapper", Namespace = "")]
    public class AceWrapper
    {
        [DataMember(Name = "id", Order = 1)]
        public Guid SubjectId { get; set; }

        [DataMember(Name = "title", Order = 2, EmitDefaultValue = false)]
        public string SubjectName { get; set; }

        [DataMember(Name = "link", Order = 3, EmitDefaultValue = false)]
        public string Link { get; set; }

        [DataMember(Name = "is_group", Order = 4)]
        public bool SubjectGroup { get; set; }

        [DataMember(Name = "owner", Order = 5)]
        public bool Owner { get; set; }

        [DataMember(Name = "ace_status", Order = 6)]
        public FileShare Share { get; set; }

        [DataMember(Name = "locked", Order = 7)]
        public bool LockedRights { get; set; }

        [DataMember(Name = "disable_remove", Order = 8)]
        public bool DisableRemove { get; set; }
    }

    [DataContract(Name = "sharingSettings", Namespace = "")]
    public class AceShortWrapper
    {
        [DataMember(Name = "user")]
        public string User { get; set; }

        [DataMember(Name = "permissions")]
        public string Permissions { get; set; }

        [DataMember(Name = "isLink", EmitDefaultValue = false, IsRequired = false)]
        public bool IsLink { get; set; }

        public AceShortWrapper(AceWrapper aceWrapper)
        {
            var permission = string.Empty;

            switch (aceWrapper.Share)
            {
                case FileShare.Read:
                    permission = FilesCommonResource.AceStatusEnum_Read;
                    break;
                case FileShare.ReadWrite:
                    permission = FilesCommonResource.AceStatusEnum_ReadWrite;
                    break;
                case FileShare.CustomFilter:
                    permission = FilesCommonResource.AceStatusEnum_CustomFilter;
                    break;
                case FileShare.Review:
                    permission = FilesCommonResource.AceStatusEnum_Review;
                    break;
                case FileShare.FillForms:
                    permission = FilesCommonResource.AceStatusEnum_FillForms;
                    break;
                case FileShare.Comment:
                    permission = FilesCommonResource.AceStatusEnum_Comment;
                    break;
                case FileShare.Restrict:
                    permission = FilesCommonResource.AceStatusEnum_Restrict;
                    break;
            }

            User = aceWrapper.SubjectName;
            if (aceWrapper.SubjectId.Equals(FileConstant.ShareLinkId))
            {
                IsLink = true;
                User = FilesCommonResource.AceShareLink;
            }
            Permissions = permission;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/plugins/jquery.tlcombobox.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


// tl combobox
(function ($, win, doc, body) {
  function converText (str) {
    var o = document.createElement('textarea');
    o.innerHTML = str;
    return o.value;
  }

  function onBodyClick (evt) {
    $(document.body).unbind('click', onBodyClick);
    jQuery('span.tl-combobox').addClass('un-showed').removeClass('showed-options').find('div.combobox-container:first').hide();
    setTimeout(function () {
      jQuery('span.tl-combobox').removeClass('un-showed');
    }, 0);
  }

  function onHelperFocus (evt, needTitleClick) {
    if (needTitleClick !== false) {
      onComboboxTitleClick(evt);
    }
  }

  function onHelperKeyup (evt) {
    return false;
  }

  function onHelperKeypress (evt) {
    switch (evt.keyCode) {
      case 9  :   //tab
        onBodyClick();
        return undefined;
      case 13 :   //enter
        onBodyClick();
        setFocusedOption(this);
        break;
      case 38 :   //up
      case 40 :   //down
        changeFocusedOption(this, evt.keyCode);
        break;
    }
    return false;
  }

  function onSelectFocus (evt, needTitleClick) {
    jQuery(this).parents('span.tl-combobox:first').find('input:first').trigger('focus', [needTitleClick]);
  }

  function onSelectChange (evt) {
    var
        $this = jQuery(this),
        $combobox = $this.parents('span.tl-combobox:first'),
        $select = $combobox.find('select:first'),
        $helper = $combobox.find('input:first'),
        $option = null,
        value = $this.val();

      if (!value && !this.value){
            return;
        }

      if (value == null && typeof this.value != "undefined"){
            value = this.value;
        }
      var
        title = $this.find('option[value="' + value + '"]').text(),
        classname = '',
        classes = $combobox.attr('class').split(/\s+/),
        classesInd = 0;
        classesInd = classes ? classes.length : 0;
    while (classesInd--) {
      classname = classes[classesInd];
      if (classname.indexOf('select-value-') === 0) {
        $combobox.removeClass(classname);
      }
    }

    $combobox.find('li.in-focus').removeClass('in-focus');
    $combobox.find('div.combobox-title-inner-text:first').text(title || ' ');
    $combobox.find('div.combobox-title-inner-text:first').attr('title' , title || ' ');
    $combobox.attr('data-value', value).addClass('select-value-' + value)
      .find('li.option-item[data-value="' + value + '"]:first').addClass('selected-item').siblings().removeClass('selected-item');

  //  $helper.trigger('focus', [false]);
  }

  function onComboboxTitleClick(evt) {
    var
      $combobox = jQuery(evt.target).parents('span.tl-combobox:first');

    if ($combobox.hasClass('disabled') || $combobox.hasClass('un-showed')) {
      return undefined;
    }

    if ($combobox.hasClass('showed-options')) {
      return undefined;
    }

    onBodyClick();
    $combobox.addClass('showed-options').find('div.combobox-container:first').show();

    var
      $select = $combobox.find('select:first'),
      $helper = $combobox.find('input:first'),
      $options = $combobox.find('li.option-item'),
      $selected = $options.filter('.selected-item:first');
    
    $options.removeClass('in-focus');
    if ($selected.length === 0) {
      $selected = $options.not('.hidden').filter(':first');
    }
    if ($selected.length > 0) {
      var selected = $selected[0];
      selected.parentNode.scrollTop = selected.offsetTop;
    }
  //  $helper.trigger('focus', [false]);

    var parent = $combobox.data('parent');
    if (parent) {
        var $parent = jQuery(parent);
        var $container = $combobox.find('div.combobox-container:first').css({ top: 0 });
        var $title = $combobox.find('div.combobox-title:first');

        var padding = 8;

        var parentTop = $parent.offset().top;
        var parentHeight = $parent.outerHeight();
        var parentBottom = parentTop + parentHeight;

        var containerTop = $container.offset().top;
        var containerHeight = $container.outerHeight();
        var containerBottom = containerTop + containerHeight;

        var titleTop = $title.offset().top;
        var titleHeight = $title.outerHeight();

        var expectedContainerTop = titleTop - padding - containerHeight;

        if (parentBottom < containerBottom) {
            if (parentTop < expectedContainerTop) {
                $container.css({ top: (-padding - containerHeight - titleHeight) })
            } else {
                $container.css({ top: (parentBottom - containerBottom) })
            }
        }
    }

    setTimeout(bindBodyEvents, 1);
  }

  function onComboboxOptionHover (evt) {
    jQuery(this).addClass('in-focus').siblings().removeClass('in-focus');
  }

  function onComboboxOptionClick (evt) {
    var
      $combobox = jQuery(this).parents('span.tl-combobox:first');

    if ($combobox.hasClass('disabled')) {
      return undefined;
    }

    var
      $select = $combobox.find('select:first'),
      $target = jQuery(evt.target),
      value = $target.attr('data-value');

    $select.val(value).change();
  }

  function setFocusedOption (helper) {
    var
      $combobox = jQuery(helper).parents('span.tl-combobox:first');

    if ($combobox.hasClass('disabled')) {
      return undefined;
    }

    var
      $select = $combobox.find('select:first'),
      $target = $combobox.find('li.option-item.in-focus'),
      value = $target.attr('data-value');

    if (value) {
      $select.val(value).change();
    }
  }

  function changeFocusedOption (helper, keycode) {
    var
      $combobox = jQuery(helper).parents('span.tl-combobox:first');

    if ($combobox.hasClass('disabled')) {
      return undefined;
    }

    var
      $options = $combobox.find('li.option-item').not('.hidden'),
      $infocus = $options.filter('.in-focus');

    if ($infocus.length === 0) {
      $infocus = $options.filter('.selected-item:first');
    }

    switch (keycode) {
      case 38 :   //up
        while(($infocus = $infocus.prev()).length > 0) {
          if (!$infocus.hasClass('hidden')) {
            break;
          }
        }
        //$infocus = $infocus.prev();
        if ($infocus.length === 0) {
          $infocus = $options.filter(':first');
        }
        break;
      case 40 :   //down
        while(($infocus = $infocus.next()).length > 0) {
          if (!$infocus.hasClass('hidden')) {
            break;
          }
        }
        //$infocus = $infocus.next();
        if ($infocus.length === 0) {
          $infocus = $options.filter(':last');
        }
        break;
    }
    if ($infocus.length > 0) {
      var
        infocus = $infocus[0],
        parent = infocus.parentNode;
      if (infocus.offsetTop < parent.scrollTop) {
        parent.scrollTop = infocus.offsetTop;
      } else if (infocus.offsetTop + infocus.offsetHeight > parent.scrollTop + parent.offsetHeight) {
        parent.scrollTop = infocus.offsetTop - parent.offsetHeight + infocus.offsetHeight;
      }
    }
    $infocus.addClass('in-focus').siblings().removeClass('in-focus');
  }

  function renderOption (option, datavalue) {
    return [
        '<li',
          ' class="option-item',
            option.classname ? ' ' + option.classname : '',
            option.selected === true ? ' selected-item' : '',
            option.disabled === true ? ' display-none' : '',
          '"',
          ' data-value="' + datavalue + '"',
          ' title="' + (Encoder.htmlEncode(jQuery.trim(option.title))  || '&nbsp;') + '"',
        '>',
        option.title || '&nbsp;',
        '</li>'
    ];
  }

  function renderCombobox(select, options) {
    var
      html = [],
      option = null,
      optionsvalue = [],
      selectclassname = select.className,
      selectoption = options.length ? options[0] : { title: "", value: "" };

    for (var i = 0, n = options.length; i < n; i++) {
      option = options[i];
      if (option.selected === true) {
        selectoption = option;
      }
      optionsvalue.push(option.value);
      html = html.concat(renderOption(option, optionsvalue.length - 1));
    }

    html = [
      '<div class="combobox-title">',
        '<div class="inner-text combobox-title-inner-text" title="' + (Encoder.htmlEncode(jQuery.trim(selectoption.title)) || '&nbsp;') + '">',
          selectoption.title || '&nbsp;',
        '</div>',
      '</div>',
      '<div class="combobox-wrapper">',
        '<div class="combobox-container">',
          '<ul class="combobox-options">',
            html.join(''),
          '</ul>',
        '</div>',
      '</div>'
    ];

    var o = doc.createElement('span');
    o.className = 'tl-combobox' + ' tl-combobox-container' + ' select-value-' + selectoption.value + (selectclassname ? ' ' + selectclassname : '');
    //if (typeof select.getAttribute('disabled') === 'string') {
    //  o.className += ' disabled';
    //}
    o.innerHTML = html.join('');

    var
      optionsvalueLen = optionsvalue.length,
      value = null,
      node = null,
      nodes = o.getElementsByTagName('li'),
      nodesInd = 0;
    nodesInd = nodes ? nodes.length : 0;
    while (nodesInd--) {
      node = nodes[nodesInd];
      value = node.getAttribute('data-value');
      value = isFinite(+value) ? +value : -1;
      if (value > -1 && value < optionsvalueLen) {
        node.setAttribute('data-value', optionsvalue[value]);
      }
    }
    return o;
  }

  function reRenderCombobox(o, select, options) {
    var
      html = [],
      option = null,
      optionsvalue = [],
      selectclassname = select.className,
      selectoption = options.length ? options[0] : null;

    for (var i = 0, n = options.length; i < n; i++) {
      option = options[i];
      if (option.selected === true) {
        selectoption = option;
      }
      optionsvalue.push(option.value);
      html = html.concat(renderOption(option, optionsvalue.length - 1));
    }

    try {
      var ul = select.previousSibling.firstChild.lastChild;
      ul.innerHTML = html.join('');
    } catch (err) {}

    if (selectoption != null) {
      try {
        var title = o.firstChild.firstChild;
        title.innerHTML = selectoption.title || '&nbsp;';
        title.setAttribute('title', converText(selectoption.title || '&nbsp;'));
        o.className = 'tl-combobox' + ' tl-combobox-container' + ' select-value-' + selectoption.value + (selectclassname ? ' ' + selectclassname : '');
      } catch (err) {}
    }

    var
      optionsvalueLen = optionsvalue.length,
      value = null,
      node = null,
      nodes = o.getElementsByTagName('li'),
      nodesInd = 0;
    nodesInd = nodes ? nodes.length : 0;
    while (nodesInd--) {
      node = nodes[nodesInd];
      value = node.getAttribute('data-value');
      value = isFinite(+value) ? +value : -1;
      if (value > -1 && value < optionsvalueLen) {
        node.setAttribute('data-value', optionsvalue[value]);
      }
    }

    return o;
  }

  function updateSelect (select) {
    var
      o = null,
      selectvalue = select.value,
      opts = [],
      optionvalue = null,
      options = null,
      optionsInd = 0,
      option = null;

    onBodyClick();

    options = select.getElementsByTagName('option');
    optionsInd = options ? options.length : 0;

    if (select.selectedIndex == -1 && options.length) {
        select.selectedIndex = 0;
        selectvalue = select.value;
    }

    while (optionsInd--) {
      option = options[optionsInd];
      optionvalue = option.getAttribute('value');
      opts.unshift({ classname: option.className, value: optionvalue, title: option.innerHTML, selected: optionvalue == selectvalue, disabled: option.disabled });
    }

    if (select.className.indexOf('tl-combobox') === -1) {
      o = renderCombobox(select, opts);
      if (o) {
        select.parentNode.insertBefore(o, select);
        o.appendChild(select);
        if (select.className.indexOf('none-helper') === -1) {
          var helper = document.createElement('input');
          o.appendChild(helper);
        }
        o.setAttribute('data-value', selectvalue);
        return o;
      }
    } else {
      o = select.parentNode;
      if (o) {
        reRenderCombobox(o, select, opts);
        o.setAttribute('data-value', selectvalue);
        return o;
      }
    }

    return null;
  }

  function bindBodyEvents () {
    jQuery(document.body).one('click', onBodyClick);
  }

  function bindComboboxEvents ($select, $combobox) {
    //setTimeout((function ($select) {
    //  return function () {
    //    $select.unbind('focus', onSelectFocus).bind('focus', onSelectFocus);
    //  };
    //})($select), 500);
    $select
      //.blur(onSelectBlur)
      //.focus(onSelectFocus)
      .unbind('change', onSelectChange).bind('change', onSelectChange);
    $combobox.find('input')
      .unbind('focus', onHelperFocus).bind('focus', onHelperFocus)
      .unbind('keydown', onHelperKeypress).bind('keydown', onHelperKeypress)
      .unbind('keyup', onHelperKeyup).bind('keyup', onHelperKeyup);
    $combobox.find('ul.combobox-options:first')
      .unbind('click', onComboboxOptionClick).bind('click', onComboboxOptionClick)
      .find('li.option-item')
        .unbind('hover', onComboboxOptionHover).bind('hover', onComboboxOptionHover);
    $combobox.find('div.combobox-title:first')
      .unbind('click', onComboboxTitleClick).bind('click', onComboboxTitleClick);
  }

  $.fn.tlCombobox = $.fn.tlcombobox = function (params) {
    var
      //wasupdated = false,
      select = null,
      combobox = null,
      $selects = $(this),
      selectsInd = 0,
      $select = null;

    if (typeof params === 'boolean') {
      selectsInd = $selects.length;
      while (selectsInd--) {
        if (params === true) {
          $($selects[selectsInd]).attr('disabled', false).parents('span.tl-combobox:first').removeClass('disabled');
        } else {
          $($selects[selectsInd]).attr('disabled', true).parents('span.tl-combobox:first').addClass('disabled');
        }
      }
      return $selects;
    }

    if (typeof params === 'string') {
      switch (params) {
        case 'show' :
          $($selects[selectsInd]).show().parents('span.tl-combobox:first').show();
          return $selects;
        case 'hide' :
          $($selects[selectsInd]).hide().parents('span.tl-combobox:first').hide();
          return $selects;
      }
    }

    selectsInd = $selects.length;
    while (selectsInd--) {
      select = $selects[selectsInd];
      $select = $(select);

      combobox = updateSelect(select);
      bindComboboxEvents($select, $(combobox));
      //setTimeout((function ($select, $combobox, callback) {
      //  return function () {
      //    callback($select, $combobox);
      //  };
      //})($(select), $(combobox), bindComboboxEvents), 500);
      $select.addClass('tl-combobox');

      if (params && params.hasOwnProperty('align')) {
          if (params.align == 'left') {
              $select.parents('span.tl-combobox:first').addClass('left-align');
          } else {
              $select.parents('span.tl-combobox:first').removeClass('left-align');
          }
      }

      if (params && params.hasOwnProperty('parent')) {
          $select.parents('span.tl-combobox:first').data('parent', params['parent']);
      }

      //wasupdated = true;
    }

    //if (wasupdated) {
    //  var
    //    zindex = 0,
    //    $comboboxes = $('span.tl-combobox'),
    //    comboboxesInd = $comboboxes.length;
    //  while (comboboxesInd--) {
    //    $($comboboxes[comboboxesInd]).css('zIndex', ++zindex);
    //  }
    //}
    return $selects;
  };
})(jQuery, window, document, document.body);

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Utils/FileMarker.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;

using ASC.Common.Caching;
using ASC.Common.Threading.Workers;
using ASC.Core;
using ASC.Core.Users;
using ASC.Files.Core;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Resources;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

using File = ASC.Files.Core.File;
using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Web.Files.Utils
{
    public static class FileMarker
    {
        private static readonly object locker = new object();
        private static readonly WorkerQueue<AsyncTaskData> tasks = new WorkerQueue<AsyncTaskData>(1, TimeSpan.FromSeconds(60), 1, false);
        private static readonly ICache cache = AscCache.Default;

        private const string CacheKeyFormat = "MarkedAsNew/{0}/folder_{1}";


        private static void ExecMarkFileAsNew(AsyncTaskData obj)
        {
            CoreContext.TenantManager.SetCurrentTenant(Convert.ToInt32(obj.TenantID));

            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                object parentFolderId;

                if (obj.FileEntry.FileEntryType == FileEntryType.File)
                    parentFolderId = ((File)obj.FileEntry).FolderID;
                else
                    parentFolderId = obj.FileEntry.ID;
                var parentFolders = folderDao.GetParentFolders(parentFolderId);
                parentFolders.Reverse();

                var userIDs = obj.UserIDs;

                var userEntriesData = new Dictionary<Guid, List<FileEntry>>();

                if (obj.FileEntry.RootFolderType == FolderType.BUNCH)
                {
                    if (!userIDs.Any()) return;

                    parentFolders.Add(folderDao.GetFolder(Global.FolderProjects));

                    var entries = new List<FileEntry> { obj.FileEntry };
                    entries = entries.Concat(parentFolders).ToList();

                    userIDs.ForEach(userID =>
                                            {
                                                if (userEntriesData.ContainsKey(userID))
                                                    userEntriesData[userID].AddRange(entries);
                                                else
                                                    userEntriesData.Add(userID, entries);

                                                RemoveFromCahce(Global.FolderProjects, userID);
                                            });
                }
                else
                {
                    var filesSecurity = Global.GetFilesSecurity();

                    if (!userIDs.Any())
                    {
                        userIDs = filesSecurity.WhoCanRead(obj.FileEntry).Where(x => x != obj.CurrentAccountId).ToList();
                    }
                    if (obj.FileEntry.ProviderEntry)
                    {
                        userIDs = userIDs.Where(u => !CoreContext.UserManager.GetUsers(u).IsVisitor()).ToList();
                    }

                    parentFolders.ForEach(parentFolder =>
                                          filesSecurity
                                              .WhoCanRead(parentFolder)
                                              .Where(userID => userIDs.Contains(userID) && userID != obj.CurrentAccountId)
                                              .ToList()
                                              .ForEach(userID =>
                                                           {
                                                               if (userEntriesData.ContainsKey(userID))
                                                                   userEntriesData[userID].Add(parentFolder);
                                                               else
                                                                   userEntriesData.Add(userID, new List<FileEntry> { parentFolder });
                                                           })
                        );



                    if (obj.FileEntry.RootFolderType == FolderType.USER)
                    {
                        var folderShare = folderDao.GetFolder(Global.FolderShare);

                        foreach (var userID in userIDs)
                        {
                            var userFolderId = folderDao.GetFolderIDUser(false, userID);
                            if (Equals(userFolderId, 0)) continue;

                            Folder rootFolder = null;
                            if (obj.FileEntry.ProviderEntry)
                            {
                                rootFolder = obj.FileEntry.RootFolderCreator == userID
                                                 ? folderDao.GetFolder(userFolderId)
                                                 : folderShare;
                            }
                            else if (!Equals(obj.FileEntry.RootFolderId, userFolderId))
                            {
                                rootFolder = folderShare;
                            }
                            else
                            {
                                RemoveFromCahce(userFolderId, userID);
                            }

                            if (rootFolder == null) continue;

                            if (userEntriesData.ContainsKey(userID))
                                userEntriesData[userID].Add(rootFolder);
                            else
                                userEntriesData.Add(userID, new List<FileEntry> { rootFolder });

                            RemoveFromCahce(rootFolder.ID, userID);
                        }
                    }
                    else if (obj.FileEntry.RootFolderType == FolderType.COMMON)
                    {
                        userIDs.ForEach(userID => RemoveFromCahce(Global.FolderCommon, userID));

                        if (obj.FileEntry.ProviderEntry)
                        {
                            var commonFolder = folderDao.GetFolder(Global.FolderCommon);
                            userIDs.ForEach(userID =>
                                                {
                                                    if (userEntriesData.ContainsKey(userID))
                                                        userEntriesData[userID].Add(commonFolder);
                                                    else
                                                        userEntriesData.Add(userID, new List<FileEntry> { commonFolder });

                                                    RemoveFromCahce(Global.FolderCommon, userID);
                                                });
                        }
                    }
                    else if (obj.FileEntry.RootFolderType == FolderType.Privacy)
                    {
                        foreach (var userID in userIDs)
                        {
                            var privacyFolderId = folderDao.GetFolderIDPrivacy(false, userID);
                            if (Equals(privacyFolderId, 0)) continue;

                            var rootFolder = folderDao.GetFolder(privacyFolderId);
                            if (rootFolder == null) continue;

                            if (userEntriesData.ContainsKey(userID))
                                userEntriesData[userID].Add(rootFolder);
                            else
                                userEntriesData.Add(userID, new List<FileEntry> { rootFolder });

                            RemoveFromCahce(rootFolder.ID, userID);
                        }
                    }

                    userIDs.ForEach(userID =>
                                        {
                                            if (userEntriesData.ContainsKey(userID))
                                                userEntriesData[userID].Add(obj.FileEntry);
                                            else
                                                userEntriesData.Add(userID, new List<FileEntry> { obj.FileEntry });
                                        });
                }

                using (var tagDao = Global.DaoFactory.GetTagDao())
                {
                    var newTags = new List<Tag>();
                    var updateTags = new List<Tag>();

                    foreach (var userID in userEntriesData.Keys)
                    {
                        if (tagDao.GetNewTags(userID, obj.FileEntry).Any())
                            continue;

                        var entries = userEntriesData[userID].Distinct().ToList();

                        var exist = tagDao.GetNewTags(userID, entries).ToList();
                        var update = exist.Where(t => t.EntryType == FileEntryType.Folder).ToList();
                        update.ForEach(t => t.Count++);
                        updateTags.AddRange(update);

                        entries.ForEach(entry =>
                                            {
                                                if (entry != null && exist.All(tag => tag != null && !tag.EntryId.Equals(entry.ID)))
                                                {
                                                    newTags.Add(Tag.New(userID, entry));
                                                }
                                            });
                    }

                    if (updateTags.Any())
                        tagDao.UpdateNewTags(updateTags);
                    if (newTags.Any())
                        tagDao.SaveTags(newTags);
                }
            }
        }

        public static void MarkAsNew(FileEntry fileEntry, List<Guid> userIDs = null)
        {
            if (CoreContext.Configuration.Personal) return;

            if (fileEntry == null) return;
            userIDs = userIDs ?? new List<Guid>();

            var taskData = new AsyncTaskData
            {
                FileEntry = (FileEntry)fileEntry.Clone(),
                UserIDs = userIDs
            };

            if (fileEntry.RootFolderType == FolderType.BUNCH && !userIDs.Any())
            {
                using (var folderDao = Global.DaoFactory.GetFolderDao())
                {
                    var path = folderDao.GetBunchObjectID(fileEntry.RootFolderId);

                    var projectID = path.Split('/').Last();
                    if (string.IsNullOrEmpty(projectID)) return;
                }

                var projectTeam = Global.GetFilesSecurity().WhoCanRead(fileEntry)
                                        .Where(x => x != SecurityContext.CurrentAccount.ID).ToList();

                if (!projectTeam.Any()) return;

                taskData.UserIDs = projectTeam;
            }

            lock (locker)
            {
                tasks.Add(taskData);

                if (!tasks.IsStarted)
                    tasks.Start(ExecMarkFileAsNew);
            }
        }

        public static void RemoveMarkAsNew(FileEntry fileEntry, Guid userID = default(Guid))
        {
            if (CoreContext.Configuration.Personal) return;

            userID = userID.Equals(default(Guid)) ? SecurityContext.CurrentAccount.ID : userID;

            if (fileEntry == null) return;

            using (var tagDao = Global.DaoFactory.GetTagDao())
            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                if (!tagDao.GetNewTags(userID, fileEntry).Any()) return;

                object folderID;
                int valueNew;
                var userFolderId = folderDao.GetFolderIDUser(false, userID);
                var privacyFolderId = folderDao.GetFolderIDPrivacy(false, userID);

                var removeTags = new List<Tag>();

                if (fileEntry.FileEntryType == FileEntryType.File)
                {
                    folderID = ((File)fileEntry).FolderID;

                    removeTags.Add(Tag.New(userID, fileEntry));
                    valueNew = 1;
                }
                else
                {
                    folderID = fileEntry.ID;

                    var listTags = tagDao.GetNewTags(userID, (Folder)fileEntry, true).ToList();
                    valueNew = listTags.FirstOrDefault(tag => tag.EntryId.Equals(fileEntry.ID)).Count;

                    if (Equals(fileEntry.ID, userFolderId) || Equals(fileEntry.ID, Global.FolderCommon) || Equals(fileEntry.ID, Global.FolderShare))
                    {
                        var folderTags = listTags.Where(tag => tag.EntryType == FileEntryType.Folder);

                        var providerFolderTags = folderTags.Select(tag => new KeyValuePair<Tag, Folder>(tag, folderDao.GetFolder(tag.EntryId)))
                                                           .Where(pair => pair.Value != null && pair.Value.ProviderEntry).ToList();

                        foreach (var providerFolderTag in providerFolderTags)
                        {
                            listTags.Remove(providerFolderTag.Key);
                            listTags.AddRange(tagDao.GetNewTags(userID, providerFolderTag.Value, true));
                        }
                    }

                    removeTags.AddRange(listTags);
                }

                var parentFolders = folderDao.GetParentFolders(folderID);
                parentFolders.Reverse();

                var rootFolder = parentFolders.LastOrDefault();
                object rootFolderId = null;
                object cacheFolderId = null;
                if (rootFolder == null)
                {
                }
                else if (rootFolder.RootFolderType == FolderType.BUNCH)
                {
                    cacheFolderId = rootFolderId = Global.FolderProjects;
                }
                else if (rootFolder.RootFolderType == FolderType.COMMON)
                {
                    if (rootFolder.ProviderEntry)
                        cacheFolderId = rootFolderId = Global.FolderCommon;
                    else
                        cacheFolderId = Global.FolderCommon;
                }
                else if (rootFolder.RootFolderType == FolderType.USER)
                {
                    if (rootFolder.ProviderEntry && rootFolder.RootFolderCreator == userID)
                        cacheFolderId = rootFolderId = userFolderId;
                    else if (!rootFolder.ProviderEntry && !Equals(rootFolder.RootFolderId, userFolderId)
                             || rootFolder.ProviderEntry && rootFolder.RootFolderCreator != userID)
                        cacheFolderId = rootFolderId = Global.FolderShare;
                    else
                        cacheFolderId = userFolderId;
                }
                else if (rootFolder.RootFolderType == FolderType.Privacy)
                {
                    if (!Equals(privacyFolderId, 0))
                    {
                        cacheFolderId = rootFolderId = privacyFolderId;
                    }
                }
                else if (rootFolder.RootFolderType == FolderType.SHARE)
                {
                    cacheFolderId = Global.FolderShare;
                }

                if (rootFolderId != null)
                {
                    parentFolders.Add(folderDao.GetFolder(rootFolderId));
                }
                if (cacheFolderId != null)
                {
                    RemoveFromCahce(cacheFolderId, userID);
                }

                var updateTags = new List<Tag>();
                foreach (var parentFolder in parentFolders)
                {
                    var parentTag = tagDao.GetNewTags(userID, parentFolder).FirstOrDefault();

                    if (parentTag != null)
                    {
                        parentTag.Count -= valueNew;

                        if (parentTag.Count > 0)
                        {
                            updateTags.Add(parentTag);
                        }
                        else
                        {
                            removeTags.Add(parentTag);
                        }
                    }
                }

                if (updateTags.Any())
                    tagDao.UpdateNewTags(updateTags);
                if (removeTags.Any())
                    tagDao.RemoveTags(removeTags);
            }
        }

        public static void RemoveMarkAsNewForAll(FileEntry fileEntry)
        {
            List<Guid> userIDs;

            using (var tagDao = Global.DaoFactory.GetTagDao())
            {
                var tags = tagDao.GetTags(fileEntry.ID, fileEntry.FileEntryType == FileEntryType.File ? FileEntryType.File : FileEntryType.Folder, TagType.New);
                userIDs = tags.Select(tag => tag.Owner).Distinct().ToList();
            }

            foreach (var userID in userIDs)
            {
                RemoveMarkAsNew(fileEntry, userID);
            }
        }

        public static Dictionary<object, int> GetRootFoldersIdMarkedAsNew()
        {
            var rootIds = new List<object>
                {
                    Global.FolderMy,
                    Global.FolderCommon,
                    Global.FolderShare,
                    Global.FolderProjects
                };

            if (PrivacyRoomSettings.Enabled)
            {
                rootIds.Add(Global.FolderPrivacy);
            }

            var requestIds = new List<object>();
            var news = new Dictionary<object, int>();

            rootIds.ForEach(rootId =>
                                {
                                    var fromCache = GetCountFromCahce(rootId);
                                    if (fromCache == -1)
                                    {
                                        requestIds.Add(rootId);
                                    }
                                    else if ((fromCache) > 0)
                                    {
                                        news.Add(rootId, (int)fromCache);
                                    }
                                });

            if (requestIds.Any())
            {
                IEnumerable<Tag> requestTags;
                using (var tagDao = Global.DaoFactory.GetTagDao())
                using (var folderDao = Global.DaoFactory.GetFolderDao())
                {

                    requestTags = tagDao.GetNewTags(SecurityContext.CurrentAccount.ID, folderDao.GetFolders(requestIds.ToArray()));
                }

                requestIds.ForEach(requestId =>
                                       {
                                           var requestTag = requestTags.FirstOrDefault(tag => tag.EntryId.Equals(requestId));
                                           InsertToCahce(requestId, requestTag == null ? 0 : requestTag.Count);
                                       });

                news = news.Concat(requestTags.ToDictionary(x => x.EntryId, x => x.Count)).ToDictionary(x => x.Key, x => x.Value);
            }

            return news;
        }

        public static List<FileEntry> MarkedItems(Folder folder)
        {
            if (folder == null) throw new ArgumentNullException("folder", FilesCommonResource.ErrorMassage_FolderNotFound);
            if (!Global.GetFilesSecurity().CanRead(folder)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ViewFolder);
            if (folder.RootFolderType == FolderType.TRASH && !Equals(folder.ID, Global.FolderTrash)) throw new SecurityException(FilesCommonResource.ErrorMassage_ViewTrashItem);

            var entryTags = new Dictionary<FileEntry, Tag>();

            using (var tagDao = Global.DaoFactory.GetTagDao())
            using (var fileDao = Global.DaoFactory.GetFileDao())
            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                var tags = (tagDao.GetNewTags(SecurityContext.CurrentAccount.ID, folder, true) ?? new List<Tag>()).ToList();

                if (!tags.Any()) return new List<FileEntry>();

                if (Equals(folder.ID, Global.FolderMy) || Equals(folder.ID, Global.FolderCommon) || Equals(folder.ID, Global.FolderShare))
                {
                    var folderTags = tags.Where(tag => tag.EntryType == FileEntryType.Folder);

                    var providerFolderTags = folderTags.Select(tag => new KeyValuePair<Tag, Folder>(tag, folderDao.GetFolder(tag.EntryId)))
                                                       .Where(pair => pair.Value != null && pair.Value.ProviderEntry).ToList();
                    providerFolderTags.Reverse();

                    foreach (var providerFolderTag in providerFolderTags)
                    {
                        tags.AddRange(tagDao.GetNewTags(SecurityContext.CurrentAccount.ID, providerFolderTag.Value, true));
                    }
                }

                tags = tags.Distinct().ToList();
                tags.RemoveAll(tag => Equals(tag.EntryId, folder.ID));
                tags = tags.Where(t => t.EntryType == FileEntryType.Folder)
                           .Concat(tags.Where(t => t.EntryType == FileEntryType.File)).ToList();

                foreach (var tag in tags)
                {
                    var entry = tag.EntryType == FileEntryType.File
                                    ? (FileEntry)fileDao.GetFile(tag.EntryId)
                                    : (FileEntry)folderDao.GetFolder(tag.EntryId);
                    if (entry != null
                        && (!entry.ProviderEntry || FilesSettings.EnableThirdParty))
                    {
                        entryTags.Add(entry, tag);
                    }
                    else
                    {
                        //todo: RemoveMarkAsNew(tag);
                    }
                }
            }

            foreach (var entryTag in entryTags)
            {
                var entry = entryTag.Key;
                var parentId =
                    entry.FileEntryType == FileEntryType.File
                        ? ((File)entry).FolderID
                        : ((Folder)entry).ParentFolderID;

                var parentEntry = entryTags.Keys.FirstOrDefault(entryCountTag => Equals(entryCountTag.ID, parentId));
                if (parentEntry != null)
                    entryTags[parentEntry].Count -= entryTag.Value.Count;
            }

            var result = new List<FileEntry>();

            foreach (var entryTag in entryTags)
            {
                if (!string.IsNullOrEmpty(entryTag.Key.Error))
                {
                    RemoveMarkAsNew(entryTag.Key);
                    continue;
                }

                if (entryTag.Value.Count > 0)
                {
                    result.Add(entryTag.Key);
                }
            }
            return result;
        }

        public static IEnumerable<FileEntry> SetTagsNew(IFolderDao folderDao, Folder parent, IEnumerable<FileEntry> entries)
        {
            using (var tagDao = Global.DaoFactory.GetTagDao())
            {
                var totalTags = tagDao.GetNewTags(SecurityContext.CurrentAccount.ID, parent, false).ToList();

                if (totalTags.Any())
                {
                    var parentFolderTag = Equals(Global.FolderShare, parent.ID)
                                              ? tagDao.GetNewTags(SecurityContext.CurrentAccount.ID, folderDao.GetFolder(Global.FolderShare)).FirstOrDefault()
                                              : totalTags.FirstOrDefault(tag => tag.EntryType == FileEntryType.Folder && Equals(tag.EntryId, parent.ID));

                    totalTags.Remove(parentFolderTag);
                    var countSubNew = 0;
                    totalTags.ForEach(tag => countSubNew += tag.Count);

                    if (parentFolderTag == null)
                    {
                        parentFolderTag = Tag.New(SecurityContext.CurrentAccount.ID, parent, 0);
                        parentFolderTag.Id = -1;
                    }

                    if (parentFolderTag.Count != countSubNew)
                    {
                        if (countSubNew > 0)
                        {
                            var diff = parentFolderTag.Count - countSubNew;

                            parentFolderTag.Count -= diff;
                            if (parentFolderTag.Id == -1)
                            {
                                tagDao.SaveTags(parentFolderTag);
                            }
                            else
                            {
                                tagDao.UpdateNewTags(parentFolderTag);
                            }

                            var cacheFolderId = parent.ID;
                            var parentsList = folderDao.GetParentFolders(parent.ID);
                            parentsList.Reverse();
                            parentsList.Remove(parent);

                            if (parentsList.Any())
                            {
                                var rootFolder = parentsList.Last();
                                object rootFolderId = null;
                                cacheFolderId = rootFolder.ID;
                                if (rootFolder.RootFolderType == FolderType.BUNCH)
                                    cacheFolderId = rootFolderId = Global.FolderProjects;
                                else if (rootFolder.RootFolderType == FolderType.USER && !Equals(rootFolder.RootFolderId, Global.FolderMy))
                                    cacheFolderId = rootFolderId = Global.FolderShare;

                                if (rootFolderId != null)
                                {
                                    parentsList.Add(folderDao.GetFolder(rootFolderId));
                                }

                                var fileSecurity = Global.GetFilesSecurity();

                                foreach (var folderFromList in parentsList)
                                {
                                    var parentTreeTag = tagDao.GetNewTags(SecurityContext.CurrentAccount.ID, folderFromList).FirstOrDefault();

                                    if (parentTreeTag == null)
                                    {
                                        if (fileSecurity.CanRead(folderFromList))
                                        {
                                            tagDao.SaveTags(Tag.New(SecurityContext.CurrentAccount.ID, folderFromList, -diff));
                                        }
                                    }
                                    else
                                    {
                                        parentTreeTag.Count -= diff;
                                        tagDao.UpdateNewTags(parentTreeTag);
                                    }
                                }
                            }

                            if (cacheFolderId != null)
                            {
                                RemoveFromCahce(cacheFolderId);
                            }
                        }
                        else
                        {
                            RemoveMarkAsNew(parent);
                        }
                    }

                    entries.ToList().ForEach(
                        entry =>
                        {
                            var curTag = totalTags.FirstOrDefault(tag => tag.EntryType == entry.FileEntryType && tag.EntryId.Equals(entry.ID));

                            if (entry.FileEntryType == FileEntryType.Folder)
                            {
                                ((Folder)entry).NewForMe = curTag != null ? curTag.Count : 0;
                            }
                            else if (curTag != null)
                            {
                                entry.IsNew = true;
                            }
                        });
                }
            }

            return entries;
        }

        private static void InsertToCahce(object folderId, int count)
        {
            var key = string.Format(CacheKeyFormat, SecurityContext.CurrentAccount.ID, folderId);
            cache.Insert(key, count.ToString(), TimeSpan.FromMinutes(10));
        }

        private static int GetCountFromCahce(object folderId)
        {
            var key = string.Format(CacheKeyFormat, SecurityContext.CurrentAccount.ID, folderId);
            var count = cache.Get<string>(key);
            return count == null ? -1 : int.Parse(count);
        }

        private static void RemoveFromCahce(object folderId)
        {
            RemoveFromCahce(folderId, SecurityContext.CurrentAccount.ID);
        }

        private static void RemoveFromCahce(object folderId, Guid userId)
        {
            var key = string.Format(CacheKeyFormat, userId, folderId);
            cache.Remove(key);
        }


        private class AsyncTaskData
        {
            public AsyncTaskData()
            {
                TenantID = TenantProvider.CurrentTenantID;
                CurrentAccountId = SecurityContext.CurrentAccount.ID;
            }

            public int TenantID { get; private set; }

            public FileEntry FileEntry { get; set; }

            public List<Guid> UserIDs { get; set; }

            public Guid CurrentAccountId { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/confirm.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Security.Cryptography;
using ASC.Web.Core;
using ASC.Web.Core.Utility.Settings;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Core.SMS;
using ASC.Web.Studio.Core.TFA;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Management;
using ASC.Web.Studio.Utility;

using Constants = ASC.Core.Users.Constants;

namespace ASC.Web.Studio
{
    public partial class Confirm : MainPage
    {
        protected override bool MayNotAuth
        {
            get { return _type != ConfirmType.EmailChange; }
        }

        protected override bool MayNotPaid
        {
            get { return true; }
        }

        protected override bool MayPhoneNotActivate
        {
            get { return true; }
        }

        public string ErrorMessage { get; set; }

        private string _email;
        private ConfirmType _type;

        protected override void OnPreInit(EventArgs e)
        {
            _type = typeof(ConfirmType).TryParseEnum(Request["type"] ?? "", ConfirmType.EmpInvite);

            base.OnPreInit(e);

            if (!SecurityContext.IsAuthenticated && CoreContext.Configuration.Personal)
            {
                SetLanguage();
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.Title = HeaderStringHelper.GetPageTitle(Resource.AccountControlPageTitle);

            Master.DisabledSidePanel = true;
            Master.TopStudioPanel.DisableProductNavigation = true;
            Master.TopStudioPanel.DisableUserInfo = true;
            Master.TopStudioPanel.DisableSearch = true;
            Master.TopStudioPanel.DisableSettings = true;
            Master.TopStudioPanel.DisableTariff = true;
            Master.TopStudioPanel.DisableLoginPersonal = true;
            Master.TopStudioPanel.DisableGift = true;

            _email = (Request["email"] ?? "").Trim();

            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            if (tenant.Status != TenantStatus.Active && _type != ConfirmType.PortalContinue)
            {
                Response.Redirect(CommonLinkUtility.GetDefault(), true);
                return;
            }

            if (_type == ConfirmType.PhoneActivation && SecurityContext.IsAuthenticated)
            {
                Master.TopStudioPanel.DisableUserInfo = false;
            }
            else
            {
                Master.DisabledTopStudioPanel = true;
            }

            if (!CheckValidationKey())
            {
                return;
            }

            LoadControls();
        }

        private bool CheckValidationKey()
        {
            var key = Request["key"] ?? "";
            var emplType = Request["emplType"] ?? "";
            var social = Request["social"] ?? "";

            var validInterval = SetupInfo.ValidEmailKeyInterval;
            var authInterval = SetupInfo.ValidAuthKeyInterval;

            EmailValidationKeyProvider.ValidationResult checkKeyResult;
            switch (_type)
            {
                case ConfirmType.PortalContinue:
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type, key);
                    break;

                case ConfirmType.PhoneActivation:
                case ConfirmType.PhoneAuth:
                case ConfirmType.TfaActivation:
                case ConfirmType.TfaAuth:
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type, key, authInterval);
                    break;

                case ConfirmType.Auth:
                {
                    var first = Request["first"] ?? "";
                    var module = Request["module"] ?? "";
                    var smsConfirm = Request["sms"] ?? "";

                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type + first + module + smsConfirm, key, authInterval);

                    if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Ok)
                    {
                        var user = _email.Contains("@")
                                       ? CoreContext.UserManager.GetUserByEmail(_email)
                                       : CoreContext.UserManager.GetUsers(new Guid(_email));

                        if (SecurityContext.IsAuthenticated && SecurityContext.CurrentAccount.ID != user.ID)
                        {
                            Auth.ProcessLogout();
                        }

                        if (!SecurityContext.IsAuthenticated)
                        {
                            if (!CoreContext.UserManager.UserExists(user.ID) || user.Status != EmployeeStatus.Active)
                            {
                                ShowError(Auth.MessageKey.ErrorUserNotFound);
                                return false;
                            }

                            if (StudioSmsNotificationSettings.IsVisibleSettings && StudioSmsNotificationSettings.Enable && smsConfirm.ToLower() != "true")
                            {
                                //todo: think about 'first' & 'module'
                                Response.Redirect(SmsConfirmUrl(user), true);
                            }

                            if (TfaAppAuthSettings.IsVisibleSettings && TfaAppAuthSettings.Enable)
                            {
                                //todo: think about 'first' & 'module'
                                Response.Redirect(TfaConfirmUrl(user), true);
                            }

                            var authCookie = SecurityContext.AuthenticateMe(user.ID);
                            CookiesManager.SetCookies(CookiesType.AuthKey, authCookie);

                            var messageAction = social == "true" ? MessageAction.LoginSuccessViaSocialAccount : MessageAction.LoginSuccess;
                            MessageService.Send(HttpContext.Current.Request, messageAction);
                        }

                        SetDefaultModule(module);

                        AuthRedirect(first.ToLower() == "true");
                    }
                }
                break;

                case ConfirmType.DnsChange:
                {
                    var dnsChangeKey = string.Join(string.Empty, new[] { _email, _type.ToString(), Request["dns"], Request["alias"] });
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(dnsChangeKey, key, validInterval);
                }
                break;

                case ConfirmType.PortalOwnerChange:
                {
                    Guid uid;
                    try
                    {
                        uid = new Guid(Request["uid"]);
                    }
                    catch
                    {
                        uid = Guid.Empty;
                    }
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type + uid, key, validInterval);
                }
                break;

                case ConfirmType.EmpInvite:
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type + emplType, key, validInterval);
                    break;

                case ConfirmType.LinkInvite:
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_type + emplType, key, validInterval);
                    break;

                case ConfirmType.EmailChange:
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type + SecurityContext.CurrentAccount.ID, key, validInterval);
                    break;

                case ConfirmType.PasswordChange:
                    var hash = CoreContext.Authentication.GetUserPasswordStamp(CoreContext.UserManager.GetUserByEmail(_email).ID).ToString("s");

                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type + hash, key, validInterval);
                    break;

                default:
                    checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(_email + _type, key, validInterval);
                    break;
            }

            if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Expired)
            {
                ShowError(Auth.MessageKey.ErrorExpiredActivationLink);
                return false;
            }

            if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Invalid)
            {
                ShowError(_type == ConfirmType.LinkInvite
                              ? Auth.MessageKey.ErrorInvalidActivationLink
                              : Auth.MessageKey.ErrorConfirmURLError);
                return false;
            }

            if (!string.IsNullOrEmpty(_email) && !_email.TestEmailRegex())
            {
                ShowError(Auth.MessageKey.ErrorNotCorrectEmail);
                return false;
            }

            return true;
        }

        private void LoadControls()
        {
            switch (_type)
            {
                case ConfirmType.EmpInvite:
                case ConfirmType.LinkInvite:
                case ConfirmType.Activation:
                    _confirmHolder2.Controls.Add(LoadControl(ConfirmInviteActivation.Location));
                    _contentWithControl.Visible = false;
                    break;

                case ConfirmType.EmailChange:
                case ConfirmType.PasswordChange:
                    _confirmHolder.Controls.Add(LoadControl(ConfirmActivation.Location));
                    break;

                case ConfirmType.EmailActivation:
                    ProcessEmailActivation(_email);
                    break;

                case ConfirmType.PortalRemove:
                case ConfirmType.PortalSuspend:
                case ConfirmType.PortalContinue:
                case ConfirmType.DnsChange:
                    _confirmHolder.Controls.Add(LoadControl(ConfirmPortalActivity.Location));
                    break;

                case ConfirmType.PortalOwnerChange:
                    _confirmHolder.Controls.Add(LoadControl(ConfirmPortalOwner.Location));
                    break;

                case ConfirmType.ProfileRemove:
                    var user = CoreContext.UserManager.GetUserByEmail(_email);
                    if (user.ID.Equals(Constants.LostUser.ID))
                    {
                        ShowError(Auth.MessageKey.ErrorUserNotFound);
                        return;
                    }

                    var control = (ProfileOperation)LoadControl(ProfileOperation.Location);
                    control.UserId = user.ID;
                    _confirmHolder.Controls.Add(control);
                    break;

                case ConfirmType.PhoneActivation:
                case ConfirmType.PhoneAuth:
                    var confirmMobileActivation = (ConfirmMobileActivation)LoadControl(ConfirmMobileActivation.Location);
                    confirmMobileActivation.Activation = _type == ConfirmType.PhoneActivation;
                    confirmMobileActivation.User = CoreContext.UserManager.GetUserByEmail(_email);
                    _confirmHolder.Controls.Add(confirmMobileActivation);
                    break;
                case ConfirmType.TfaActivation:
                case ConfirmType.TfaAuth:
                    var confirmTfaActivation = (TfaActivation)LoadControl(TfaActivation.Location);
                    confirmTfaActivation.Activation = _type == ConfirmType.TfaActivation;
                    confirmTfaActivation.User = CoreContext.UserManager.GetUserByEmail(_email);
                    _confirmHolder.Controls.Add(confirmTfaActivation);
                    break;
            }
        }

        private void ProcessEmailActivation(string email)
        {
            var user = CoreContext.UserManager.GetUserByEmail(email);

            if (user.ID.Equals(Constants.LostUser.ID))
            {
                ShowError(Auth.MessageKey.ErrorConfirmURLError);
            }
            else if (user.ActivationStatus.HasFlag(EmployeeActivationStatus.Activated))
            {
                Response.Redirect(CommonLinkUtility.GetDefault());
            }
            else
            {
                try
                {
                    SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);

                    if (user.ActivationStatus.HasFlag(EmployeeActivationStatus.AutoGenerated))
                    {
                        user.ActivationStatus |= EmployeeActivationStatus.Activated;
                    }
                    else
                    {
                        user.ActivationStatus = EmployeeActivationStatus.Activated;
                    }

                    user = CoreContext.UserManager.SaveUserInfo(user);

                    var first = Request["first"] ?? "";
                    if (first.ToLower() == "true" && !CoreContext.Configuration.Personal && user.IsAdmin())
                    {
                        StudioNotifyService.Instance.SendAdminWelcome(user);
                    }

                    MessageService.Send(HttpContext.Current.Request, MessageInitiator.System, MessageAction.UserActivated, user.DisplayUserName(false));
                }
                finally
                {
                    Auth.ProcessLogout();
                }

                string redirectUrl;

                if (user.IsLDAP())
                {
                    redirectUrl = String.Format("~/Auth.aspx?ldap-login={0}", user.UserName);
                }
                else
                {
                    redirectUrl = String.Format("~/Auth.aspx?confirmed-email={0}", email);
                }

                Response.Redirect(redirectUrl, true);
            }
        }

        private void ShowError(Auth.MessageKey messageKey = Auth.MessageKey.None)
        {
            if (SecurityContext.IsAuthenticated)
            {
                ErrorMessage = Auth.GetAuthMessage(messageKey);
                _confirmHolder.Visible = false;
            }
            else
            {
                Response.Redirect(string.Format("~/Auth.aspx?am={0}", (int)messageKey));
            }
        }

        private void AuthRedirect(bool first)
        {
            var wizardSettings = WizardSettings.Load();
            if (first && wizardSettings.Completed)
            {
                wizardSettings.Completed = false;
                wizardSettings.Save();
            }

            string url;
            if (wizardSettings.Completed)
            {
                url = CommonLinkUtility.GetDefault();
            }
            else
            {
                url = SecurityContext.IsAuthenticated ? "~/Wizard.aspx" : "~/Auth.aspx";
            }

            if (Request.DesktopApp())
            {
                if (wizardSettings.Completed)
                {
                    url = WebItemManager.Instance[WebItemManager.DocumentsProductID].StartURL;
                }
                url += "?desktop=true&first=true";
            }

            Response.Redirect(url, true);
        }

        public static string SmsConfirmUrl(UserInfo user)
        {
            if (user == null)
                return string.Empty;

            var confirmType =
                string.IsNullOrEmpty(user.MobilePhone) ||
                user.MobilePhoneActivationStatus == MobilePhoneActivationStatus.NotActivated
                    ? ConfirmType.PhoneActivation
                    : ConfirmType.PhoneAuth;

            return CommonLinkUtility.GetConfirmationUrl(user.Email, confirmType);
        }

        public static string TfaConfirmUrl(UserInfo user)
        {
            if (user == null)
                return string.Empty;
            var confirmType = TfaAppUserSettings.EnableForUser(user.ID)
                ? ConfirmType.TfaAuth
                : ConfirmType.TfaActivation;
            return CommonLinkUtility.GetConfirmationUrl(user.Email, confirmType);
        }

        private static void SetDefaultModule(string module)
        {
            if (string.IsNullOrEmpty(module)) return;
            try
            {
                LogManager.GetLogger("ASC.Web").Debug("SetDefaultModule " + module);
                new StudioDefaultPageSettings { DefaultProductID = new Guid(module) }.Save();
                MessageService.Send(HttpContext.Current.Request, MessageAction.DefaultStartPageSettingsUpdated);
            }
            catch (Exception ex)
            {
                LogManager.GetLogger("ASC.Web").Error("SetDefaultModule", ex);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/ConfirmActivation/ConfirmActivation.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Threading;
using System.Web;
using System.Web.UI;

using ASC.Core;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Studio.Core.SMS;
using ASC.Web.Studio.Core.TFA;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

using Constants = ASC.Core.Users.Constants;

namespace ASC.Web.Studio.UserControls.Management
{
    public partial class ConfirmActivation : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/ConfirmActivation/ConfirmActivation.ascx"; }
        }

        private UserInfo User { get; set; }
        protected ConfirmType Type { get; set; }

        protected bool isPersonal
        {
            get { return CoreContext.Configuration.Personal; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterBodyScripts(
                    "~/js/third-party/xregexp.js",
                    "~/UserControls/Management/ConfirmActivation/js/confirmactivation.js")
                .RegisterStyle("~/UserControls/Management/ConfirmActivation/css/confirmactivation.less");
            Page.Title = HeaderStringHelper.GetPageTitle(Resource.Authorization);

            var email = (Request["email"] ?? "").Trim();
            if (string.IsNullOrEmpty(email))
            {
                ShowError(Resource.ErrorNotCorrectEmail);
                return;
            }

            Type = typeof(ConfirmType).TryParseEnum(Request["type"] ?? "", ConfirmType.EmpInvite);

            try
            {
                if (Type == ConfirmType.EmailChange)
                {
                    User = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
                    User.Email = email;
                    CoreContext.UserManager.SaveUserInfo(User);
                    MessageService.Send(Request, MessageAction.UserUpdatedEmail);

                    ActivateMail(User);
                    const string successParam = "email_change=success";
                    if (User.IsVisitor())
                    {
                        Response.Redirect(CommonLinkUtility.ToAbsolute("~/My.aspx?" + successParam), true);
                    }
                    Response.Redirect(string.Format("{0}&{1}", User.GetUserProfilePageURL(), successParam), true);
                    return;
                }

                User = CoreContext.UserManager.GetUserByEmail(email);
                if (User.ID.Equals(Constants.LostUser.ID))
                {
                    ShowError(string.Format(Resource.ErrorUserNotFoundByEmail, email));
                    return;
                }

                if (!User.ID.Equals(SecurityContext.CurrentAccount.ID))
                {
                    Auth.ProcessLogout();
                }

                UserAuth(User);
                ActivateMail(User);

                passwordSetter.Visible = true;
                ButtonEmailAndPasswordOK.Text = Resource.EmailAndPasswordOK;
            }
            catch (ThreadAbortException)
            {
            }
            catch (Exception ex)
            {
                ShowError(ex.Message);
            }

            if (IsPostBack)
            {
                LoginToPortal();
            }
        }

        private void UserAuth(UserInfo user)
        {
            if (SecurityContext.IsAuthenticated) return;

            if (StudioSmsNotificationSettings.IsVisibleSettings && StudioSmsNotificationSettings.Enable)
            {
                Session["refererURL"] = Request.GetUrlRewriter().AbsoluteUri;
                Response.Redirect(Confirm.SmsConfirmUrl(user), true);
                return;
            }
            if (TfaAppAuthSettings.IsVisibleSettings && TfaAppAuthSettings.Enable)
            {
                Session["refererURL"] = Request.GetUrlRewriter().AbsoluteUri;
                Response.Redirect(Confirm.TfaConfirmUrl(user), true);
                return;
            }

            var cookiesKey = SecurityContext.AuthenticateMe(user.ID);
            CookiesManager.SetCookies(CookiesType.AuthKey, cookiesKey);
            MessageService.Send(Request, MessageAction.LoginSuccess);
        }

        private void ActivateMail(UserInfo user)
        {
            if (user.ActivationStatus.HasFlag(EmployeeActivationStatus.Activated)) return;

            user.ActivationStatus = EmployeeActivationStatus.Activated;
            CoreContext.UserManager.SaveUserInfo(user);

            MessageService.Send(Request,
                                user.IsVisitor() ? MessageAction.GuestActivated : MessageAction.UserActivated,
                                MessageTarget.Create(user.ID),
                                user.DisplayUserName(false));
        }

        private void ShowError(string message, bool redirect = true)
        {
            var confirm = Page as Confirm;
            if (confirm != null)
                confirm.ErrorMessage = HttpUtility.HtmlEncode(message);

            Auth.ProcessLogout();

            if (redirect)
                RegisterRedirect();
        }

        private void RegisterRedirect()
        {
            Page.ClientScript.RegisterStartupScript(GetType(), "redirect",
                                                    string.Format("setTimeout('location.href = \"{0}\";',10000);", CommonLinkUtility.GetDefault()),
                                                    true);
        }

        protected void LoginToPortal()
        {
            try
            {
                var passwordHash = Request["passwordHash"];
                if (string.IsNullOrEmpty(passwordHash)) throw new Exception(Resource.ErrorPasswordEmpty);

                SecurityContext.SetUserPasswordHash(User.ID, passwordHash);
                MessageService.Send(Request, MessageAction.UserUpdatedPassword);

                CookiesManager.ResetUserCookie();
                MessageService.Send(Request, MessageAction.CookieSettingsUpdated);
            }
            catch (SecurityContext.PasswordException)
            {
                ShowError(Resource.ErrorPasswordRechange, false);
                return;
            }
            catch (Exception ex)
            {
                ShowError(ex.Message, false);
                return;
            }

            Response.Redirect(CommonLinkUtility.GetDefault());
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Enums/ContactInfoCategoryEnum.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.ComponentModel;

using ASC.Web.CRM.Classes;


namespace ASC.CRM.Core
{
    [TypeConverter(typeof(LocalizedEnumConverter))]
    public enum ContactInfoBaseCategory
    {
        Home,
        Work,
        Other
    }

    [TypeConverter(typeof(LocalizedEnumConverter))]
    public enum PhoneCategory
    {
        Home,
        Work,
        Mobile,
        Fax,
        Direct,
        Other
    }

    [TypeConverter(typeof(LocalizedEnumConverter))]
    public enum AddressPart
    {
        Street,
        City,
        State,
        Zip,
        Country
    }

    [TypeConverter(typeof(LocalizedEnumConverter))]
    public enum AddressCategory
    {
        Home,
        Postal,
        Office,
        Billing,
        Other,
        Work
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Classes/ReportInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Web.Projects.Classes
{
    [Serializable]
    public class ReportInfo
    {
        public static ReportInfo Empty = new ReportInfo(string.Empty, string.Empty, new string[0]);

        public string Description { get; set; }

        public string Title { get; set; }

        public string[] Columns { get; set; }

        public ReportInfo(string desc, string title, string[] columns)
        {
            Description = desc;
            Title = title;
            Columns = columns ?? new string[0];
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Code/CategoryDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Data.Sql.Expressions;

namespace ASC.Web.UserControls.Wiki.Data
{
    class CategoryDao : BaseDao
    {
        public CategoryDao(string dbid, int tenant)
            : base(dbid, tenant)
        {
        }


        public List<Category> GetCategories()
        {
            var q = Query("wiki_categories").Select("CategoryName").GroupBy(1);

            return db.ExecuteList(q)
                .ConvertAll(r => ToCategory(r));
        }

        public List<Category> GetCategories(string pagename, bool onlyWithThisPage)
        {
            var q = Query("wiki_categories c2").Select("c2.CategoryName").Where("c2.PageName", pagename);
            if (onlyWithThisPage)
            {
                q = Query("wiki_categories c1").Select("c1.CategoryName")
                    .InnerJoin(q, "t", Exp.EqColumns("c1.CategoryName", "t.CategoryName"))
                    .GroupBy(1)
                    .Having(Exp.Eq("count(*)", 1));
            }

            return db.ExecuteList(q)
                .ConvertAll(r => ToCategory(r));
        }

        public Category SaveCategory(Category category)
        {
            if (category == null) throw new ArgumentNullException("category");
            if (string.IsNullOrEmpty(category.CategoryName) || string.IsNullOrEmpty(category.PageName)) return category;

            var i = Insert("wiki_categories")
                .InColumnValue("CategoryName", category.CategoryName)
                .InColumnValue("PageName", category.PageName);
            db.ExecuteNonQuery(i);
            return category;
        }

        public void RemoveCategories(string pagename)
        {
            var d = Delete("wiki_categories").Where("PageName", pagename);
            db.ExecuteNonQuery(d);
        }


        private Category ToCategory(object[] r)
        {
            return new Category
            {
                CategoryName = (string)r[0],
                PageName = 1 < r.Length ? (string)r[1] : string.Empty,
            };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/MIME/MIME_b_Provider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.MIME
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using IO;

    #endregion

    /// <summary>
    /// This class represent MIME entity body provider.
    /// </summary>
    public class MIME_b_Provider
    {
        #region Members

        private readonly Dictionary<string, Type> m_pBodyTypes;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public MIME_b_Provider()
        {
            m_pBodyTypes = new Dictionary<string, Type>(StringComparer.CurrentCultureIgnoreCase);
            m_pBodyTypes.Add("message/rfc822", typeof (MIME_b_MessageRfc822));
            m_pBodyTypes.Add("multipart/alternative", typeof (MIME_b_MultipartAlternative));
            m_pBodyTypes.Add("multipart/digest", typeof (MIME_b_MultipartDigest));
            m_pBodyTypes.Add("multipart/encrypted", typeof (MIME_b_MultipartEncrypted));
            m_pBodyTypes.Add("multipart/form-data", typeof (MIME_b_MultipartFormData));
            m_pBodyTypes.Add("multipart/mixed", typeof (MIME_b_MultipartMixed));
            m_pBodyTypes.Add("multipart/parallel", typeof (MIME_b_MultipartParallel));
            m_pBodyTypes.Add("multipart/related", typeof (MIME_b_MultipartRelated));
            m_pBodyTypes.Add("multipart/report", typeof (MIME_b_MultipartReport));
            m_pBodyTypes.Add("multipart/signed", typeof (MIME_b_MultipartSigned));
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses MIME entity body from specified stream.
        /// </summary>
        /// <param name="owner">Owner MIME entity.</param>
        /// <param name="stream">Stream from where to parse entity body.</param>
        /// <param name="defaultContentType">Default content type.</param>
        /// <returns>Returns parsed body.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>owner</b>, <b>strean</b> or <b>defaultContentType</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public MIME_b Parse(MIME_Entity owner, SmartStream stream, MIME_h_ContentType defaultContentType)
        {
            if (owner == null)
            {
                throw new ArgumentNullException("owner");
            }
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (defaultContentType == null)
            {
                throw new ArgumentNullException("defaultContentType");
            }

            string mediaType = defaultContentType.TypeWithSubype;
            string mediaTypeWithParams = defaultContentType.ToString().Split(':')[1].TrimStart(' ');
            if (owner.ContentType != null)
            {
                mediaType = owner.ContentType.TypeWithSubype;
                mediaTypeWithParams = owner.ContentType.ToString().Split(':')[1].TrimStart(' ');
            }

            Type bodyType = null;

            // We have exact body provider for specified mediaType.
            if (m_pBodyTypes.ContainsKey(mediaType))
            {
                bodyType = m_pBodyTypes[mediaType];
            }
                // Use default mediaType.
            else
            {
                // Registered list of mediaTypes are available: http://www.iana.org/assignments/media-types/.

                string mediaRootType = mediaType.Split('/')[0].ToLowerInvariant();
                if (mediaRootType == "application")
                {
                    bodyType = typeof (MIME_b_Application);
                }
                else if (mediaRootType == "audio")
                {
                    bodyType = typeof (MIME_b_Audio);
                }
                else if (mediaRootType == "image")
                {
                    bodyType = typeof (MIME_b_Image);
                }
                else if (mediaRootType == "message")
                {
                    bodyType = typeof (MIME_b_Message);
                }
                else if (mediaRootType == "multipart")
                {
                    bodyType = typeof (MIME_b_Multipart);
                }
                else if (mediaRootType == "text")
                {
                    bodyType = typeof (MIME_b_Text);
                }
                else if (mediaRootType == "video")
                {
                    bodyType = typeof (MIME_b_Video);
                }
                else
                {
                    throw new ParseException("Invalid media-type '" + mediaType + "'.");
                }
            }

            return
                (MIME_b)
                bodyType.GetMethod("Parse",
                                   BindingFlags.Static | BindingFlags.NonPublic |
                                   BindingFlags.FlattenHierarchy).Invoke(null,
                                                                         new object[] { owner, mediaTypeWithParams, stream });
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Auth.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls;
using ASC.Web.Studio.UserControls.Common;
using ASC.Web.Studio.UserControls.Common.AuthorizeDocs;
using ASC.Web.Studio.UserControls.Management.SingleSignOnSettings;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio
{
    public partial class Auth : MainPage
    {
        protected string LogoPath
        {
            get { return String.Format("/TenantLogo.ashx?logotype={0}&general={1}", (int)WhiteLabelLogoTypeEnum.Dark, (!TenantLogoManager.IsRetina(Request)).ToString().ToLower()); }
        }

        protected bool withHelpBlock { get; set; }

        protected override bool MayNotAuth { get { return true; } }

        protected override bool MayNotPaid { get { return true; } }

        protected override bool MayPhoneNotActivate { get { return true; } }

        protected string TenantName;

        protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);

            if (!SecurityContext.IsAuthenticated)
            {
                if (CoreContext.Configuration.Personal)
                {
                    CheckSocialMedia();

                    SetLanguage();
                }

                var token = Request["asc_auth_key"];
                if (SecurityContext.AuthenticateMe(token))
                {
                    CookiesManager.SetCookies(CookiesType.AuthKey, token);

                    var refererURL = Request["refererURL"];
                    if (string.IsNullOrEmpty(refererURL)) refererURL = "~/Auth.aspx";

                    Response.Redirect(refererURL, true);
                }

                return;
            }

            if (IsLogout)
            {
                var user = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);

                var loginName = user.DisplayUserName(false);
                ProcessLogout();
                MessageService.Send(HttpContext.Current.Request, loginName, MessageAction.Logout);

                if (!string.IsNullOrEmpty(user.SsoNameId))
                {
                    var settings = SsoSettingsV2.Load();

                    if (settings.EnableSso && !string.IsNullOrEmpty(settings.IdpSettings.SloUrl))
                    {
                        var logoutSsoUserData = Signature.Create(new LogoutSsoUserData
                        {
                            NameId = user.SsoNameId,
                            SessionId = user.SsoSessionId
                        });

                        HttpContext.Current.Response.Redirect(SetupInfo.SsoSamlLogoutUrl + "?data=" + HttpUtility.UrlEncode(logoutSsoUserData), true);
                    }
                }

                Response.Redirect("~/Auth.aspx", true);
            }
            else
            {
                Response.Redirect(CommonLinkUtility.GetDefault(), true);
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            TenantName = CoreContext.TenantManager.GetCurrentTenant().Name;
            Page.Title = TenantName;

            Master.DisabledSidePanel = true;
            if (Request.DesktopApp())
            {
                Master.DisabledTopStudioPanel = true;
            }

            withHelpBlock = false;
            if (CoreContext.Configuration.Personal)
            {
                Master.DisabledLayoutMedia = true;
                Master.TopStudioPanel.TopLogo = WebImageSupplier.GetAbsoluteWebPath("personal_logo/logo_personal_auth.svg");
                AutorizeDocuments.Controls.Add(CoreContext.Configuration.CustomMode
                                                   ? LoadControl(AuthorizeDocs.LocationCustomMode)
                                                   : LoadControl(AuthorizeDocs.Location));
            }
            else
            {
                var authControl = (Authorize)LoadControl(Authorize.Location);
                authControl.IsLogout = IsLogout;
                AuthorizeHolder.Controls.Add(authControl);

                CommunitationsHolder.Controls.Add(LoadControl(AuthCommunications.Location));
                withHelpBlock = true;
            }
        }

        public static void ProcessLogout()
        {
            //logout
            CookiesManager.ClearCookies(CookiesType.AuthKey);
            CookiesManager.ClearCookies(CookiesType.SocketIO);
            SecurityContext.Logout();
        }

        private bool IsLogout
        {
            get
            {
                var logoutParam = Request["t"];
                if (String.IsNullOrEmpty(logoutParam))
                    return false;

                return logoutParam.ToLower() == "logout";
            }
        }

        private void CheckSocialMedia()
        {
            var social = Request["from"];
            if (string.IsNullOrEmpty(social)) return;

            social = social.ToLower();
            if (string.Equals(social, "openid", StringComparison.InvariantCultureIgnoreCase))
            {
                social = "google";
            }

            var loginUrl = string.Empty;

            if (string.Equals(social, "facebook", StringComparison.InvariantCultureIgnoreCase)
                || string.Equals(social, "google", StringComparison.InvariantCultureIgnoreCase))
            {
                var returnUrl = new Uri(Request.GetUrlRewriter(), "Auth.aspx");
                loginUrl = "~/login.ashx?auth=" + social
                           + "&mode=Redirect&returnurl=" + HttpUtility.UrlEncode(returnUrl.ToString());
            }

            if (!string.IsNullOrEmpty(loginUrl))
            {
                Response.Redirect(loginUrl, true);
            }
        }


        public static string GetAuthMessage(string messageKey)
        {
            MessageKey authMessage;
            if (!Enum.TryParse(messageKey, out authMessage)) return null;
            return GetAuthMessage(authMessage);
        }

        public static string GetAuthMessage(MessageKey messageKey)
        {
            switch (messageKey)
            {
                case MessageKey.Error:
                    return Resource.ErrorBadRequest;
                case MessageKey.ErrorUserNotFound:
                    return Resource.ErrorUserNotFound;
                case MessageKey.ErrorExpiredActivationLink:
                    return Resource.ErrorExpiredActivationLink;
                case MessageKey.ErrorInvalidActivationLink:
                    return Resource.ErrorInvalidActivationLink;
                case MessageKey.ErrorConfirmURLError:
                    return Resource.ErrorConfirmURLError;
                case MessageKey.ErrorNotCorrectEmail:
                    return Resource.ErrorNotCorrectEmail;
                case MessageKey.LoginWithBruteForce:
                    return Resource.LoginWithBruteForce;
                case MessageKey.RecaptchaInvalid:
                    return Resource.RecaptchaInvalid;
                case MessageKey.LoginWithAccountNotFound:
                    return Resource.LoginWithAccountNotFound;
                case MessageKey.InvalidUsernameOrPassword:
                    return Resource.InvalidUsernameOrPassword;
                case MessageKey.SsoSettingsDisabled:
                    return Resource.SsoSettingsDisabled;
                case MessageKey.ErrorNotAllowedOption:
                    return Resource.ErrorNotAllowedOption;
                case MessageKey.SsoSettingsEmptyToken:
                    return Resource.SsoSettingsEmptyToken;
                case MessageKey.SsoSettingsNotValidToken:
                    return Resource.SsoSettingsNotValidToken;
                case MessageKey.SsoSettingsCantCreateUser:
                    return Resource.SsoSettingsCantCreateUser;
                case MessageKey.SsoSettingsUserTerminated:
                    return Resource.SsoSettingsUserTerminated;
                case MessageKey.SsoError:
                    return Resource.SsoError;
                case MessageKey.SsoAuthFailed:
                    return Resource.SsoAuthFailed;
                case MessageKey.SsoAttributesNotFound:
                    return Resource.SsoAttributesNotFound;
                default: return null;
            }
        }

        public enum MessageKey
        {
            None,
            Error,
            ErrorUserNotFound,
            ErrorExpiredActivationLink,
            ErrorInvalidActivationLink,
            ErrorConfirmURLError,
            ErrorNotCorrectEmail,
            LoginWithBruteForce,
            RecaptchaInvalid,
            LoginWithAccountNotFound,
            InvalidUsernameOrPassword,
            SsoSettingsDisabled,
            ErrorNotAllowedOption,
            SsoSettingsEmptyToken,
            SsoSettingsNotValidToken,
            SsoSettingsCantCreateUser,
            SsoSettingsUserTerminated,
            SsoError,
            SsoAuthFailed,
            SsoAttributesNotFound,
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/ServerDomainDnsData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

namespace ASC.Mail.Data.Contracts
{
    [Serializable]
    [DataContract(Namespace = "", Name = "DNSInfo")]
    public class ServerDomainDnsData
    {
        [DataMember(IsRequired = true)]
        public int Id { get; set; }

        [DataMember(IsRequired = true)]
        public ServerDomainMxRecordData MxRecord { get; set; }

        [DataMember(IsRequired = true)]
        public ServerDomainDnsRecordData SpfRecord { get; set; }

        [DataMember(IsRequired = true)]
        public ServerDomainDkimRecordData DkimRecord { get; set; }

        [DataMember(IsRequired = true)]
        public ServerDomainDnsRecordData DomainCheckRecord { get; set; }

        [DataMember(IsRequired = true)]
        public bool IsVerified
        {
            get
            {
                return MxRecord.IsVerified &&
                       SpfRecord.IsVerified &&
                       DkimRecord.IsVerified;
            }
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Settings/SsoSettingsV2Api.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Web;

using ASC.Api.Attributes;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Management.SingleSignOnSettings;
using ASC.Web.Studio.Utility;

using Newtonsoft.Json;

namespace ASC.Api.Settings
{
    public partial class SettingsApi
    {
        /// <summary>
        /// Returns current portal SSO settings
        /// </summary>
        /// <short>
        /// Get SSO settings
        /// </short>
        /// <returns>SsoSettingsV2 object</returns>
        [Read("ssov2")]
        public SsoSettingsV2 GetSsoSettingsV2()
        {
            CheckSsoPermissions();

            var settings = SsoSettingsV2.Load();

            if (string.IsNullOrEmpty(settings.SpLoginLabel))
                settings.SpLoginLabel = SsoSettingsV2.SSO_SP_LOGIN_LABEL;

            return settings;
        }

        /// <summary>
        /// Returns default portal SSO settings
        /// </summary>
        /// <short>
        /// Get default SSO settings
        /// </short>
        /// <returns>SsoSettingsV2 object</returns>
        [Read("ssov2/default")]
        public SsoSettingsV2 GetDefaultSsoSettingsV2()
        {
            CheckSsoPermissions();

            return new SsoSettingsV2().GetDefault() as SsoSettingsV2;
        }

        /// <summary>
        /// Returns SSO settings constants
        /// </summary>
        /// <short>
        /// Get SSO settings constants
        /// </short>
        /// <returns>object</returns>
        [Read("ssov2/constants")]
        public object GetSsoSettingsV2Constants()
        {
            return new
            {
                SsoNameIdFormatType = new SsoNameIdFormatType(),
                SsoBindingType = new SsoBindingType(),
                SsoSigningAlgorithmType = new SsoSigningAlgorithmType(),
                SsoEncryptAlgorithmType = new SsoEncryptAlgorithmType(),
                SsoSpCertificateActionType = new SsoSpCertificateActionType(),
                SsoIdpCertificateActionType = new SsoIdpCertificateActionType()
            };
        }

        /// <summary>
        /// Save SSO settings for current portal
        /// </summary>
        /// <short>
        /// Save SSO settings
        /// </short>
        /// <param name="serializeSettings">serialized SsoSettingsV2 object</param>
        /// <returns>SsoSettingsV2 object</returns>
        [Create("ssov2")]
        public SsoSettingsV2 SaveSsoSettingsV2(string serializeSettings)
        {
            CheckSsoPermissions();

            if (string.IsNullOrEmpty(serializeSettings))
                throw new ArgumentException(Resource.SsoSettingsCouldNotBeNull);

            var settings = JsonConvert.DeserializeObject<SsoSettingsV2>(serializeSettings);

            if (settings == null)
                throw new ArgumentException(Resource.SsoSettingsCouldNotBeNull);

            if (string.IsNullOrWhiteSpace(settings.IdpSettings.EntityId))
                throw new Exception(Resource.SsoSettingsInvalidEntityId);

            if (string.IsNullOrWhiteSpace(settings.IdpSettings.SsoUrl) ||
                !CheckUri(settings.IdpSettings.SsoUrl))
                throw new Exception(string.Format(Resource.SsoSettingsInvalidBinding, "SSO " + settings.IdpSettings.SsoBinding));

            if (!string.IsNullOrWhiteSpace(settings.IdpSettings.SloUrl) &&
                !CheckUri(settings.IdpSettings.SloUrl))
                throw new Exception(string.Format(Resource.SsoSettingsInvalidBinding, "SLO " + settings.IdpSettings.SloBinding));

            if (string.IsNullOrWhiteSpace(settings.FieldMapping.FirstName) ||
                string.IsNullOrWhiteSpace(settings.FieldMapping.LastName) ||
                string.IsNullOrWhiteSpace(settings.FieldMapping.Email))
                throw new Exception(Resource.SsoSettingsInvalidMapping);

            if (string.IsNullOrEmpty(settings.SpLoginLabel))
            {
                settings.SpLoginLabel = SsoSettingsV2.SSO_SP_LOGIN_LABEL;
            }
            else if (settings.SpLoginLabel.Length > 100)
            {
                settings.SpLoginLabel = settings.SpLoginLabel.Substring(0, 100);
            }

            if (!settings.Save())
                throw new Exception(Resource.SsoSettingsCantSaveSettings);

            if (!settings.EnableSso)
                ConverSsoUsersToOrdinary();

            var messageAction = settings.EnableSso ? MessageAction.SSOEnabled : MessageAction.SSODisabled;

            MessageService.Send(HttpContext.Current.Request, messageAction);

            return settings;
        }

        /// <summary>
        /// Reset SSO settings for current portal
        /// </summary>
        /// <short>
        /// Reset SSO settings
        /// </short>
        /// <returns>SsoSettingsV2 object</returns>
        [Delete("ssov2")]
        public SsoSettingsV2 ResetSsoSettingsV2()
        {
            CheckSsoPermissions();

            var defaultSettings = new SsoSettingsV2().GetDefault() as SsoSettingsV2;

            if (defaultSettings != null && !defaultSettings.Save())
                throw new Exception(Resource.SsoSettingsCantSaveSettings);

            ConverSsoUsersToOrdinary();

            MessageService.Send(HttpContext.Current.Request, MessageAction.SSODisabled);

            return defaultSettings;
        }

        private static void ConverSsoUsersToOrdinary()
        {
            var ssoUsers = CoreContext.UserManager.GetUsers().Where(u => u.IsSSO()).ToList();

            if (!ssoUsers.Any())
                return;

            foreach (var existingSsoUser in ssoUsers)
            {
                existingSsoUser.SsoNameId = null;
                existingSsoUser.SsoSessionId = null;

                existingSsoUser.ConvertExternalContactsToOrdinary();

                CoreContext.UserManager.SaveUserInfo(existingSsoUser);
            }
        }

        private static bool CheckUri(string uriName)
        {
            Uri uriResult;
            return Uri.TryCreate(uriName, UriKind.Absolute, out uriResult) &&
                   (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);
        }

        private static void CheckSsoPermissions()
        {
            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

            if ((!SetupInfo.IsVisibleSettings(ManagementType.SingleSignOnSettings.ToString()) && !CoreContext.Configuration.Standalone) ||
                !CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Sso)
            {
                throw new BillingException(Resource.ErrorNotAllowedOption, "Sso");
            }
        }
    }
}


<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/OpenIdLoginProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.FederatedLogin.Profile;

using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using DotNetOpenAuth.OpenId.RelyingParty;

namespace ASC.FederatedLogin.LoginProviders
{
    class OpenIdLoginProvider : ILoginProvider
    {
        private static readonly OpenIdRelyingParty Openid = new OpenIdRelyingParty();


        public LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params)
        {
            var response = Openid.GetResponse();
            if (response == null)
            {
                Identifier id;
                if (Identifier.TryParse(@params["oid"], out id))
                {
                    try
                    {
                        IAuthenticationRequest request;

                        var realmUrlString = String.Empty;

                        if (@params.ContainsKey("realmUrl"))
                            realmUrlString = @params["realmUrl"];

                        if (!String.IsNullOrEmpty(realmUrlString))
                            request = Openid.CreateRequest(id, new Realm(realmUrlString));
                        else
                            request = Openid.CreateRequest(id);

                        request.AddExtension(new ClaimsRequest
                        {
                            Email = DemandLevel.Require,
                            Nickname = DemandLevel.Require,
                            Country = DemandLevel.Request,
                            Gender = DemandLevel.Request,
                            PostalCode = DemandLevel.Request,
                            TimeZone = DemandLevel.Request,
                            FullName = DemandLevel.Request,


                        });
                        var fetch = new FetchRequest();
                        fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
                        //Duplicating attributes
                        fetch.Attributes.AddRequired("http://schema.openid.net/contact/email");//Add two more
                        fetch.Attributes.AddRequired("http://openid.net/schema/contact/email");
                        fetch.Attributes.AddRequired(WellKnownAttributes.Name.Alias);
                        fetch.Attributes.AddRequired(WellKnownAttributes.Name.First);
                        fetch.Attributes.AddRequired(WellKnownAttributes.Media.Images.Default);
                        fetch.Attributes.AddRequired(WellKnownAttributes.Name.Last);
                        fetch.Attributes.AddRequired(WellKnownAttributes.Name.Middle);
                        fetch.Attributes.AddRequired(WellKnownAttributes.Person.Gender);
                        fetch.Attributes.AddRequired(WellKnownAttributes.BirthDate.WholeBirthDate);
                        request.AddExtension(fetch);
                        request.RedirectToProvider();
                        context.Response.End();//This will throw thread abort

                    }
                    catch (ProtocolException ex)
                    {
                        return LoginProfile.FromError(ex);
                    }
                }
                else
                {
                    return LoginProfile.FromError(new Exception("invalid OpenID identifier"));
                }
            }
            else
            {
                // Stage 3: OpenID Provider sending assertion response
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        var spprofile = response.GetExtension<ClaimsResponse>();
                        var fetchprofile = response.GetExtension<FetchResponse>();

                        var realmUrlString = String.Empty;
                        if (@params.ContainsKey("realmUrl"))
                            realmUrlString = @params["realmUrl"];

                        var profile = ProfileFromOpenId(spprofile, fetchprofile, response.ClaimedIdentifier.ToString(), realmUrlString);
                        return profile;
                    case AuthenticationStatus.Canceled:
                        return LoginProfile.FromError(new Exception("Canceled at provider"));
                    case AuthenticationStatus.Failed:
                        return LoginProfile.FromError(response.Exception);
                }
            }
            return null;
        }

        public LoginProfile GetLoginProfile(string accessToken)
        {
            throw new NotImplementedException();
        }

        public string Scopes { get { return ""; } }
        public string CodeUrl { get { return ""; } }
        public string AccessTokenUrl { get { return ""; } }
        public string RedirectUri { get { return ""; } }
        public string ClientID { get { return ""; } }
        public string ClientSecret { get { return ""; } }
        public bool IsEnabled { get { return GoogleLoginProvider.Instance.IsEnabled; } }

        internal static LoginProfile ProfileFromOpenId(ClaimsResponse spprofile, FetchResponse fetchprofile, string claimedId, string realmUrlString)
        {
            var profile = new LoginProfile
            {
                Link = claimedId,
                Id = claimedId,
                Provider = ProviderConstants.OpenId,
            };
            if (spprofile != null)
            {
                //Fill
                profile.BirthDay = spprofile.BirthDateRaw;
                profile.DisplayName = spprofile.FullName;
                profile.EMail = spprofile.Email;
                profile.Name = spprofile.Nickname;
                profile.Gender = spprofile.Gender.HasValue ? spprofile.Gender.Value.ToString() : "";
                profile.TimeZone = spprofile.TimeZone;
                profile.Locale = spprofile.Language;
            }
            if (fetchprofile != null)
            {
                profile.Name = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Alias);
                profile.LastName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Last);
                profile.FirstName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.First);
                profile.DisplayName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.FullName);
                profile.MiddleName = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Middle);
                profile.Salutation = fetchprofile.GetAttributeValue(WellKnownAttributes.Name.Prefix);
                profile.Avatar = fetchprofile.GetAttributeValue(WellKnownAttributes.Media.Images.Default);
                profile.EMail = fetchprofile.GetAttributeValue(WellKnownAttributes.Contact.Email);
                profile.Gender = fetchprofile.GetAttributeValue(WellKnownAttributes.Person.Gender);
                profile.BirthDay = fetchprofile.GetAttributeValue(WellKnownAttributes.BirthDate.WholeBirthDate);
            }
            profile.RealmUrl = realmUrlString;
            return profile;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Product/CommunityProduct.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Core;
using ASC.Web.Community.Resources;
using ASC.Web.Core;

namespace ASC.Web.Community.Product
{
    public class CommunityProduct : Core.Product
    {
        private static ProductContext ctx;


        public static Guid ID
        {
            get { return WebItemManager.CommunityProductID; }
        }

        public override Guid ProductID
        {
            get { return ID; }
        }

        public override string Name
        {
            get { return CommunityResource.ProductName; }
        }

        public override string Description
        {
            get
            {
                var id = SecurityContext.CurrentAccount.ID;

                if (CoreContext.UserManager.IsUserInGroup(id, ASC.Core.Users.Constants.GroupVisitor.ID))
                    return CommunityResource.ProductDescriptionShort;

                if (CoreContext.UserManager.IsUserInGroup(id, ASC.Core.Users.Constants.GroupAdmin.ID) || CoreContext.UserManager.IsUserInGroup(id, ID))
                    return CommunityResource.ProductDescriptionExt;

                return CommunityResource.ProductDescription;
            }
        }

        public override string StartURL
        {
            get { return "~/Products/Community/"; }
        }

        public override string HelpURL
        {
            get { return "~/Products/Community/Help.aspx"; }
        }

        public override string ProductClassName
        {
            get { return "community"; }
        }

        public override bool Visible { get { return true; } }

        public override ProductContext Context
        {
            get { return ctx; }
        }


        public override void Init()
        {
            ctx = new ProductContext
            {
                MasterPageFile = "~/Products/Community/Master/Community.Master",
                DisabledIconFileName = "product_disabled_logo.png",
                IconFileName = "product_logo.png",
                LargeIconFileName = "product_logolarge.svg",
                DefaultSortOrder = 40,

                SubscriptionManager = new CommunitySubscriptionManager(),

                SpaceUsageStatManager = new CommunitySpaceUsageStatManager(),

                AdminOpportunities = () => CommunityResource.ProductAdminOpportunities.Split('|').ToList(),
                UserOpportunities = () => CommunityResource.ProductUserOpportunities.Split('|').ToList(),
            };
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Billing/TariffService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;

using ASC.Common.Caching;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;
using ASC.Core.Data;
using ASC.Core.Tenants;

namespace ASC.Core.Billing
{
    public class TariffService : DbBaseService, ITariffService
    {
        private const int DEFAULT_TRIAL_PERIOD = 30;
        private static readonly TimeSpan DEFAULT_CACHE_EXPIRATION = TimeSpan.FromMinutes(5);
        private static readonly TimeSpan STANDALONE_CACHE_EXPIRATION = TimeSpan.FromMinutes(15);

        private readonly static ICache cache;
        private readonly static ICacheNotify notify;

        private static readonly ILog log = LogManager.GetLogger("ASC");
        private readonly IQuotaService quotaService;
        private readonly ITenantService tenantService;
        private readonly CoreConfiguration config;
        private readonly bool test;
        private readonly int paymentDelay;

        public readonly static int ACTIVE_USERS_MIN;
        public readonly static int ACTIVE_USERS_MAX;


        public TimeSpan CacheExpiration { get; set; }


        static TariffService()
        {
            cache = AscCache.Memory;
            notify = AscCache.Notify;
            notify.Subscribe<TariffCacheItem>((i, a) =>
            {
                cache.Remove(GetTariffCacheKey(i.TenantId));
                cache.Remove(GetBillingUrlCacheKey(i.TenantId));
                cache.Remove(GetBillingPaymentCacheKey(i.TenantId)); // clear all payments
            });


            var range = (ConfigurationManager.AppSettings["core.payment-user-range"] ?? "").Split('-');
            if (!int.TryParse(range[0], out ACTIVE_USERS_MIN))
            {
                ACTIVE_USERS_MIN = 0;
            }
            if (range.Length < 2 || !int.TryParse(range[1], out ACTIVE_USERS_MAX))
            {
                ACTIVE_USERS_MAX = Users.Constants.MaxEveryoneCount;
            }
        }


        public TariffService(ConnectionStringSettings connectionString, IQuotaService quotaService, ITenantService tenantService)
            : base(connectionString, "tenant")
        {
            this.quotaService = quotaService;
            this.tenantService = tenantService;
            config = new CoreConfiguration(tenantService);
            CacheExpiration = DEFAULT_CACHE_EXPIRATION;
            test = ConfigurationManagerExtension.AppSettings["core.payment-test"] == "true";
            int.TryParse(ConfigurationManagerExtension.AppSettings["core.payment-delay"], out paymentDelay);
        }


        public Tariff GetTariff(int tenantId, bool withRequestToPaymentSystem = true)
        {
            //single tariff for all portals
            if (CoreContext.Configuration.Standalone)
                tenantId = -1;

            var key = GetTariffCacheKey(tenantId);
            var tariff = cache.Get<Tariff>(key);
            if (tariff == null)
            {
                tariff = GetBillingInfo(tenantId);

                tariff = CalculateTariff(tenantId, tariff);
                cache.Insert(key, tariff, DateTime.UtcNow.Add(GetCacheExpiration()));

                if (BillingClient.Configured && withRequestToPaymentSystem)
                {
                    Task.Run(() =>
                    {
                        try
                        {
                            var client = GetBillingClient();
                            var lastPayment = client.GetLastPayment(GetPortalId(tenantId));

                            var quota = quotaService.GetTenantQuotas().SingleOrDefault(q => q.AvangateId == lastPayment.ProductId);
                            if (quota == null)
                            {
                                throw new InvalidOperationException(string.Format("Quota with id {0} not found for portal {1}.", lastPayment.ProductId, GetPortalId(tenantId)));
                            }

                            var asynctariff = Tariff.CreateDefault();
                            asynctariff.QuotaId = quota.Id;
                            asynctariff.Autorenewal = lastPayment.Autorenewal;
                            asynctariff.DueDate = 9999 <= lastPayment.EndDate.Year ? DateTime.MaxValue : lastPayment.EndDate;

                            if (quota.ActiveUsers == -1
                                && lastPayment.Quantity < ACTIVE_USERS_MIN)
                            {
                                throw new BillingException(string.Format("The portal {0} is paid for {1} users", tenantId, lastPayment.Quantity));
                            }
                            asynctariff.Quantity = lastPayment.Quantity;

                            if (SaveBillingInfo(tenantId, asynctariff, false))
                            {
                                asynctariff = CalculateTariff(tenantId, asynctariff);
                                ClearCache(tenantId);
                                cache.Insert(key, asynctariff, DateTime.UtcNow.Add(GetCacheExpiration()));
                            }
                        }
                        catch (BillingNotFoundException)
                        {
                        }
                        catch (Exception error)
                        {
                            LogError(error, tenantId.ToString());
                        }
                    });
                }
            }

            return tariff;
        }

        public void SetTariff(int tenantId, Tariff tariff)
        {
            if (tariff == null)
            {
                throw new ArgumentNullException("tariff");
            }

            var q = quotaService.GetTenantQuota(tariff.QuotaId);
            if (q == null) return;

            SaveBillingInfo(tenantId, tariff);

            if (q.Trial)
            {
                // reset trial date
                var tenant = tenantService.GetTenant(tenantId);
                if (tenant != null)
                {
                    tenant.VersionChanged = DateTime.UtcNow;
                    tenantService.SaveTenant(tenant);
                }
            }

            ClearCache(tenantId);
        }

        private static string GetTariffCacheKey(int tenantId)
        {
            return string.Format("{0}:{1}", tenantId, "tariff");
        }

        private static string GetBillingUrlCacheKey(int tenantId)
        {
            return string.Format("{0}:{1}", tenantId, "billing:urls");
        }

        private static string GetBillingPaymentCacheKey(int tenantId)
        {
            return string.Format("{0}:{1}", tenantId, "billing:payments");
        }


        public void ClearCache(int tenantId)
        {
            notify.Publish(new TariffCacheItem { TenantId = tenantId }, CacheNotifyAction.Remove);
        }

        public IEnumerable<PaymentInfo> GetPayments(int tenantId)
        {
            var key = GetBillingPaymentCacheKey(tenantId);
            var payments = cache.Get<List<PaymentInfo>>(key);
            if (payments == null)
            {
                payments = new List<PaymentInfo>();
                if (BillingClient.Configured)
                {
                    try
                    {
                        var quotas = quotaService.GetTenantQuotas();
                        var client = GetBillingClient();
                        foreach (var pi in client.GetPayments(GetPortalId(tenantId)))
                        {
                            var quota = quotas.SingleOrDefault(q => q.AvangateId == pi.ProductRef);
                            if (quota != null)
                            {
                                pi.QuotaId = quota.Id;
                            }
                            payments.Add(pi);
                        }
                    }
                    catch (Exception error)
                    {
                        LogError(error, tenantId.ToString());
                    }
                }

                cache.Insert(key, payments, DateTime.UtcNow.Add(TimeSpan.FromMinutes(10)));
            }

            return payments;
        }

        public Uri GetShoppingUri(int? tenant, int quotaId, string affiliateId, string currency = null, string language = null, string customerId = null, string quantity = null)
        {
            var quota = quotaService.GetTenantQuota(quotaId);
            if (quota == null) return null;

            var key = tenant.HasValue
                          ? GetBillingUrlCacheKey(tenant.Value)
                          : String.Format("notenant{0}", !string.IsNullOrEmpty(affiliateId) ? "_" + affiliateId : "");
            key += quota.Visible ? "" : "0";
            var urls = cache.Get<Dictionary<string, Tuple<Uri, Uri>>>(key) as IDictionary<string, Tuple<Uri, Uri>>;
            if (urls == null)
            {
                urls = new Dictionary<string, Tuple<Uri, Uri>>();
                if (BillingClient.Configured)
                {
                    try
                    {
                        var products = quotaService.GetTenantQuotas()
                                                   .Where(q => !string.IsNullOrEmpty(q.AvangateId) && q.Visible == quota.Visible)
                                                   .Select(q => q.AvangateId)
                                                   .ToArray();

                        var client = GetBillingClient();
                        urls =
                            client.GetPaymentUrls(
                                tenant.HasValue ? GetPortalId(tenant.Value) : null,
                                products,
                                tenant.HasValue ? GetAffiliateId(tenant.Value) : affiliateId,
                                tenant.HasValue ? GetCampaign(tenant.Value) : null,
                                !string.IsNullOrEmpty(currency) ? "__Currency__" : null,
                                !string.IsNullOrEmpty(language) ? "__Language__" : null,
                                !string.IsNullOrEmpty(customerId) ? "__CustomerID__" : null,
                                !string.IsNullOrEmpty(quantity) ? "__Quantity__" : null
                                );
                    }
                    catch (Exception error)
                    {
                        log.Error(error);
                    }
                }
                cache.Insert(key, urls, DateTime.UtcNow.Add(TimeSpan.FromMinutes(10)));
            }

            ResetCacheExpiration();

            Tuple<Uri, Uri> tuple;
            if (!string.IsNullOrEmpty(quota.AvangateId) && urls.TryGetValue(quota.AvangateId, out tuple))
            {
                var result = tuple.Item2;

                if (result == null)
                {
                    result = tuple.Item1;
                }
                else
                {
                    var tariff = tenant.HasValue ? GetTariff(tenant.Value) : null;
                    if (tariff == null || tariff.QuotaId == quotaId || tariff.State >= TariffState.Delay)
                    {
                        result = tuple.Item1;
                    }
                }

                if (result == null) return null;

                result = new Uri(result.ToString()
                                       .Replace("__Currency__", HttpUtility.UrlEncode(currency ?? ""))
                                       .Replace("__Language__", HttpUtility.UrlEncode((language ?? "").ToLower()))
                                       .Replace("__CustomerID__", HttpUtility.UrlEncode(customerId ?? ""))
                                       .Replace("__Quantity__", HttpUtility.UrlEncode(quantity ?? "")));
                return result;
            }
            return null;
        }

        public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds)
        {
            if (productIds == null)
            {
                throw new ArgumentNullException("productIds");
            }
            try
            {
                var key = "biling-prices" + string.Join(",", productIds);
                var result = cache.Get<IDictionary<string, Dictionary<string, decimal>>>(key);
                if (result == null)
                {
                    var client = GetBillingClient();
                    result = client.GetProductPriceInfo(productIds);
                    cache.Insert(key, result, DateTime.Now.AddHours(1));
                }
                return result;
            }
            catch (Exception error)
            {
                LogError(error);
                return productIds
                    .Select(p => new { ProductId = p, Prices = new Dictionary<string, decimal>() })
                    .ToDictionary(e => e.ProductId, e => e.Prices);
            }
        }


        public string GetButton(int tariffId, string partnerId)
        {
            var q = new SqlQuery("tenants_buttons")
               .Select("button_url")
               .Where(Exp.Eq("tariff_id", tariffId) & Exp.Eq("partner_id", partnerId))
               .SetMaxResults(1);

            return ExecList(q).ConvertAll(r => (string)r[0]).SingleOrDefault();
        }

        public void SaveButton(int tariffId, string partnerId, string buttonUrl)
        {
            var q = new SqlInsert("tenants_buttons", true)
                .InColumnValue("tariff_id", tariffId)
                .InColumnValue("partner_id", partnerId)
                .InColumnValue("button_url", buttonUrl);

            ExecNonQuery(q);
        }


        private Tariff GetBillingInfo(int tenant)
        {
            var q = new SqlQuery("tenants_tariff")
                .Select("tariff", "stamp", "quantity")
                .Where("tenant", tenant)
                .OrderBy("id", false)
                .SetMaxResults(1);

            return ExecList(q)
                .ConvertAll(r =>
                {
                    var tariff = Tariff.CreateDefault();
                    tariff.QuotaId = Convert.ToInt32(r[0]);
                    tariff.DueDate = ((DateTime)r[1]).Year < 9999 ? (DateTime)r[1] : DateTime.MaxValue;
                    tariff.Quantity = Convert.ToInt32(r[2]);
                    return tariff;
                })
                .SingleOrDefault()
                ?? Tariff.CreateDefault();
        }

        private bool SaveBillingInfo(int tenant, Tariff tariffInfo, bool renewal = true)
        {
            var inserted = false;
            var currentTariff = GetBillingInfo(tenant);
            if (!tariffInfo.EqualsByParams(currentTariff))
            {
                using (var db = GetDb())
                using (var tx = db.BeginTransaction())
                {
                    // last record is not the same
                    var q = new SqlQuery("tenants_tariff")
                        .SelectCount()
                        .Where("tenant", tenant)
                        .Where("tariff", tariffInfo.QuotaId)
                        .Where("stamp", tariffInfo.DueDate)
                        .Where("quantity", tariffInfo.Quantity);

                    if (tariffInfo.DueDate == DateTime.MaxValue || renewal || db.ExecuteScalar<int>(q) == 0)
                    {
                        var i = new SqlInsert("tenants_tariff")
                            .InColumnValue("tenant", tenant)
                            .InColumnValue("tariff", tariffInfo.QuotaId)
                            .InColumnValue("stamp", tariffInfo.DueDate)
                            .InColumnValue("quantity", tariffInfo.Quantity);
                        db.ExecuteNonQuery(i);
                        cache.Remove(GetTariffCacheKey(tenant));
                        inserted = true;
                    }
                    tx.Commit();
                }
            }

            if (inserted)
            {
                var t = tenantService.GetTenant(tenant);
                if (t != null)
                {
                    // update tenant.LastModified to flush cache in documents
                    tenantService.SaveTenant(t);
                }
            }
            return inserted;
        }

        public void DeleteDefaultBillingInfo()
        {
            const int tenant = Tenant.DEFAULT_TENANT;
            using (var db = GetDb())
            {
                db.ExecuteNonQuery(new SqlUpdate("tenants_tariff")
                                       .Set("tenant", -2)
                                       .Where("tenant", tenant));
            }

            ClearCache(tenant);
        }


        private Tariff CalculateTariff(int tenantId, Tariff tariff)
        {
            tariff.State = TariffState.Paid;
            var q = quotaService.GetTenantQuota(tariff.QuotaId);

            if (q == null || q.GetFeature("old"))
            {
                tariff.QuotaId = Tenant.DEFAULT_TENANT;
                q = quotaService.GetTenantQuota(tariff.QuotaId);
            }

            var delay = 0;
            if (q != null && q.Trial)
            {
                tariff.State = TariffState.Trial;
                if (tariff.DueDate == DateTime.MinValue || tariff.DueDate == DateTime.MaxValue)
                {
                    var tenant = tenantService.GetTenant(tenantId);
                    if (tenant != null)
                    {
                        var fromDate = tenant.CreatedDateTime < tenant.VersionChanged ? tenant.VersionChanged : tenant.CreatedDateTime;
                        var trialPeriod = GetPeriod("TrialPeriod", DEFAULT_TRIAL_PERIOD);
                        if (fromDate == DateTime.MinValue) fromDate = DateTime.UtcNow.Date;
                        tariff.DueDate = trialPeriod != default(int) ? fromDate.Date.AddDays(trialPeriod) : DateTime.MaxValue;
                    }
                    else
                    {
                        tariff.DueDate = DateTime.MaxValue;
                    }
                }
            }
            else
            {
                delay = paymentDelay;
            }

            if (tariff.DueDate != DateTime.MinValue && tariff.DueDate.Date < DateTime.Today && delay > 0)
            {
                tariff.State = TariffState.Delay;

                tariff.DelayDueDate = tariff.DueDate.Date.AddDays(delay);
            }

            if (tariff.DueDate == DateTime.MinValue ||
                tariff.DueDate != DateTime.MaxValue && tariff.DueDate.Date.AddDays(delay) < DateTime.Today)
            {
                tariff.State = TariffState.NotPaid;

                if (config.Standalone)
                {
                    if (q != null)
                    {
                        var defaultQuota = quotaService.GetTenantQuota(Tenant.DEFAULT_TENANT);
                        defaultQuota.Name = "overdue";

                        defaultQuota.Features = q.Features;
                        defaultQuota.Support = false;

                        quotaService.SaveTenantQuota(defaultQuota);
                    }

                    var unlimTariff = Tariff.CreateDefault();
                    unlimTariff.LicenseDate = tariff.DueDate;

                    tariff = unlimTariff;
                }
            }

            tariff.Prolongable = tariff.DueDate == DateTime.MinValue || tariff.DueDate == DateTime.MaxValue ||
                                 tariff.State == TariffState.Trial ||
                                 new DateTime(tariff.DueDate.Year, tariff.DueDate.Month, 1) <= new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1).AddMonths(1);

            return tariff;
        }

        private int GetPeriod(string key, int defaultValue)
        {
            var settings = tenantService.GetTenantSettings(Tenant.DEFAULT_TENANT, key);
            return settings != null ? Convert.ToInt32(Encoding.UTF8.GetString(settings)) : defaultValue;
        }

        private BillingClient GetBillingClient()
        {
            try
            {
                return new BillingClient(test);
            }
            catch (InvalidOperationException ioe)
            {
                throw new BillingNotConfiguredException(ioe.Message, ioe);
            }
            catch (ReflectionTypeLoadException rtle)
            {
                log.ErrorFormat("{0}{1}LoaderExceptions: {2}",
                    rtle,
                    Environment.NewLine,
                    string.Join(Environment.NewLine, rtle.LoaderExceptions.Select(e => e.ToString())));
                throw;
            }
        }

        private string GetPortalId(int tenant)
        {
            return config.GetKey(tenant);
        }

        private string GetAffiliateId(int tenant)
        {
            return config.GetAffiliateId(tenant);
        }

        private string GetCampaign(int tenant)
        {
            return config.GetCampaign(tenant);
        }

        private TimeSpan GetCacheExpiration()
        {
            if (config.Standalone && CacheExpiration < STANDALONE_CACHE_EXPIRATION)
            {
                CacheExpiration = CacheExpiration.Add(TimeSpan.FromSeconds(30));
            }
            return CacheExpiration;
        }

        private void ResetCacheExpiration()
        {
            if (config.Standalone)
            {
                CacheExpiration = DEFAULT_CACHE_EXPIRATION;
            }
        }

        private static void LogError(Exception error, string tenantId = null)
        {
            if (error is BillingNotFoundException)
            {
                log.DebugFormat("Payment tenant {0} not found: {1}", tenantId, error.Message);
            }
            else if (error is BillingNotConfiguredException)
            {
                log.DebugFormat("Billing tenant {0} not configured: {1}", tenantId, error.Message);
            }
            else
            {
                if (log.IsDebugEnabled)
                {
                    log.Error("Billing tenant " + tenantId);
                    log.Error(error);
                }
                else
                {
                    log.ErrorFormat("Billing tenant {0}: {1}", tenantId, error.Message);
                }
            }
        }


        [Serializable]
        class TariffCacheItem
        {
            public int TenantId { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Domain/Entities/Project.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Diagnostics;

using ASC.Web.Projects.Classes;

#endregion

namespace ASC.Projects.Core.Domain
{
    [DebuggerDisplay("Project: ID = {ID}, Title = {Title}")]
    public class Project : DomainObject<Int32>
    {
        public override EntityType EntityType { get { return EntityType.Project; } }

        public override string ItemPath { get { return "{0}Tasks.aspx?prjID={1}"; } }

        public string Title { get; set; }

        public string HtmlTitle
        {
            get
            {
                if (Title == null) return string.Empty;
                return Title.Length <= 40 ? Title : Title.Remove(37) + "...";
            }
        }

        public String Description { get; set; }

        public ProjectStatus Status { get; set; }

        public Guid Responsible { get; set; }

        public bool Private { get; set; }

        public ProjectSecurityInfo Security { get; set; }


        public Guid CreateBy { get; set; }

        public DateTime CreateOn { get; set; }

        public Guid LastModifiedBy { get; set; }

        public DateTime LastModifiedOn { get; set; }

        /// <summary>
        /// Opened
        /// </summary>
        public int TaskCount { get; set; }

        /// <summary>
        /// Total
        /// </summary>
        public int TaskCountTotal { get; set; }

        public int MilestoneCount { get; set; }

        public int ParticipantCount { get; set; }

        public int DiscussionCount { get; set; }

        public string TimeTrackingTotal { get; set; }

        public int DocumentsCount { get; set; }

        public DateTime StatusChangedOn { get; set; }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Core/SetupInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;

using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Core
{
    public static class SetupInfo
    {
        private static string web_autotest_secret_email;
        private static string[] web_display_mobapps_banner;
        private static string[] hideSettings;


        public static string MetaImageURL
        {
            get;
            private set;
        }

        public static string StatisticTrackURL
        {
            get;
            private set;
        }

        public static bool EnableAppServer
        {
            get;
            private set;
        }

        public static string UserVoiceURL
        {
            get;
            private set;
        }

        public static string MainLogoURL
        {
            get;
            private set;
        }

        public static string MainLogoMailTmplURL
        {
            get;
            private set;
        }

        public static List<CultureInfo> EnabledCultures
        {
            get;
            private set;
        }

        private static List<CultureInfo> EnabledCulturesPersonal
        {
            get;
            set;
        }

        public static List<KeyValuePair<string, CultureInfo>> PersonalCultures
        {
            get;
            private set;
        }

        public static decimal ExchangeRateRuble
        {
            get;
            private set;
        }

        public static long MaxImageUploadSize
        {
            get;
            private set;
        }

        /// <summary>
        /// Max possible file size for not chunked upload. Less or equal than 100 mb.
        /// </summary>
        public static long MaxUploadSize
        {
            get { return Math.Min(AvailableFileSize, MaxChunkedUploadSize); }
        }

        public static long AvailableFileSize
        {
            get;
            private set;
        }

        /// <summary>
        /// Max possible file size for chunked upload.
        /// </summary>
        public static long MaxChunkedUploadSize
        {
            get
            {
                var diskQuota = TenantExtra.GetTenantQuota();
                if (diskQuota != null)
                {
                    var usedSize = TenantStatisticsProvider.GetUsedSize();
                    var freeSize = Math.Max(diskQuota.MaxTotalSize - usedSize, 0);
                    return Math.Min(freeSize, diskQuota.MaxFileSize);
                }
                return ChunkUploadSize;
            }
        }

        public static string TeamlabSiteRedirect
        {
            get;
            private set;
        }

        public static long ChunkUploadSize
        {
            get;
            private set;
        }

        public static bool ThirdPartyAuthEnabled
        {
            get;
            private set;
        }

        public static bool ThirdPartyBannerEnabled
        {
            get;
            private set;
        }

        public static string NoTenantRedirectURL
        {
            get;
            private set;
        }

        public static string NotifyAddress
        {
            get;
            private set;
        }

        public static string TipsAddress
        {
            get;
            private set;
        }

        public static string UserForum
        {
            get;
            private set;
        }

        public static string SupportFeedback
        {
            get;
            private set;
        }

        public static string WebApiBaseUrl
        {
            get { return VirtualPathUtility.ToAbsolute(GetAppSettings("api.url", "~/api/2.0/")); }
        }

        public static TimeSpan ValidEmailKeyInterval
        {
            get;
            private set;
        }

        public static TimeSpan ValidAuthKeyInterval
        {
            get;
            private set;
        }

        public static string SalesEmail
        {
            get;
            private set;
        }

        public static bool IsSecretEmail(string email)
        {
            //the point is not needed in gmail.com
            email = Regex.Replace(email ?? "", "\\.*(?=\\S*(@gmail.com$))", "").ToLower();
            if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(web_autotest_secret_email))
                return false;

            var regex = new Regex(web_autotest_secret_email, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
            return regex.IsMatch(email);
        }

        public static bool DisplayMobappBanner(string product)
        {
            return web_display_mobapps_banner.Contains(product, StringComparer.InvariantCultureIgnoreCase);
        }

        public static string ShareTwitterUrl
        {
            get;
            private set;
        }

        public static string ShareFacebookUrl
        {
            get;
            private set;
        }

        public static string ControlPanelUrl
        {
            get;
            private set;
        }

        public static string FontOpenSansUrl
        {
            get;
            private set;
        }

        public static bool VoipEnabled
        {
            get;
            private set;
        }


        public static string StartProductList
        {
            get;
            private set;
        }

        public static string SsoSamlLoginUrl
        {
            get;
            private set;
        }

        public static string DownloadForDesktopUrl
        {
            get;
            private set;
        }
        public static string DownloadForIosDocuments
        {
            get;
            private set;
        }
        public static string DownloadForIosProjects
        {
            get;
            private set;
        }
        public static string DownloadForAndroidDocuments
        {
            get;
            private set;
        }

        public static string SsoSamlLogoutUrl
        {
            get;
            private set;
        }


        public static bool SmsTrial
        {
            get;
            private set;
        }

        public static string TfaRegistration
        {
            get;
            private set;
        }

        public static int TfaAppBackupCodeLength
        {
            get;
            private set;
        }

        public static int TfaAppBackupCodeCount
        {
            get;
            private set;
        }

        public static string TfaAppSender
        {
            get;
            private set;
        }

        public static string RecaptchaPublicKey
        {
            get;
            private set;
        }

        public static string RecaptchaPrivateKey
        {
            get;
            private set;
        }

        public static string RecaptchaVerifyUrl
        {
            get;
            private set;
        }

        public static int LoginThreshold
        {
            get;
            private set;
        }

        public static string AmiMetaUrl
        {
            get;
            private set;
        }

        static SetupInfo()
        {
            Refresh();
        }

        public static void Refresh()
        { 
            EnableAppServer = GetAppSettings("appserver.enable", "false") == "true";
            MetaImageURL = GetAppSettings("web.meta-image-url", "https://download.onlyoffice.com/assets/fb/fb_icon_325x325.jpg");
            StatisticTrackURL = GetAppSettings("web.track-url", string.Empty);
            UserVoiceURL = GetAppSettings("web.uservoice", string.Empty);
            MainLogoURL = GetAppSettings("web.logo.main", string.Empty);
            MainLogoMailTmplURL = GetAppSettings("web.logo.mail.tmpl", string.Empty);
            DownloadForDesktopUrl = GetAppSettings("web.download.for.desktop.url", "https://www.onlyoffice.com/desktop.aspx");
            DownloadForIosDocuments = GetAppSettings("web.download.for.ios.doc", "https://itunes.apple.com/app/onlyoffice-documents/id944896972");
            DownloadForIosProjects = GetAppSettings("web.download.for.ios.proj", "https://itunes.apple.com/app/onlyoffice-projects/id1353395928?mt=8");
            DownloadForAndroidDocuments = GetAppSettings("web.download.for.android.doc", "https://play.google.com/store/apps/details?id=com.onlyoffice.documents");

            EnabledCultures = GetAppSettings("web.cultures", "en-US")
                .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Distinct()
                .Select(l => CultureInfo.GetCultureInfo(l.Trim()))
                .OrderBy(l => l.DisplayName)
                .ToList();

            EnabledCulturesPersonal = GetAppSettings("web.cultures.personal", GetAppSettings("web.cultures", "en-US"))
                .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Distinct()
                .Select(l => CultureInfo.GetCultureInfo(l.Trim()))
                .ToList();

            PersonalCultures = GetPersonalCultures();

            ExchangeRateRuble = GetAppSettings("exchange-rate.ruble", 65);
            MaxImageUploadSize = GetAppSettings<long>("web.max-upload-size", 1024 * 1024);
            AvailableFileSize = GetAppSettings("web.available-file-size", 100L * 1024L * 1024L);

            TeamlabSiteRedirect = GetAppSettings("web.teamlab-site", string.Empty);
            ChunkUploadSize = GetAppSettings("files.uploader.chunk-size", 5 * 1024 * 1024);
            ThirdPartyAuthEnabled = string.Equals(GetAppSettings("web.thirdparty-auth", "true"), "true");
            ThirdPartyBannerEnabled = string.Equals(GetAppSettings("web.thirdparty-banner", "false"), "true");
            NoTenantRedirectURL = GetAppSettings("web.notenant-url", "");

            NotifyAddress = GetAppSettings("web.promo-url", string.Empty);
            TipsAddress = GetAppSettings("web.promo-tips-url", string.Empty);
            UserForum = GetAppSettings("web.user-forum", string.Empty);
            SupportFeedback = GetAppSettings("web.support-feedback", string.Empty);

            ValidEmailKeyInterval = GetAppSettings("email.validinterval", TimeSpan.FromDays(7));
            ValidAuthKeyInterval = GetAppSettings("auth.validinterval", TimeSpan.FromHours(1));

            SalesEmail = GetAppSettings("web.payment.email", "<EMAIL>");
            web_autotest_secret_email = (ConfigurationManagerExtension.AppSettings["web.autotest.secret-email"] ?? "").Trim();

            RecaptchaPublicKey = GetAppSettings("web.recaptcha.public-key", "");
            RecaptchaPrivateKey = GetAppSettings("web.recaptcha.private-key", "");
            RecaptchaVerifyUrl = GetAppSettings("web.recaptcha.verify-url", "https://www.recaptcha.net/recaptcha/api/siteverify");
            LoginThreshold = Convert.ToInt32(GetAppSettings("web.login.threshold", "0"));
            if (LoginThreshold < 1) LoginThreshold = 5;

            web_display_mobapps_banner = (ConfigurationManagerExtension.AppSettings["web.display.mobapps.banner"] ?? "").Trim().Split(new char[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);
            ShareTwitterUrl = GetAppSettings("web.share.twitter", "https://twitter.com/intent/tweet?text={0}");
            ShareFacebookUrl = GetAppSettings("web.share.facebook", "");
            ControlPanelUrl = GetAppSettings("web.controlpanel.url", "");
            FontOpenSansUrl = GetAppSettings("web.font.opensans.url", "");
            VoipEnabled = GetAppSettings("voip.enabled", true);
            StartProductList = GetAppSettings("web.start.product.list", "");
            SsoSamlLoginUrl = GetAppSettings("web.sso.saml.login.url", "");
            SsoSamlLogoutUrl = GetAppSettings("web.sso.saml.logout.url", "");

            hideSettings = GetAppSettings("web.hide-settings", string.Empty).Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries);

            SmsTrial = GetAppSettings("core.sms.trial", false);

            TfaRegistration = (GetAppSettings("core.tfa.registration", "") ?? "").Trim().ToLower();

            TfaAppBackupCodeLength = GetAppSettings("web.tfaapp.backup.length", 6);
            TfaAppBackupCodeCount = GetAppSettings("web.tfaapp.backup.count", 5);
            TfaAppSender = GetAppSettings("web.tfaapp.backup.title", "ONLYOFFICE");

            AmiMetaUrl = GetAppSettings("web.ami.meta", "");
        }


        public static bool IsVisibleSettings<TSettings>()
        {
            return IsVisibleSettings(typeof(TSettings).Name);
        }

        public static bool IsVisibleSettings(string settings)
        {
            return hideSettings == null || !hideSettings.Contains(settings, StringComparer.CurrentCultureIgnoreCase);
        }


        private static string GetAppSettings(string key, string defaultValue)
        {
            var result = ConfigurationManagerExtension.AppSettings[key] ?? defaultValue;

            if (!string.IsNullOrEmpty(result))
                result = result.Trim();

            return result;

        }

        private static T GetAppSettings<T>(string key, T defaultValue)
        {
            var configSetting = ConfigurationManagerExtension.AppSettings[key];
            if (!string.IsNullOrEmpty(configSetting))
            {
                configSetting = configSetting.Trim();
                var converter = TypeDescriptor.GetConverter(typeof(T));
                if (converter != null && converter.CanConvertFrom(typeof(string)))
                {
                    return (T)converter.ConvertFromString(configSetting);
                }
            }
            return defaultValue;
        }

        private static List<KeyValuePair<string, CultureInfo>> GetPersonalCultures()
        {
            var result = new Dictionary<string, CultureInfo>();

            foreach (var culture in EnabledCulturesPersonal)
            {
                if (result.ContainsKey(culture.TwoLetterISOLanguageName))
                {
                    result.Add(culture.Name, culture);
                }
                else
                {
                    result.Add(culture.TwoLetterISOLanguageName, culture);
                }
            }

            return result.OrderBy(item => item.Value.DisplayName).ToList();
        }

        public static KeyValuePair<string, CultureInfo> GetPersonalCulture(string lang)
        {
            foreach (var item in PersonalCultures)
            {
                if (string.Equals(item.Key, lang, StringComparison.InvariantCultureIgnoreCase))
                {
                    return item;
                }
            }

            var cultureInfo = EnabledCulturesPersonal.Find(c => string.Equals(c.Name, lang, StringComparison.InvariantCultureIgnoreCase));

            if (cultureInfo == null)
            {
                cultureInfo = EnabledCulturesPersonal.Find(c => string.Equals(c.TwoLetterISOLanguageName, lang, StringComparison.InvariantCultureIgnoreCase));
            }

            if (cultureInfo != null)
            {
                foreach (var item in PersonalCultures)
                {
                    if (item.Value == cultureInfo)
                    {
                        return item;
                    }
                }
            }

            return new KeyValuePair<string, CultureInfo>(lang, cultureInfo);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/UserControls/ImportUsers/ImportUsers.ascx.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Core.Users;
using ASC.Web.People.Core;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

namespace ASC.Web.People.UserControls
{
    [AjaxNamespace("ImportUsersController")]
    public partial class ImportUsers : UserControl
    {
        public static string Location
        {
            get { return PeopleProduct.ProductPath + "UserControls/ImportUsers/ImportUsers.ascx"; }
        }

        public enum Operation
        {
            Success = 1,
            Error = 0
        }
        protected int PeopleLimit { get; set; }

        protected bool FreeTariff { get; set; }

        protected string HelpLink { get; set; }

        public int EnableUsers { get; set; }

        public int EnableGuests { get; set; }

        public bool IsStandalone { get; set; }

        protected bool EnableInviteLink = TenantStatisticsProvider.GetUsersCount() < TenantExtra.GetTenantQuota().ActiveUsers;

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!SecurityContext.CheckPermissions(Constants.Action_AddRemoveUser))
            {
                Response.Redirect(CommonLinkUtility.GetDefault());
            }

            EnableUsers = TenantExtra.GetTenantQuota().ActiveUsers - TenantStatisticsProvider.GetUsersCount();
            EnableGuests = Constants.CoefficientOfVisitors * TenantExtra.GetTenantQuota().ActiveUsers - TenantStatisticsProvider.GetVisitorsCount();
            EnableGuests = EnableGuests >= 0 ? EnableGuests : 0;
            IsStandalone = CoreContext.Configuration.Standalone;
            var tariff = (Studio.UserControls.Management.TariffLimitExceed)LoadControl(Studio.UserControls.Management.TariffLimitExceed.Location);
            Tariff.Controls.Add(tariff);
            var quota = TenantExtra.GetTenantQuota();

            PeopleLimit = Math.Min(quota.ActiveUsers - TenantStatisticsProvider.GetUsersCount(), 0);
            FreeTariff = (quota.Free || quota.NonProfit || quota.Trial) && !quota.Open;
            HelpLink = CommonLinkUtility.GetHelpLink();

            icon.Options.IsPopup = true;
            icon.Options.PopupContainerCssClass = "okcss popupContainerClass";
            icon.Options.OnCancelButtonClick = "ASC.People.Import.hideInfoWindow('okcss');";

            limitPanel.Options.IsPopup = true;
            limitPanel.Options.OnCancelButtonClick = "ASC.People.Import.hideImportUserLimitPanel();";

            Utility.RegisterTypeForAjax(GetType());

            RegisterScript();

        }

        private void RegisterScript()
        {
            Page.RegisterStyle(PeopleProduct.ProductPath + "UserControls/ImportUsers/css/import.less")
                .RegisterBodyScripts("~/js/uploader/ajaxupload.js", "~/js/third-party/xregexp.js",
                PeopleProduct.ProductPath + "UserControls/ImportUsers/js/importusers.js");
        }
    }
}




<|start_filename|>module/ASC.Api/ASC.Specific/ApiDateTime.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.Serialization;

using ASC.Api.Interfaces;
using ASC.Core;

using Newtonsoft.Json;

namespace ASC.Specific
{
    [DataContract(Name = "date", Namespace = "")]
    [JsonConverter(typeof(ApiDateTimeConverter))]
    [TypeConverter(typeof(ApiDateTimeTypeConverter))]
    public class ApiDateTime : IComparable<ApiDateTime>, IApiDateTime, IComparable
    {
        private static readonly string[] Formats = new[]
                                                       {
                                                           "o",
                                                           "yyyy'-'MM'-'dd'T'HH'-'mm'-'ss'.'fffffffK",
                                                           "yyyy'-'MM'-'dd'T'HH'-'mm'-'ss'.'fffK",
                                                           "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK",
                                                           "yyyy'-'MM'-'dd'T'HH'-'mm'-'ssK",
                                                           "yyyy'-'MM'-'dd'T'HH':'mm':'ssK",
                                                           "yyyy'-'MM'-'dd"
                                                       };

        public ApiDateTime()
            : this(null)
        {
        }

        public ApiDateTime(DateTime? dateTime)
            : this(dateTime, null)
        {
        }

        public ApiDateTime(DateTime? dateTime, TimeZoneInfo timeZone)
        {
            if (dateTime.HasValue && dateTime.Value > DateTime.MinValue && dateTime.Value < DateTime.MaxValue)
            {
                SetDate(dateTime.Value, timeZone);
            }
            else
            {
                UtcTime = DateTime.MinValue;
                TimeZoneOffset = TimeSpan.Zero;
            }
        }

        public ApiDateTime(DateTime utcTime, TimeSpan offset)
        {
            UtcTime = new DateTime(utcTime.Ticks, DateTimeKind.Utc);
            TimeZoneOffset = offset;
        }

        public static ApiDateTime Parse(string data)
        {
            return Parse(data, null);
        }

        public static ApiDateTime Parse(string data, TimeZoneInfo tz)
        {
            if (string.IsNullOrEmpty(data)) throw new ArgumentNullException("data");

            if (data.Length < 7) throw new ArgumentException("invalid date time format");

            var offsetPart = data.Substring(data.Length - 6, 6);
            DateTime dateTime;
            if (DateTime.TryParseExact(data, Formats, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out dateTime))
            {
                //Parse time   
                TimeSpan tzOffset = TimeSpan.Zero;
                if (offsetPart.Contains(":") && TimeSpan.TryParse(offsetPart.TrimStart('+'), out tzOffset))
                {
                    return new ApiDateTime(dateTime, tzOffset);
                }
                if (!data.EndsWith("Z", true, CultureInfo.InvariantCulture))
                {
                    if (tz == null)
                    {
                        tz = GetTimeZoneInfo();
                    }
                    tzOffset = tz.GetUtcOffset(dateTime);
                    dateTime = dateTime.Subtract(tzOffset);
                }
                return new ApiDateTime(dateTime, tzOffset);

            }
            throw new ArgumentException("invalid date time format: " + data);
        }


        private void SetDate(DateTime value, TimeZoneInfo timeZone)
        {
            TimeZoneOffset = TimeSpan.Zero;
            UtcTime = DateTime.MinValue;

            if (timeZone == null)
            {
                timeZone = GetTimeZoneInfo();
            }

            //Hack
            if (timeZone.IsInvalidTime(new DateTime(value.Ticks, DateTimeKind.Unspecified)))
            {
                value = value.AddHours(1);
            }

            if (value.Kind == DateTimeKind.Local)
            {
                value = TimeZoneInfo.ConvertTimeToUtc(new DateTime(value.Ticks, DateTimeKind.Unspecified), timeZone);
            }
            if (value.Kind == DateTimeKind.Unspecified)
            {
                //Assume it's utc
                value = new DateTime(value.Ticks, DateTimeKind.Utc);
            }

            if (value.Kind == DateTimeKind.Utc)
            {
                UtcTime = value; //Set UTC time
                TimeZoneOffset = timeZone.GetUtcOffset(value);
            }

        }

        private static TimeZoneInfo GetTimeZoneInfo()
        {
            var timeZone = TimeZoneInfo.Local;
            try
            {
                timeZone = CoreContext.TenantManager.GetCurrentTenant().TimeZone;
            }
            catch (Exception)
            {
                //Tenant failed
            }
            return timeZone;
        }

        private string ToRoundTripString(DateTime date, TimeSpan offset)
        {
            var dateString = date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffff", CultureInfo.InvariantCulture);
            var offsetString = offset.Ticks == 0 ? "Z" : ((offset < TimeSpan.Zero) ? "-" : "+") + offset.ToString("hh\\:mm", CultureInfo.InvariantCulture);
            return dateString + offsetString;
        }

        public static explicit operator ApiDateTime(DateTime d)
        {
            var date = new ApiDateTime(d);
            return date;
        }

        public static explicit operator ApiDateTime(DateTime? d)
        {
            if (d.HasValue)
            {
                var date = new ApiDateTime(d);
                return date;
            }
            return null;
        }


        public static bool operator >(ApiDateTime left, ApiDateTime right)
        {
            if (ReferenceEquals(left, right)) return false;
            if (left == null) return false;

            return left.CompareTo(right) > 0;
        }
        public static bool operator >=(ApiDateTime left, ApiDateTime right)
        {
            if (ReferenceEquals(left, right)) return false;
            if (left == null) return false;

            return left.CompareTo(right) >= 0;
        }

        public static bool operator <=(ApiDateTime left, ApiDateTime right)
        {
            return !(left >= right);
        }

        public static bool operator <(ApiDateTime left, ApiDateTime right)
        {
            return !(left > right);
        }

        public static bool operator ==(ApiDateTime left, ApiDateTime right)
        {
            return Equals(left, right);
        }

        public static bool operator !=(ApiDateTime left, ApiDateTime right)
        {
            return !(left == right);
        }

        public static implicit operator DateTime(ApiDateTime d)
        {
            if (d == null) return DateTime.MinValue;
            return d.UtcTime;
        }

        public static implicit operator DateTime?(ApiDateTime d)
        {
            if (d == null) return null;
            return d.UtcTime;
        }

        public int CompareTo(DateTime other)
        {
            return this.CompareTo(new ApiDateTime(other));
        }

        public int CompareTo(ApiDateTime other)
        {
            if (other == null) return 1;
            return UtcTime.CompareTo(other.UtcTime);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != typeof(ApiDateTime)) return false;
            return Equals((ApiDateTime)obj);
        }

        public bool Equals(ApiDateTime other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return UtcTime.Equals(other.UtcTime) && TimeZoneOffset.Equals(other.TimeZoneOffset);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return UtcTime.GetHashCode() * 397 + TimeZoneOffset.GetHashCode();
            }
        }

        public int CompareTo(object obj)
        {
            if (obj is DateTime)
                return CompareTo((DateTime)obj);
            return obj is ApiDateTime ? CompareTo((ApiDateTime)obj) : 0;
        }

        public override string ToString()
        {
            DateTime localUtcTime = UtcTime;

            if (!UtcTime.Equals(DateTime.MinValue))
                localUtcTime = UtcTime.Add(TimeZoneOffset);

            return ToRoundTripString(localUtcTime, TimeZoneOffset);
        }

        public DateTime UtcTime { get; private set; }
        public TimeSpan TimeZoneOffset { get; private set; }

        public static ApiDateTime GetSample()
        {
            return new ApiDateTime(DateTime.UtcNow, TimeSpan.Zero);
        }
    }

    public class ApiDateTimeTypeConverter : DateTimeConverter
    {
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(string))
                return value.ToString();
            return base.ConvertTo(context, culture, value, destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value is string)
            {
                return ApiDateTime.Parse((string)value);
            }
            if (value is DateTime)
            {
                return new ApiDateTime((DateTime)value);
            }
            return base.ConvertFrom(context, culture, value);
        }
    }

    public class ApiDateTimeConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value is IApiDateTime)
            {
                writer.WriteValue(value.ToString());
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override bool CanConvert(Type objectType)
        {
            return typeof(IApiDateTime).IsAssignableFrom(objectType);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/StudioSettings/StudioSettings.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Web.UI;

using ASC.Core;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    [ManagementControl(ManagementType.Customization, Location)]
    public partial class StudioSettings : UserControl
    {
        public const string Location = "~/UserControls/Management/StudioSettings/StudioSettings.ascx";

        protected string HelpLink { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            //timezone & language
            _timelngHolder.Controls.Add(LoadControl(TimeAndLanguage.Location));

            if (SetupInfo.IsVisibleSettings<PromoCode>() &&
                TenantExtra.GetCurrentTariff().State == ASC.Core.Billing.TariffState.Trial &&
                string.IsNullOrEmpty(CoreContext.TenantManager.GetCurrentTenant().PartnerId))
            {
                promoCodeSettings.Controls.Add(LoadControl(PromoCode.Location));
            }

            //dns
            if (SetupInfo.IsVisibleSettings<DnsSettings.DnsSettings>())
                _dnsSettings.Controls.Add(LoadControl(DnsSettings.DnsSettings.Location));

            //Portal version
            if (SetupInfo.IsVisibleSettings<VersionSettings.VersionSettings>() && 1 < CoreContext.TenantManager.GetTenantVersions().Count())
                _portalVersionSettings.Controls.Add(LoadControl(VersionSettings.VersionSettings.Location));

            //greeting settings
            _greetingSettings.Controls.Add(LoadControl(GreetingSettings.Location));

            //portal rename control
            _portalRename.Controls.Add(LoadControl(PortalRename.Location));

            HelpLink = CommonLinkUtility.GetHelpLink();
        }
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/ModuleProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal static class ModuleProvider
    {
        public static readonly List<IModuleSpecifics> AllModules = new List<IModuleSpecifics>
            {
                new TenantsModuleSpecifics(),
                new AuditModuleSpecifics(),
                new CommunityModuleSpecifics(),
                new CalendarModuleSpecifics(),
                new ProjectsModuleSpecifics(),
                new CrmModuleSpecifics(),
                new FilesModuleSpecifics(),
                new MailModuleSpecifics(),
                new CrmModuleSpecifics2(),
                new FilesModuleSpecifics2(),
                new CrmInvoiceModuleSpecifics(),
                new WebStudioModuleSpecifics(),
                new CoreModuleSpecifics()
            }
            .ToList();

        public static IModuleSpecifics GetByStorageModule(string storageModuleName, string storageDomainName = null)
        {
            switch (storageModuleName)
            {
                case "files":
                    return AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Files);

                case "projects":
                    return AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Projects);

                case "crm":
                    return AllModules.FirstOrDefault(m => m.ModuleName == (storageDomainName == "mail_messages" ? ModuleName.Crm2 : ModuleName.Crm));

                case "forum":
                    return AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Community);

                case "mailaggregator":
                    return AllModules.FirstOrDefault(m => m.ModuleName == ModuleName.Mail);

                default:
                    return null;
            }
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Community/Bookmarks/BookmarkApi.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.Bookmarks;
using ASC.Api.Collections;
using ASC.Api.Exceptions;
using ASC.Bookmarking.Business;
using ASC.Bookmarking.Business.Permissions;
using ASC.Bookmarking.Pojo;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Web.Studio.UserControls.Common.Comments;
using ASC.Web.Studio.Utility.HtmlUtility;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;
using ASC.Web.UserControls.Bookmarking.Common.Util;

namespace ASC.Api.Community
{
    public partial class CommunityApi
    {
        private BookmarkingService _bookmarkingDao;

        private BookmarkingService BookmarkingDao
        {
            get { return _bookmarkingDao ?? (_bookmarkingDao = BookmarkingService.GetCurrentInstanse()); }
        }

        ///<summary>
        ///Returns the list of all bookmarks on the portal with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///All bookmarks
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>List of all bookmarks</returns>
        [Read("bookmark")]
        public IEnumerable<BookmarkWrapper> GetBookmarks()
        {
            var bookmarks = BookmarkingDao.GetAllBookmarks((int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of all bookmarks for the current user with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///Added by me
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>List of bookmarks</returns>
        [Read("bookmark/@self")]
        public IEnumerable<BookmarkWrapper> GetMyBookmarks()
        {
            var bookmarks = BookmarkingDao.GetBookmarksCreatedByUser(SecurityContext.CurrentAccount.ID, (int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns a list of bookmarks matching the search query with the bookmark title, date of creation and update, bookmark description and author
        ///</summary>
        ///<short>
        ///Search
        ///</short>
        ///<category>Bookmarks</category>
        /// <param name="query">search query</param>
        ///<returns>List of bookmarks</returns>
        [Read("bookmark/@search/{query}")]
        public IEnumerable<BookmarkWrapper> SearchBookmarks(string query)
        {
            var bookmarks = BookmarkingDao.SearchBookmarks(new List<string> { query }, (int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of favorite bookmarks for the current user with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///My favorite
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>List of bookmarks</returns>
        [Read("bookmark/@favs")]
        public IEnumerable<BookmarkWrapper> GetFavsBookmarks()
        {
            var bookmarks = BookmarkingDao.GetFavouriteBookmarksSortedByDate((int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns a list of all tags used for bookmarks with the number showing the tag usage
        ///</summary>
        ///<short>
        ///All tags
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>List of tags</returns>
        [Read("bookmark/tag")]
        public IEnumerable<TagWrapper> GetBookmarksTags()
        {
            var bookmarks = BookmarkingDao.GetAllTags();
            return bookmarks.Select(x => new TagWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of all bookmarks marked by the tag specified with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///By tag
        ///</short>
        ///<category>Bookmarks</category>
        ///<param name="tag">tag</param>
        ///<returns>List of bookmarks</returns>
        [Read("bookmark/bytag")]
        public IEnumerable<BookmarkWrapper> GetBookmarksByTag(string tag)
        {
            var bookmarks = BookmarkingDao.SearchBookmarksByTag(tag, (int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of recenty added bookmarks with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///Recently added
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>List of bookmarks</returns>
        [Read("bookmark/top/recent")]
        public IEnumerable<BookmarkWrapper> GetRecentBookmarks()
        {
            var bookmarks = BookmarkingDao.GetMostRecentBookmarks((int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of the bookmarks most popular on the current date with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///Top of day
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>List of bookmarks</returns>
        [Read("bookmark/top/day")]
        public IEnumerable<BookmarkWrapper> GetTopDayBookmarks()
        {
            var bookmarks = BookmarkingDao.GetTopOfTheDay((int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of the bookmarks most popular in the current month with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///Top of month
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>List of bookmarks</returns>
        [Read("bookmark/top/month")]
        public IEnumerable<BookmarkWrapper> GetTopMonthBookmarks()
        {
            var bookmarks = BookmarkingDao.GetTopOfTheMonth((int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of the bookmarks most popular on the current week with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///Top of week
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>list of bookmarks</returns>
        [Read("bookmark/top/week")]
        public IEnumerable<BookmarkWrapper> GetTopWeekBookmarks()
        {
            var bookmarks = BookmarkingDao.GetTopOfTheWeek((int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        ///Returns the list of the bookmarks most popular in the current year with the bookmark titles, date of creation and update, bookmark text and author
        ///</summary>
        ///<short>
        ///Top of year
        ///</short>
        ///<category>Bookmarks</category>
        ///<returns>list of bookmarks</returns>
        [Read("bookmark/top/year")]
        public IEnumerable<BookmarkWrapper> GetTopYearBookmarks()
        {
            var bookmarks = BookmarkingDao.GetTopOfTheYear((int)_context.StartIndex, (int)_context.Count);
            _context.SetDataPaginated();
            return bookmarks.Select(x => new BookmarkWrapper(x)).ToSmartList();
        }

        ///<summary>
        /// Returns the list of all comments to the bookmark with the specified ID
        ///</summary>
        ///<short>
        /// Get comments
        ///</short>
        ///<category>Bookmarks</category>
        ///<param name="id">Bookmark ID</param>
        ///<returns>list of bookmark comments</returns>
        [Read("bookmark/{id}/comment")]
        public IEnumerable<BookmarkCommentWrapper> GetBookmarkComments(long id)
        {
            var comments = BookmarkingDao.GetBookmarkComments(BookmarkingDao.GetBookmarkByID(id));
            return comments.Select(x => new BookmarkCommentWrapper(x)).ToSmartList();
        }

        ///<summary>
        /// Adds a comment to the bookmark with the specified ID. The parent bookmark ID can be also specified if needed.
        ///</summary>
        ///<short>
        /// Add comment
        ///</short>
        ///<param name="id">Bookmark ID</param>
        ///<param name="content">comment content</param>
        ///<param name="parentId">parent comment ID</param>
        ///<returns>list of bookmark comments</returns>
        /// <example>
        /// <![CDATA[
        /// Sending data in application/json:
        /// 
        /// {
        ///     content:"My comment",
        ///     parentId:"9924256A-739C-462b-AF15-E652A3B1B6EB"
        /// }
        /// 
        /// Sending data in application/x-www-form-urlencoded
        /// content="My comment"&parentId="9924256A-739C-462b-AF15-E652A3B1B6EB"
        /// ]]>
        /// </example>
        /// <remarks>
        /// Send parentId=00000000-0000-0000-0000-000000000000 or don't send it at all if you want your comment to be on the root level
        /// </remarks>
        /// <category>Bookmarks</category>
        [Create("bookmark/{id}/comment")]
        public BookmarkCommentWrapper AddBookmarkComment(long id, string content, Guid parentId)
        {
            var bookmark = BookmarkingDao.GetBookmarkByID(id);
            if (bookmark == null) throw new ItemNotFoundException("bookmark not found");

            var comment = new Comment
            {
                ID = Guid.NewGuid(),
                BookmarkID = id,
                Content = content,
                Datetime = DateTime.UtcNow,
                UserID = SecurityContext.CurrentAccount.ID,
                Parent = parentId.ToString()
            };
            BookmarkingDao.AddComment(comment);
            return new BookmarkCommentWrapper(comment);
        }

        ///<summary>
        /// Returns a detailed information on the bookmark with the specified ID
        ///</summary>
        ///<short>
        /// Get bookmarks by ID
        ///</short>
        ///<param name="id">Bookmark ID</param>
        ///<returns>bookmark</returns>
        ///<category>Bookmarks</category>
        [Read("bookmark/{id}")]
        public BookmarkWrapper GetBookmarkById(long id)
        {
            return new BookmarkWrapper(BookmarkingDao.GetBookmarkByID(id));
        }

        ///<summary>
        /// Adds a bookmark with a specified title, description and tags
        ///</summary>
        ///<short>
        /// Add bookmark
        ///</short>
        ///<param name="url">absolute url of bookmarking page</param>
        ///<param name="title">title to show</param>
        ///<param name="description">description</param>
        ///<param name="tags">tags. separated by semicolon</param>
        ///<returns>newly added bookmark</returns>
        /// <example>
        /// <![CDATA[
        /// Sending data in application/json:
        /// 
        /// {
        ///     url:"https://www.teamlab.com",
        ///     title: "TeamLab",
        ///     description: "best site i've ever seen",
        ///     tags: "project management, collaboration"
        /// }
        /// 
        /// Sending data in application/x-www-form-urlencoded
        /// url="https://www.teamlab.com"&title="TeamLab"&description="best site i've ever seen"&tags="project management, collaboration"
        /// ]]>
        /// </example>
        /// <category>Bookmarks</category>
        [Create("bookmark")]
        public BookmarkWrapper AddBookmark(string url, string title, string description, string tags)
        {
            try
            {
                var uri = new Uri(url, UriKind.Absolute);
            }
            catch (Exception)
            {
                throw new ArgumentException("invalid absolute url", "url");
            }

            if (string.IsNullOrEmpty(title))
            {
                throw new ArgumentException("title can't be empty", "title");
            }

            var bookmark = new Bookmark(url, TenantUtil.DateTimeNow(), title, description) { UserCreatorID = SecurityContext.CurrentAccount.ID };
            BookmarkingDao.AddBookmark(bookmark, !string.IsNullOrEmpty(tags) ? tags.Split(',').Select(x => new Tag { Name = x }).ToList() : new List<Tag>());
            return new BookmarkWrapper(bookmark);
        }


        /// <summary>
        /// Get comment preview with the content specified in the request
        /// </summary>
        /// <short>Get comment preview</short>
        /// <section>Comments</section>
        /// <param name="commentid">Comment ID</param>
        /// <param name="htmltext">Comment content</param>
        /// <returns>Comment info</returns>
        /// <category>Bookmarks</category>
        [Create("bookmark/comment/preview")]
        public CommentInfo GetBookmarkCommentPreview(string commentid, string htmltext)
        {
            var comment = new Comment
            {
                Datetime = TenantUtil.DateTimeNow(),
                UserID = SecurityContext.CurrentAccount.ID
            };

            if (!String.IsNullOrEmpty(commentid))
            {
                comment = BookmarkingServiceHelper.GetCurrentInstanse().GetCommentById(commentid);

                comment.Parent = string.Empty;
            }
            comment.Content = htmltext;

            var ci = BookmarkingConverter.ConvertComment(comment, new List<Comment>());
            ci.IsEditPermissions = false;
            ci.IsResponsePermissions = false;

            //var isRoot = string.IsNullOrEmpty(comment.Parent) || comment.Parent.Equals(Guid.Empty.ToString(), StringComparison.CurrentCultureIgnoreCase);

            return ci;
        }


        /// <summary>
        ///Remove comment with the id specified in the request
        /// </summary>
        /// <short>Remove comment</short>
        /// <section>Comments</section>
        /// <param name="commentid">Comment ID</param>
        /// <returns>Comment id</returns>
        /// <category>Bookmarks</category>
        [Delete("bookmark/comment/{commentid}")]
        public string RemoveBookmarkComment(string commentid)
        {
            var comment = BookmarkingServiceHelper.GetCurrentInstanse().GetCommentById(commentid);
            if (comment != null && BookmarkingPermissionsCheck.PermissionCheckEditComment(comment))
            {
                BookmarkingServiceHelper.GetCurrentInstanse().RemoveComment(commentid);
                return commentid;
            }
            return null;
        }

        /// <category>Bookmarks</category>
        [Create("bookmark/comment")]
        public CommentInfo AddBookmarkComment(string parentcommentid, long entityid, string content)
        {
            var comment = new Comment
            {
                Content = content,
                Datetime = TenantUtil.DateTimeNow(),
                UserID = SecurityContext.CurrentAccount.ID
            };

            var parentID = Guid.Empty;
            try
            {
                if (!string.IsNullOrEmpty(parentcommentid))
                {
                    parentID = new Guid(parentcommentid);
                }
            }
            catch
            {
                parentID = Guid.Empty;
            }
            comment.Parent = parentID.ToString();
            comment.BookmarkID = entityid;
            comment.ID = Guid.NewGuid();

            BookmarkingServiceHelper.GetCurrentInstanse().AddComment(comment);

            return BookmarkingConverter.ConvertComment(comment, new List<Comment>());
        }

        /// <category>Bookmarks</category>
        [Update("bookmark/comment/{commentid}")]
        public string UpdateBookmarkComment(string commentid, string content)
        {
            var comment = BookmarkingServiceHelper.GetCurrentInstanse().GetCommentById(commentid);
            if (comment == null || !BookmarkingPermissionsCheck.PermissionCheckEditComment(comment)) throw new ArgumentException();

            BookmarkingServiceHelper.GetCurrentInstanse().UpdateComment(commentid, content);
            return HtmlUtility.GetFull(content);
        }

        /// <summary>
        /// Removes bookmark from favourite. If after removing user bookmark raiting of this bookmark is 0, the bookmark will be removed completely.
        /// </summary>
        /// <short>Removes bookmark from favourite</short>
        /// <param name="id">Bookmark ID</param>
        /// <returns>bookmark</returns>
        /// <category>Bookmarks</category>
        [Delete("bookmark/@favs/{id}")]
        public BookmarkWrapper RemoveBookmarkFromFavourite(long id)
        {
            var bookmark = BookmarkingServiceHelper.GetCurrentInstanse().RemoveBookmarkFromFavourite(id);

            return bookmark == null ? null : new BookmarkWrapper(bookmark);
        }

        /// <summary>
        /// Removes bookmark
        /// </summary>
        /// <short>Removes bookmark</short>
        /// <param name="id">Bookmark ID</param>
        /// <category>Bookmarks</category>
        [Delete("bookmark/{id}")]
        public void RemoveBookmark(long id)
        {
            BookmarkingServiceHelper.GetCurrentInstanse().RemoveBookmark(id);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Settings.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.Web.CRM.Controls.Settings;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.CRM
{
    public partial class Settings : BasePage
    {
        protected string PageTitle { get; private set; }

        protected bool IsInvoiceItemsList { get; private set; }

        protected override void PageLoad()
        {
            if (!CRMSecurity.IsAdmin)
                Response.Redirect(PathProvider.StartURL());

            Page.RegisterBodyScripts(PathProvider.GetFileStaticRelativePath,
                                         "settings.js",
                                         "settings.invoices.js"
                                     );

            var typeValue = (HttpContext.Current.Request["type"] ?? "common").ToLower();
            ListItemView listItemViewControl;

            var headerView = (SettingsHeaderView)LoadControl(SettingsHeaderView.Location);

            switch (typeValue)
            {
                case "common":
                    PageTitle = CRMSettingResource.CommonSettings;

                    headerView.HeaderText = CRMSettingResource.ExportData;
                    TitleContentHolder.Controls.Add(headerView);

                    CommonContainerHolder.Controls.Add(LoadControl(CommonSettingsView.Location));
                    break;

                case "currency":
                    PageTitle = CRMSettingResource.CurrencySettings;

                    headerView.HeaderText = PageTitle;
                    TitleContentHolder.Controls.Add(headerView);

                    CommonContainerHolder.Controls.Add(LoadControl(CurrencySettingsView.Location));
                    break;

                case "deal_milestone":
                    PageTitle = CRMDealResource.DealMilestone;

                    headerView.HeaderText = PageTitle;
                    headerView.DescriptionText = CRMSettingResource.DescriptionTextDealMilestone;
                    headerView.DescriptionTextEditDelete = CRMSettingResource.DescriptionTextDealMilestoneEditDelete;
                    headerView.AddListButtonId = "createNewDealMilestone";
                    headerView.AddListButtonText = CRMSettingResource.CreateNewDealMilestoneListButton;
                    TitleContentHolder.Controls.Add(headerView);

                    CommonContainerHolder.Controls.Add(LoadControl(DealMilestoneView.Location));
                    break;

                case "task_category":
                    PageTitle = CRMTaskResource.TaskCategories;

                    headerView.HeaderText = PageTitle;
                    headerView.DescriptionText = CRMSettingResource.DescriptionTextTaskCategory;
                    headerView.DescriptionTextEditDelete = CRMSettingResource.DescriptionTextTaskCategoryEditDelete;
                    headerView.AddListButtonText = CRMSettingResource.CreateNewCategoryListButton;
                    TitleContentHolder.Controls.Add(headerView);

                    listItemViewControl = (ListItemView)LoadControl(ListItemView.Location);
                    listItemViewControl.CurrentTypeValue = ListType.TaskCategory;
                    listItemViewControl.AddButtonText = CRMSettingResource.AddThisCategory;
                    listItemViewControl.AddPopupWindowText = CRMSettingResource.CreateNewCategory;
                    listItemViewControl.AjaxProgressText = CRMSettingResource.CreateCategoryInProgressing;
                    listItemViewControl.DeleteText = CRMSettingResource.DeleteCategory;
                    listItemViewControl.EditText = CRMSettingResource.EditCategory;
                    listItemViewControl.EditPopupWindowText = CRMSettingResource.EditSelectedCategory;
                    CommonContainerHolder.Controls.Add(listItemViewControl);
                    break;

                case "history_category":
                    PageTitle = CRMSettingResource.HistoryCategories;

                    headerView.HeaderText = PageTitle;
                    headerView.DescriptionText = CRMSettingResource.DescriptionTextHistoryCategory;
                    headerView.DescriptionTextEditDelete = CRMSettingResource.DescriptionTextHistoryCategoryEditDelete;
                    headerView.AddListButtonText = CRMSettingResource.CreateNewCategoryListButton;
                    TitleContentHolder.Controls.Add(headerView);

                    listItemViewControl = (ListItemView)LoadControl(ListItemView.Location);
                    listItemViewControl.CurrentTypeValue = ListType.HistoryCategory;
                    listItemViewControl.AddButtonText = CRMSettingResource.AddThisCategory;
                    listItemViewControl.AddPopupWindowText = CRMSettingResource.CreateNewCategory;
                    listItemViewControl.AjaxProgressText = CRMSettingResource.CreateCategoryInProgressing;
                    listItemViewControl.DeleteText = CRMSettingResource.DeleteCategory;
                    listItemViewControl.EditText = CRMSettingResource.EditCategory;
                    listItemViewControl.EditPopupWindowText = CRMSettingResource.EditSelectedCategory;
                    CommonContainerHolder.Controls.Add(listItemViewControl);
                    break;

                case "contact_stage":
                    PageTitle = CRMContactResource.ContactStages;

                    headerView.HeaderText = PageTitle;
                    headerView.DescriptionText = CRMSettingResource.DescriptionTextContactStage;
                    headerView.DescriptionTextEditDelete = CRMSettingResource.DescriptionTextContactStageEditDelete;
                    headerView.AddListButtonText = CRMSettingResource.CreateNewStageListButton;
                    headerView.ShowContactStatusAskingDialog = true;
                    TitleContentHolder.Controls.Add(headerView);

                    listItemViewControl = (ListItemView)LoadControl(ListItemView.Location);
                    listItemViewControl.CurrentTypeValue = ListType.ContactStatus;
                    listItemViewControl.AddButtonText = CRMSettingResource.AddThisStage;
                    listItemViewControl.AddPopupWindowText = CRMSettingResource.CreateNewStage;
                    listItemViewControl.AjaxProgressText = CRMSettingResource.CreateContactStageInProgressing;
                    listItemViewControl.DeleteText = CRMSettingResource.DeleteContactStage;
                    listItemViewControl.EditText = CRMSettingResource.EditContactStage;
                    listItemViewControl.EditPopupWindowText = CRMSettingResource.EditSelectedContactStage;
                    CommonContainerHolder.Controls.Add(listItemViewControl);
                    break;

                case "contact_type":
                    PageTitle = CRMSettingResource.ContactTypes;

                    headerView.HeaderText = PageTitle;
                    headerView.DescriptionText = CRMSettingResource.DescriptionTextContactType;
                    headerView.DescriptionTextEditDelete = CRMSettingResource.DescriptionTextContactTypeEditDelete;
                    headerView.AddListButtonText = CRMSettingResource.CreateNewContactTypeListButton;
                    TitleContentHolder.Controls.Add(headerView);

                    listItemViewControl = (ListItemView)LoadControl(ListItemView.Location);
                    listItemViewControl.CurrentTypeValue = ListType.ContactType;
                    listItemViewControl.AddButtonText = CRMSettingResource.AddThisContactType;
                    listItemViewControl.AddPopupWindowText = CRMSettingResource.CreateNewContactType;
                    listItemViewControl.AjaxProgressText = CRMSettingResource.CreateContactTypeInProgressing;
                    listItemViewControl.DeleteText = CRMSettingResource.DeleteContactType;
                    listItemViewControl.EditText = CRMSettingResource.EditContactType;
                    listItemViewControl.EditPopupWindowText = CRMSettingResource.EditSelectedContactType;
                    CommonContainerHolder.Controls.Add(listItemViewControl);
                    break;

                case "tag":
                    PageTitle = CRMCommonResource.Tags;

                    headerView.HeaderText = PageTitle;
                    headerView.TabsContainerId = "TagSettingsTabs";
                    headerView.AddListButtonId = "createNewTagSettings";
                    headerView.AddListButtonText = CRMSettingResource.CreateNewTagListButton;
                    headerView.ShowTagAskingDialog = true;
                    TitleContentHolder.Controls.Add(headerView);

                    CommonContainerHolder.Controls.Add(LoadControl(TagSettingsView.Location));
                    break;

                case "web_to_lead_form":
                    PageTitle = CRMSettingResource.WebToLeadsForm;

                    CommonContainerHolder.Controls.Add(LoadControl(WebToLeadFormView.Location));
                    break;

                //case "task_template":
                //    PageTitle = CRMSettingResource.TaskTemplates;

                //    CommonContainerHolder.Controls.Add(LoadControl(TaskTemplateView.Location));
                //    break;

                case "invoice_items":

                    var actionValue = (HttpContext.Current.Request["action"] ?? "").ToLower();
                    if (!String.IsNullOrEmpty(actionValue) && actionValue == "manage")
                    {
                        var idParam = HttpContext.Current.Request["id"];
                        InvoiceItem targetInvoiceItem = null;

                        if (!String.IsNullOrEmpty(idParam))
                        {
                            targetInvoiceItem = DaoFactory.InvoiceItemDao.GetByID(Convert.ToInt32(idParam));
                            if (targetInvoiceItem == null)
                            {
                                Response.Redirect(PathProvider.StartURL() + "Settings.aspx?type=invoice_items");
                            }
                        }

                        PageTitle = targetInvoiceItem == null ?
                                              CRMInvoiceResource.CreateNewInvoiceItem :
                                              String.Format(CRMInvoiceResource.UpdateInvoiceItem, targetInvoiceItem.Title);

                        headerView.HeaderText = PageTitle;
                        TitleContentHolder.Controls.Add(headerView);

                        var invoiceProductsViewControl = (InvoiceItemActionView)LoadControl(InvoiceItemActionView.Location);
                        invoiceProductsViewControl.TargetInvoiceItem = targetInvoiceItem;
                        CommonContainerHolder.Controls.Add(invoiceProductsViewControl);
                    }
                    else
                    {
                        PageTitle = CRMCommonResource.ProductsAndServices;

                        headerView.HeaderText = PageTitle;
                        TitleContentHolder.Controls.Add(headerView);

                        IsInvoiceItemsList = true;

                        CommonContainerHolder.Controls.Add(LoadControl(InvoiceItemsView.Location));
                    }
                    break;

                case "invoice_tax":
                    PageTitle = CRMCommonResource.InvoiceTaxes;

                    headerView.HeaderText = PageTitle;
                    headerView.DescriptionText = CRMInvoiceResource.InvoiceTaxesDescriptionText;
                    headerView.DescriptionTextEditDelete = CRMInvoiceResource.InvoiceTaxesDescriptionTextEditDelete;
                    headerView.AddListButtonId = "createNewTax";
                    headerView.AddListButtonText = CRMInvoiceResource.CreateInvoiceTax;
                    TitleContentHolder.Controls.Add(headerView);

                    CommonContainerHolder.Controls.Add(LoadControl(InvoiceTaxesView.Location));
                    break;

                case "organisation_profile":
                    PageTitle = CRMCommonResource.OrganisationProfile;

                    CommonContainerHolder.Controls.Add(LoadControl(OrganisationProfile.Location));
                    break;

                case "voip.common":
                    PageTitle = CRMCommonResource.VoIPCommonSettings;

                    CommonContainerHolder.Controls.Add(LoadControl(VoipCommon.Location));
                    break;

                case "voip.numbers":
                    PageTitle = CRMCommonResource.VoIPNumbersSettings;

                    CommonContainerHolder.Controls.Add(LoadControl(VoipNumbers.Location));
                    break;

                default:
                    PageTitle = CRMSettingResource.CustomFields;

                    headerView.HeaderText = PageTitle;
                    headerView.TabsContainerId = "CustomFieldsTabs";
                    headerView.AddListButtonId = "createNewField";
                    headerView.AddListButtonText = CRMSettingResource.CreateNewFieldListButton;
                    TitleContentHolder.Controls.Add(headerView);

                    CommonContainerHolder.Controls.Add(LoadControl(CustomFieldsView.Location));
                    break;
            }

            Title = HeaderStringHelper.GetPageTitle(Master.CurrentPageCaption ?? PageTitle);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Domain/Reports/ReportFilter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Core.Tenants;

#endregion

namespace ASC.Projects.Core.Domain.Reports
{
    public class ReportFilter
    {
        public ReportTimeInterval TimeInterval { get; set; }

        public DateTime FromDate { get; set; }

        public DateTime ToDate { get; set; }


        public List<int> ProjectIds { get; set; }

        public int TagId { get; set; }

        public string ProjectTag { get; set; }

        public Guid UserId { get; set; }

        public Guid DepartmentId { get; set; }


        public List<ProjectStatus> ProjectStatuses { get; set; }

        public List<MilestoneStatus> MilestoneStatuses { get; set; }

        public MessageStatus? MessageStatus { get; set; }

        public List<TaskStatus> TaskStatuses { get; set; }

        public List<PaymentStatus> PaymentStatuses { get; set; }

        public int ViewType { get; set; }

        public bool NoResponsible { get; set; }


        public bool HasUserId
        {
            get { return UserId != default(Guid) || DepartmentId != default(Guid); }
        }

        public bool HasProjectIds
        {
            get { return 0 < ProjectIds.Count; }
        }

        public bool HasProjectStatuses
        {
            get { return 0 < ProjectStatuses.Count; }
        }

        public bool HasMilestoneStatuses
        {
            get { return 0 < MilestoneStatuses.Count; }
        }

        public virtual bool HasTaskStatuses
        {
            get { return 0 < TaskStatuses.Count && Substatus.HasValue; }
        }

        public int? Substatus { get; set; }

        public ReportFilter()
        {
            ToDate = DateTime.MaxValue;
            ProjectIds = new List<int>();
            ProjectStatuses = new List<ProjectStatus>();
            MilestoneStatuses = new List<MilestoneStatus>();
            TaskStatuses = new List<TaskStatus>();
            PaymentStatuses = new List<PaymentStatus>();
        }


        public void SetProjectIds(IEnumerable<int> ids)
        {
            ProjectIds.Clear();
            if (ids != null && ids.Any()) ProjectIds.AddRange(ids);
            else ProjectIds.Add(-1);
        }


        public List<string> GetUserIds()
        {
            var result = new List<string>();
            if (UserId != Guid.Empty)
            {
                result.Add(UserId.ToString());
            }
            else if (DepartmentId != Guid.Empty)
            {
                result.AddRange(CoreContext.UserManager.GetUsersByGroup(DepartmentId).Select(u => u.ID.ToString()));
            }
            return result;
        }

        public DateTime GetFromDate()
        {
            return GetFromDate(false);
        }

        public DateTime GetToDate()
        {
            return GetToDate(false);
        }

        public DateTime GetFromDate(bool toUtc)
        {
            var date = DateTime.MinValue;
            switch (TimeInterval)
            {
                case ReportTimeInterval.Absolute:
                    date = FromDate;
                    break;
                case ReportTimeInterval.Relative:
                    if (FromDate != DateTime.MinValue && FromDate != DateTime.MaxValue)
                    {
                        date = TenantUtil.DateTimeNow();
                    }
                    break;
                //Hack for Russian Standard Time
                case ReportTimeInterval.CurrYear:
                    date = GetDate(true);
                    date = date.AddHours(1);
                    break;
                default:
                    date = GetDate(true);
                    break;
            }
            if (date != DateTime.MinValue && date != DateTime.MaxValue && TimeInterval != ReportTimeInterval.CurrYear)
            {
                date = date.Date;
                if (toUtc) date = TenantUtil.DateTimeToUtc(date);
            }
            return date;
        }

        public DateTime GetToDate(bool toUtc)
        {
            var date = DateTime.MaxValue;
            switch (TimeInterval)
            {
                case ReportTimeInterval.Absolute:
                    date = ToDate;
                    break;
                case ReportTimeInterval.Relative:
                    if (FromDate != DateTime.MinValue && FromDate != DateTime.MaxValue && ToDate != DateTime.MinValue && ToDate != DateTime.MaxValue)
                    {
                        date = TenantUtil.DateTimeNow().Add(ToDate - FromDate);
                    }
                    break;
                default:
                    date = GetDate(false);
                    break;
            }
            if (date != DateTime.MinValue && date != DateTime.MaxValue)
            {
                date = date.Date.AddTicks(TimeSpan.TicksPerDay - 1);
                if (toUtc) date = TenantUtil.DateTimeToUtc(date);
            }
            return date;
        }

        private DateTime GetDate(bool start)
        {
            var date = TenantUtil.DateTimeNow();
            if (TimeInterval == ReportTimeInterval.Today)
            {
                return date;
            }
            if (TimeInterval == ReportTimeInterval.Yesterday)
            {
                return date.AddDays(-1);
            }
            if (TimeInterval == ReportTimeInterval.Tomorrow)
            {
                return date.AddDays(1);
            }
            if (TimeInterval == ReportTimeInterval.CurrWeek || TimeInterval == ReportTimeInterval.NextWeek || TimeInterval == ReportTimeInterval.PrevWeek)
            {
                var diff = CoreContext.TenantManager.GetCurrentTenant().GetCulture().DateTimeFormat.FirstDayOfWeek - date.DayOfWeek;
                if (0 < diff) diff -= 7;
                date = date.AddDays(diff);
                if (TimeInterval == ReportTimeInterval.NextWeek) date = date.AddDays(7);
                if (TimeInterval == ReportTimeInterval.PrevWeek) date = date.AddDays(-7);
                if (!start) date = date.AddDays(7).AddDays(-1);
                return date;
            }
            if (TimeInterval == ReportTimeInterval.CurrMonth || TimeInterval == ReportTimeInterval.NextMonth || TimeInterval == ReportTimeInterval.PrevMonth)
            {
                date = new DateTime(date.Year, date.Month, 1);
                if (TimeInterval == ReportTimeInterval.NextMonth) date = date.AddMonths(1);
                if (TimeInterval == ReportTimeInterval.PrevMonth) date = date.AddMonths(-1);
                if (!start) date = date.AddMonths(1).AddDays(-1);
                return date;
            }
            if (TimeInterval == ReportTimeInterval.CurrYear || TimeInterval == ReportTimeInterval.NextYear || TimeInterval == ReportTimeInterval.PrevYear)
            {
                date = new DateTime(date.Year, 1, 1);
                if (TimeInterval == ReportTimeInterval.NextYear) date = date.AddYears(1);
                if (TimeInterval == ReportTimeInterval.PrevYear) date = date.AddYears(-1);
                if (!start) date = date.AddYears(1).AddDays(-1);
                return date;
            }
            throw new ArgumentOutOfRangeException(string.Format("TimeInterval"));
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Projects/Wrappers/TaskLinkWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

using ASC.Projects.Core.Domain;

namespace ASC.Api.Projects.Wrappers
{
    public class TaskLinkWrapper
    {
        [DataMember]
        public int DependenceTaskId { get; set; }

        [DataMember]
        public int ParentTaskId { get; set; }

        [DataMember]
        public TaskLinkType LinkType { get; set; }

        public TaskLinkWrapper(TaskLink link)
        {
            DependenceTaskId = link.DependenceTaskId;
            ParentTaskId = link.ParentTaskId;
            LinkType = link.LinkType;
        }
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/RestorePortalTask.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Xml.Linq;

using ASC.Common.Caching;
using ASC.Common.Data;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Tenants;
using ASC.Data.Backup.Extensions;
using ASC.Data.Backup.Tasks.Modules;
using ASC.Data.Storage;

namespace ASC.Data.Backup.Tasks
{
    public class RestorePortalTask : PortalTaskBase
    {
        private readonly ColumnMapper _columnMapper;

        public string BackupFilePath { get; private set; }
        public string UpgradesPath { get; private set; }
        public bool UnblockPortalAfterCompleted { get; set; }
        public bool ReplaceDate { get; set; }
        public bool Dump { get; set; }

        public RestorePortalTask(ILog logger, string toConfigPath, string fromFilePath, ColumnMapper columnMapper = null, string upgradesPath = null)
            : this(logger, -1, toConfigPath, fromFilePath, columnMapper, upgradesPath)
        {

        }

        public RestorePortalTask(ILog logger, int tenantId, string toConfigPath, string fromFilePath, ColumnMapper columnMapper = null, string upgradesPath = null)
            : base(logger, tenantId, toConfigPath)
        {
            if (fromFilePath == null)
                throw new ArgumentNullException("fromFilePath");

            if (!File.Exists(fromFilePath))
                throw new FileNotFoundException("file not found at given path");

            BackupFilePath = fromFilePath;
            UpgradesPath = upgradesPath;
            _columnMapper = columnMapper ?? new ColumnMapper();
        }

        public override void RunJob()
        {
            Logger.Debug("begin restore portal");

            Logger.Debug("begin restore data");

            using (var dataReader = new ZipReadOperator(BackupFilePath))
            {
                using (var entry = dataReader.GetEntry(KeyHelper.GetDumpKey()))
                {
                    Dump = entry != null && CoreContext.Configuration.Standalone;
                }

                var dbFactory = new DbFactory(ConfigPath);
                if (Dump)
                {
                    RestoreFromDump(dataReader);
                }
                else
                {
                    var modulesToProcess = GetModulesToProcess().ToList();
                    SetStepsCount(ProcessStorage ? modulesToProcess.Count + 1 : modulesToProcess.Count);

                    foreach (var module in modulesToProcess)
                    {
                        var restoreTask = new RestoreDbModuleTask(Logger, module, dataReader, _columnMapper, dbFactory, ReplaceDate, Dump);
                        restoreTask.ProgressChanged += (sender, args) => SetCurrentStepProgress(args.Progress);
                        foreach (var tableName in IgnoredTables)
                        {
                            restoreTask.IgnoreTable(tableName);
                        }
                        restoreTask.RunJob();
                    }
                }

                Logger.Debug("end restore data");

                if (ProcessStorage)
                {
                    if (CoreContext.Configuration.Standalone)
                    {
                        Logger.Debug("clear cache");
                        AscCache.ClearCache();
                    }
                    DoRestoreStorage(dataReader);
                }
                if (UnblockPortalAfterCompleted)
                {
                    SetTenantActive(dbFactory, _columnMapper.GetTenantMapping());
                }
            }

            if (CoreContext.Configuration.Standalone)
            {
                Logger.Debug("refresh license");
                try
                {
                    LicenseReader.RejectLicense();
                }
                catch (Exception ex)
                {
                    Logger.Error(ex);
                }

                Logger.Debug("clear cache");
                AscCache.ClearCache();
            }

            Logger.Debug("end restore portal");
        }

        private void RestoreFromDump(IDataReadOperator dataReader)
        {
            var keyBase = KeyHelper.GetDatabaseSchema();
            var keys = dataReader.GetEntries(keyBase).Select(r=> Path.GetFileName(r)).ToList();
            var upgrades = new List<string>();

            var upgradesPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), UpgradesPath));
            if (!string.IsNullOrEmpty(upgradesPath) && Directory.Exists(upgradesPath))
            {
                upgrades = Directory.GetFiles(upgradesPath).ToList();
            }

            var stepscount = keys.Count * 2 + upgrades.Count;

            if (ProcessStorage)
            {
                var storageModules = StorageFactory.GetModuleList(ConfigPath).Where(IsStorageModuleAllowed);
                var tenants = CoreContext.TenantManager.GetTenants(false);

                stepscount += storageModules.Count() * tenants.Count;

                SetStepsCount(stepscount + 1);

                DoDeleteStorage(storageModules, tenants);
            }
            else
            {
                SetStepsCount(stepscount);
            }


            for (var i = 0; i < keys.Count; i += TasksLimit)
            {
                var tasks = new List<Task>(TasksLimit * 2);

                for (var j = 0; j < TasksLimit && i + j < keys.Count; j++)
                {
                    var key1 = Path.Combine(KeyHelper.GetDatabaseSchema(), keys[i + j]);
                    tasks.Add(RestoreFromDumpFile(dataReader, key1).ContinueWith(r => RestoreFromDumpFile(dataReader, KeyHelper.GetDatabaseData(key1.Substring(keyBase.Length + 1)))));
                }

                Task.WaitAll(tasks.ToArray());
            }

            var comparer = new SqlComparer();
            foreach (var u in upgrades.OrderBy(Path.GetFileName, comparer))
            {
                using (var s = File.OpenRead(u))
                {
                    if (u.Contains(".upgrade."))
                    {
                        RunMysqlFile(s, null).Wait();
                    }
                    else if (u.Contains(".data") || u.Contains(".upgrade"))
                    {
                        RunMysqlProcedure(s).Wait();
                    }
                    else
                    {
                        RunMysqlFile(s).Wait();
                    }
                }

                SetStepCompleted();
            }
        }

        private async Task RestoreFromDumpFile(IDataReadOperator dataReader, string fileName)
        {
            Logger.DebugFormat("Restore from {0}", fileName);
            using (var stream = dataReader.GetEntry(fileName))
            {
                await RunMysqlFile(stream);
            }
            SetStepCompleted();
        }

        private class SqlComparer : IComparer<string>
        {
            public int Compare(string x, string y)
            {
                if (x == y)
                {
                    return 0;
                }

                if (!string.IsNullOrEmpty(x))
                {
                    var splittedX = x.Split('.');
                    if (splittedX.Length <= 2) return -1;
                    if (splittedX[1] == "upgrade") return 1;

                    if (splittedX[1].StartsWith("upgrade") && !string.IsNullOrEmpty(y))
                    {
                        var splittedY = y.Split('.');
                        if (splittedY.Length <= 2) return 1;
                        if (splittedY[1] == "upgrade") return -1;

                        if (splittedY[1].StartsWith("upgrade"))
                        {
                            return string.Compare(x, y, StringComparison.Ordinal);
                        }

                        return -1;
                    }

                    return -1;
                }

                return string.Compare(x, y, StringComparison.Ordinal);
            }
        }

        private void DoRestoreStorage(IDataReadOperator dataReader)
        {
            Logger.Debug("begin restore storage");

            var fileGroups = GetFilesToProcess(dataReader).GroupBy(file => file.Module).ToList();
            var groupsProcessed = 0;
            foreach (var group in fileGroups)
            {
                foreach (var file in group)
                {
                    var storage = StorageFactory.GetStorage(ConfigPath, Dump ? file.Tenant.ToString() : _columnMapper.GetTenantMapping().ToString(), group.Key);
                    var quotaController = storage.QuotaController;
                    storage.SetQuotaController(null);

                    try
                    {
                        var adjustedPath = file.Path;
                        var module = ModuleProvider.GetByStorageModule(file.Module, file.Domain);
                        if (module == null || module.TryAdjustFilePath(Dump, _columnMapper, ref adjustedPath))
                        {
                            var key = file.GetZipKey();
                            if (Dump)
                            {
                                key = Path.Combine(KeyHelper.GetStorage(), key);
                            }
                            using (var stream = dataReader.GetEntry(key))
                            {
                                try
                                {
                                    storage.Save(file.Domain, adjustedPath, module != null ? module.PrepareData(key, stream, _columnMapper) : stream);
                                }
                                catch (Exception error)
                                {
                                    Logger.WarnFormat("can't restore file ({0}:{1}): {2}", file.Module, file.Path, error);
                                }
                            }
                        }
                    }
                    finally
                    {
                        if (quotaController != null)
                        {
                            storage.SetQuotaController(quotaController);
                        }
                    }
                }

                SetCurrentStepProgress((int)(++groupsProcessed * 100 / (double)fileGroups.Count));
            }

            if (fileGroups.Count == 0)
            {
                SetStepCompleted();
            }
            Logger.Debug("end restore storage");
        }

        private void DoDeleteStorage(IEnumerable<string> storageModules, IEnumerable<Tenant> tenants)
        {
            Logger.Debug("begin delete storage");

            foreach (var tenant in tenants)
            {
                foreach (var module in storageModules)
                {
                    var storage = StorageFactory.GetStorage(ConfigPath, tenant.TenantId.ToString(), module);
                    var domains = StorageFactory.GetDomainList(ConfigPath, module).ToList();

                    domains.Add(string.Empty); //instead storage.DeleteFiles("\\", "*.*", true);

                    foreach (var domain in domains)
                    {
                        ActionInvoker.Try(
                            state =>
                            {
                                if (storage.IsDirectory((string)state))
                                {
                                    storage.DeleteFiles((string)state, "\\", "*.*", true);
                                }
                            },
                            domain,
                            5,
                            onFailure: error => Logger.WarnFormat("Can't delete files for domain {0}: \r\n{1}", domain, error)
                        );
                    }

                    SetStepCompleted();
                }
            }

            Logger.Debug("end delete storage");
        }

        private static IEnumerable<BackupFileInfo> GetFilesToProcess(IDataReadOperator dataReader)
        {
            using (var stream = dataReader.GetEntry(KeyHelper.GetStorageRestoreInfoZipKey()))
            {
                if (stream == null)
                {
                    return Enumerable.Empty<BackupFileInfo>();
                }
                var restoreInfo = XElement.Load(new StreamReader(stream));
                return restoreInfo.Elements("file").Select(BackupFileInfo.FromXElement).ToList();
            }
        }

        private static void SetTenantActive(DbFactory dbFactory, int tenantId)
        {
            using (var connection = dbFactory.OpenConnection())
            {
                var commandText = string.Format(
                    "update tenants_tenants " +
                    "set " +
                    "  status={0}, " +
                    "  last_modified='{1}', " +
                    "  statuschanged='{1}' " +
                    "where id = '{2}'",
                    (int)TenantStatus.Active,
                    DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"),
                    tenantId);

                connection.CreateCommand(commandText).WithTimeout(120).ExecuteNonQuery();
            }
        }
    }
}


<|start_filename|>module/ASC.TelegramService/Launcher.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.ServiceModel;
using System.Threading.Tasks;

using ASC.Common.Logging;
using ASC.Common.Module;
using ASC.Core;
using ASC.FederatedLogin.LoginProviders;
using ASC.TelegramService.Core;

namespace ASC.TelegramService
{
    public class Launcher : IServiceController
    {
        public static TelegramHandler Handler { get; private set; }

        private ServiceHost _serviceHost;
        private readonly CommandModule command;

        private readonly ILog log = LogManager.GetLogger("ASC.Telegram");

        public Launcher()
        {
            command = new CommandModule(log);
            Handler = new TelegramHandler(command, log);
        }

        public void Start()
        {
            _ = Task.Run(CreateClients);
            _serviceHost = new ServiceHost(typeof(TelegramService));
            _serviceHost.Open();
        }

        public void Stop()
        {
            _serviceHost.Close();
            _serviceHost = null;
        }

        private void CreateClients()
        {
            var tenants = CoreContext.TenantManager.GetTenants();
            foreach (var tenant in tenants)
            {
                CoreContext.TenantManager.SetCurrentTenant(tenant);
                var consumer = TelegramLoginProvider.Instance;
                if (consumer.IsEnabled())
                {
                    Handler.CreateOrUpdateClientForTenant(tenant.TenantId, consumer.TelegramBotToken, consumer.TelegramAuthTokenLifespan, consumer.TelegramProxy, true);
                }
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Controls/Common/EmptyScreenControl.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ASC.Web.Studio.Controls.Common
{
    public class EmptyScreenControl : WebControl
    {
        public string ImgSrc { get; set; }

        public string Header { get; set; }

        public string HeaderDescribe { get; set; }

        public string Describe { get; set; }

        public string ButtonHTML { get; set; }

        protected override void Render(HtmlTextWriter writer)
        {
            var html = new StringBuilder();

            html.AppendFormat("<div id='{0}' class='noContentBlock emptyScrCtrl {1}' >", ID, !String.IsNullOrEmpty(CssClass) ? CssClass : String.Empty);
            if (!String.IsNullOrEmpty(ImgSrc))
            {
                html.AppendFormat("<table><tr><td><div style=\"background-image: url('{0}');\" class=\"emptyScrImage\" ></div></td>", ImgSrc)
                    .Append("<td><div class='emptyScrTd' >");
            }
            if (!String.IsNullOrEmpty(Header))
            {
                html.AppendFormat("<div class='header-base-big' >{0}</div>", Header);
            }
            if (!String.IsNullOrEmpty(HeaderDescribe))
            {
                html.AppendFormat("<div class='emptyScrHeadDscr' >{0}</div>", HeaderDescribe);
            }
            if (!String.IsNullOrEmpty(Describe))
            {
                html.AppendFormat("<div class='emptyScrDscr' >{0}</div>", Describe);
            }
            if (!String.IsNullOrEmpty(ButtonHTML))
            {
                html.AppendFormat("<div class='emptyScrBttnPnl' >{0}</div>", ButtonHTML);
            }
            if (!String.IsNullOrEmpty(ImgSrc))
            {
                html.Append("</div></td></tr></table>");
            }

            html.Append("</div>");

            writer.WriteLine(html.ToString());
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Community/Forums/ForumCategoryWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Forum;
using ASC.Specific;

namespace ASC.Api.Forums
{
    [DataContract(Name = "category", Namespace = "")]
    public class ForumCategoryWrapper : IApiSortableDate
    {
        [DataMember(Order = 0)]
        public int Id { get; set; }

        [DataMember(Order = 1)]
        public string Title { get; set; }

        [DataMember(Order = 2)]
        public ApiDateTime Created { get; set; }

        [DataMember(Order = 3)]
        public ApiDateTime Updated { get; set; }


        [DataMember(Order = 10)]
        public string Description { get; set; }

        public ForumCategoryWrapper(ThreadCategory category, IEnumerable<Thread> threads)
        {
            Id = category.ID;

            Title = category.Title;
            Updated = Created = (ApiDateTime)category.CreateDate;

            Description = category.Description;
            Threads = (from thread in threads where thread.IsApproved select new ForumThreadWrapper(thread)).ToList();
        }

        private ForumCategoryWrapper()
        {
        }

        [DataMember(Order = 100)]
        public List<ForumThreadWrapper> Threads { get; set; }

        public static ForumCategoryWrapper GetSample()
        {
            return new ForumCategoryWrapper()
            {
                Id = 0,
                Created = ApiDateTime.GetSample(),
                Description = "Sample category",
                Title = "Sample title",
                Updated = ApiDateTime.GetSample(),
                Threads = new List<ForumThreadWrapper> { ForumThreadWrapper.GetSample() }
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Settings/CurrencySettingsView.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.CRM.Core;
using ASC.Web.CRM.Classes;

namespace ASC.Web.CRM.Controls.Settings
{
    public partial class CurrencySettingsView : BaseUserControl
    {
        #region Property

        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Settings/CurrencySettingsView.ascx"); }
        }

        protected List<CurrencyInfo> BasicCurrencyRates { get; set; }
        protected List<CurrencyInfo> OtherCurrencyRates { get; set; }

        #endregion

        #region Events

        protected void Page_Load(object sender, EventArgs e)
        {
            BasicCurrencyRates = CurrencyProvider.GetBasic();
            OtherCurrencyRates = CurrencyProvider.GetOther();

            RegisterScript();
        }

        private void RegisterScript()
        {
            Page.JsonPublisher(DaoFactory.CurrencyRateDao.GetAll(), "currencyRates");
            Page.JsonPublisher(Global.TenantSettings.DefaultCurrency.Abbreviation, "defaultCurrency");

            Page.RegisterInlineScript("ASC.CRM.CurrencySettingsView.init();");
        }

        public bool IsSelectedBidCurrency(String abbreviation)
        {
            return string.Compare(abbreviation, Global.TenantSettings.DefaultCurrency.Abbreviation, StringComparison.OrdinalIgnoreCase) == 0;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Socket.IO/app/middleware/authService.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = () => {
    const 
        config = require('../../config'),
        crypto = require('crypto'),
        moment = require('moment');

    const skey = config.get("core.machinekey");
    const trustInterval = 5 * 60 * 1000;

    function check(req) {
        const authHeader = req.headers["authorization"] || req.cookies["authorization"];
        if(!authHeader) return false;

        const splitted = authHeader.split(':');
        if (splitted.length < 3) return false;

        const pkey = splitted[0].substr(4);
        const date = splitted[1];
        const orighash = splitted[2];

        const timestamp = moment.utc(date, "YYYYMMDDHHmmss");
        if (moment.utc() - timestamp > trustInterval) {
            return false;
        }

        const hasher = crypto.createHmac('sha1', skey);
        const hash = hasher.update(date + "\n" + pkey);

        if (hash.digest('base64') !== orighash) {
            return false;
        }

        return true;
    }

    return check;
};

<|start_filename|>web/studio/ASC.Web.Studio/PublicResources/StudioCountriesResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Studio.PublicResources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class StudioCountriesResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal StudioCountriesResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Studio.PublicResources.StudioCountriesResource", typeof(StudioCountriesResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Afghanistan (‫افغانستان‬&amp;lrm;).
        /// </summary>
        public static string Afghanistan {
            get {
                return ResourceManager.GetString("Afghanistan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Albania (Shqipëria).
        /// </summary>
        public static string Albania {
            get {
                return ResourceManager.GetString("Albania", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Algeria (‫الجزائر‬&amp;lrm;).
        /// </summary>
        public static string Algeria {
            get {
                return ResourceManager.GetString("Algeria", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to American Samoa (American Samoa).
        /// </summary>
        public static string AmericanSamoa {
            get {
                return ResourceManager.GetString("AmericanSamoa", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Andorra (Andorra).
        /// </summary>
        public static string Andorra {
            get {
                return ResourceManager.GetString("Andorra", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Angola (Angola).
        /// </summary>
        public static string Angola {
            get {
                return ResourceManager.GetString("Angola", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Anguilla (Anguilla).
        /// </summary>
        public static string Anguilla {
            get {
                return ResourceManager.GetString("Anguilla", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Antigua and Barbuda (Antigua and Barbuda).
        /// </summary>
        public static string AntiguaAndBarbuda {
            get {
                return ResourceManager.GetString("AntiguaAndBarbuda", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Argentina (Argentina).
        /// </summary>
        public static string Argentina {
            get {
                return ResourceManager.GetString("Argentina", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Armenia (Հայաստանի Հանրապետություն).
        /// </summary>
        public static string Armenia {
            get {
                return ResourceManager.GetString("Armenia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Aruba (Aruba).
        /// </summary>
        public static string Aruba {
            get {
                return ResourceManager.GetString("Aruba", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ascension Island (Ascension Island).
        /// </summary>
        public static string AscensionIsland {
            get {
                return ResourceManager.GetString("AscensionIsland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Australia (Australia).
        /// </summary>
        public static string Australia {
            get {
                return ResourceManager.GetString("Australia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Austria (Österreich).
        /// </summary>
        public static string Austria {
            get {
                return ResourceManager.GetString("Austria", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Azerbaijan (Azərbaycan).
        /// </summary>
        public static string Azerbaijan {
            get {
                return ResourceManager.GetString("Azerbaijan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bahamas (Bahamas).
        /// </summary>
        public static string Bahamas {
            get {
                return ResourceManager.GetString("Bahamas", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bahrain (‫البحرين‬&amp;lrm;).
        /// </summary>
        public static string Bahrain {
            get {
                return ResourceManager.GetString("Bahrain", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bangladesh (বাংলাদেশ).
        /// </summary>
        public static string Bangladesh {
            get {
                return ResourceManager.GetString("Bangladesh", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Barbados (Barbados).
        /// </summary>
        public static string Barbados {
            get {
                return ResourceManager.GetString("Barbados", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Belarus (Беларусь).
        /// </summary>
        public static string Belarus {
            get {
                return ResourceManager.GetString("Belarus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Belgium (België).
        /// </summary>
        public static string Belgium {
            get {
                return ResourceManager.GetString("Belgium", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Belize (Belize).
        /// </summary>
        public static string Belize {
            get {
                return ResourceManager.GetString("Belize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Benin (Bénin).
        /// </summary>
        public static string Benin {
            get {
                return ResourceManager.GetString("Benin", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bermuda (Bermuda).
        /// </summary>
        public static string Bermuda {
            get {
                return ResourceManager.GetString("Bermuda", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bhutan (འབྲུག).
        /// </summary>
        public static string Bhutan {
            get {
                return ResourceManager.GetString("Bhutan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bolivia (Bolivia).
        /// </summary>
        public static string Bolivia {
            get {
                return ResourceManager.GetString("Bolivia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bonaire, Sint Eustatius and Saba (Caribbean Netherlands).
        /// </summary>
        public static string BonaireSintEustatiusAndSaba {
            get {
                return ResourceManager.GetString("BonaireSintEustatiusAndSaba", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bosnia and Herzegovina (Bosna i Hercegovina).
        /// </summary>
        public static string BosniaAndHerzegovina {
            get {
                return ResourceManager.GetString("BosniaAndHerzegovina", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Botswana (Botswana).
        /// </summary>
        public static string Botswana {
            get {
                return ResourceManager.GetString("Botswana", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Brazil (Brasil).
        /// </summary>
        public static string Brazil {
            get {
                return ResourceManager.GetString("Brazil", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to British Indian Ocean Territory (British Indian Ocean Territory).
        /// </summary>
        public static string BritishIndianOceanTerritory {
            get {
                return ResourceManager.GetString("BritishIndianOceanTerritory", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to British Virgin Islands (British Virgin Islands).
        /// </summary>
        public static string BritishVirginIslands {
            get {
                return ResourceManager.GetString("BritishVirginIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Brunei Darussalam (Brunei).
        /// </summary>
        public static string BruneiDarussalam {
            get {
                return ResourceManager.GetString("BruneiDarussalam", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bulgaria (България).
        /// </summary>
        public static string Bulgaria {
            get {
                return ResourceManager.GetString("Bulgaria", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Burkina Faso (Burkina Faso).
        /// </summary>
        public static string BurkinaFaso {
            get {
                return ResourceManager.GetString("BurkinaFaso", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Burundi (Uburundi).
        /// </summary>
        public static string Burundi {
            get {
                return ResourceManager.GetString("Burundi", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cambodia (កម្ពុជា).
        /// </summary>
        public static string Cambodia {
            get {
                return ResourceManager.GetString("Cambodia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cameroon (Cameroun).
        /// </summary>
        public static string Cameroon {
            get {
                return ResourceManager.GetString("Cameroon", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Canada (Canada).
        /// </summary>
        public static string Canada {
            get {
                return ResourceManager.GetString("Canada", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cape Verde (Kabu Verdi).
        /// </summary>
        public static string CapeVerde {
            get {
                return ResourceManager.GetString("CapeVerde", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cayman Islands (Cayman Islands).
        /// </summary>
        public static string CaymanIslands {
            get {
                return ResourceManager.GetString("CaymanIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Central African Republic (République centrafricaine).
        /// </summary>
        public static string CentralAfricanRepublic {
            get {
                return ResourceManager.GetString("CentralAfricanRepublic", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Chad (Tchad).
        /// </summary>
        public static string Chad {
            get {
                return ResourceManager.GetString("Chad", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Chile (Chile).
        /// </summary>
        public static string Chile {
            get {
                return ResourceManager.GetString("Chile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to China (中国).
        /// </summary>
        public static string China {
            get {
                return ResourceManager.GetString("China", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Colombia (Colombia).
        /// </summary>
        public static string Colombia {
            get {
                return ResourceManager.GetString("Colombia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comoros (‫جزر القمر‬&amp;lrm;).
        /// </summary>
        public static string Comoros {
            get {
                return ResourceManager.GetString("Comoros", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Congo-Brazzaville (Congo-Brazzaville).
        /// </summary>
        public static string CongoBrazzaville {
            get {
                return ResourceManager.GetString("CongoBrazzaville", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cook Islands (Cook Islands).
        /// </summary>
        public static string CookIslands {
            get {
                return ResourceManager.GetString("CookIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Costa Rica (Costa Rica).
        /// </summary>
        public static string CostaRica {
            get {
                return ResourceManager.GetString("CostaRica", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Croatia (Hrvatska).
        /// </summary>
        public static string Croatia {
            get {
                return ResourceManager.GetString("Croatia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cuba (Cuba).
        /// </summary>
        public static string Cuba {
            get {
                return ResourceManager.GetString("Cuba", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Curacao (Curaçao).
        /// </summary>
        public static string Curacao {
            get {
                return ResourceManager.GetString("Curacao", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cyprus (Κύπρος).
        /// </summary>
        public static string Cyprus {
            get {
                return ResourceManager.GetString("Cyprus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Czech Republic (Česká republika).
        /// </summary>
        public static string CzechRepublic {
            get {
                return ResourceManager.GetString("CzechRepublic", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Denmark (Danmark).
        /// </summary>
        public static string Denmark {
            get {
                return ResourceManager.GetString("Denmark", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Djibouti (Djibouti).
        /// </summary>
        public static string Djibouti {
            get {
                return ResourceManager.GetString("Djibouti", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Dominica (Dominica).
        /// </summary>
        public static string Dominica {
            get {
                return ResourceManager.GetString("Dominica", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Dominican Republic (República Dominicana).
        /// </summary>
        public static string DominicanRepublic {
            get {
                return ResourceManager.GetString("DominicanRepublic", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ecuador (Ecuador).
        /// </summary>
        public static string Ecuador {
            get {
                return ResourceManager.GetString("Ecuador", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Egypt (‫مصر‬&amp;lrm;).
        /// </summary>
        public static string Egypt {
            get {
                return ResourceManager.GetString("Egypt", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to El Salvador (El Salvador).
        /// </summary>
        public static string ElSalvador {
            get {
                return ResourceManager.GetString("ElSalvador", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Equatorial Guinea (Guinea Ecuatorial).
        /// </summary>
        public static string EquatorialGuinea {
            get {
                return ResourceManager.GetString("EquatorialGuinea", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Eritrea (Eritrea).
        /// </summary>
        public static string Eritrea {
            get {
                return ResourceManager.GetString("Eritrea", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Estonia (Eesti).
        /// </summary>
        public static string Estonia {
            get {
                return ResourceManager.GetString("Estonia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ethiopia (Ethiopia).
        /// </summary>
        public static string Ethiopia {
            get {
                return ResourceManager.GetString("Ethiopia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Faroe Islands (Føroyar).
        /// </summary>
        public static string FaroeIslands {
            get {
                return ResourceManager.GetString("FaroeIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Fiji (Fiji).
        /// </summary>
        public static string Fiji {
            get {
                return ResourceManager.GetString("Fiji", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Finland (Suomi).
        /// </summary>
        public static string Finland {
            get {
                return ResourceManager.GetString("Finland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to France (France).
        /// </summary>
        public static string France {
            get {
                return ResourceManager.GetString("France", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to French Guiana (Guyane française).
        /// </summary>
        public static string FrenchGuiana {
            get {
                return ResourceManager.GetString("FrenchGuiana", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to French Polynesia (Polynésie française).
        /// </summary>
        public static string FrenchPolynesia {
            get {
                return ResourceManager.GetString("FrenchPolynesia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Gabon (Gabon).
        /// </summary>
        public static string Gabon {
            get {
                return ResourceManager.GetString("Gabon", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Gambia (Gambia).
        /// </summary>
        public static string Gambia {
            get {
                return ResourceManager.GetString("Gambia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Georgia (საქართველო).
        /// </summary>
        public static string Georgia {
            get {
                return ResourceManager.GetString("Georgia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Germany (Deutschland).
        /// </summary>
        public static string Germany {
            get {
                return ResourceManager.GetString("Germany", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ghana (Gaana).
        /// </summary>
        public static string Ghana {
            get {
                return ResourceManager.GetString("Ghana", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Gibraltar (Gibraltar).
        /// </summary>
        public static string Gibraltar {
            get {
                return ResourceManager.GetString("Gibraltar", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Greece (Ελλάδα).
        /// </summary>
        public static string Greece {
            get {
                return ResourceManager.GetString("Greece", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Greenland (Greenland).
        /// </summary>
        public static string Greenland {
            get {
                return ResourceManager.GetString("Greenland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Grenada (Grenada).
        /// </summary>
        public static string Grenada {
            get {
                return ResourceManager.GetString("Grenada", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Guadeloupe (Guadeloupe).
        /// </summary>
        public static string Guadeloupe {
            get {
                return ResourceManager.GetString("Guadeloupe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Guam (Guam).
        /// </summary>
        public static string Guam {
            get {
                return ResourceManager.GetString("Guam", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Guatemala (Guatemala).
        /// </summary>
        public static string Guatemala {
            get {
                return ResourceManager.GetString("Guatemala", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Guinea (Guinée).
        /// </summary>
        public static string Guinea {
            get {
                return ResourceManager.GetString("Guinea", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Guinea-Bissau (Guiné Bissau).
        /// </summary>
        public static string GuineaBissau {
            get {
                return ResourceManager.GetString("GuineaBissau", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Guyana (Guyana).
        /// </summary>
        public static string Guyana {
            get {
                return ResourceManager.GetString("Guyana", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Haiti (Haiti).
        /// </summary>
        public static string Haiti {
            get {
                return ResourceManager.GetString("Haiti", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Honduras (Honduras).
        /// </summary>
        public static string Honduras {
            get {
                return ResourceManager.GetString("Honduras", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Hong Kong (香港).
        /// </summary>
        public static string HongKong {
            get {
                return ResourceManager.GetString("HongKong", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Hungary (Magyarország).
        /// </summary>
        public static string Hungary {
            get {
                return ResourceManager.GetString("Hungary", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Iceland (Ísland).
        /// </summary>
        public static string Iceland {
            get {
                return ResourceManager.GetString("Iceland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to India (भारत).
        /// </summary>
        public static string India {
            get {
                return ResourceManager.GetString("India", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Indonesia (Indonesia).
        /// </summary>
        public static string Indonesia {
            get {
                return ResourceManager.GetString("Indonesia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Iran (‫ایران‬&amp;lrm;).
        /// </summary>
        public static string Iran {
            get {
                return ResourceManager.GetString("Iran", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Iraq (‫العراق‬&amp;lrm;).
        /// </summary>
        public static string Iraq {
            get {
                return ResourceManager.GetString("Iraq", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ireland (Ireland).
        /// </summary>
        public static string Ireland {
            get {
                return ResourceManager.GetString("Ireland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Israel (‫ישראל‬&amp;lrm;).
        /// </summary>
        public static string Israel {
            get {
                return ResourceManager.GetString("Israel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Italy (Italia).
        /// </summary>
        public static string Italy {
            get {
                return ResourceManager.GetString("Italy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ivory Coast (Côte d’Ivoire).
        /// </summary>
        public static string IvoryCoast {
            get {
                return ResourceManager.GetString("IvoryCoast", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Jamaica (Jamaica).
        /// </summary>
        public static string Jamaica {
            get {
                return ResourceManager.GetString("Jamaica", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Japan (日本).
        /// </summary>
        public static string Japan {
            get {
                return ResourceManager.GetString("Japan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Jordan (‫الأردن‬&amp;lrm;).
        /// </summary>
        public static string Jordan {
            get {
                return ResourceManager.GetString("Jordan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Kazakhstan (Казахстан).
        /// </summary>
        public static string Kazakhstan {
            get {
                return ResourceManager.GetString("Kazakhstan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Kenya (Kenya).
        /// </summary>
        public static string Kenya {
            get {
                return ResourceManager.GetString("Kenya", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Kiribati (Kiribati).
        /// </summary>
        public static string Kiribati {
            get {
                return ResourceManager.GetString("Kiribati", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Kuwait (‫الكويت‬&amp;lrm;).
        /// </summary>
        public static string Kuwait {
            get {
                return ResourceManager.GetString("Kuwait", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Kyrgyzstan (Kyrgyzstan).
        /// </summary>
        public static string Kyrgyzstan {
            get {
                return ResourceManager.GetString("Kyrgyzstan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Laos (ສ.ປ.ປ ລາວ).
        /// </summary>
        public static string Laos {
            get {
                return ResourceManager.GetString("Laos", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Latvia (Latvija).
        /// </summary>
        public static string Latvia {
            get {
                return ResourceManager.GetString("Latvia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Lebanon (‫لبنان‬&amp;lrm;).
        /// </summary>
        public static string Lebanon {
            get {
                return ResourceManager.GetString("Lebanon", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Lesotho (Lesotho).
        /// </summary>
        public static string Lesotho {
            get {
                return ResourceManager.GetString("Lesotho", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Liberia (Liberia).
        /// </summary>
        public static string Liberia {
            get {
                return ResourceManager.GetString("Liberia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Libya (‫ليبيا‬&amp;lrm;).
        /// </summary>
        public static string Libya {
            get {
                return ResourceManager.GetString("Libya", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Liechtenstein (Liechtenstein).
        /// </summary>
        public static string Liechtenstein {
            get {
                return ResourceManager.GetString("Liechtenstein", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Lithuania (Lietuva).
        /// </summary>
        public static string Lithuania {
            get {
                return ResourceManager.GetString("Lithuania", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Luxembourg (Luxembourg).
        /// </summary>
        public static string Luxembourg {
            get {
                return ResourceManager.GetString("Luxembourg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Macau (澳門).
        /// </summary>
        public static string Macau {
            get {
                return ResourceManager.GetString("Macau", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Macedonia (Македонија).
        /// </summary>
        public static string Macedonia {
            get {
                return ResourceManager.GetString("Macedonia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Madagascar (Madagasikara).
        /// </summary>
        public static string Madagascar {
            get {
                return ResourceManager.GetString("Madagascar", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Malawi (Malawi).
        /// </summary>
        public static string Malawi {
            get {
                return ResourceManager.GetString("Malawi", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Malaysia (Malaysia).
        /// </summary>
        public static string Malaysia {
            get {
                return ResourceManager.GetString("Malaysia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Maldives (Maldives).
        /// </summary>
        public static string Maldives {
            get {
                return ResourceManager.GetString("Maldives", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mali (Mali).
        /// </summary>
        public static string Mali {
            get {
                return ResourceManager.GetString("Mali", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Malta (Malta).
        /// </summary>
        public static string Malta {
            get {
                return ResourceManager.GetString("Malta", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Malvinas (Falkland Islands [Islas Malvinas]).
        /// </summary>
        public static string Malvinas {
            get {
                return ResourceManager.GetString("Malvinas", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Marshall Islands (Marshall Islands).
        /// </summary>
        public static string MarshallIslands {
            get {
                return ResourceManager.GetString("MarshallIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Martinique (Martinique).
        /// </summary>
        public static string Martinique {
            get {
                return ResourceManager.GetString("Martinique", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mauritania (‫موريتانيا‬&amp;lrm;).
        /// </summary>
        public static string Mauritania {
            get {
                return ResourceManager.GetString("Mauritania", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mauritius (Moris).
        /// </summary>
        public static string Mauritius {
            get {
                return ResourceManager.GetString("Mauritius", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mexico (México).
        /// </summary>
        public static string Mexico {
            get {
                return ResourceManager.GetString("Mexico", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Micronesia (Micronesia).
        /// </summary>
        public static string Micronesia {
            get {
                return ResourceManager.GetString("Micronesia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Moldova (Republica Moldova).
        /// </summary>
        public static string Moldova {
            get {
                return ResourceManager.GetString("Moldova", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Monaco (Monaco).
        /// </summary>
        public static string Monaco {
            get {
                return ResourceManager.GetString("Monaco", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mongolia (Mongolia).
        /// </summary>
        public static string Mongolia {
            get {
                return ResourceManager.GetString("Mongolia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Montenegro (Crna Gora).
        /// </summary>
        public static string Montenegro {
            get {
                return ResourceManager.GetString("Montenegro", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Montserrat (Montserrat).
        /// </summary>
        public static string Montserrat {
            get {
                return ResourceManager.GetString("Montserrat", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Morocco (‫المغرب‬&amp;lrm;).
        /// </summary>
        public static string Morocco {
            get {
                return ResourceManager.GetString("Morocco", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mozambique (Moçambique).
        /// </summary>
        public static string Mozambique {
            get {
                return ResourceManager.GetString("Mozambique", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Myanmar [Burma] (မြန်မာ).
        /// </summary>
        public static string Myanmar {
            get {
                return ResourceManager.GetString("Myanmar", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Namibia (Namibia).
        /// </summary>
        public static string Namibia {
            get {
                return ResourceManager.GetString("Namibia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nauru (Nauru).
        /// </summary>
        public static string Nauru {
            get {
                return ResourceManager.GetString("Nauru", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nepal (नेपाल).
        /// </summary>
        public static string Nepal {
            get {
                return ResourceManager.GetString("Nepal", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Netherlands (Nederland).
        /// </summary>
        public static string Netherlands {
            get {
                return ResourceManager.GetString("Netherlands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Caledonia (Nouvelle-Calédonie).
        /// </summary>
        public static string NewCaledonia {
            get {
                return ResourceManager.GetString("NewCaledonia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Zealand (New Zealand).
        /// </summary>
        public static string NewZealand {
            get {
                return ResourceManager.GetString("NewZealand", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nicaragua (Nicaragua).
        /// </summary>
        public static string Nicaragua {
            get {
                return ResourceManager.GetString("Nicaragua", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Niger (Nijar).
        /// </summary>
        public static string Niger {
            get {
                return ResourceManager.GetString("Niger", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nigeria (Nigeria).
        /// </summary>
        public static string Nigeria {
            get {
                return ResourceManager.GetString("Nigeria", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Niue (Niue).
        /// </summary>
        public static string Niue {
            get {
                return ResourceManager.GetString("Niue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Norfolk Island (Norfolk Island).
        /// </summary>
        public static string NorfolkIsland {
            get {
                return ResourceManager.GetString("NorfolkIsland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Northern Mariana Islands (Northern Mariana Islands).
        /// </summary>
        public static string NorthernMarianaIslands {
            get {
                return ResourceManager.GetString("NorthernMarianaIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to North Korea (조선 민주주의 인민 공화국).
        /// </summary>
        public static string NorthKorea {
            get {
                return ResourceManager.GetString("NorthKorea", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Norway (Norge).
        /// </summary>
        public static string Norway {
            get {
                return ResourceManager.GetString("Norway", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Oman (‫عُمان‬&amp;lrm;).
        /// </summary>
        public static string Oman {
            get {
                return ResourceManager.GetString("Oman", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Pakistan (‫پاکستان‬&amp;lrm;).
        /// </summary>
        public static string Pakistan {
            get {
                return ResourceManager.GetString("Pakistan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Palau (Palau).
        /// </summary>
        public static string Palau {
            get {
                return ResourceManager.GetString("Palau", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Palestine (‫فلسطين‬&amp;lrm;).
        /// </summary>
        public static string Palestine {
            get {
                return ResourceManager.GetString("Palestine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Panama (Panamá).
        /// </summary>
        public static string Panama {
            get {
                return ResourceManager.GetString("Panama", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Papua New Guinea (Papua New Guinea).
        /// </summary>
        public static string PapuaNewGuinea {
            get {
                return ResourceManager.GetString("PapuaNewGuinea", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Paraguay (Paraguay).
        /// </summary>
        public static string Paraguay {
            get {
                return ResourceManager.GetString("Paraguay", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Peru (Perú).
        /// </summary>
        public static string Peru {
            get {
                return ResourceManager.GetString("Peru", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Philippines (Philippines).
        /// </summary>
        public static string Philippines {
            get {
                return ResourceManager.GetString("Philippines", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Poland (Polska).
        /// </summary>
        public static string Poland {
            get {
                return ResourceManager.GetString("Poland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Portugal (Portugal).
        /// </summary>
        public static string Portugal {
            get {
                return ResourceManager.GetString("Portugal", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Puerto Rico (Puerto Rico).
        /// </summary>
        public static string PuertoRico {
            get {
                return ResourceManager.GetString("PuertoRico", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Qatar (‫قطر‬&amp;lrm;).
        /// </summary>
        public static string Qatar {
            get {
                return ResourceManager.GetString("Qatar", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Republic of Korea (대한민국).
        /// </summary>
        public static string RepublicOfKorea {
            get {
                return ResourceManager.GetString("RepublicOfKorea", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reunion (Réunion).
        /// </summary>
        public static string Reunion {
            get {
                return ResourceManager.GetString("Reunion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Romania (România).
        /// </summary>
        public static string Romania {
            get {
                return ResourceManager.GetString("Romania", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Russia (Россия).
        /// </summary>
        public static string Russia {
            get {
                return ResourceManager.GetString("Russia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Rwanda (Rwanda).
        /// </summary>
        public static string Rwanda {
            get {
                return ResourceManager.GetString("Rwanda", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saint Barthélemy (Saint-Barthélémy).
        /// </summary>
        public static string SaintBarthelemy {
            get {
                return ResourceManager.GetString("SaintBarthelemy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saint Helena (Saint Helena).
        /// </summary>
        public static string SaintHelena {
            get {
                return ResourceManager.GetString("SaintHelena", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saint Kitts and Nevis (Saint Kitts and Nevis).
        /// </summary>
        public static string SaintKittsAndNevis {
            get {
                return ResourceManager.GetString("SaintKittsAndNevis", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saint Lucia (Saint Lucia).
        /// </summary>
        public static string SaintLucia {
            get {
                return ResourceManager.GetString("SaintLucia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saint Martin Island (Saint-Martin [partie française]).
        /// </summary>
        public static string SaintMartinIsland {
            get {
                return ResourceManager.GetString("SaintMartinIsland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon).
        /// </summary>
        public static string SaintPierreAndMiquelon {
            get {
                return ResourceManager.GetString("SaintPierreAndMiquelon", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saint Vincent and the Grenadines (Saint Vincent and the Grenadines).
        /// </summary>
        public static string SaintVincentAndTheGrenadines {
            get {
                return ResourceManager.GetString("SaintVincentAndTheGrenadines", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Samoa (Samoa).
        /// </summary>
        public static string Samoa {
            get {
                return ResourceManager.GetString("Samoa", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to San Marino (San Marino).
        /// </summary>
        public static string SanMarino {
            get {
                return ResourceManager.GetString("SanMarino", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sao Tome and Principe (São Tomé e Príncipe).
        /// </summary>
        public static string SaoTomeAndPrincipe {
            get {
                return ResourceManager.GetString("SaoTomeAndPrincipe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saudi Arabia (‫المملكة العربية السعودية‬&amp;lrm;).
        /// </summary>
        public static string SaudiArabia {
            get {
                return ResourceManager.GetString("SaudiArabia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Senegal (Sénégal).
        /// </summary>
        public static string Senegal {
            get {
                return ResourceManager.GetString("Senegal", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Serbia (Србија).
        /// </summary>
        public static string Serbia {
            get {
                return ResourceManager.GetString("Serbia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Seychelles (Seychelles).
        /// </summary>
        public static string Seychelles {
            get {
                return ResourceManager.GetString("Seychelles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sierra Leone (Sierra Leone).
        /// </summary>
        public static string SierraLeone {
            get {
                return ResourceManager.GetString("SierraLeone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Singapore (Singapore).
        /// </summary>
        public static string Singapore {
            get {
                return ResourceManager.GetString("Singapore", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sint Maarten (Sint Maarten).
        /// </summary>
        public static string SintMaarten {
            get {
                return ResourceManager.GetString("SintMaarten", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Slovakia (Slovensko).
        /// </summary>
        public static string Slovakia {
            get {
                return ResourceManager.GetString("Slovakia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Slovenia (Slovenija).
        /// </summary>
        public static string Slovenia {
            get {
                return ResourceManager.GetString("Slovenia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Solomon Islands (Solomon Islands).
        /// </summary>
        public static string SolomonIslands {
            get {
                return ResourceManager.GetString("SolomonIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Somalia (Soomaaliya).
        /// </summary>
        public static string Somalia {
            get {
                return ResourceManager.GetString("Somalia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to South Africa (South Africa).
        /// </summary>
        public static string SouthAfrica {
            get {
                return ResourceManager.GetString("SouthAfrica", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to South Sudan (‫جنوب السودان‬&amp;lrm;).
        /// </summary>
        public static string SouthSudan {
            get {
                return ResourceManager.GetString("SouthSudan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Spain (España).
        /// </summary>
        public static string Spain {
            get {
                return ResourceManager.GetString("Spain", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sri Lanka (ශ්&amp;zwj;රී ලංකාව).
        /// </summary>
        public static string SriLanka {
            get {
                return ResourceManager.GetString("SriLanka", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sudan (‫السودان‬&amp;lrm;).
        /// </summary>
        public static string Sudan {
            get {
                return ResourceManager.GetString("Sudan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Suriname (Suriname).
        /// </summary>
        public static string Suriname {
            get {
                return ResourceManager.GetString("Suriname", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Swaziland (Swaziland).
        /// </summary>
        public static string Swaziland {
            get {
                return ResourceManager.GetString("Swaziland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sweden (Sverige).
        /// </summary>
        public static string Sweden {
            get {
                return ResourceManager.GetString("Sweden", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Switzerland (Schweiz).
        /// </summary>
        public static string Switzerland {
            get {
                return ResourceManager.GetString("Switzerland", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Syria (‫سوريا‬&amp;lrm;).
        /// </summary>
        public static string Syria {
            get {
                return ResourceManager.GetString("Syria", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Taiwan (台灣).
        /// </summary>
        public static string Taiwan {
            get {
                return ResourceManager.GetString("Taiwan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tajikistan (Tajikistan).
        /// </summary>
        public static string Tajikistan {
            get {
                return ResourceManager.GetString("Tajikistan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tanzania (Tanzania).
        /// </summary>
        public static string Tanzania {
            get {
                return ResourceManager.GetString("Tanzania", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Thailand (ไทย).
        /// </summary>
        public static string Thailand {
            get {
                return ResourceManager.GetString("Thailand", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The Democratic Republic of the Congo (Jamhuri ya Kidemokrasia ya Kongo).
        /// </summary>
        public static string TheDemocraticRepublicOfTheCongo {
            get {
                return ResourceManager.GetString("TheDemocraticRepublicOfTheCongo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Timor-Leste (Timor-Leste).
        /// </summary>
        public static string TimorLeste {
            get {
                return ResourceManager.GetString("TimorLeste", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Togo (Togo).
        /// </summary>
        public static string Togo {
            get {
                return ResourceManager.GetString("Togo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tokelau (Tokelau).
        /// </summary>
        public static string Tokelau {
            get {
                return ResourceManager.GetString("Tokelau", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tonga (Tonga).
        /// </summary>
        public static string Tonga {
            get {
                return ResourceManager.GetString("Tonga", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Trinidad and Tobago (Trinidad and Tobago).
        /// </summary>
        public static string TrinidadAndTobago {
            get {
                return ResourceManager.GetString("TrinidadAndTobago", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tunisia (‫تونس‬&amp;lrm;).
        /// </summary>
        public static string Tunisia {
            get {
                return ResourceManager.GetString("Tunisia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Turkey (Türkiye).
        /// </summary>
        public static string Turkey {
            get {
                return ResourceManager.GetString("Turkey", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Turkmenistan (Turkmenistan).
        /// </summary>
        public static string Turkmenistan {
            get {
                return ResourceManager.GetString("Turkmenistan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Turks and Caicos Islands (Turks and Caicos Islands).
        /// </summary>
        public static string TurksAndCaicosIslands {
            get {
                return ResourceManager.GetString("TurksAndCaicosIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tuvalu (Tuvalu).
        /// </summary>
        public static string Tuvalu {
            get {
                return ResourceManager.GetString("Tuvalu", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uganda (Uganda).
        /// </summary>
        public static string Uganda {
            get {
                return ResourceManager.GetString("Uganda", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to UK (United Kingdom).
        /// </summary>
        public static string UK {
            get {
                return ResourceManager.GetString("UK", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ukraine (Україна).
        /// </summary>
        public static string Ukraine {
            get {
                return ResourceManager.GetString("Ukraine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to United Arab Emirates (‫الإمارات العربية المتحدة‬&amp;lrm;).
        /// </summary>
        public static string UnitedArabEmirates {
            get {
                return ResourceManager.GetString("UnitedArabEmirates", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to United States (United States).
        /// </summary>
        public static string UnitedStates {
            get {
                return ResourceManager.GetString("UnitedStates", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uruguay (Uruguay).
        /// </summary>
        public static string Uruguay {
            get {
                return ResourceManager.GetString("Uruguay", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to US Virgin Islands (US Virgin Islands).
        /// </summary>
        public static string USVirginIslands {
            get {
                return ResourceManager.GetString("USVirginIslands", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uzbekistan (Ўзбекистон).
        /// </summary>
        public static string Uzbekistan {
            get {
                return ResourceManager.GetString("Uzbekistan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Vanuatu (Vanuatu).
        /// </summary>
        public static string Vanuatu {
            get {
                return ResourceManager.GetString("Vanuatu", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Vatican City (Città del Vaticano).
        /// </summary>
        public static string VaticanCity {
            get {
                return ResourceManager.GetString("VaticanCity", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Venezuela (Venezuela).
        /// </summary>
        public static string Venezuela {
            get {
                return ResourceManager.GetString("Venezuela", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Vietnam (Việt Nam).
        /// </summary>
        public static string Vietnam {
            get {
                return ResourceManager.GetString("Vietnam", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Wallis and Futuna (Wallis and Futuna).
        /// </summary>
        public static string WallisAndFutuna {
            get {
                return ResourceManager.GetString("WallisAndFutuna", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Yemen (‫اليمن‬&amp;lrm;).
        /// </summary>
        public static string Yemen {
            get {
                return ResourceManager.GetString("Yemen", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Zambia (Zambia).
        /// </summary>
        public static string Zambia {
            get {
                return ResourceManager.GetString("Zambia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Zimbabwe (Zimbabwe).
        /// </summary>
        public static string Zimbabwe {
            get {
                return ResourceManager.GetString("Zimbabwe", resourceCulture);
            }
        }
    }
}


<|start_filename|>common/ASC.ActiveDirectory/Base/Settings/LdapSettingsStatus.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.ActiveDirectory.Base.Settings
{
    public enum LdapSettingsStatus
    {
        Ok = 0,
        WrongServerOrPort = 1,
        WrongUserDn = 2,
        IncorrectLDAPFilter = 3,
        UsersNotFound = 4,
        WrongLoginAttribute = 5,
        WrongGroupDn = 6,
        IncorrectGroupLDAPFilter = 7,
        GroupsNotFound = 8,
        WrongGroupAttribute = 9,
        WrongUserAttribute = 10,
        WrongGroupNameAttribute = 11,
        CredentialsNotValid = 12,
        ConnectError = 13,
        StrongAuthRequired = 14,
        WrongSidAttribute = 15,
        CertificateRequest = 16,
        TlsNotSupported = 17,
        DomainNotFound = 18
    }
}


<|start_filename|>module/ASC.Mail/Services/ASC.Mail.Reloader/Program.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Threading;
using ASC.Common.Logging;
using ASC.Mail.Clients;
using ASC.Mail.Core;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Core.Engine;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Enums;
using ASC.Mail.Utils;
using MimeKit;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace ASC.Mail.Reloader
{
    internal partial class Program
    {
        private static void Main(string[] args)
        {
            var options = new Options();

            if (!CommandLine.Parser.Default.ParseArgumentsStrict(args, options,
                () => Console.WriteLine(@"Bad command line parameters.")))
            {
                ShowAnyKey();
                return;
            }

            try
            {
                var reloadList = new Dictionary<int, List<int>>();

                if (!string.IsNullOrEmpty(options.PathToJson) && File.Exists(options.PathToJson))
                {
                    using (var streamReader = new StreamReader(options.PathToJson))
                    {
                        using (var reader = new JsonTextReader(streamReader))
                        {
                            var jObject = JObject.Load(reader);

                            if (jObject["data"] == null || !jObject["data"].Any())
                            {
                                Console.WriteLine(@"[ERROR] json tasks not found. Array is empty.");

                                ShowAnyKey();
                                return;
                            }

                            var results = jObject["data"].ToList().GroupBy(
                                p => Convert.ToInt32(p["id_mailbox"]),
                                p => Convert.ToInt32(p["id"]),
                                (key, g) => new {MailboxId = key, Ids = g.ToList()});

                            foreach (var result in results)
                            {
                                if(reloadList.ContainsKey(result.MailboxId))
                                    continue;

                                reloadList.Add(result.MailboxId, result.Ids);
                            }
                        }
                    }
                }
                else
                {
                    if (options.MailboxId < 0)
                    {
                        Console.WriteLine(@"[ERROR] MailboxId invalid.");

                        ShowAnyKey();
                        return;
                    }

                    if (options.MessageId < 0)
                    {
                        Console.WriteLine(@"[ERROR] MailboxId invalid.");

                        ShowAnyKey();
                        return;
                    }


                    reloadList.Add(options.MailboxId, new List<int> {options.MessageId});
                }

                foreach (var reloadItem in reloadList)
                {
                    MailClient client = null;

                    try
                    {
                        var mailboxId = reloadItem.Key;

                        Console.WriteLine(@"Searching account with id {0}", mailboxId);

                        var mailbox = GetMailBox(mailboxId);

                        if (mailbox == null)
                        {
                            Console.WriteLine(@"[ERROR] Account not found.");
                            ShowAnyKey();
                            return;
                        }

                        var messageIds = reloadItem.Value;

                        foreach (var messageId in messageIds)
                        {
                            Console.WriteLine(@"Searching message with id {0}", messageId);

                            if (messageId < 0)
                            {
                                Console.WriteLine(@"[ERROR] MessageId not setup.");
                                continue;
                            }

                            var storedMessage = GetMail(mailbox, messageId);

                            if (storedMessage == null)
                            {
                                Console.WriteLine(@"[ERROR] Message not found.");
                                continue;
                            }

                            var messageUid = storedMessage.Uidl;

                            if (mailbox.Imap)
                            {
                                var uidlStucture = ParserImapUidl(messageUid);
                                if (uidlStucture.folderId != FolderType.Inbox)
                                {
                                    Console.WriteLine(@"Only inbox messages are supported for downloading.");
                                    continue;
                                }
                            }

                            var certificatePermit = ConfigurationManager.AppSettings["mail.certificate-permit"] !=
                                                    null &&
                                                    Convert.ToBoolean(
                                                        ConfigurationManager.AppSettings["mail.certificate-permit"]);

                            var log = new NullLog();

                            if (client == null)
                                client = new MailClient(mailbox, CancellationToken.None,
                                    certificatePermit: certificatePermit);

                            MimeMessage mimeMessage;

                            try
                            {
                                mimeMessage = client.GetInboxMessage(messageUid);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(@"[ERROR] Failed GetInboxMessage(""{0}"") Exception: {1}", messageUid, e);
                                continue;
                            }

                            MailMessageData message;

                            try
                            {
                                message = mimeMessage.ConvertToMailMessage(new MailFolder(FolderType.Inbox, ""),
                                    storedMessage.IsNew, storedMessage.ChainId, storedMessage.ChainDate,
                                    storedMessage.StreamId, mailboxId, false, log);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(@"[ERROR] Failed ConvertToMailMessage(""{0}"") Exception: {1}",
                                    messageUid, ex);
                                continue;
                            }

                            if (!storedMessage.From.Equals(MailUtil.NormalizeStringForMySql(message.From)) ||
                                !storedMessage.To.Equals(MailUtil.NormalizeStringForMySql(message.To)) ||
                                !storedMessage.Subject.Equals(MailUtil.NormalizeStringForMySql(message.Subject)))
                            {
                                Console.WriteLine(@"storedMessage.From = '{0}'", storedMessage.From);
                                Console.WriteLine(@"message.From = '{0}'",
                                    MailUtil.NormalizeStringForMySql(message.From));

                                Console.WriteLine(@"storedMessage.To = '{0}'", storedMessage.To);
                                Console.WriteLine(@"message.To = '{0}'",
                                    MailUtil.NormalizeStringForMySql(message.To));

                                Console.WriteLine(@"storedMessage.Subject = '{0}'", storedMessage.Subject);
                                Console.WriteLine(@"message.Subject = '{0}'",
                                    MailUtil.NormalizeStringForMySql(message.Subject));

                                Console.WriteLine(@"[ERROR] Stored message not equals to server message");
                                continue;
                            }

                            if (storedMessage.Attachments.Any() && message.Attachments.Any())
                            {
                                var newAttachments = new List<MailAttachmentData>();

                                foreach (var attachment in message.Attachments)
                                {
                                    var storedAttachment =
                                        storedMessage.Attachments.FirstOrDefault(
                                            a =>
                                                (!string.IsNullOrEmpty(a.fileName) &&
                                                 a.fileName.Equals(attachment.fileName,
                                                     StringComparison.InvariantCultureIgnoreCase)) ||
                                                !string.IsNullOrEmpty(a.contentId) &&
                                                a.contentId.Equals(attachment.contentId,
                                                    StringComparison.InvariantCultureIgnoreCase) ||
                                                !string.IsNullOrEmpty(a.contentLocation) &&
                                                a.contentLocation.Equals(attachment.contentLocation,
                                                    StringComparison.InvariantCultureIgnoreCase));

                                    if (storedAttachment == null)
                                        continue;

                                    attachment.fileName = storedAttachment.fileName;
                                    attachment.storedName = storedAttachment.storedName;
                                    attachment.fileNumber = storedAttachment.fileNumber;
                                    attachment.streamId = storedAttachment.streamId;
                                    attachment.mailboxId = storedAttachment.mailboxId;
                                    attachment.tenant = storedAttachment.tenant;
                                    attachment.user = storedAttachment.user;

                                    newAttachments.Add(attachment);
                                }

                                message.Attachments = newAttachments;
                            }

                            if (!MessageEngine.TryStoreMailData(message, mailbox, log))
                            {
                                Console.WriteLine(@"[ERROR] Failed to store mail data");
                                continue;
                            }

                            Console.WriteLine(@"[SUCCESS] Mail ""{0}"" data was reloaded", messageId);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                    finally
                    {
                        if (client != null)
                        {
                            client.Dispose();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            ShowAnyKey();
        }

        private static void ShowAnyKey()
        {
            Console.WriteLine();
            Console.WriteLine(@"Any key to exit...");
            Console.ReadKey();
        }

        private struct ImapUidl
        {
            public FolderType folderId;
#pragma warning disable 414
            public int uid;
#pragma warning restore 414
        }

        private static ImapUidl ParserImapUidl(string uidl)
        {
            var elements = uidl.Split('-');

            return new ImapUidl
            {
                uid = Convert.ToInt32(elements[0]),
                folderId = (FolderType) Convert.ToInt32(elements[1])
            };
        }

        private static MailMessageData GetMail(MailBoxData mailbox, int mailId)
        {
            var engine = new EngineFactory(mailbox.TenantId, mailbox.UserId);

            return engine.MessageEngine.GetMessage(mailId, new MailMessageData.Options
            {
                LoadBody = false,
                LoadImages = false,
                NeedProxyHttp = false,
                NeedSanitizer = false,
                OnlyUnremoved = true,
                LoadEmebbedAttachements = true
            });
        }

        private static MailBoxData GetMailBox(int mailboxId)
        {
            var engine = new EngineFactory(-1);
            return engine.MailboxEngine.GetMailboxData(new ConcreteSimpleMailboxExp(mailboxId));
        }
    }
}


<|start_filename|>module/ASC.Socket.IO/app/apiRequestManager.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


const apiBasePath = "/api/2.0/",
    portalManager = require('./portalManager.js'),
    request = require('request'),
    log = require("./log.js");

function makeRequest(apiMethod, req, options, onSuccess){
    makeHeaders(req, options);
    options.uri = getBasePath(req) + apiMethod;
    log.info(options.uri);

    return new Promise((resolve, reject) => {
        request(options, (error, response, body) => {
            let result = {};
            try {
                result = typeof body === "string" ? JSON.parse(body) : body;
            } catch (err) {
                log.error(options.uri, err);
            }

            error = checkError(error, response, result);
            if(error) {
                log.error(options.uri, error);
                if (error == 401 && req.session) {
                    req.session.destroy(() => reject(error));
                    return
                } else {
                    reject(error);
                    return;
                }
            }

            resolve(onSuccess(result));
        });
    });
}

function makeHeaders(req, options) {
	options.gzip = true;
    options.headers = {};
    
    if (req.cookies && req.cookies['asc_auth_key']) {
        options.headers["Authorization"] = req.cookies['asc_auth_key'];
    }

    if (req.headers) {
        const xRewriterUrlHeader = 'x-rewriter-url',
            xForwardedForHeader = 'x-forwarded-for';

        if (req.headers[xRewriterUrlHeader]) {
            options.headers[xRewriterUrlHeader] = req.headers[xRewriterUrlHeader];
        }
        if (req.headers[xForwardedForHeader]) {
            options.headers[xForwardedForHeader] = req.headers[xForwardedForHeader];
        }
    }
}

function getBasePath(req) {
    return portalManager(req).replace(/\/$/g, '') + apiBasePath;
}

function checkError(error, response, result) {
    if (error) {
        return error;
    }
    
    if (result && result.error && result.error.message) {
        return result.error.message;
    }

    if (response.statusCode > 400) {
        return response.statusCode;
    }
}

class RequestManager {
    constructor() { }

    makeRequest(apiMethod, req, options) {
        return makeRequest(apiMethod, req, options, (result) => {
            return typeof result.response !== "undefined" ? result.response : result;
        });
    }
    get(apiMethod, req, body) {
        if (body) {
            apiMethod = `${apiMethod}?`;
            for (const item in body) {
                if (body.hasOwnProperty(item)) {
                    apiMethod = `${apiMethod}${item}=${body[item]}&`;
                }
            }
            apiMethod = apiMethod.substring(0, apiMethod.length - 1);
        }
        return this.makeRequest(apiMethod, req, { method: "GET" });
    }
    post(apiMethod, req, body) {
        return this.makeRequest(apiMethod, req, { method: "POST", body, json: true });
    }
    put(apiMethod, req, body) {
        return this.makeRequest(apiMethod, req, { method: "PUT", body, json: true });
    }
    dlt(apiMethod, req, body) {
        const options = { method: "DELETE" };
        if (typeof body !== "undefined") {
            options.body = req.body;
            options.json = true;
        }
        return this.makeRequest(apiMethod, req, options);
    }
    batch(batchMethod, req){
        const options = { 
            method: "POST", 
            form:{ batch: JSON.stringify(batchMethod.methods) }, 
            json: true
        };

        return makeRequest("batch.json", req, options, (result) => {
            const resultResponse = result.response;
            if(result.response !== "undefined" && Array.isArray(result.response)) {
                let data = [];

                for(let i = 0, j = resultResponse.length; i < j; i++){
                    const dataItem = typeof resultResponse[i].data === "string" ? JSON.parse(resultResponse[i].data) : resultResponse[i].data
                    data.push(dataItem.response);
                }

                return data;
            }

            return result;
        });
    }
    batchFactory(){
        return new batchFactory();
    }
}

class batchFactory {
    constructor() { 
        this.methods = [];
    }
    get(url) {
        this.methods.push({method: "get", RelativeUrl: `${apiBasePath}${url}`});
        return this;
    }
}

module.exports = new RequestManager();

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTP_SendStream.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements RTP session send stream.
    /// </summary>
    public class RTP_SendStream
    {
        #region Events

        /// <summary>
        /// Is raised when stream is closed.
        /// </summary>
        public event EventHandler Closed = null;

        /// <summary>
        /// Is raised when stream has disposed.
        /// </summary>
        public event EventHandler Disposed = null;

        #endregion

        #region Members

        private bool m_IsDisposed;
        private uint m_LastPacketRtpTimestamp;
        private DateTime m_LastPacketTime;
        private RTP_Source_Local m_pSource;
        private int m_RtcpCyclesSinceWeSent = 9999;
        private long m_RtpBytesSent;
        private long m_RtpDataBytesSent;
        private long m_RtpPacketsSent;
        private int m_SeqNo;
        private int m_SeqNoWrapCount;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get { return m_IsDisposed; }
        }

        /// <summary>
        /// Gets stream owner RTP session.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public RTP_Session Session
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pSource.Session;
            }
        }

        /// <summary>
        /// Gets stream owner source.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public RTP_Source Source
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pSource;
            }
        }

        /// <summary>
        /// Gets number of times <b>SeqNo</b> has wrapped around.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public int SeqNoWrapCount
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_SeqNoWrapCount;
            }
        }

        /// <summary>
        /// Gets next packet sequence number.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public int SeqNo
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_SeqNo;
            }
        }

        /// <summary>
        /// Gets last packet send time.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public DateTime LastPacketTime
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_LastPacketTime;
            }
        }

        /// <summary>
        /// Gets last sent RTP packet RTP timestamp header value.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public uint LastPacketRtpTimestamp
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_LastPacketRtpTimestamp;
            }
        }

        /// <summary>
        /// Gets how many RTP packets has sent by this stream.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public long RtpPacketsSent
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_RtpPacketsSent;
            }
        }

        /// <summary>
        /// Gets how many RTP bytes has sent by this stream.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public long RtpBytesSent
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_RtpBytesSent;
            }
        }

        /// <summary>
        /// Gets how many RTP data(no RTP header included) bytes has sent by this stream.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public long RtpDataBytesSent
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_RtpDataBytesSent;
            }
        }

        /// <summary>
        /// Gets how many RTCP cycles has passed since we sent data.
        /// </summary>
        internal int RtcpCyclesSinceWeSent
        {
            get { return m_RtcpCyclesSinceWeSent; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="source">Owner RTP source.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>source</b> is null reference.</exception>
        internal RTP_SendStream(RTP_Source_Local source)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            m_pSource = source;

            /* RFC 3550 4.
                The initial value of the sequence number SHOULD be random (unpredictable) to make known-plaintext 
                attacks on encryption more difficult.
            */
            m_SeqNo = new Random().Next(1, Workaround.Definitions.MaxStreamLineLength);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Closes this sending stream.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        public void Close()
        {
            Close(null);
        }

        /// <summary>
        /// Closes this sending stream.
        /// </summary>
        /// <param name="closeReason">Stream closing reason text what is reported to the remote party. Value null means not specified.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        public void Close(string closeReason)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            m_pSource.Close(closeReason);

            OnClosed();
            Dispose();
        }

        /// <summary>
        /// Sends specified packet to the RTP session remote party.
        /// </summary>
        /// <param name="packet">RTP packet.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>packet</b> is null reference.</exception>
        /// <remarks>Properties <b>packet.SSRC</b>,<b>packet.SeqNo</b>,<b>packet.PayloadType</b> filled by this method automatically.</remarks>
        public void Send(RTP_Packet packet)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (packet == null)
            {
                throw new ArgumentNullException("packet");
            }

            // RTP was designed around the concept of Application Level Framing (ALF), 
            // because of it we only allow to send packets and don't deal with breaking frames into packets.

            packet.SSRC = Source.SSRC;
            packet.SeqNo = NextSeqNo();
            packet.PayloadType = Session.Payload;

            // Send RTP packet.
            m_RtpBytesSent += m_pSource.SendRtpPacket(packet);

            m_RtpPacketsSent++;
            m_RtpDataBytesSent += packet.Data.Length;
            m_LastPacketTime = DateTime.Now;
            m_LastPacketRtpTimestamp = packet.Timestamp;
            m_RtcpCyclesSinceWeSent = 0;
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        private void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            m_IsDisposed = true;

            m_pSource = null;

            OnDisposed();

            Disposed = null;
            Closed = null;
        }

        /// <summary>
        /// Gets next packet sequence number.
        /// </summary>
        /// <returns>Returns next packet sequence number.</returns>
        private ushort NextSeqNo()
        {
            // Wrap around sequence number.
            if (m_SeqNo >= ushort.MaxValue)
            {
                m_SeqNo = 0;
                m_SeqNoWrapCount++;
            }

            return (ushort) m_SeqNo++;
        }

        /// <summary>
        /// Raises <b>Disposed</b> event.
        /// </summary>
        private void OnDisposed()
        {
            if (Disposed != null)
            {
                Disposed(this, new EventArgs());
            }
        }

        /// <summary>
        /// Raises <b>Closed</b> event.
        /// </summary>
        private void OnClosed()
        {
            if (Closed != null)
            {
                Closed(this, new EventArgs());
            }
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Is called by RTP session if RTCP cycle compled.
        /// </summary>
        internal void RtcpCycle()
        {
            m_RtcpCyclesSinceWeSent++;
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Common/Utils/Signature.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Script.Serialization;

using ASC.Security.Cryptography;

namespace ASC.Common.Utils
{
    public static class Signature
    {
        public static string Create<T>(T obj)
        {
            return Create(obj, Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()));
        }

        public static string Create<T>(T obj, string secret)
        {
            var serializer = new JavaScriptSerializer();
            var str = serializer.Serialize(obj);
            var payload = GetHashBase64(str + secret) + "?" + str;
            return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(payload));
        }

        public static T Read<T>(string signature)
        {
            return Read<T>(signature, Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()));
        }

        public static T Read<T>(string signature, string secret)
        {
            try
            {
                var payloadParts = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(signature)).Split('?');
                if (GetHashBase64(payloadParts[1] + secret) == payloadParts[0])
                {
                    //Sig correct
                    return new JavaScriptSerializer().Deserialize<T>(payloadParts[1]);
                }
            }
            catch (Exception)
            {
            }
            return default(T);
        }

        private static string GetHashBase64(string str)
        {
            return Convert.ToBase64String(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(str)));
        }

        private static string GetHashBase64MD5(string str)
        {
            return Convert.ToBase64String(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(str)));
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Users/UserFormatter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Threading;

namespace ASC.Core.Users
{
    public class UserFormatter : IComparer<UserInfo>
    {
        private readonly DisplayUserNameFormat format;
        private static bool forceFormatChecked;
        private static string forceFormat;


        public UserFormatter()
            : this(DisplayUserNameFormat.Default)
        {
        }

        public UserFormatter(DisplayUserNameFormat format)
        {
            this.format = format;
        }


        public static string GetUserName(UserInfo userInfo, DisplayUserNameFormat format)
        {
            if (userInfo == null) throw new ArgumentNullException("userInfo");
            return string.Format(GetUserDisplayFormat(format), userInfo.FirstName, userInfo.LastName);
        }

        public static string GetUserName(string firstName, string lastName)
        {
            if (string.IsNullOrEmpty(firstName) || string.IsNullOrEmpty(lastName)) throw new ArgumentException();

            return string.Format(GetUserDisplayFormat(DisplayUserNameFormat.Default), firstName, lastName);
        }

        public static string GetUserName(UserInfo userInfo)
        {
            return GetUserName(userInfo, DisplayUserNameFormat.Default);
        }

        int IComparer<UserInfo>.Compare(UserInfo x, UserInfo y)
        {
            return Compare(x, y, format);
        }

        public static int Compare(UserInfo x, UserInfo y)
        {
            return Compare(x, y, DisplayUserNameFormat.Default);
        }

        public static int Compare(UserInfo x, UserInfo y, DisplayUserNameFormat format)
        {
            if (x == null && y == null) return 0;
            if (x == null && y != null) return -1;
            if (x != null && y == null) return +1;

            var result = 0;
            if (format == DisplayUserNameFormat.Default) format = GetUserDisplayDefaultOrder();
            if (format == DisplayUserNameFormat.FirstLast)
            {
                result = String.Compare(x.FirstName, y.FirstName, true);
                if (result == 0) result = String.Compare(x.LastName, y.LastName, true);
            }
            else
            {
                result = String.Compare(x.LastName, y.LastName, true);
                if (result == 0) result = String.Compare(x.FirstName, y.FirstName, true);
            }
            return result;
        }

        private static readonly Dictionary<string, Dictionary<DisplayUserNameFormat, string>> DisplayFormats = new Dictionary<string, Dictionary<DisplayUserNameFormat, string>>
        {
            { "ru", new Dictionary<DisplayUserNameFormat, string>{ { DisplayUserNameFormat.Default, "{1} {0}" }, { DisplayUserNameFormat.FirstLast, "{0} {1}" }, { DisplayUserNameFormat.LastFirst, "{1} {0}" } } },
            { "default", new Dictionary<DisplayUserNameFormat, string>{ {DisplayUserNameFormat.Default, "{0} {1}" }, { DisplayUserNameFormat.FirstLast, "{0} {1}" }, { DisplayUserNameFormat.LastFirst, "{1}, {0}" } } },
        };

        private static string GetUserDisplayFormat()
        {
            return GetUserDisplayFormat(DisplayUserNameFormat.Default);
        }


        private static string GetUserDisplayFormat(DisplayUserNameFormat format)
        {
            if (!forceFormatChecked)
            {
                forceFormat = ConfigurationManagerExtension.AppSettings["core.user-display-format"];
                if (String.IsNullOrEmpty(forceFormat)) forceFormat = null;
                forceFormatChecked = true;
            }
            if (forceFormat != null) return forceFormat;
            var culture = Thread.CurrentThread.CurrentCulture.Name;
            Dictionary<DisplayUserNameFormat, string> formats = null;
            if (!DisplayFormats.TryGetValue(culture, out formats))
            {
                var twoletter = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
                if (!DisplayFormats.TryGetValue(twoletter, out formats)) formats = DisplayFormats["default"];
            }
            return formats[format];
        }

        public static DisplayUserNameFormat GetUserDisplayDefaultOrder()
        {
            var culture = Thread.CurrentThread.CurrentCulture.Name;
            Dictionary<DisplayUserNameFormat, string> formats = null;
            if (!DisplayFormats.TryGetValue(culture, out formats))
            {
                string twoletter = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
                if (!DisplayFormats.TryGetValue(twoletter, out formats)) formats = DisplayFormats["default"];
            }
            var format = formats[DisplayUserNameFormat.Default];
            return format.IndexOf("{0}") < format.IndexOf("{1}") ? DisplayUserNameFormat.FirstLast : DisplayUserNameFormat.LastFirst;
        }

        public static Regex UserNameRegex = new Regex(ConfigurationManagerExtension.AppSettings["core.username.regex"] ?? "");

        public static bool IsValidUserName(string firstName, string lastName)
        {
            return UserNameRegex.IsMatch(firstName + lastName);
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiRouteHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Routing;

using ASC.Api.Interfaces;
using ASC.Api.Utils;
using ASC.Common.Logging;

using Autofac;

namespace ASC.Api.Impl
{
    public class ApiRouteHandler : IApiRouteHandler
    {
        public ILifetimeScope Container { get; set; }

        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            var authorizations = Container.Resolve<IEnumerable<IApiAuthorization>>().ToList();
            var log = Container.Resolve<ILog>();

            //Authorize request first
            log.DebugFormat("Authorizing {0}", requestContext.HttpContext.Request.Url);


            if (requestContext.RouteData.DataTokens.ContainsKey(DataTokenConstants.RequiresAuthorization)
                && !(bool)requestContext.RouteData.DataTokens[DataTokenConstants.RequiresAuthorization])
            {
                //Authorization is not required for method
                log.Debug("Authorization is not required");
                return GetHandler(requestContext);
            }

            foreach (var apiAuthorization in authorizations)
            {
                log.DebugFormat("Authorizing with:{0}", apiAuthorization.GetType().ToString());
                if (apiAuthorization.Authorize(requestContext.HttpContext))
                {
                    return GetHandler(requestContext);
                }
            }

            if (authorizations.Any(apiAuthorization => apiAuthorization.OnAuthorizationFailed(requestContext.HttpContext)))
            {
                log.Debug("Unauthorized");
                return new ErrorHttpHandler(HttpStatusCode.Unauthorized, HttpStatusCode.Unauthorized.ToString());
            }
            log.Debug("Forbidden");

            return new ErrorHttpHandler(HttpStatusCode.Unauthorized, HttpStatusCode.Unauthorized.ToString());
        }

        public virtual IHttpHandler GetHandler(RequestContext requestContext)
        {
            return Container.BeginLifetimeScope().Resolve<IApiHttpHandler>(new TypedParameter(typeof(RouteData), requestContext.RouteData));
        }
    }

    class ApiAsyncRouteHandler : ApiRouteHandler
    {
        public override IHttpHandler GetHandler(RequestContext requestContext)
        {
            throw new NotImplementedException("This handler is not yet implemented");
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/App_Themes/default/css/import.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#importTools .field-container {
    width: 400px;
}
#importTools .field-container .textEdit {
    width: 400px;
    height: 20px;
}
#importTools .big-margin-top {
    margin-top: 32px;
}
#importTools .middle-margin-top {
    margin-top: 16px;
}
#importTools .min-margin-top {
    margin-top: 8px;
}
#importTools .checkbox-container {
    margin-bottom: 14px;
}
#importTools .checkbox-container input {
    margin: 3px 3px 0 0;
    vertical-align: text-top;
}
#import_info_popup .import-statuses-container {
    margin-top: 16px;
    height: 100px;
    max-height: 100px;
    overflow:auto;
    border: solid 1px #DCDCDC;
}
#import_info_popup .importStatusClosed{
	background: url("../images/common-icons.png") no-repeat 0 -40px;
	padding-left: 16px;
}
#import_info_popup .importStatus{
	padding-left: 10px;
}

#chooseProjectsPopup .basecamp-projects-container {
    max-height: 150px;
    overflow:auto;
    border-bottom: solid 1px #DCDCDC;
    list-style-type: none;
    margin: 0;
    margin-top: 16px;
    padding: 0;
}

#chooseProjectsPopup .basecamp-projects-container li {
    display: block;
    padding: 8px 10px;
    background-color: #f3f3f3;
    border-top: solid 1px #DCDCDC;
}
#chooseProjectsPopup .basecamp-projects-container li.unchecked {
    background-color: #fff;
}
#chooseProjectsPopup .basecamp-projects-container li input,
#chooseProjectsPopup .archived-proj-note input,
#chooseProjectsPopup .active-proj-note input {
    margin-right: 12px;
    padding: 0;
}
#chooseProjectsPopup .basecamp-projects-container li label,
#chooseProjectsPopup .archived-proj-note label,
#chooseProjectsPopup .active-proj-note label {
    margin-top: 3px;
    vertical-align: top;
    display: inline-block;
    max-width: 380px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
#chooseProjectsPopup .archived-proj-note {
    margin-top: 16px;
}
#chooseProjectsPopup .active-proj-note {
    margin-top: 10px;
}

#popupImportErrorContainer .popup-header {
	 color: #333333;
    font-size: 18px;
    font-weight: normal;
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Controls/BlankModal/js/blankmodal.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.blankModal = (function ($) {

    var init = function () {
        jq(".dashboard-center-box .close").on("click", close);

        jq(document).keyup(function (event) {
            var code;

            if (event.keyCode) {
                code = event.keyCode;
            } else if (event.which) {
                code = event.which;
            }

            if (code == 27) {
                close();
            }
        });

        jq(".dashboard-center-box .slick-carousel").slick({
            slidesToShow: 1,
            slidesToScroll: 1,
            arrows: true,
            dots: true,
            fade: true,
            centerMode: true
        });
    }

    var show = function () {
        init();
        $('[blank-page]').removeClass("hidden");
        jq(".dashboard-center-box .slick-next").focus();
    };

    var close = function() {
        $('[blank-page]').remove();
    };

    var addAccount = function() {
        ASC.Controls.AnchorController.move('#accounts');
        accountsModal.addBox(undefined);
        close();
    };

    var setUpDomain = function() {
        ASC.Controls.AnchorController.move('#administration');
        close();
    };

    var addMailbox = function () {
        ASC.Controls.AnchorController.move('#accounts');
        accountsModal.addMailbox(undefined);
        close();
    };

    return {
        show: show,
        close: close,
        addAccount: addAccount,
        setUpDomain: setUpDomain,
        addMailbox: addMailbox
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Resources/MailResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Mail.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class MailResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal MailResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Mail.Resources.MailResource", typeof(MailResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Portal Access Rights.
        /// </summary>
        public static string AccessRightsSettings {
            get {
                return ResourceManager.GetString("AccessRightsSettings", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, check all the account settings you entered. If you are sure your settings are correct, sign in to the mail service you use and confirm any verification questions, in case there are some. After that try again..
        /// </summary>
        public static string AccountCreationErrorBody {
            get {
                return ResourceManager.GetString("AccountCreationErrorBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This account is not receiving mail..
        /// </summary>
        public static string AccountDisableForReceiving {
            get {
                return ResourceManager.GetString("AccountDisableForReceiving", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This account is not sending mail..
        /// </summary>
        public static string AccountDisableForSending {
            get {
                return ResourceManager.GetString("AccountDisableForSending", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Account name.
        /// </summary>
        public static string AccountLabel {
            get {
                return ResourceManager.GetString("AccountLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create a new mailbox with the default domain. Manage user accounts and adjust settings using this list.
        ///.
        /// </summary>
        public static string AccountsCommonInformationText {
            get {
                return ResourceManager.GetString("AccountsCommonInformationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The settings for the accounts connected using OAuth cannot be edited. You can only change the account name for them..
        /// </summary>
        public static string AccountsCommonNotificationText {
            get {
                return ResourceManager.GetString("AccountsCommonNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Account Management.
        /// </summary>
        public static string AccountsSettingsLabel {
            get {
                return ResourceManager.GetString("AccountsSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to After activating your account you will resume receiving mail from it.
        /// </summary>
        public static string ActivateAccountAttention {
            get {
                return ResourceManager.GetString("ActivateAccountAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Activate account.
        /// </summary>
        public static string ActivateAccountLabel {
            get {
                return ResourceManager.GetString("ActivateAccountLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Activate.
        /// </summary>
        public static string ActivateBtnLabel {
            get {
                return ResourceManager.GetString("ActivateBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add copy.
        /// </summary>
        public static string AddCopy {
            get {
                return ResourceManager.GetString("AddCopy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add email address.
        /// </summary>
        public static string AddEmailAddressHint {
            get {
                return ResourceManager.GetString("AddEmailAddressHint", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Email Address.
        /// </summary>
        public static string AddEmailPlaceholder {
            get {
                return ResourceManager.GetString("AddEmailPlaceholder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do the same as Mail user|Manage Mail Server|Manage the general Mail settings.
        /// </summary>
        public static string AddonAdminOpportunities {
            get {
                return ResourceManager.GetString("AddonAdminOpportunities", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Manage own mail accounts, receive and send letters|Manage own Mail settings|Manage the tags and address book.
        /// </summary>
        public static string AddonUserOpportunities {
            get {
                return ResourceManager.GetString("AddonUserOpportunities", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Contacts.
        /// </summary>
        public static string AddressBook {
            get {
                return ResourceManager.GetString("AddressBook", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tags.
        /// </summary>
        public static string AddTag {
            get {
                return ResourceManager.GetString("AddTag", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Advanced.
        /// </summary>
        public static string AdvancedLinkLabel {
            get {
                return ResourceManager.GetString("AdvancedLinkLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Always display external images.
        /// </summary>
        public static string AlwaysDisplayAllImagesSettingsLabel {
            get {
                return ResourceManager.GetString("AlwaysDisplayAllImagesSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Always display images from.
        /// </summary>
        public static string AlwaysDisplayImagesLabel {
            get {
                return ResourceManager.GetString("AlwaysDisplayImagesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apply filter.
        /// </summary>
        public static string ApplyBtnLabel {
            get {
                return ResourceManager.GetString("ApplyBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you apply this filter, the following actions will be performed to all the filtered existing messages:.
        /// </summary>
        public static string ApplyFilterAttention {
            get {
                return ResourceManager.GetString("ApplyFilterAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apply filter to existing messages.
        /// </summary>
        public static string ApplyFilterBtnLabel {
            get {
                return ResourceManager.GetString("ApplyFilterBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete All.
        /// </summary>
        public static string AttachDeleteAllLabel {
            get {
                return ResourceManager.GetString("AttachDeleteAllLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Download All.
        /// </summary>
        public static string AttachDownloadAll {
            get {
                return ResourceManager.GetString("AttachDownloadAll", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attach links to files.
        /// </summary>
        public static string AttachFilesAsLinksLabel {
            get {
                return ResourceManager.GetString("AttachFilesAsLinksLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attach files from Documents.
        /// </summary>
        public static string AttachFilesFromDocsLabel {
            get {
                return ResourceManager.GetString("AttachFilesFromDocsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attachments.
        /// </summary>
        public static string Attachments {
            get {
                return ResourceManager.GetString("Attachments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attach to CRM Contact.
        /// </summary>
        public static string AttacToCRMContact {
            get {
                return ResourceManager.GetString("AttacToCRMContact", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Authentication Type.
        /// </summary>
        public static string AuthenticationType {
            get {
                return ResourceManager.GetString("AuthenticationType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Replies automatically to all incoming messages, e.g. while you are absent. If some contact sends you several messages, the autoreply will be sent once every {0} at most..
        /// </summary>
        public static string AutoreplyInformationText {
            get {
                return ResourceManager.GetString("AutoreplyInformationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to BCC.
        /// </summary>
        public static string BCCLabel {
            get {
                return ResourceManager.GetString("BCCLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add New Account.
        /// </summary>
        public static string BlankModalCreateBtn {
            get {
                return ResourceManager.GetString("BlankModalCreateBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create mailbox.
        /// </summary>
        public static string BlankModalCreateMailboxBtn {
            get {
                return ResourceManager.GetString("BlankModalCreateMailboxBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set up domain.
        /// </summary>
        public static string BlankModalSetUpDomainBtn {
            get {
                return ResourceManager.GetString("BlankModalSetUpDomainBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Images are disabled..
        /// </summary>
        public static string BlockedContentWarning {
            get {
                return ResourceManager.GetString("BlockedContentWarning", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Body.
        /// </summary>
        public static string BodyLabel {
            get {
                return ResourceManager.GetString("BodyLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Load the unread messages from the Inbox folder to the cache for the user to open them faster..
        /// </summary>
        public static string CacheUnreadMessagesSettingsHelperBlock {
            get {
                return ResourceManager.GetString("CacheUnreadMessagesSettingsHelperBlock", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cache unread Inbox messages.
        /// </summary>
        public static string CacheUnreadMessagesSettingsLabel {
            get {
                return ResourceManager.GetString("CacheUnreadMessagesSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The current time is displayed according to your calendar settings..
        /// </summary>
        public static string CalendarDateInformationText {
            get {
                return ResourceManager.GetString("CalendarDateInformationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Change password.
        /// </summary>
        public static string ChangeAccountPasswordLabel {
            get {
                return ResourceManager.GetString("ChangeAccountPasswordLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Check filter.
        /// </summary>
        public static string CheckFilterBtnLabel {
            get {
                return ResourceManager.GetString("CheckFilterBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Empty folder.
        /// </summary>
        public static string ClearBtnLabel {
            get {
                return ResourceManager.GetString("ClearBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comment.
        /// </summary>
        public static string Comment {
            get {
                return ResourceManager.GetString("Comment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Common Settings.
        /// </summary>
        public static string CommonSettingsLabel {
            get {
                return ResourceManager.GetString("CommonSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Compose.
        /// </summary>
        public static string ComposeLabel {
            get {
                return ResourceManager.GetString("ComposeLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete messages forever?.
        /// </summary>
        public static string ConfirmFilterActionDeleteForeverLabel {
            get {
                return ResourceManager.GetString("ConfirmFilterActionDeleteForeverLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Copy to My documents.
        /// </summary>
        public static string CopyFilesToMyDocumentsBtn {
            get {
                return ResourceManager.GetString("CopyFilesToMyDocumentsBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Copy.
        /// </summary>
        public static string CopyLabel {
            get {
                return ResourceManager.GetString("CopyLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to create a CRM contact and link with this conversation?.
        /// </summary>
        public static string CreateAndLinkToCrmConfirmMessage {
            get {
                return ResourceManager.GetString("CreateAndLinkToCrmConfirmMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create and link.
        /// </summary>
        public static string CreateCrmContactAndLinkPopupBtnLabel {
            get {
                return ResourceManager.GetString("CreateCrmContactAndLinkPopupBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Just create contact.
        /// </summary>
        public static string CreateCrmWithoutLinkPopupBtnLabel {
            get {
                return ResourceManager.GetString("CreateCrmWithoutLinkPopupBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create Email to Sender.
        /// </summary>
        public static string CreateEmailToSenderLabel {
            get {
                return ResourceManager.GetString("CreateEmailToSenderLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create filter.
        /// </summary>
        public static string CreateFilterBtn {
            get {
                return ResourceManager.GetString("CreateFilterBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create filter.
        /// </summary>
        public static string CreateFilterBtnLabel {
            get {
                return ResourceManager.GetString("CreateFilterBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create mailbox.
        /// </summary>
        public static string CreateMailboxBtn {
            get {
                return ResourceManager.GetString("CreateMailboxBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add New Account.
        /// </summary>
        public static string CreateNewAccountBtn {
            get {
                return ResourceManager.GetString("CreateNewAccountBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create New Tag.
        /// </summary>
        public static string CreateNewTagBtn {
            get {
                return ResourceManager.GetString("CreateNewTagBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create.
        /// </summary>
        public static string CreateUserFolderBtn {
            get {
                return ResourceManager.GetString("CreateUserFolderBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create folder.
        /// </summary>
        public static string CreateUserFolderLabel {
            get {
                return ResourceManager.GetString("CreateUserFolderLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Collect all emails in one place.
        /// </summary>
        public static string DashboardCollectAllEmailsInOnePlace {
            get {
                return ResourceManager.GetString("DashboardCollectAllEmailsInOnePlace", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connect all 3rd party mail accounts..
        /// </summary>
        public static string DashboardCollectAllEmailsInOnePlaceFirstLine {
            get {
                return ResourceManager.GetString("DashboardCollectAllEmailsInOnePlaceFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Send and receive messages on your portal..
        /// </summary>
        public static string DashboardCollectAllEmailsInOnePlaceSecondLine {
            get {
                return ResourceManager.GetString("DashboardCollectAllEmailsInOnePlaceSecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Access your emails from anywhere..
        /// </summary>
        public static string DashboardCollectAllEmailsInOnePlaceThirdLine {
            get {
                return ResourceManager.GetString("DashboardCollectAllEmailsInOnePlaceThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Communicate easily.
        /// </summary>
        public static string DashboardCommunicateEasily {
            get {
                return ResourceManager.GetString("DashboardCommunicateEasily", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save your typical reply as a template to send emails faster..
        /// </summary>
        public static string DashboardCommunicateEasilyFirstLine {
            get {
                return ResourceManager.GetString("DashboardCommunicateEasilyFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Request delivery and read notifications..
        /// </summary>
        public static string DashboardCommunicateEasilySecondLine {
            get {
                return ResourceManager.GetString("DashboardCommunicateEasilySecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Recieve event notifications, accept or decline invitations..
        /// </summary>
        public static string DashboardCommunicateEasilyThirdLine {
            get {
                return ResourceManager.GetString("DashboardCommunicateEasilyThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Structure correspondence.
        /// </summary>
        public static string DashboardStructureCorrespondence {
            get {
                return ResourceManager.GetString("DashboardStructureCorrespondence", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add tags, link conversations and single messages to CRM..
        /// </summary>
        public static string DashboardStructureCorrespondenceFirstLine {
            get {
                return ResourceManager.GetString("DashboardStructureCorrespondenceFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create custom folders and subfolders..
        /// </summary>
        public static string DashboardStructureCorrespondenceSecondLine {
            get {
                return ResourceManager.GetString("DashboardStructureCorrespondenceSecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Use filters to sort mail automatically..
        /// </summary>
        public static string DashboardStructureCorrespondenceThirdLine {
            get {
                return ResourceManager.GetString("DashboardStructureCorrespondenceThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Use mail server.
        /// </summary>
        public static string DashboardUseMailServer {
            get {
                return ResourceManager.GetString("DashboardUseMailServer", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Configure your mail server using your domain..
        /// </summary>
        public static string DashboardUseMailServerFirstLine {
            get {
                return ResourceManager.GetString("DashboardUseMailServerFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create and manage corporate mailboxes..
        /// </summary>
        public static string DashboardUseMailServerSecondLine {
            get {
                return ResourceManager.GetString("DashboardUseMailServerSecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Assign aliases to users and organize mail groups..
        /// </summary>
        public static string DashboardUseMailServerThirdLine {
            get {
                return ResourceManager.GetString("DashboardUseMailServerThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to After deactivation of an account you will no longer receive mail from it..
        /// </summary>
        public static string DeactivateAccountAttention {
            get {
                return ResourceManager.GetString("DeactivateAccountAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deactivate.
        /// </summary>
        public static string DeactivateAccountLabel {
            get {
                return ResourceManager.GetString("DeactivateAccountLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deactivate.
        /// </summary>
        public static string DeactovateBtnLabel {
            get {
                return ResourceManager.GetString("DeactovateBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you delete your account all the messages will be removed from the mailbox..
        /// </summary>
        public static string DeleteAccountAttention {
            get {
                return ResourceManager.GetString("DeleteAccountAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string DeleteAccountLabel {
            get {
                return ResourceManager.GetString("DeleteAccountLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string DeleteAttachment {
            get {
                return ResourceManager.GetString("DeleteAttachment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string DeleteBtnLabel {
            get {
                return ResourceManager.GetString("DeleteBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are about to delete the selected contact. This operation cannot be undone..
        /// </summary>
        public static string DeleteContactAttention {
            get {
                return ResourceManager.GetString("DeleteContactAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete contacts.
        /// </summary>
        public static string DeleteContacts {
            get {
                return ResourceManager.GetString("DeleteContacts", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are about to delete several contacts. This operation cannot be undone..
        /// </summary>
        public static string DeleteContactsAttention {
            get {
                return ResourceManager.GetString("DeleteContactsAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete contact {0}?.
        /// </summary>
        public static string DeleteContactShure {
            get {
                return ResourceManager.GetString("DeleteContactShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete the selected contacts?.
        /// </summary>
        public static string DeleteContactsShure {
            get {
                return ResourceManager.GetString("DeleteContactsShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string DeleteFilterBtn {
            get {
                return ResourceManager.GetString("DeleteFilterBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete the selected filter?.
        /// </summary>
        public static string DeleteFilterItemShure {
            get {
                return ResourceManager.GetString("DeleteFilterItemShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You chose to delete the messages permanently. If you want to be able to recover these messages later, you should move them to the trash instead..
        /// </summary>
        public static string DeleteFilterShure {
            get {
                return ResourceManager.GetString("DeleteFilterShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete tag.
        /// </summary>
        public static string DeleteTag {
            get {
                return ResourceManager.GetString("DeleteTag", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you delete the tag from the list, it will also be removed from the contacts and messages marked with it..
        /// </summary>
        public static string DeleteTagAttention {
            get {
                return ResourceManager.GetString("DeleteTagAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you delete your folder all the messages will be moved into Trash folder..
        /// </summary>
        public static string DeleteUserFolderAttention {
            get {
                return ResourceManager.GetString("DeleteUserFolderAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string DeleteUserFolderBtn {
            get {
                return ResourceManager.GetString("DeleteUserFolderBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Description.
        /// </summary>
        public static string DescriptionLabel {
            get {
                return ResourceManager.GetString("DescriptionLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Disable.
        /// </summary>
        public static string DisableBtnLabel {
            get {
                return ResourceManager.GetString("DisableBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Display images.
        /// </summary>
        public static string DisplayImagesLabel {
            get {
                return ResourceManager.GetString("DisplayImagesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to It is possible to {0}export data from the MS Exchange.{1}.
        /// </summary>
        public static string DomainHelperExportFromMSExchange {
            get {
                return ResourceManager.GetString("DomainHelperExportFromMSExchange", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The ready-made free default domain is provided for you to create your new mailbox right away..
        /// </summary>
        public static string DomainHelperInformationText_1 {
            get {
                return ResourceManager.GetString("DomainHelperInformationText_1", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This domain is common for all portals, so it is recommended that your corporate domain is used for corporate email correspondence..
        /// </summary>
        public static string DomainHelperInformationText_2 {
            get {
                return ResourceManager.GetString("DomainHelperInformationText_2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Download.
        /// </summary>
        public static string DownloadAttachment {
            get {
                return ResourceManager.GetString("DownloadAttachment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string Edit {
            get {
                return ResourceManager.GetString("Edit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string EditAccountLabel {
            get {
                return ResourceManager.GetString("EditAccountLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open in document editor.
        /// </summary>
        public static string EditAttachment {
            get {
                return ResourceManager.GetString("EditAttachment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit contact.
        /// </summary>
        public static string EditContact {
            get {
                return ResourceManager.GetString("EditContact", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string EditFilterBtn {
            get {
                return ResourceManager.GetString("EditFilterBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string EditUserFolderBtn {
            get {
                return ResourceManager.GetString("EditUserFolderBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit folder.
        /// </summary>
        public static string EditUserFolderLabel {
            get {
                return ResourceManager.GetString("EditUserFolderLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Email.
        /// </summary>
        public static string EMailLabel {
            get {
                return ResourceManager.GetString("EMailLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enable.
        /// </summary>
        public static string EnableBtnLabel {
            get {
                return ResourceManager.GetString("EnableBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enable Conversations.
        /// </summary>
        public static string EnableConversationsSettingsLabel {
            get {
                return ResourceManager.GetString("EnableConversationsSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail autoreply is enabled for this account..
        /// </summary>
        public static string EnabledAutoreplyNotification {
            get {
                return ResourceManager.GetString("EnabledAutoreplyNotification", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Encrypted Password.
        /// </summary>
        public static string EncryptedPaswordAuthentication {
            get {
                return ResourceManager.GetString("EncryptedPaswordAuthentication", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This address already exists.
        /// </summary>
        public static string ErrorEmailExist {
            get {
                return ResourceManager.GetString("ErrorEmailExist", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Body cannot be empty.
        /// </summary>
        public static string ErrorEmptyBody {
            get {
                return ResourceManager.GetString("ErrorEmptyBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your pricing plan does not support this option.
        /// </summary>
        public static string ErrorNotAllowedOption {
            get {
                return ResourceManager.GetString("ErrorNotAllowedOption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save all in My documents.
        /// </summary>
        public static string ExportAttachmentsToMyDocuments {
            get {
                return ResourceManager.GetString("ExportAttachmentsToMyDocuments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, choose CRM items to attach this message to:.
        /// </summary>
        public static string ExportMessagePopupChooseMessage {
            get {
                return ResourceManager.GetString("ExportMessagePopupChooseMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Export.
        /// </summary>
        public static string ExportMessagePopupExportBtnLbl {
            get {
                return ResourceManager.GetString("ExportMessagePopupExportBtnLbl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Export to:.
        /// </summary>
        public static string ExportMessagePopupExportLabel {
            get {
                return ResourceManager.GetString("ExportMessagePopupExportLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailing history will be avaliable to CRM users according to access rights..
        /// </summary>
        public static string ExportMessagePopupInfoMessage {
            get {
                return ResourceManager.GetString("ExportMessagePopupInfoMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Export to CRM.
        /// </summary>
        public static string ExportMessageToCRM {
            get {
                return ResourceManager.GetString("ExportMessageToCRM", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have &quot;View Only&quot; access rights for some attached file, thus you will not be able to share them with others. {0}{0} These files can be copied to the &apos;&apos;My documents&quot; folder and attached as links afterward. {0}{0} Alternatively you can ask document owners to give you &quot;Full Access&quot; permissions to the files you want to attach as links and repeat the operation once again..
        /// </summary>
        public static string FilesCannotBeAttachedAsLinks_Body {
            get {
                return ResourceManager.GetString("FilesCannotBeAttachedAsLinks_Body", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Some files cannot be attached as links..
        /// </summary>
        public static string FilesCannotBeAttachedAsLinks_Header {
            get {
                return ResourceManager.GetString("FilesCannotBeAttachedAsLinks_Header", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unlink folder.
        /// </summary>
        public static string FilesFolderUnlinkButton {
            get {
                return ResourceManager.GetString("FilesFolderUnlinkButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Form Filling.
        /// </summary>
        public static string FillForms {
            get {
                return ResourceManager.GetString("FillForms", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {!Group}.
        /// </summary>
        public static string FilterByGroup {
            get {
                return ResourceManager.GetString("FilterByGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Filtered messages.
        /// </summary>
        public static string FilterFilteredMessagesTitle {
            get {
                return ResourceManager.GetString("FilterFilteredMessagesTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can manage your filters on this page..
        /// </summary>
        public static string FiltersCommonInformationText {
            get {
                return ResourceManager.GetString("FiltersCommonInformationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Filters can help you move your incoming mail into folders, add labels and delete unwanted mail instantly..
        /// </summary>
        public static string FiltersCommonNotificationText {
            get {
                return ResourceManager.GetString("FiltersCommonNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Drafts.
        /// </summary>
        public static string FolderNameDrafts {
            get {
                return ResourceManager.GetString("FolderNameDrafts", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Inbox.
        /// </summary>
        public static string FolderNameInbox {
            get {
                return ResourceManager.GetString("FolderNameInbox", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sent.
        /// </summary>
        public static string FolderNameSent {
            get {
                return ResourceManager.GetString("FolderNameSent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Spam.
        /// </summary>
        public static string FolderNameSpam {
            get {
                return ResourceManager.GetString("FolderNameSpam", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Templates.
        /// </summary>
        public static string FolderNameTemplates {
            get {
                return ResourceManager.GetString("FolderNameTemplates", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Trash.
        /// </summary>
        public static string FolderNameTrash {
            get {
                return ResourceManager.GetString("FolderNameTrash", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Forward.
        /// </summary>
        public static string ForwardLabel {
            get {
                return ResourceManager.GetString("ForwardLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Full Access.
        /// </summary>
        public static string FullAccess {
            get {
                return ResourceManager.GetString("FullAccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Full size.
        /// </summary>
        public static string FullSize {
            get {
                return ResourceManager.GetString("FullSize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Get default settings.
        /// </summary>
        public static string GetDefaultSettingsLinkLabel {
            get {
                return ResourceManager.GetString("GetDefaultSettingsLinkLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Otherwise return to the current folder..
        /// </summary>
        public static string GoNextAfterMoveSettingsHelperBlock {
            get {
                return ResourceManager.GetString("GoNextAfterMoveSettingsHelperBlock", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to the next message after moving/deleting the currently viewed.
        /// </summary>
        public static string GoNextAfterMoveSettingsLabel {
            get {
                return ResourceManager.GetString("GoNextAfterMoveSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Next.
        /// </summary>
        public static string GoToNextMessage {
            get {
                return ResourceManager.GetString("GoToNextMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Previous.
        /// </summary>
        public static string GoToPrevMessage {
            get {
                return ResourceManager.GetString("GoToPrevMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail group, edited in administration panel only.
        /// </summary>
        public static string GroupNotificationText {
            get {
                return ResourceManager.GetString("GroupNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to IMAP Server.
        /// </summary>
        public static string ImapServerLabel {
            get {
                return ResourceManager.GetString("ImapServerLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Important.
        /// </summary>
        public static string ImportantLabel {
            get {
                return ResourceManager.GetString("ImportantLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Link with CRM.
        /// </summary>
        public static string LinkChainWithCRM {
            get {
                return ResourceManager.GetString("LinkChainWithCRM", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose item:.
        /// </summary>
        public static string LinkConversationChooseContactsLabel {
            get {
                return ResourceManager.GetString("LinkConversationChooseContactsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string LinkConversationLinkButtonLabel {
            get {
                return ResourceManager.GetString("LinkConversationLinkButtonLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case.
        /// </summary>
        public static string LinkConversationOptionCasesLbl {
            get {
                return ResourceManager.GetString("LinkConversationOptionCasesLbl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Contact.
        /// </summary>
        public static string LinkConversationOptionContactsLbl {
            get {
                return ResourceManager.GetString("LinkConversationOptionContactsLbl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Opportunity.
        /// </summary>
        public static string LinkConversationOptionOpportunitiesLbl {
            get {
                return ResourceManager.GetString("LinkConversationOptionOpportunitiesLbl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, choose CRM items to attach this conversation to:.
        /// </summary>
        public static string LinkConversationPopupChooseMessage {
            get {
                return ResourceManager.GetString("LinkConversationPopupChooseMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All the messages from this conversation (including future messages) will be shown in CRM. Mailing history will be available to CRM users according to access rights..
        /// </summary>
        public static string LinkConversationPopupInfoMessage {
            get {
                return ResourceManager.GetString("LinkConversationPopupInfoMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Link to:.
        /// </summary>
        public static string LinkConversationPopupLinkLabel {
            get {
                return ResourceManager.GetString("LinkConversationPopupLinkLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Find by name.
        /// </summary>
        public static string LinkConversationSearchPlaceHolderLabel {
            get {
                return ResourceManager.GetString("LinkConversationSearchPlaceHolderLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unlink all.
        /// </summary>
        public static string LinkConversationUnlinkAllBtnLabel {
            get {
                return ResourceManager.GetString("LinkConversationUnlinkAllBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Loading....
        /// </summary>
        public static string LoadingLabel {
            get {
                return ResourceManager.GetString("LoadingLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Login.
        /// </summary>
        public static string Login {
            get {
                return ResourceManager.GetString("Login", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incoming Mail (IMAP):.
        /// </summary>
        public static string MailboxIncommingSetiingsLabel {
            get {
                return ResourceManager.GetString("MailboxIncommingSetiingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Outgoing Mail (SMTP):.
        /// </summary>
        public static string MailboxOutgoingSetiingsLabel {
            get {
                return ResourceManager.GetString("MailboxOutgoingSetiingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No mailboxes in this list.
        /// </summary>
        public static string MailBoxSelectorEmptyList {
            get {
                return ResourceManager.GetString("MailBoxSelectorEmptyList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no mailboxes.
        /// </summary>
        public static string MailBoxSelectorNoItems {
            get {
                return ResourceManager.GetString("MailBoxSelectorNoItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such mailbox.
        /// </summary>
        public static string MailBoxSelectorNoResult {
            get {
                return ResourceManager.GetString("MailBoxSelectorNoResult", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Use the following settings for other email clients:.
        /// </summary>
        public static string MailboxSetiingsInfoLabel {
            get {
                return ResourceManager.GetString("MailboxSetiingsInfoLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Description.
        /// </summary>
        public static string MailDescription {
            get {
                return ResourceManager.GetString("MailDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Import messages only for the last 30 days.
        /// </summary>
        public static string MailLimitLabel {
            get {
                return ResourceManager.GetString("MailLimitLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail.
        /// </summary>
        public static string MailTitle {
            get {
                return ResourceManager.GetString("MailTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as Important.
        /// </summary>
        public static string MarkAsImportant {
            get {
                return ResourceManager.GetString("MarkAsImportant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as Not Important.
        /// </summary>
        public static string MarkAsNotImportant {
            get {
                return ResourceManager.GetString("MarkAsNotImportant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as Read.
        /// </summary>
        public static string MarkAsRead {
            get {
                return ResourceManager.GetString("MarkAsRead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as Unread.
        /// </summary>
        public static string MarkAsUnread {
            get {
                return ResourceManager.GetString("MarkAsUnread", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark all messages from.
        /// </summary>
        public static string MarkFrom {
            get {
                return ResourceManager.GetString("MarkFrom", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Filter Management.
        /// </summary>
        public static string MessageFilterSettingsLabel {
            get {
                return ResourceManager.GetString("MessageFilterSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This account has been deactivated..
        /// </summary>
        public static string MessageFromWarning {
            get {
                return ResourceManager.GetString("MessageFromWarning", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to more.
        /// </summary>
        public static string MoreLabel {
            get {
                return ResourceManager.GetString("MoreLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to More.
        /// </summary>
        public static string MoreMenuButton {
            get {
                return ResourceManager.GetString("MoreMenuButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move here.
        /// </summary>
        public static string MoveHere {
            get {
                return ResourceManager.GetString("MoveHere", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move to.
        /// </summary>
        public static string MoveTo {
            get {
                return ResourceManager.GetString("MoveTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Name.
        /// </summary>
        public static string NameLabel {
            get {
                return ResourceManager.GetString("NameLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new tag.
        /// </summary>
        public static string NewTag {
            get {
                return ResourceManager.GetString("NewTag", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to no address.
        /// </summary>
        public static string NoAddress {
            get {
                return ResourceManager.GetString("NoAddress", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to None.
        /// </summary>
        public static string NoEcncryptionNeeded {
            get {
                return ResourceManager.GetString("NoEcncryptionNeeded", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to None.
        /// </summary>
        public static string NonePasswordAuthentication {
            get {
                return ResourceManager.GetString("NonePasswordAuthentication", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to no subject.
        /// </summary>
        public static string NoSubject {
            get {
                return ResourceManager.GetString("NoSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to or link with:.
        /// </summary>
        public static string OAuthLabel {
            get {
                return ResourceManager.GetString("OAuthLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Send autoreply to people in contacts only.
        /// </summary>
        public static string OnlySendAutoreplyToContacts {
            get {
                return ResourceManager.GetString("OnlySendAutoreplyToContacts", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to On top.
        /// </summary>
        public static string OnTopLabel {
            get {
                return ResourceManager.GetString("OnTopLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string OpenBtnLabel {
            get {
                return ResourceManager.GetString("OpenBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open in new tab.
        /// </summary>
        public static string OpenInNewTabBtnLabel {
            get {
                return ResourceManager.GetString("OpenInNewTabBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to or.
        /// </summary>
        public static string Or {
            get {
                return ResourceManager.GetString("Or", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to all.
        /// </summary>
        public static string OverallConceptAll {
            get {
                return ResourceManager.GetString("OverallConceptAll", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to important.
        /// </summary>
        public static string OverallConceptImportant_Acc {
            get {
                return ResourceManager.GetString("OverallConceptImportant_Acc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to important.
        /// </summary>
        public static string OverallConceptImportant_Gen {
            get {
                return ResourceManager.GetString("OverallConceptImportant_Gen", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to read.
        /// </summary>
        public static string OverallConceptRead_Acc {
            get {
                return ResourceManager.GetString("OverallConceptRead_Acc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to read.
        /// </summary>
        public static string OverallConceptRead_Gen {
            get {
                return ResourceManager.GetString("OverallConceptRead_Gen", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to unread.
        /// </summary>
        public static string OverallConceptUnread_Acc {
            get {
                return ResourceManager.GetString("OverallConceptUnread_Acc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to unread.
        /// </summary>
        public static string OverallConceptUnread_Gen {
            get {
                return ResourceManager.GetString("OverallConceptUnread_Gen", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to with attachments.
        /// </summary>
        public static string OverallConceptWithAttachments_Acc {
            get {
                return ResourceManager.GetString("OverallConceptWithAttachments_Acc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to with attachments.
        /// </summary>
        public static string OverallConceptWithAttachments_Gen {
            get {
                return ResourceManager.GetString("OverallConceptWithAttachments_Gen", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deselect all.
        /// </summary>
        public static string OverallDeselectAll {
            get {
                return ResourceManager.GetString("OverallDeselectAll", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to selected.
        /// </summary>
        public static string OverallSelected {
            get {
                return ResourceManager.GetString("OverallSelected", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Password.
        /// </summary>
        public static string Password {
            get {
                return ResourceManager.GetString("Password", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Phone.
        /// </summary>
        public static string PhoneLabel {
            get {
                return ResourceManager.GetString("PhoneLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to POP Server.
        /// </summary>
        public static string PopServerLabel {
            get {
                return ResourceManager.GetString("PopServerLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Port.
        /// </summary>
        public static string Port {
            get {
                return ResourceManager.GetString("Port", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail.
        /// </summary>
        public static string ProductName {
            get {
                return ResourceManager.GetString("ProductName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Random password.
        /// </summary>
        public static string RandomPasswordLabel {
            get {
                return ResourceManager.GetString("RandomPasswordLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Read Only.
        /// </summary>
        public static string ReadOnly {
            get {
                return ResourceManager.GetString("ReadOnly", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Receive mail.
        /// </summary>
        public static string ReceiveMailLabel {
            get {
                return ResourceManager.GetString("ReceiveMailLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reconnect.
        /// </summary>
        public static string ReconnectLabel {
            get {
                return ResourceManager.GetString("ReconnectLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Get new messages.
        /// </summary>
        public static string RefreshBtnHint {
            get {
                return ResourceManager.GetString("RefreshBtnHint", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Completely replace text of the email when you insert a template.
        /// </summary>
        public static string ReplaceMessageBody {
            get {
                return ResourceManager.GetString("ReplaceMessageBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reply All.
        /// </summary>
        public static string ReplyAllBtnLabel {
            get {
                return ResourceManager.GetString("ReplyAllBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reply.
        /// </summary>
        public static string ReplyBtnLabel {
            get {
                return ResourceManager.GetString("ReplyBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Request notification.
        /// </summary>
        public static string RequestNotificationHint {
            get {
                return ResourceManager.GetString("RequestNotificationHint", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Review.
        /// </summary>
        public static string Review {
            get {
                return ResourceManager.GetString("Review", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save &amp; Send Message.
        /// </summary>
        public static string SaveAndSendMessageBtn {
            get {
                return ResourceManager.GetString("SaveAndSendMessageBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save to Calendar.
        /// </summary>
        public static string SaveAttachToCalendar {
            get {
                return ResourceManager.GetString("SaveAttachToCalendar", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save to Documents.
        /// </summary>
        public static string SaveAttachToDocs {
            get {
                return ResourceManager.GetString("SaveAttachToDocs", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save to My documents.
        /// </summary>
        public static string SaveAttachToMyDocs {
            get {
                return ResourceManager.GetString("SaveAttachToMyDocs", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save to Projects Documents.
        /// </summary>
        public static string SaveAttachToProjDocs {
            get {
                return ResourceManager.GetString("SaveAttachToProjDocs", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string SaveBtnLabel {
            get {
                return ResourceManager.GetString("SaveBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saved at.
        /// </summary>
        public static string SavedAt {
            get {
                return ResourceManager.GetString("SavedAt", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save filter.
        /// </summary>
        public static string SaveFilterBtnLabel {
            get {
                return ResourceManager.GetString("SaveFilterBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save template.
        /// </summary>
        public static string SaveTemplate {
            get {
                return ResourceManager.GetString("SaveTemplate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select.
        /// </summary>
        public static string Select {
            get {
                return ResourceManager.GetString("Select", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select all.
        /// </summary>
        public static string SelectAll {
            get {
                return ResourceManager.GetString("SelectAll", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folder for Attachments.
        /// </summary>
        public static string SelectAttachmentsFolderLabel {
            get {
                return ResourceManager.GetString("SelectAttachmentsFolderLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folder for Attachments.
        /// </summary>
        public static string SelectFolderDialogTitle {
            get {
                return ResourceManager.GetString("SelectFolderDialogTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Send.
        /// </summary>
        public static string SendBtnLabel {
            get {
                return ResourceManager.GetString("SendBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Send mail.
        /// </summary>
        public static string SendMail {
            get {
                return ResourceManager.GetString("SendMail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Server.
        /// </summary>
        public static string ServerLabel {
            get {
                return ResourceManager.GetString("ServerLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail autoreply.
        /// </summary>
        public static string SetMailAutoreply {
            get {
                return ResourceManager.GetString("SetMailAutoreply", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Settings.
        /// </summary>
        public static string Settings {
            get {
                return ResourceManager.GetString("Settings", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The file(s) you attached as link(s) will be shared for email recipient(s) via link for people outside the portal. You can change access rights to the files in the Documents module later..
        /// </summary>
        public static string SharingSettingForFileLinks_Body {
            get {
                return ResourceManager.GetString("SharingSettingForFileLinks_Body", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set up access rights for file(s) attached as links for email recipient(s):.
        /// </summary>
        public static string SharingSettingForFileLinks_Header {
            get {
                return ResourceManager.GetString("SharingSettingForFileLinks_Header", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show more.
        /// </summary>
        public static string ShowMore {
            get {
                return ResourceManager.GetString("ShowMore", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show more accounts.
        /// </summary>
        public static string ShowMoreAccounts {
            get {
                return ResourceManager.GetString("ShowMoreAccounts", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show more tags.
        /// </summary>
        public static string ShowMoreTags {
            get {
                return ResourceManager.GetString("ShowMoreTags", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show on page.
        /// </summary>
        public static string ShowOnPage {
            get {
                return ResourceManager.GetString("ShowOnPage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Simple Password.
        /// </summary>
        public static string SimplePasswordAuthentication {
            get {
                return ResourceManager.GetString("SimplePasswordAuthentication", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open in new tab.
        /// </summary>
        public static string SingleViewLabel {
            get {
                return ResourceManager.GetString("SingleViewLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to SMTP Server.
        /// </summary>
        public static string SmtpServerLabel {
            get {
                return ResourceManager.GetString("SmtpServerLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to SSL/TLS.
        /// </summary>
        public static string SSLorTLSLabel {
            get {
                return ResourceManager.GetString("SSLorTLSLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit Tag.
        /// </summary>
        public static string TagEdit {
            get {
                return ResourceManager.GetString("TagEdit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tag name.
        /// </summary>
        public static string TagNamePlaceholder {
            get {
                return ResourceManager.GetString("TagNamePlaceholder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can mark messages and contacts using the tags. It will ease the search for the necessary ones using the tag filtering option in future..
        /// </summary>
        public static string TagsCommonInformationText {
            get {
                return ResourceManager.GetString("TagsCommonInformationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can edit and delete the tags created in Mail only. The tags imported from the CRM module cannot be either edited or deleted. They can be changed right in the CRM module by an administrator..
        /// </summary>
        public static string TagsCommonNotificationText {
            get {
                return ResourceManager.GetString("TagsCommonNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tag Management.
        /// </summary>
        public static string TagsSettingsLabel {
            get {
                return ResourceManager.GetString("TagsSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Today.
        /// </summary>
        public static string TodayLabel {
            get {
                return ResourceManager.GetString("TodayLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To you.
        /// </summary>
        public static string ToYouLabel {
            get {
                return ResourceManager.GetString("ToYouLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Turn autoreply on.
        /// </summary>
        public static string TurnAutoreplyOn {
            get {
                return ResourceManager.GetString("TurnAutoreplyOn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can turn it off..
        /// </summary>
        public static string TurnOffAutoreplyLabel {
            get {
                return ResourceManager.GetString("TurnOffAutoreplyLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Turn it on.
        /// </summary>
        public static string TurnOnAccountLabel {
            get {
                return ResourceManager.GetString("TurnOnAccountLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you really want to unlink this conversation from CRM?.
        /// </summary>
        public static string UnlinkAllConfirmationMessage {
            get {
                return ResourceManager.GetString("UnlinkAllConfirmationMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unlinking this conversation from CRM you unlink it from all contacts, opportunities and cases you have chosen earlier.
        ///All messages which were received before, will be left in the CRM mailing history, but future messages from the conversation won&apos;t be shown in CRM..
        /// </summary>
        public static string UnlinkAllInformationMessage {
            get {
                return ResourceManager.GetString("UnlinkAllInformationMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unlink.
        /// </summary>
        public static string UnlinkAllPopupUnlinkBtnLabel {
            get {
                return ResourceManager.GetString("UnlinkAllPopupUnlinkBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upload file.
        /// </summary>
        public static string UploadFileLabel {
            get {
                return ResourceManager.GetString("UploadFileLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Encryption for IMAP Server.
        /// </summary>
        public static string UseImapSSL {
            get {
                return ResourceManager.GetString("UseImapSSL", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Encryption for POP Server.
        /// </summary>
        public static string UsePOP3SSL {
            get {
                return ResourceManager.GetString("UsePOP3SSL", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can move messages into these folders..
        /// </summary>
        public static string UserFolderCommonInformationText {
            get {
                return ResourceManager.GetString("UserFolderCommonInformationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can edit and delete the folders created in Mail only..
        /// </summary>
        public static string UserFolderCommonNotificationText {
            get {
                return ResourceManager.GetString("UserFolderCommonNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create folder.
        /// </summary>
        public static string UserFolderCreateFolderLink {
            get {
                return ResourceManager.GetString("UserFolderCreateFolderLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Manage folders.
        /// </summary>
        public static string UserFolderManageFolderLink {
            get {
                return ResourceManager.GetString("UserFolderManageFolderLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folder name.
        /// </summary>
        public static string UserFolderPlaceholder {
            get {
                return ResourceManager.GetString("UserFolderPlaceholder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folder Management.
        /// </summary>
        public static string UserFolderSettingsLabel {
            get {
                return ResourceManager.GetString("UserFolderSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Encryption for SMTP Server.
        /// </summary>
        public static string UseSmtpSSL {
            get {
                return ResourceManager.GetString("UseSmtpSSL", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connection settings.
        /// </summary>
        public static string ViewAccountConnectionSettingsLabel {
            get {
                return ResourceManager.GetString("ViewAccountConnectionSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to View.
        /// </summary>
        public static string ViewAttachment {
            get {
                return ResourceManager.GetString("ViewAttachment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to View contact profile.
        /// </summary>
        public static string ViewContact {
            get {
                return ResourceManager.GetString("ViewContact", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to See pricing plans.
        /// </summary>
        public static string ViewTariffPlans {
            get {
                return ResourceManager.GetString("ViewTariffPlans", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Compose mail.
        /// </summary>
        public static string WriteLetter {
            get {
                return ResourceManager.GetString("WriteLetter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create Email.
        /// </summary>
        public static string WriteNewLetterBtnLabel {
            get {
                return ResourceManager.GetString("WriteNewLetterBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Yesterday.
        /// </summary>
        public static string YesterdayLabel {
            get {
                return ResourceManager.GetString("YesterdayLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your mailbox email.
        /// </summary>
        public static string YourMailboxEmailHint {
            get {
                return ResourceManager.GetString("YourMailboxEmailHint", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your mailbox password.
        /// </summary>
        public static string YourMailboxPasswordHint {
            get {
                return ResourceManager.GetString("YourMailboxPasswordHint", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Common/ForumModule.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Web.Community.Modules.Forum.Resources;
using ASC.Web.Community.Product;
using ASC.Web.Core;
using ASC.Web.Core.ModuleManagement;

namespace ASC.Web.Community.Forum.Common
{
    public class ForumModule : Module
    {
        public override Guid ID
        {
            get { return ForumManager.ModuleID; }
        }

        public override Guid ProjectId
        {
            get { return CommunityProduct.ID; }
        }

        public override string Name
        {
            get { return ForumResource.AddonName; }
        }

        public override string Description
        {
            get { return ForumResource.AddonDescription; }
        }

        public override string StartURL
        {
            get { return "~/Products/Community/Modules/Forum/"; }
        }

        public ForumModule()
        {
            Context = new ModuleContext
            {
                DefaultSortOrder = 2,
                SmallIconFileName = "forum_mini_icon.png",
                IconFileName = "forum_icon.png",
                SubscriptionManager = new ForumSubscriptionManager(),
                GetCreateContentPageAbsoluteUrl = ForumShortcutProvider.GetCreateContentPageUrl,
                SearchHandler = new ForumSearchHandler(),
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/FullTextSearch/js/fulltextsearch.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC.Settings === "undefined")
    ASC.Settings = {};

ASC.Settings.FullTextSearch = (function () {
    var settingsBlock = jq(".fts-settings-block"),
        hostInput = settingsBlock.find(".host input"),
        portInput = settingsBlock.find(".port input"),
        inputs = [portInput, hostInput];
    
    var init = function () {
        jq('#ftsButtonSave').on("click", save);
        jq('#ftsButtonTest').on("click", test);
    };

    var save = function () {
        if (checkError()) return;

        blockFields();
        
        FullTextSearch.Save(getSettings(), function (result) {
            if (result.error != null) {
                toastr.error(result.error.Message);
            }
            unblockFields();
        });
    };

    var checkError = function() {
        HideRequiredError();

        var result = false;
        inputs.forEach(function (item) {
            if (!item.val()) {
                ShowRequiredError(item);
                result = true;
            }
        });
        
        return result;
    };

    var blockFields = function () {
        inputs.forEach(function(item) { item.attr("disabled", true); });
        LoadingBanner.showLoaderBtn("#settingsContainer");
    };
    
    var getSettings = function () {
        return {
            Host: hostInput.val(),
            Port: portInput.val()
        };
    };
    
    var unblockFields = function () {
        inputs.forEach(function (item) { item.attr("disabled", false); });
        LoadingBanner.hideLoaderBtn("#settingsContainer");
    };
    
    var test = function () {
        FullTextSearch.Test(function (result) {
            var toasterSuccessOrError = result.value.success ? toastr.success : toastr.error;
            toasterSuccessOrError(result.value.message);
        });
    };

    return {
        init: init
    };

})(jQuery);


jq(function() {
    ASC.Settings.FullTextSearch.init();
});

<|start_filename|>common/ASC.Data.Storage/Encryption/EncryptionFactory.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.DependencyInjection;
using ASC.Core.Encryption;

using Autofac;

namespace ASC.Data.Storage.Encryption
{
    class EncryptionFactory
    {
        private static IContainer Builder { get; set; }

        static EncryptionFactory()
        {
            var container = AutofacConfigLoader.Load("encryption");

            if (container != null)
            {
                Builder = container.Build();
            }
        }

        public static ICrypt GetCrypt(string storageName, EncryptionSettings encryptionSettings)
        {
            ICrypt result = null;

            if (Builder != null)
            {
                result = Builder.Resolve<ICrypt>(new TypedParameter(typeof(string), storageName), new TypedParameter(typeof(EncryptionSettings), encryptionSettings));
            }

            return result ?? new FakeCrypt(storageName, encryptionSettings);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/NamingPeopleSettings/NamingPeopleSettingsContent.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.MessagingSystem;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;

namespace ASC.Web.Studio.UserControls.Management
{
    [AjaxNamespace("NamingPeopleContentController")]
    public partial class NamingPeopleSettingsContent : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/NamingPeopleSettings/NamingPeopleSettingsContent.ascx"; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            AjaxPro.Utility.RegisterTypeForAjax(GetType());

            Page.RegisterBodyScripts("~/UserControls/Management/NamingPeopleSettings/js/namingpeoplecontent.js")
                .RegisterStyle("~/UserControls/Management/NamingPeopleSettings/css/namingpeople.less");

            var schemas = new List<object>();
            var currentSchemaId = CustomNamingPeople.Current.Id;

            foreach (var schema in CustomNamingPeople.GetSchemas())
            {
                schemas.Add(new
                {
                    Id = schema.Key,
                    Name = schema.Value,
                    Current = string.Equals(schema.Key, currentSchemaId, StringComparison.InvariantCultureIgnoreCase)
                });
            }

            namingSchemaRepeater.DataSource = schemas;
            namingSchemaRepeater.DataBind();
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object GetPeopleNames(string schemaId)
        {
            var names = CustomNamingPeople.GetPeopleNames(schemaId);

            return new
            {
                names.Id,
                names.UserCaption,
                names.UsersCaption,
                names.GroupCaption,
                names.GroupsCaption,
                names.UserPostCaption,
                names.RegDateCaption,
                names.GroupHeadCaption,
                names.GuestCaption,
                names.GuestsCaption,
            };
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object SaveNamingSettings(string schemaId)
        {
            try
            {
                SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

                CustomNamingPeople.SetPeopleNames(schemaId);

                CoreContext.TenantManager.SaveTenant(CoreContext.TenantManager.GetCurrentTenant());

                MessageService.Send(HttpContext.Current.Request, MessageAction.TeamTemplateChanged);

                return new { Status = 1, Message = Resource.SuccessfullySaveSettingsMessage };
            }
            catch (Exception e)
            {
                return new { Status = 0, e.Message };
            }
        }


        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object SaveCustomNamingSettings(string usrCaption, string usrsCaption, string grpCaption, string grpsCaption,
                                               string usrStatusCaption, string regDateCaption,
                                               string grpHeadCaption,
                                               string guestCaption, string guestsCaption)
        {
            try
            {
                SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

                usrCaption = (usrCaption ?? "").Trim();
                usrsCaption = (usrsCaption ?? "").Trim();
                grpCaption = (grpCaption ?? "").Trim();
                grpsCaption = (grpsCaption ?? "").Trim();
                usrStatusCaption = (usrStatusCaption ?? "").Trim();
                regDateCaption = (regDateCaption ?? "").Trim();
                grpHeadCaption = (grpHeadCaption ?? "").Trim();
                guestCaption = (guestCaption ?? "").Trim();
                guestsCaption = (guestsCaption ?? "").Trim();

                if (String.IsNullOrEmpty(usrCaption)
                    || String.IsNullOrEmpty(usrsCaption)
                    || String.IsNullOrEmpty(grpCaption)
                    || String.IsNullOrEmpty(grpsCaption)
                    || String.IsNullOrEmpty(usrStatusCaption)
                    || String.IsNullOrEmpty(regDateCaption)
                    || String.IsNullOrEmpty(grpHeadCaption)
                    || String.IsNullOrEmpty(guestCaption)
                    || String.IsNullOrEmpty(guestsCaption))
                {
                    throw new Exception(Resource.ErrorEmptyFields);
                }

                var names = new PeopleNamesItem
                {
                    Id = PeopleNamesItem.CustomID,
                    UserCaption = usrCaption.Substring(0, Math.Min(30, usrCaption.Length)),
                    UsersCaption = usrsCaption.Substring(0, Math.Min(30, usrsCaption.Length)),
                    GroupCaption = grpCaption.Substring(0, Math.Min(30, grpCaption.Length)),
                    GroupsCaption = grpsCaption.Substring(0, Math.Min(30, grpsCaption.Length)),
                    UserPostCaption = usrStatusCaption.Substring(0, Math.Min(30, usrStatusCaption.Length)),
                    RegDateCaption = regDateCaption.Substring(0, Math.Min(30, regDateCaption.Length)),
                    GroupHeadCaption = grpHeadCaption.Substring(0, Math.Min(30, grpHeadCaption.Length)),
                    GuestCaption = guestCaption.Substring(0, Math.Min(30, guestCaption.Length)),
                    GuestsCaption = guestsCaption.Substring(0, Math.Min(30, guestsCaption.Length)),
                };

                CustomNamingPeople.SetPeopleNames(names);

                CoreContext.TenantManager.SaveTenant(CoreContext.TenantManager.GetCurrentTenant());

                MessageService.Send(HttpContext.Current.Request, MessageAction.TeamTemplateChanged);

                return new { Status = 1, Message = Resource.SuccessfullySaveSettingsMessage };
            }
            catch (Exception e)
            {
                return new { Status = 0, e.Message };
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/ProjectApi.TimeSpend.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.Exceptions;
using ASC.Api.Projects.Wrappers;
using ASC.Api.Utils;
using ASC.Core;
using ASC.MessagingSystem;
using ASC.Projects.Core.Domain;
using ASC.Specific;

namespace ASC.Api.Projects
{
    public partial class ProjectApi
    {
        ///<summary>
        ///Returns the list with the detailed information about all the time spent matching the filter parameters specified in the request
        ///</summary>
        ///<short>
        ///Get time spent by filter
        ///</short>
        ///<category>Time</category>
        ///<param name="projectid" optional="true"> Project Id</param>
        ///<param name="tag" optional="true">Project Tag</param>
        ///<param name="departament" optional="true">Departament GUID</param>
        ///<param name="participant" optional="true">Participant GUID</param>
        ///<param name="createdStart" optional="true">Minimum value of create time</param>
        ///<param name="createdStop" optional="true">Maximum value of create time</param>
        ///<param name="lastId">Last time spent ID</param>
        ///<param name="myProjects">Tasks time in My Projects</param>
        ///<param name="myMilestones">Tasks time in My Milestones</param>
        ///<param name="milestone" optional="true">Milestone ID</param>
        ///<param name="status" optional="true">Payment status</param>
        ///<returns>List of time spent</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"time/filter")]
        public IEnumerable<TimeWrapper> GetTaskTimeByFilter(
            int projectid,
            bool myProjects,
            int? milestone,
            bool myMilestones,
            int tag,
            Guid departament,
            Guid participant,
            ApiDateTime createdStart,
            ApiDateTime createdStop,
            int lastId,
            PaymentStatus? status)
        {
            var filter = CreateFilter(EntityType.TimeSpend);
            filter.DepartmentId = departament;
            filter.UserId = participant;
            filter.FromDate = createdStart;
            filter.ToDate = createdStop;
            filter.TagId = tag;
            filter.LastId = lastId;
            filter.MyProjects = myProjects;
            filter.MyMilestones = myMilestones;
            filter.Milestone = milestone;

            if (projectid != 0)
                filter.ProjectIds.Add(projectid);

            if (status.HasValue)
                filter.PaymentStatuses.Add(status.Value);

            SetTotalCount(EngineFactory.TimeTrackingEngine.GetByFilterCount(filter));

            return EngineFactory.TimeTrackingEngine.GetByFilter(filter).NotFoundIfNull().Select(TimeWrapperSelector);
        }

        ///<summary>
        ///Returns the total time spent matching the filter parameters specified in the request
        ///</summary>
        ///<short>
        ///Get total time spent by tilter
        ///</short>
        ///<category>Time</category>
        ///<param name="projectid" optional="true"> Project ID</param>
        ///<param name="tag" optional="true">Project tag</param>
        ///<param name="departament" optional="true">Departament GUID</param>
        ///<param name="participant" optional="true">Participant GUID</param>
        ///<param name="createdStart" optional="true">Minimum value of create time</param>
        ///<param name="createdStop" optional="true">Maximum value of create time</param>
        ///<param name="lastId">Last time spent ID</param>
        ///<param name="myProjects">Tasks time in My Projects</param>
        ///<param name="myMilestones">Tasks time in My Milestones</param>
        ///<param name="milestone" optional="true">Milestone ID</param>
        ///<param name="status" optional="true">Payment status</param>
        ///<returns>Total time spent</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"time/filter/total")]
        public float GetTotalTaskTimeByFilter(
            int projectid,
            bool myProjects,
            int? milestone,
            bool myMilestones,
            int tag,
            Guid departament,
            Guid participant,
            ApiDateTime createdStart,
            ApiDateTime createdStop,
            int lastId,
            PaymentStatus? status)
        {
            var filter = CreateFilter(EntityType.TimeSpend);
            filter.DepartmentId = departament;
            filter.UserId = participant;
            filter.FromDate = createdStart;
            filter.ToDate = createdStop;
            filter.TagId = tag;
            filter.LastId = lastId;
            filter.MyProjects = myProjects;
            filter.MyMilestones = myMilestones;
            filter.Milestone = milestone;

            if (projectid != 0)
            {
                filter.ProjectIds.Add(projectid);
            }

            if (status.HasValue)
            {
                filter.PaymentStatuses.Add(status.Value);
            }

            return EngineFactory.TimeTrackingEngine.GetByFilterTotal(filter);
        }

        ///<summary>
        ///Returns the time spent on the task with the ID specified in the request
        ///</summary>
        ///<short>
        ///Get time spent
        ///</short>
        ///<category>Time</category>
        ///<param name="taskid">Task ID</param>
        ///<returns></returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"task/{taskid:[0-9]+}/time")]
        public IEnumerable<TimeWrapper> GetTaskTime(int taskid)
        {
            if (!EngineFactory.TaskEngine.IsExists(taskid)) throw new ItemNotFoundException();
            var times = EngineFactory.TimeTrackingEngine.GetByTask(taskid).NotFoundIfNull();
            Context.SetTotalCount(times.Count);
            return times.Select(TimeWrapperSelector);
        }

        ///<summary>
        ///Adds the time to the selected task with the time parameters specified in the request
        ///</summary>
        ///<short>
        ///Add task time
        ///</short>
        ///<category>Time</category>
        ///<param name="taskid">Task ID</param>
        ///<param name="note">Note</param>
        ///<param name="date">Date</param>
        ///<param name="personId">Person that spends time</param>
        ///<param name="hours">Hours spent</param>
        ///<param name="projectId">Project ID</param>
        ///<returns>Created time</returns>
        ///<exception cref="ArgumentException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        [Create(@"task/{taskid:[0-9]+}/time")]
        public TimeWrapper AddTaskTime(int taskid, string note, DateTime date, Guid personId, float hours, int projectId)
        {
            if (date == DateTime.MinValue) throw new ArgumentException("date can't be empty");
            if (personId == Guid.Empty) throw new ArgumentException("person can't be empty");

            var task = EngineFactory.TaskEngine.GetByID(taskid);

            if (task == null) throw new ItemNotFoundException();

            if (!EngineFactory.ProjectEngine.IsExists(projectId)) throw new ItemNotFoundException("project");

            var ts = new TimeSpend
            {
                Date = date.Date,
                Person = personId,
                Hours = hours,
                Note = note,
                Task = task,
                CreateBy = SecurityContext.CurrentAccount.ID
            };

            ts = EngineFactory.TimeTrackingEngine.SaveOrUpdate(ts);
            MessageService.Send(Request, MessageAction.TaskTimeCreated, MessageTarget.Create(ts.ID), task.Project.Title, task.Title, ts.Note);

            return TimeWrapperSelector(ts);
        }

        ///<summary>
        ///Updates the time for the selected task with the time parameters specified in the request
        ///</summary>
        ///<short>
        ///Update task time
        ///</short>
        ///<category>Time</category>
        ///<param name="timeid">ID of time spent</param>
        ///<param name="note">Note</param>
        ///<param name="date">Date</param>
        ///<param name="personId">Person that spends time</param>
        ///<param name="hours">Hours spent</param>
        ///<returns>Created time</returns>
        ///<exception cref="ArgumentException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        [Update(@"time/{timeid:[0-9]+}")]
        public TimeWrapper UpdateTime(int timeid, string note, DateTime date, Guid personId, float hours)
        {
            if (date == DateTime.MinValue) throw new ArgumentException("date can't be empty");
            if (personId == Guid.Empty) throw new ArgumentException("person can't be empty");

            var timeTrackingEngine = EngineFactory.TimeTrackingEngine;

            var time = timeTrackingEngine.GetByID(timeid).NotFoundIfNull();

            time.Date = date.Date;
            time.Person = personId;
            time.Hours = hours;
            time.Note = note;

            timeTrackingEngine.SaveOrUpdate(time);
            MessageService.Send(Request, MessageAction.TaskTimeUpdated, MessageTarget.Create(time.ID), time.Task.Project.Title, time.Task.Title, time.Note);

            return TimeWrapperSelector(time);
        }

        ///<summary>
        ///Updates the time status of payment
        ///</summary>
        ///<short>
        ///Updates the time status of payment
        ///</short>
        ///<category>Time</category>
        ///<param name="timeids">List IDs of time spent</param>
        ///<param name="status">Status</param>
        ///<returns>Created time</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Update(@"time/times/status")]
        public List<TimeWrapper> UpdateTimes(int[] timeids, PaymentStatus status)
        {
            var timeTrackingEngine = EngineFactory.TimeTrackingEngine;
            var times = new List<TimeWrapper>();

            foreach (var timeid in timeids)
            {
                var time = timeTrackingEngine.GetByID(timeid).NotFoundIfNull();
                timeTrackingEngine.ChangePaymentStatus(time, status);
                times.Add(TimeWrapperSelector(time));
            }

            MessageService.Send(Request, MessageAction.TaskTimesUpdatedStatus, MessageTarget.Create(timeids), times.Select(t => t.RelatedTaskTitle), LocalizedEnumConverter.ConvertToString(status));

            return times;
        }

        ///<summary>
        ///Deletes the times from the tasks with the ID specified in the request
        ///</summary>
        ///<short>
        ///Delete time spents
        ///</short>
        ///<category>Time</category>
        ///<param name="timeids">IDs of time spents</param>
        ///<returns></returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Delete(@"time/times/remove")]
        public List<TimeWrapper> DeleteTaskTimes(int[] timeids)
        {
            var listDeletedTimers = new List<TimeWrapper>();
            foreach (var timeid in timeids.Distinct())
            {
                var timeTrackingEngine = EngineFactory.TimeTrackingEngine;
                var time = timeTrackingEngine.GetByID(timeid).NotFoundIfNull();

                timeTrackingEngine.Delete(time);
                listDeletedTimers.Add(TimeWrapperSelector(time));
            }

            MessageService.Send(Request, MessageAction.TaskTimesDeleted, MessageTarget.Create(timeids), listDeletedTimers.Select(t => t.RelatedTaskTitle));

            return listDeletedTimers;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Classes/Global.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Text;
using System.Web;

using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.Data.Storage;
using ASC.Web.Core;
using ASC.Web.Core.Files;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace ASC.Web.CRM.Classes
{
    public class Global
    {
        public static readonly int EntryCountOnPage = 25;
        public static readonly int VisiblePageCount = 10;

        public static readonly int MaxCustomFieldSize = 150;
        public static readonly int MaxCustomFieldRows = 25;
        public static readonly int MaxCustomFieldCols = 150;

        public static readonly int DefaultCustomFieldSize = 40;
        public static readonly int DefaultCustomFieldRows = 2;
        public static readonly int DefaultCustomFieldCols = 40;

        public static readonly int MaxHistoryEventCharacters = 65000;
        public static readonly decimal MaxInvoiceItemPrice = (decimal)99999999.99;

        public static CRMSettings TenantSettings
        {
            get { return CRMSettings.Load(); }
        }

        public static IDataStore GetStore()
        {
            return StorageFactory.GetStorage(TenantProvider.CurrentTenantID.ToString(), "crm");
        }

        public static IDataStore GetStoreTemplate()
        {
            return StorageFactory.GetStorage(String.Empty, "crm_template");
        }

        public static bool CanCreateProjects()
        {
            try
            {
                var apiUrl = String.Format("{0}project/securityinfo.json", SetupInfo.WebApiBaseUrl);

                var cacheKey = String.Format("{0}-{1}", ASC.Core.SecurityContext.CurrentAccount.ID, apiUrl);

                bool canCreateProject;

                if (HttpRuntime.Cache[cacheKey] != null)
                    return Convert.ToBoolean(HttpRuntime.Cache[cacheKey]);

                var apiServer = new Api.ApiServer();

                var responseApi = JObject.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(apiServer.GetApiResponse(apiUrl, "GET"))))["response"];

                if (responseApi.HasValues)
                    canCreateProject = Convert.ToBoolean(responseApi["canCreateProject"].Value<String>());
                else
                    canCreateProject = false;
                HttpRuntime.Cache.Remove(cacheKey);
                HttpRuntime.Cache.Insert(cacheKey, canCreateProject, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
                                  TimeSpan.FromMinutes(5));

                return canCreateProject;

            }
            catch
            {
                return false;
            }

        }

        public static bool CanDownloadInvoices
        {
            get
            {
                var canDownloadFiles = false;

                var value = ConfigurationManagerExtension.AppSettings["crm.invoice.download.enable"];
                if (string.IsNullOrEmpty(value)) return false;

                canDownloadFiles = Convert.ToBoolean(value);

                if (canDownloadFiles && string.IsNullOrEmpty(FilesLinkUtility.DocServiceConverterUrl))
                {
                    canDownloadFiles = false;
                }

                return canDownloadFiles;
            }
        }

        public static bool CanCreateReports
        {
            get
            {
                return !string.IsNullOrEmpty(FilesLinkUtility.DocServiceDocbuilderUrl) && CRMSecurity.IsAdmin;
            }
        }

        #region Queue Settings

        public static int GetQueueWorkerCount(string queueName)
        {
            int value;
            var strValue = ConfigurationManagerExtension.AppSettings[string.Format("crm.queue.{0}.workercount", queueName)];
            if (string.IsNullOrEmpty(strValue) || !int.TryParse(strValue, out value))
            {
                value = 1;
            }
            return value;
        }

        public static TimeSpan GetQueueWaitInterval(string queueName)
        {
            TimeSpan value;
            var strValue = ConfigurationManagerExtension.AppSettings[string.Format("crm.queue.{0}.waitinterval", queueName)];
            if (string.IsNullOrEmpty(strValue) || !TimeSpan.TryParse(strValue, out value))
            {
                value = TimeSpan.FromMinutes(1);
            }
            return value;
        }

        #endregion

        #region CRM Settings

        public static void SaveDefaultCurrencySettings(CurrencyInfo currency)
        {
            var tenantSettings = TenantSettings;
            tenantSettings.DefaultCurrency = currency;
            tenantSettings.Save();
        }

        #endregion

        #region Invoice PDF

        public static ASC.Files.Core.File GetInvoicePdfExistingOrCreate(ASC.CRM.Core.Entities.Invoice invoice, DaoFactory factory)
        {
            var existingFile = invoice.GetInvoiceFile(factory);
            if (existingFile != null)
            {
                return existingFile;
            }
            else
            {
                var newFile = PdfCreator.CreateFile(invoice, factory);
                invoice.FileID = Int32.Parse(newFile.ID.ToString());
                factory.InvoiceDao.UpdateInvoiceFileID(invoice.ID, invoice.FileID);
                factory.RelationshipEventDao.AttachFiles(invoice.ContactID, invoice.EntityType, invoice.EntityID, new[] { invoice.FileID });
                return newFile;
            }
        }

        #endregion

        //Code snippet

        public static String GetUpButtonHTML(Uri requestUrlReferrer)
        {
            return String.Format(@"<a title='{0}' {1} class='studio-level-up{2}' style='margin-top: 2px;'></a>",
                                  CRMCommonResource.Up,
                                  requestUrlReferrer != null ? "href='" + requestUrlReferrer.OriginalString + "'" : "",
                                  requestUrlReferrer != null ? "" : " disable");
        }

        public static String RenderItemHeaderWithMenu(String title, EntityType entityType, Boolean isPrivate, Boolean canEdit)
        {
            var sbIcon = new StringBuilder();
            var sbPrivateMark = new StringBuilder();

            string titleIconClass;
            switch (entityType)
            {
                case EntityType.Contact:
                    titleIconClass = "group";
                    break;
                case EntityType.Person:
                    titleIconClass = "people";
                    break;
                case EntityType.Company:
                    titleIconClass = "company";
                    break;
                case EntityType.Case:
                    titleIconClass = "cases";
                    break;
                case EntityType.Opportunity:
                    titleIconClass = "opportunities";
                    break;
                case EntityType.Invoice:
                    titleIconClass = "documents";
                    break;
                default:
                    titleIconClass = string.Empty;
                    break;
            }
            if (!String.IsNullOrEmpty(titleIconClass))
            {
                if (isPrivate)
                {
                    sbPrivateMark.AppendFormat("<div class='privateMark' title='{0}'></div>", CRMCommonResource.Private);
                }
                sbIcon.AppendFormat("<span class='main-title-icon {0}'>{1}</span>", titleIconClass, sbPrivateMark);
            }

            return String.Format(@" <div class='header-with-menu crm-pageHeader'>
                                        {0}<span class='crm-pageHeaderText text-overflow'>{1}</span>
                                        {2}
                                    </div>
                                  ",
                                        sbIcon,
                                        title,
                                        canEdit ? "<span class='menu-small'></span>" : ""
                                      );
        }


        /// <summary>
        /// The method to Decode your Base64 strings.
        /// </summary>
        /// <param name="encodedData">The String containing the characters to decode.</param>
        /// <returns>A String containing the results of decoding the specified sequence of bytes.</returns>
        public static string DecodeFrom64(string encodedData)
        {
            var encodedDataAsBytes = Convert.FromBase64String(encodedData);
            return System.Text.Encoding.UTF8.GetString(encodedDataAsBytes);
        }

        /// <summary>
        /// The method create a Base64 encoded string from a normal string.
        /// </summary>
        /// <param name="toEncode">The String containing the characters to encode.</param>
        /// <returns>The Base64 encoded string.</returns>
        public static string EncodeTo64(string toEncode)
        {
            var toEncodeAsBytes = System.Text.Encoding.UTF8.GetBytes(toEncode);

            return Convert.ToBase64String(toEncodeAsBytes);
        }

        public static byte[] ToByteArray(Stream inputStream)
        {
            var br = new MemoryStream();
            var data = new byte[1024];
            var readed = 0;

            while ((readed = inputStream.Read(data, 0, data.Length)) > 0)
            {
                br.Write(data, 0, readed);
            }
            br.Close();
            return br.ToArray();
        }

        #region CRM Images download

        public static string GetImgFormatName(ImageFormat format)
        {
            if (format.Equals(ImageFormat.Bmp)) return "bmp";
            if (format.Equals(ImageFormat.Emf)) return "emf";
            if (format.Equals(ImageFormat.Exif)) return "exif";
            if (format.Equals(ImageFormat.Gif)) return "gif";
            if (format.Equals(ImageFormat.Icon)) return "icon";
            if (format.Equals(ImageFormat.Jpeg)) return "jpeg";
            if (format.Equals(ImageFormat.MemoryBmp)) return "MemoryBMP";
            if (format.Equals(ImageFormat.Png)) return "png";
            if (format.Equals(ImageFormat.Tiff)) return "tiff";
            if (format.Equals(ImageFormat.Wmf)) return "wmf";

            return "jpg";
        }

        public static byte[] SaveToBytes(Image img)
        {
            return CommonPhotoManager.SaveToBytes(img, GetImgFormatName(img.RawFormat));
        }

        #endregion

        #region Parse JOjbect with ApiDateTime

        private static readonly string[] Formats = new[]
                                                       {
                                                           "o",
                                                           "yyyy'-'MM'-'dd'T'HH'-'mm'-'ss'.'fffK",
                                                           "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK",
                                                           "yyyy-MM-ddTHH:mm:ss"
                                                       };

        public static DateTime ApiDateTimeParse(string data)
        {
            if (string.IsNullOrEmpty(data)) throw new ArgumentNullException("data");

            if (data.Length < 7) throw new ArgumentException(CRMErrorsResource.DateTimeFormatInvalid);

            DateTime dateTime;
            if (DateTime.TryParseExact(data, Formats, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out dateTime))
            {
                return new DateTime(dateTime.Ticks, DateTimeKind.Unspecified);
            }
            throw new ArgumentException(CRMErrorsResource.DateTimeFormatInvalid);
        }

        public static JObject JObjectParseWithDateAsString(string data)
        {
            JsonReader reader = new JsonTextReader(
                          new StringReader(data)
                          );
            reader.DateParseHandling = DateParseHandling.None;
            return JObject.Load(reader);
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/js/navigatorhandler.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined")
    ASC = {};

if (typeof ASC.People === "undefined")
    ASC.People = {};

ASC.People.PageNavigator = (function () {
    var pgNavigator, $totalUsers;

    var init = function () {
        var people = ASC.People,
            resources = people.Resources;

        pgNavigator = new ASC.Controls.PageNavigator.init(
                "ASC.People.PageNavigator.pgNavigator",
                "#peoplePageNavigator",
                25,
                3,
                1,
                resources.PreviousPage,
                resources.NextPage);

        pgNavigator.changePageCallback = function (page) {
            people.PeopleController.moveToPage(page);
        }

        function onRenderProfiles(evt, params) {
            var usersCount = params.__total || params.__count;
            pgNavigator.drawPageNavigator(params.page, usersCount);
            if (!$totalUsers) {
                $totalUsers = jq("#totalUsers");
            }
            $totalUsers.text(usersCount);
        }

        jq(window).bind('people-render-profiles', onRenderProfiles);
    };

    return {
        init: init,
        get pgNavigator() {
            return pgNavigator;
        }
    }
})();

;
jq(document).ready(function () {
    ASC.People.PageNavigator.init();
});


<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailUserFolderData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

namespace ASC.Mail.Data.Contracts
{
    [Serializable]
    [DataContract(Namespace = "", Name = "UserFolder")]
    public class MailUserFolderData
    {
        [DataMember(IsRequired = true, Name = "id")]
        public uint Id { get; set; }

        [DataMember(IsRequired = true, Name = "parent")]
        public uint ParentId { get; set; }

        [DataMember(IsRequired = true, Name = "name")]
        public string Name { get; set; }

        [DataMember(IsRequired = true, Name = "unread_count")]
        public int UnreadCount { get; set; }

        [DataMember(IsRequired = true, Name = "total_count")]
        public int TotalCount { get; set; }

        [DataMember(IsRequired = true, Name = "unread_chain_count")]
        public int UnreadChainCount { get; set; }

        [DataMember(IsRequired = true, Name = "total_chain_count")]
        public int TotalChainCount { get; set; }

        [DataMember(IsRequired = true, Name = "folder_count")]
        public int FolderCount { get; set; }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Masters/ClientScripts/CRMSettingsResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Globalization;
using System.Web;

using ASC.Core;
using ASC.Core.Users;
using ASC.CRM.Core;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Configuration;

namespace ASC.Web.CRM.Masters.ClientScripts
{
    public class CRMSettingsResources : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.CRM.Data"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            var imgs = new Dictionary<string, string>
                {
                    {"empty_screen_filter", WebImageSupplier.GetAbsoluteWebPath("empty_screen_filter.png")},
                    {"empty_screen_tasks", WebImageSupplier.GetAbsoluteWebPath("empty_screen_tasks.png", ProductEntryPoint.ID)},
                    {"empty_screen_deals", WebImageSupplier.GetAbsoluteWebPath("empty_screen_deals.png", ProductEntryPoint.ID)},
                    {"empty_screen_cases", WebImageSupplier.GetAbsoluteWebPath("empty_screen_cases.png", ProductEntryPoint.ID)},
                    {"empty_screen_invoices", WebImageSupplier.GetAbsoluteWebPath("empty_screen_invoices.png", ProductEntryPoint.ID)},
                    {"empty_screen_products_services", WebImageSupplier.GetAbsoluteWebPath("empty_screen_products_services.png", ProductEntryPoint.ID)},
                    {"empty_screen_taxes", WebImageSupplier.GetAbsoluteWebPath("empty_screen_taxes.png", ProductEntryPoint.ID)},
                    {"empty_screen_persons", WebImageSupplier.GetAbsoluteWebPath("empty_screen_persons.png", ProductEntryPoint.ID)},
                    {"empty_screen_phones", WebImageSupplier.GetAbsoluteWebPath("empty_screen_phones.png", ProductEntryPoint.ID)},
                    {"empty_screen_voip_settings", WebImageSupplier.GetAbsoluteWebPath("empty_screen_voip_settings.png", ProductEntryPoint.ID)},
                    {"empty_people_logo_40_40", WebImageSupplier.GetAbsoluteWebPath("empty_people_logo_40_40.png", ProductEntryPoint.ID)},
                    {"empty_screen_opportunity_participants", WebImageSupplier.GetAbsoluteWebPath("empty_screen_opportunity_participants.png", ProductEntryPoint.ID)},
                    {"empty_screen_company_participants", WebImageSupplier.GetAbsoluteWebPath("empty_screen_company_participants.png", ProductEntryPoint.ID)},
                    {"empty_screen_case_participants", WebImageSupplier.GetAbsoluteWebPath("empty_screen_case_participants.png", ProductEntryPoint.ID)},
                    {"empty_screen_projects", WebImageSupplier.GetAbsoluteWebPath("empty_screen_projects.png", ProductEntryPoint.ID)},
                    {"empty_screen_userfields", WebImageSupplier.GetAbsoluteWebPath("empty_screen_userfields.png", ProductEntryPoint.ID)},
                    {"empty_screen_tags", WebImageSupplier.GetAbsoluteWebPath("empty_screen_tags.png", ProductEntryPoint.ID)},
                    {"empty_screen_twitter", WebImageSupplier.GetAbsoluteWebPath("empty_screen_twitter.png", ProductEntryPoint.ID)}
                };

            return new List<KeyValuePair<string, object>>(1)
                   {
                       RegisterObject(
                           new
                           {
                               MediumSizePhotoCompany = ContactPhotoManager.GetMediumSizePhoto(0, true),
                               MediumSizePhoto = ContactPhotoManager.GetMediumSizePhoto(0, false),
                               SmallSizePhotoCompany = ContactPhotoManager.GetSmallSizePhoto(0, true),
                               SmallSizePhoto = ContactPhotoManager.GetSmallSizePhoto(0, false),
                               ProfileRemoved = Constants.LostUser.DisplayUserName(),
                               System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencyDecimalSeparator,
                               KeyCodeCurrencyDecimalSeparator = (int)System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.CurrencyDecimalSeparator[0],
                               Global.VisiblePageCount,
                               DefaultEntryCountOnPage = Global.EntryCountOnPage,
                               Global.DefaultCustomFieldSize,
                               Global.DefaultCustomFieldRows,
                               Global.DefaultCustomFieldCols,
                               Global.MaxCustomFieldSize,
                               Global.MaxCustomFieldRows,
                               Global.MaxCustomFieldCols,
                               Global.MaxHistoryEventCharacters,
                               Global.MaxInvoiceItemPrice,
                               Global.CanDownloadInvoices,
                               IsCRMAdmin = CRMSecurity.IsAdmin,
                               EmptyScrImgs = imgs,
                               ImageWebPath = WebImageSupplier.GetImageFolderAbsoluteWebPath(ProductEntryPoint.ID),

                               ContactSelectorTypeEnum =
                                    new Dictionary<string, int>
                                    {
                                        {"All", (int)ContactSelectorTypeEnum.All},
                                        {"Companies", (int)ContactSelectorTypeEnum.Companies},
                                        {"CompaniesAndPersonsWithoutCompany", (int)ContactSelectorTypeEnum.CompaniesAndPersonsWithoutCompany},
                                        {"Persons", (int)ContactSelectorTypeEnum.Persons},
                                        {"PersonsWithoutCompany", (int)ContactSelectorTypeEnum.PersonsWithoutCompany}
                                    },

                               HistoryCategorySystem =
                                   new Dictionary<string, int>
                                       {
                                           {"TaskClosed", (int)HistoryCategorySystem.TaskClosed},
                                           {"FilesUpload", (int)HistoryCategorySystem.FilesUpload},
                                           {"MailMessage", (int)HistoryCategorySystem.MailMessage}
                                       },

                               DefaultContactPhoto =
                                   new Dictionary<string, string>
                                       {
                                           {"CompanyBigSizePhoto", ContactPhotoManager.GetBigSizePhoto(0, true)},
                                           {"PersonBigSizePhoto", ContactPhotoManager.GetBigSizePhoto(0, false)},
                                           {"CompanyMediumSizePhoto", ContactPhotoManager.GetMediumSizePhoto(0, true)},
                                           {"PersonMediumSizePhoto", ContactPhotoManager.GetMediumSizePhoto(0, false)}
                                       },

                               CookieKeyForPagination =
                                   new Dictionary<string, string>
                                       {
                                           {"contacts", "contactPageNumber"},
                                           {"tasks", "taskPageNumber"},
                                           {"deals", "dealPageNumber"},
                                           {"cases", "casesPageNumber"},
                                           {"invoices", "invoicePageNumber"},
                                           {"invoiceitems", "invoiceItemsPageNumber"}
                                       },

                               CanCreateProjects = Global.CanCreateProjects()
                           })
                   };
        }

        protected override string GetCacheHash()
        {
            /* return user last mod time + culture */
            var hash = SecurityContext.CurrentAccount.ID.ToString()
                       + CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).LastModified.ToString(CultureInfo.InvariantCulture)
                       + CoreContext.TenantManager.GetCurrentTenant().LastModified.ToString(CultureInfo.InvariantCulture);
            return hash;
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Configuration/SmtpSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

namespace ASC.Core.Configuration
{
    public class SmtpSettings
    {
        public const int DefaultSmtpPort = 25;
        public const string DefaultSenderDisplayName = "ONLYOFFICE Postman";

        public string Host { get; private set; }

        public int Port { get; private set; }

        public string SenderAddress { get; private set; }

        public string SenderDisplayName { get; private set; }

        public string CredentialsDomain { get; private set; }

        public string CredentialsUserName { get; private set; }

        public string CredentialsUserPassword { get; private set; }

        public bool EnableSSL { get; set; }

        public bool EnableAuth { get; set; }

        public bool IsDefaultSettings { get; internal set; }

        public static SmtpSettings Empty = new SmtpSettings();

        private SmtpSettings()
        {

        }

        public SmtpSettings(string host, string senderAddress)
            : this(host, senderAddress, DefaultSenderDisplayName)
        {

        }

        public SmtpSettings(string host, string senderAddress, string senderDisplayName)
            : this(host, DefaultSmtpPort, senderAddress, senderDisplayName)
        {

        }

        public SmtpSettings(string host, int port, string senderAddress)
            : this(host, port, senderAddress, DefaultSenderDisplayName)
        {

        }

        public SmtpSettings(string host, int port, string senderAddress, string senderDisplayName)
        {
            if (string.IsNullOrEmpty(host))
            {
                throw new ArgumentException("Empty smtp host.", "host");
            }
            if (string.IsNullOrEmpty(senderAddress))
            {
                throw new ArgumentException("Empty sender address.", "senderAddress");
            }
            if (senderDisplayName == null)
            {
                throw new ArgumentNullException("senderDisplayName");
            }
            Host = host;
            Port = port;
            SenderAddress = senderAddress;
            SenderDisplayName = senderDisplayName;
        }

        public void SetCredentials(string userName, string password)
        {
            SetCredentials(userName, password, string.Empty);
        }

        public void SetCredentials(string userName, string password, string domain)
        {
            if (string.IsNullOrEmpty(userName))
            {
                throw new ArgumentException("Empty user name.", "userName");
            }
            if (string.IsNullOrEmpty(password))
            {
                throw new ArgumentException("Empty password.", "password");
            }
            CredentialsUserName = userName;
            CredentialsUserPassword = password;
            CredentialsDomain = domain;
        }

        public string Serialize()
        {
            return ToString();
        }

        public static SmtpSettings Deserialize(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return Empty;
            }

            var props = value.Split(new[] { '#' }, StringSplitOptions.None);
            props = Array.ConvertAll(props, p => !string.IsNullOrEmpty(p) ? p : null);

            var host = HttpUtility.UrlDecode(props[3]);
            var port = !string.IsNullOrEmpty(props[4]) ? Int32.Parse(props[4]) : DefaultSmtpPort;
            var senderAddress = HttpUtility.UrlDecode(props[5]);
            var senderDisplayName = HttpUtility.UrlDecode(props[6]) ?? DefaultSenderDisplayName;

            var settings = new SmtpSettings(host, port, senderAddress, senderDisplayName)
            {
                EnableSSL = 7 < props.Length && !string.IsNullOrEmpty(props[7]) && Convert.ToBoolean(props[7])
            };

            var credentialsUserName = HttpUtility.UrlDecode(props[1]);
            var credentialsUserPassword = HttpUtility.UrlDecode(props[2]);
            var credentialsDomain = HttpUtility.UrlDecode(props[0]);
            if (!string.IsNullOrEmpty(credentialsUserName) && !string.IsNullOrEmpty(credentialsUserPassword))
            {
                settings.SetCredentials(credentialsUserName, credentialsUserPassword, credentialsDomain);
                settings.EnableAuth = true;
            }
            else
            {
                settings.EnableAuth = false;
            }

            return settings;
        }

        public override string ToString()
        {
            return string.Join("#",
                               HttpUtility.UrlEncode(CredentialsDomain),
                               HttpUtility.UrlEncode(CredentialsUserName),
                               HttpUtility.UrlEncode(CredentialsUserPassword),
                               HttpUtility.UrlEncode(Host),
                               Port.ToString(),
                               HttpUtility.UrlEncode(SenderAddress),
                               HttpUtility.UrlEncode(SenderDisplayName),
                               EnableSSL.ToString());
        }
    }
}


<|start_filename|>module/ASC.Mail/Services/ASC.Mail.Aggregator.CollectionService/Queue/Data/Extensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Net.Mail;

using ASC.Mail.Data.Contracts;

namespace ASC.Mail.Aggregator.CollectionService.Queue.Data
{
    public static class Extensions
    {
        public static MailBoxData ToMailbox(this MailboxData mailboxData)
        {
            return new MailBoxData
            {
                TenantId = mailboxData.TenantId,
                UserId = mailboxData.UserId,
                MailBoxId = mailboxData.MailboxId,
                EMail = new MailAddress(mailboxData.EMail),
                Imap = mailboxData.Imap,
                IsTeamlab = mailboxData.IsTeamlab,
                Size = mailboxData.Size,
                MessagesCount = mailboxData.MessagesCount
            };
        }

        public static MailboxData ToMailboxData(this MailBoxData mailbox)
        {
            return new MailboxData
            {
                MailboxId = mailbox.MailBoxId,
                TenantId = mailbox.TenantId,
                UserId = mailbox.UserId,
                EMail = mailbox.EMail.Address,
                Imap = mailbox.Imap,
                IsTeamlab = mailbox.IsTeamlab,
                MessagesCount = mailbox.MessagesCount,
                Size = mailbox.Size
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Utils/FileSharing.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;

using ASC.Core;
using ASC.Core.Users;
using ASC.Files.Core;
using ASC.Files.Core.Security;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Services.DocumentService;
using ASC.Web.Files.Services.NotifyService;
using ASC.Web.Files.Services.WCFService;
using ASC.Web.Studio.Utility;

using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Web.Files.Utils
{
    public static class FileSharing
    {
        public static bool CanSetAccess(FileEntry entry)
        {
            return
                entry != null
                && (entry.RootFolderType == FolderType.COMMON && Global.IsAdministrator
                    || !CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor()
                        && (entry.RootFolderType == FolderType.USER
                            && (Equals(entry.RootFolderId, Global.FolderMy) || Global.GetFilesSecurity().CanEdit(entry))
                            || entry.RootFolderType == FolderType.Privacy
                                && entry is File
                                && (Equals(entry.RootFolderId, Global.FolderPrivacy) || Global.GetFilesSecurity().CanEdit(entry))));
        }

        public static List<AceWrapper> GetSharedInfo(FileEntry entry)
        {
            if (entry == null) throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest);
            if (!CanSetAccess(entry))
            {
                Global.Logger.ErrorFormat("User {0} can't get shared info for {1} {2}", SecurityContext.CurrentAccount.ID, (entry.FileEntryType == FileEntryType.File ? "file" : "folder"), entry.ID);
                throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);
            }

            var linkAccess = FileShare.Restrict;
            var result = new List<AceWrapper>();

            var fileSecurity = Global.GetFilesSecurity();

            var records = fileSecurity
                .GetShares(entry)
                .GroupBy(r => r.Subject)
                .Select(g => g.OrderBy(r => r.Level)
                              .ThenBy(r => r.Level)
                              .ThenByDescending(r => r.Share, new FileShareRecord.ShareComparer()).FirstOrDefault());

            foreach (var r in records)
            {
                if (r.Subject == FileConstant.ShareLinkId)
                {
                    linkAccess = r.Share;
                    continue;
                }

                var u = CoreContext.UserManager.GetUsers(r.Subject);
                var isgroup = false;
                var title = u.DisplayUserName(false);
                var share = r.Share;

                if (u.ID == Constants.LostUser.ID)
                {
                    var g = CoreContext.UserManager.GetGroupInfo(r.Subject);
                    isgroup = true;
                    title = g.Name;

                    if (g.ID == Constants.GroupAdmin.ID)
                        title = FilesCommonResource.Admin;
                    if (g.ID == Constants.GroupEveryone.ID)
                        title = FilesCommonResource.Everyone;

                    if (g.ID == Constants.LostGroupInfo.ID)
                    {
                        fileSecurity.RemoveSubject(r.Subject);
                        continue;
                    }
                }
                else if (u.IsVisitor()
                    && new FileShareRecord.ShareComparer().Compare(FileShare.Read, share) > 0)
                {
                    share = FileShare.Read;
                }

                var w = new AceWrapper
                {
                    SubjectId = r.Subject,
                    SubjectName = title,
                    SubjectGroup = isgroup,
                    Share = share,
                    Owner =
                            entry.RootFolderType == FolderType.USER
                                ? entry.RootFolderCreator == r.Subject
                                : entry.CreateBy == r.Subject,
                    LockedRights = r.Subject == SecurityContext.CurrentAccount.ID
                };
                result.Add(w);
            }

            if (entry.FileEntryType == FileEntryType.File
                && !((File)entry).Encrypted
                && result.All(w => w.SubjectId != FileConstant.ShareLinkId)
                && (linkAccess != FileShare.Restrict || CoreContext.Configuration.Standalone || !TenantExtra.GetTenantQuota().Trial || FileUtility.CanWebView(entry.Title)))
            {
                var w = new AceWrapper
                {
                    SubjectId = FileConstant.ShareLinkId,
                    Link = FileShareLink.GetLink((File)entry),
                    SubjectGroup = true,
                    Share = linkAccess,
                    Owner = false
                };
                result.Add(w);
            }

            if (!result.Any(w => w.Owner))
            {
                var ownerId = entry.RootFolderType == FolderType.USER ? entry.RootFolderCreator : entry.CreateBy;
                var w = new AceWrapper
                {
                    SubjectId = ownerId,
                    SubjectName = Global.GetUserName(ownerId),
                    SubjectGroup = false,
                    Share = FileShare.ReadWrite,
                    Owner = true
                };
                result.Add(w);
            }

            if (result.Any(w => w.SubjectId == SecurityContext.CurrentAccount.ID))
            {
                result.Single(w => w.SubjectId == SecurityContext.CurrentAccount.ID).LockedRights = true;
            }

            if (entry.RootFolderType == FolderType.COMMON)
            {
                if (result.All(w => w.SubjectId != Constants.GroupAdmin.ID))
                {
                    var w = new AceWrapper
                    {
                        SubjectId = Constants.GroupAdmin.ID,
                        SubjectName = FilesCommonResource.Admin,
                        SubjectGroup = true,
                        Share = FileShare.ReadWrite,
                        Owner = false,
                        LockedRights = true,
                    };
                    result.Add(w);
                }
                if (result.All(w => w.SubjectId != Constants.GroupEveryone.ID))
                {
                    var w = new AceWrapper
                    {
                        SubjectId = Constants.GroupEveryone.ID,
                        SubjectName = FilesCommonResource.Everyone,
                        SubjectGroup = true,
                        Share = fileSecurity.DefaultCommonShare,
                        Owner = false,
                        DisableRemove = true
                    };
                    result.Add(w);
                }
            }

            return result;
        }

        public static bool SetAceObject(List<AceWrapper> aceWrappers, FileEntry entry, bool notify, string message)
        {
            if (entry == null) throw new ArgumentNullException(FilesCommonResource.ErrorMassage_BadRequest);
            if (!CanSetAccess(entry)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

            var fileSecurity = Global.GetFilesSecurity();

            var entryType = entry.FileEntryType;
            var recipients = new Dictionary<Guid, FileShare>();
            var usersWithoutRight = new List<Guid>();
            var changed = false;

            foreach (var w in aceWrappers.OrderByDescending(ace => ace.SubjectGroup))
            {
                var subjects = fileSecurity.GetUserSubjects(w.SubjectId);

                var ownerId = entry.RootFolderType == FolderType.USER ? entry.RootFolderCreator : entry.CreateBy;
                if (entry.RootFolderType == FolderType.COMMON && subjects.Contains(Constants.GroupAdmin.ID)
                    || ownerId == w.SubjectId)
                    continue;

                var share = w.Share;

                if (w.SubjectId == FileConstant.ShareLinkId)
                {
                    if (w.Share == FileShare.ReadWrite && CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor())
                        throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

                    // only editable format on personal
                    if (CoreContext.Configuration.Personal && !FileUtility.CanWebView(entry.Title) && w.Share != FileShare.Restrict)
                        throw new SecurityException(FilesCommonResource.ErrorMassage_BadRequest);

                    // only editable format on SaaS trial
                    if (w.Share != FileShare.Restrict && !CoreContext.Configuration.Standalone && TenantExtra.GetTenantQuota().Trial && !FileUtility.CanWebView(entry.Title))
                        throw new SecurityException(FilesCommonResource.ErrorMassage_BadRequest);

                    share = w.Share == FileShare.Restrict ? FileShare.None : w.Share;
                }

                fileSecurity.Share(entry.ID, entryType, w.SubjectId, share);
                changed = true;

                if (w.SubjectId == FileConstant.ShareLinkId)
                    continue;

                entry.Access = share;

                var listUsersId = new List<Guid>();

                if (w.SubjectGroup)
                    listUsersId = CoreContext.UserManager.GetUsersByGroup(w.SubjectId).Select(ui => ui.ID).ToList();
                else
                    listUsersId.Add(w.SubjectId);
                listUsersId.Remove(SecurityContext.CurrentAccount.ID);

                if (entryType == FileEntryType.File)
                {
                    listUsersId.ForEach(uid => FileTracker.ChangeRight(entry.ID, uid, true));
                }

                var addRecipient = share == FileShare.Read
                                   || share == FileShare.CustomFilter
                                   || share == FileShare.ReadWrite
                                   || share == FileShare.Review
                                   || share == FileShare.FillForms
                                   || share == FileShare.Comment
                                   || share == FileShare.None && entry.RootFolderType == FolderType.COMMON;
                var removeNew = share == FileShare.None && entry.RootFolderType == FolderType.USER
                                || share == FileShare.Restrict;
                listUsersId.ForEach(id =>
                                        {
                                            recipients.Remove(id);
                                            if (addRecipient)
                                            {
                                                recipients.Add(id, share);
                                            }
                                            else if (removeNew)
                                            {
                                                usersWithoutRight.Add(id);
                                            }
                                        });
            }

            if (entryType == FileEntryType.File)
            {
                DocumentServiceHelper.CheckUsersForDrop((File)entry);
            }

            if (recipients.Any())
            {
                if (entryType == FileEntryType.File
                    || ((Folder)entry).TotalSubFolders + ((Folder)entry).TotalFiles > 0
                    || entry.ProviderEntry)
                {
                    FileMarker.MarkAsNew(entry, recipients.Keys.ToList());
                }

                if ((entry.RootFolderType == FolderType.USER
                    || entry.RootFolderType == FolderType.Privacy)
                    && notify)
                {
                    NotifyClient.SendShareNotice(entry, recipients, message);
                }
            }

            usersWithoutRight.ForEach(userId => FileMarker.RemoveMarkAsNew(entry, userId));

            return changed;
        }

        public static void RemoveAce(List<FileEntry> entries)
        {
            var fileSecurity = Global.GetFilesSecurity();

            entries.ForEach(
                entry =>
                    {
                        if (entry.RootFolderType != FolderType.USER && entry.RootFolderType != FolderType.Privacy
                            || Equals(entry.RootFolderId, Global.FolderMy)
                            || Equals(entry.RootFolderId, Global.FolderPrivacy))
                            return;

                        var entryType = entry.FileEntryType;
                        fileSecurity.Share(entry.ID, entryType, SecurityContext.CurrentAccount.ID,
                            entry.RootFolderType == FolderType.USER
                            ? fileSecurity.DefaultMyShare
                            : fileSecurity.DefaultPrivacyShare);

                        if (entryType == FileEntryType.File)
                        {
                            DocumentServiceHelper.CheckUsersForDrop((File)entry);
                        }

                        FileMarker.RemoveMarkAsNew(entry);
                    });
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Search/FieldsWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Core;
using ASC.ElasticSearch;

namespace ASC.Web.CRM.Core.Search
{
    public sealed class FieldsWrapper : Wrapper
    {
        [ColumnLastModified("last_modifed_on")]
        public override DateTime LastModifiedOn { get; set; }

        [ColumnCondition("field_id", 1)]
        public int FieldId { get; set; }

        [ColumnCondition("entity_id", 2)]
        public int EntityId { get; set; }

        [ColumnCondition("entity_type", 3)]
        public int EntityType { get; set; }

        [Column("value", 4)]
        public string Value { get; set; }

        protected override string Table { get { return "crm_field_value"; } }

        public static implicit operator FieldsWrapper(ASC.CRM.Core.Entities.CustomField cf)
        {
            return new FieldsWrapper
            {
                Id = cf.ID,
                EntityId = cf.EntityID,
                EntityType = (int)cf.EntityType,
                Value = cf.Value,
                TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Search/InvoicesWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Core;
using ASC.ElasticSearch;

namespace ASC.Web.CRM.Core.Search
{
    public sealed class InvoicesWrapper : Wrapper
    {
        [ColumnLastModified("last_modifed_on")]
        public override DateTime LastModifiedOn { get; set; }

        [Column("number", 1)]
        public string Number { get; set; }

        [Column("terms", 2)]
        public string Terms { get; set; }

        [Column("description", 3)]
        public string Description { get; set; }

        [Column("purchase_order_number", 4)]
        public string PurchaseOrderNumber { get; set; }

        protected override string Table { get { return "crm_invoice"; } }

        public static implicit operator InvoicesWrapper(ASC.CRM.Core.Entities.Invoice invoice)
        {
            return new InvoicesWrapper
            {
                Id = invoice.ID,
                Number = invoice.Number,
                Terms = invoice.Terms,
                Description = invoice.Description,
                PurchaseOrderNumber = invoice.PurchaseOrderNumber,
                TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Controls/Tree/treebuilder.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#treeViewContainer {
    overflow: unset;
    padding: 0 0 2px 4px;
}
#treeViewContainer.jstree-inprojects {
    max-height: 500px;
}
.page-menu .menu-list .menu-sub-list #treeViewContainer {
    padding-left: 24px;
}
#treeViewPanelSelector {
    max-height: 520px;
    max-width: 850px;
    overflow: auto;
    position: absolute;
    z-index: 700;
}
#treeViewPanelSelector .select-folder-header {
    margin-bottom: 5px;
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Sample/Configuration/SampleSearchHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Web.Core.ModuleManagement.Common;
using ASC.Web.Core.Utility;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Sample.Classes;
using ASC.Web.Sample.Resources;

namespace ASC.Web.Sample.Configuration
{
    public class SampleSearchHandler : BaseSearchHandlerEx
    {
        public override Guid ProductID
        {
            get { return ProductEntryPoint.Id; }
        }

        public override Guid ModuleID
        {
            get { return ProductID; }
        }

        public override ImageOptions Logo
        {
            get { return new ImageOptions { ImageFileName = "common_search_icon.png" }; }
        }

        public override string SearchName
        {
            get { return SampleResource.Search; }
        }

        public override IItemControl Control
        {
            get { return new SearchResultsView(); }
        }

        public override SearchResultItem[] Search(string searchText)
        {
            //TODO: search by text implementation
            return new[]
                {
                    new SearchResultItem
                        {
                            Name = "SearchResultItem " + searchText + " Name",
                            Description = "SearchResultItem " + searchText + " Description",
                            URL = PathProvider.BaseAbsolutePath,
                            Date = DateTime.Now
                        }
                };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Server/IMAP_eArgs_Search.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace LumiSoft.Net.IMAP.Server
{
	/// <summary>
	/// Provides data from IMAP Search command.
	/// </summary>
	public class IMAP_eArgs_Search
	{
		private IMAP_Session       m_pSession  = null;
		private string             m_Folder    = "";
		private IMAP_Messages      m_pMessages = null;
		private IMAP_SearchMatcher m_pMatcher  = null;

		/// <summary>
		/// Default constructor.
		/// </summary>
		/// <param name="session">IMAP session what calls this search.</param>
		/// <param name="folder">IMAP folder name which messages to search.</param>
		/// <param name="matcher">Matcher what must be used to check if message matches searching criterial.</param>
		public IMAP_eArgs_Search(IMAP_Session session,string folder,IMAP_SearchMatcher matcher)
		{
			m_pSession  = session;
			m_Folder    = folder;
			m_pMatcher  = matcher;
			
			m_pMessages = new IMAP_Messages(folder);
		}

        
		#region Properties Implementation

		/// <summary>
		/// Gets current session.
		/// </summary>
		public IMAP_Session Session
		{
			get{ return m_pSession; }
		}

		/// <summary>
		/// Gets folder name which messages to search.
		/// </summary>
		public string Folder
		{
			get{ return m_Folder; }
		}

		/// <summary>
		/// Gets or sets messges what match searching criterial. 
		/// </summary>
		public IMAP_Messages MatchingMessages
		{
			get{ return m_pMessages; }
		}

		/// <summary>
		/// Gets matcher what must be used to check if message matches searching criterial.
		/// </summary>
		public IMAP_SearchMatcher Matcher
		{
			get{ return m_pMatcher; }
		}

		#endregion

	}
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/ServerEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Security;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Extensions;
using ASC.Mail.Server.Core.Entities;
using ASC.Mail.Server.Utils;
using ASC.Mail.Utils;
using ASC.Web.Core;

using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Mail.Core.Engine
{
    public class ServerEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ILog Log { get; private set; }

        public ServerEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.ServerEngine");
        }

        public List<MailAddressInfo> GetAliases(int mailboxId)
        {
            const string server_address = "sa";
            const string server_domain = "sd";

            var queryForExecution = new SqlQuery(ServerAddressTable.TABLE_NAME.Alias(server_address))
                .Select(ServerAddressTable.Columns.Id.Prefix(server_address))
                .Select(ServerAddressTable.Columns.AddressName.Prefix(server_address))
                .Select(ServerDomainTable.Columns.DomainName.Prefix(server_domain))
                .Select(ServerDomainTable.Columns.Id.Prefix(server_domain))
                .InnerJoin(ServerDomainTable.TABLE_NAME.Alias(server_domain),
                    Exp.EqColumns(ServerAddressTable.Columns.DomainId.Prefix(server_address),
                        ServerDomainTable.Columns.Id.Prefix(server_domain)))
                .Where(ServerAddressTable.Columns.MailboxId.Prefix(server_address), mailboxId)
                .Where(ServerAddressTable.Columns.IsAlias.Prefix(server_address), true);

            using (var daoFactory = new DaoFactory())
            {
                var res = daoFactory.DbManager.ExecuteList(queryForExecution);
                if (res == null)
                {
                    return new List<MailAddressInfo>();
                }
                return res.ConvertAll(r => new MailAddressInfo(Convert.ToInt32(r[0]),
                      string.Format("{0}@{1}", r[1], r[2]), Convert.ToInt32(r[3])));
            }
        }

        public List<MailAddressInfo> GetGroups(int mailboxId)
        {
            const string groups = "sg";
            const string group_x_address = "ga";
            const string server_address = "sa";
            const string server_domain = "sd";

            var queryForExecution = new SqlQuery(ServerAddressTable.TABLE_NAME.Alias(server_address))
                .Select(ServerMailGroupTable.Columns.Id.Prefix(groups))
                .Select(ServerMailGroupTable.Columns.Address.Prefix(groups))
                .Select(ServerDomainTable.Columns.Id.Prefix(server_domain))
                .InnerJoin(ServerDomainTable.TABLE_NAME.Alias(server_domain),
                           Exp.EqColumns(ServerAddressTable.Columns.DomainId.Prefix(server_address),
                                         ServerDomainTable.Columns.Id.Prefix(server_domain)))
                .InnerJoin(ServerMailGroupXAddressesTable.TABLE_NAME.Alias(group_x_address),
                           Exp.EqColumns(ServerAddressTable.Columns.Id.Prefix(server_address),
                                         ServerMailGroupXAddressesTable.Columns.AddressId.Prefix(group_x_address)))
                .InnerJoin(ServerMailGroupTable.TABLE_NAME.Alias(groups),
                           Exp.EqColumns(ServerMailGroupXAddressesTable.Columns.MailGroupId.Prefix(group_x_address),
                                         ServerMailGroupTable.Columns.Id.Prefix(groups)))
                .Where(ServerAddressTable.Columns.MailboxId.Prefix(server_address), mailboxId);

            using (var daoFactory = new DaoFactory())
            {
                var res = daoFactory.DbManager.ExecuteList(queryForExecution);
                if (res == null)
                {
                    return new List<MailAddressInfo>();
                }
                return res.ConvertAll(r =>
                    new MailAddressInfo(Convert.ToInt32(r[0]), Convert.ToString(r[1]), Convert.ToInt32(r[2])));
            }
        }

        public Entities.Server GetLinkedServer()
        {
            using (var daoFactory = new DaoFactory())
            {
                var serverDao = daoFactory.CreateServerDao();

                var linkedServer = serverDao.Get(Tenant);

                return linkedServer;
            }
        }

        public List<Entities.Server> GetAllServers()
        {
            using (var daoFactory = new DaoFactory())
            {
                return GetAllServers(daoFactory);
            }
        }

        private static List<Entities.Server> GetAllServers(IDaoFactory daoFactory)
        {
            var serverDao = daoFactory.CreateServerDao();

            var servers = serverDao.GetList();

            return servers;
        }

        public void Link(Entities.Server server, int tenant)
        {
            if (server == null)
                return;

            using (var daoFactory = new DaoFactory())
            {
                Link(daoFactory, server, tenant);
            }
        }

        public void Link(IDaoFactory daoFactory, Entities.Server server, int tenant)
        {
            if (server == null)
                return;

            var serverDao = daoFactory.CreateServerDao();

            var result = serverDao.Link(server, Tenant);

            if (result <= 0)
                throw new Exception("Invalid insert operation");
        }

        public void UnLink(Entities.Server server, int tenant)
        {
            if (server == null)
                return;

            using (var daoFactory = new DaoFactory())
            {
                var serverDao = daoFactory.CreateServerDao();

                serverDao.UnLink(server, Tenant);
            }
        }

        public int Save(Entities.Server server)
        {
            if (server == null)
                throw new ArgumentNullException("server");

            using (var daoFactory = new DaoFactory())
            {
                var serverDao = daoFactory.CreateServerDao();

                var id = serverDao.Save(server);

                return id;
            }
        }

        public void Delete(int serverId)
        {
            if (serverId <= 0)
                throw new ArgumentOutOfRangeException("serverId");

            using (var daoFactory = new DaoFactory())
            {
                var serverDao = daoFactory.CreateServerDao();

                serverDao.Delete(serverId);
            }
        }

        public Entities.Server GetOrCreate(IDaoFactory daoFactory)
        {
            var serverDao = daoFactory.CreateServerDao();

            var linkedServer = serverDao.Get(Tenant);

            if (linkedServer != null)
                return linkedServer;

            var servers = GetAllServers(daoFactory);

            if (!servers.Any())
                throw new Exception("Mail Server not configured");

            var server = servers.First();

            Link(daoFactory, server, Tenant);

            linkedServer = server;

            return linkedServer;
        }

        public ServerData GetMailServer()
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            using (var daoFactory = new DaoFactory())
            {
                return GetMailServer(daoFactory);
            }
        }

        public string GetMailServerMxDomain()
        {
            using (var daoFactory = new DaoFactory())
            {
                var server = GetMailServer(daoFactory);

                return server.Dns.MxRecord.Host;
            }
        }

        private ServerData GetMailServer(IDaoFactory daoFactory)
        {
            var linkedServer = GetOrCreate(daoFactory);

            var dns = GetOrCreateUnusedDnsData(daoFactory, linkedServer);

            var mailboxServerDao = daoFactory.CreateMailboxServerDao();

            var inServer = mailboxServerDao.GetServer(linkedServer.ImapSettingsId);
            var outServer = mailboxServerDao.GetServer(linkedServer.SmtpSettingsId);

            return new ServerData
            {
                Id = linkedServer.Id,
                Dns = dns,
                ServerLimits = new ServerLimitData
                {
                    MailboxMaxCountPerUser = Defines.ServerDomainMailboxPerUserLimit
                },
                InServer = inServer,
                OutServer = outServer
            };
        }

        public ServerDomainDnsData GetOrCreateUnusedDnsData()
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            using (var daoFactory = new DaoFactory())
            {
                var server = GetOrCreate(daoFactory);
                return GetOrCreateUnusedDnsData(daoFactory, server);
            }
        }

        public ServerDomainDnsData GetOrCreateUnusedDnsData(IDaoFactory daoFactory, Entities.Server server)
        {
            var serverDnsDao = daoFactory.CreateServerDnsDao(Tenant, User);

            var dnsSettings = serverDnsDao.GetFree();

            if (dnsSettings == null)
            {
                string privateKey, publicKey;
                CryptoUtil.GenerateDkimKeys(out privateKey, out publicKey);

                var domainCheckValue = PasswordGenerator.GenerateNewPassword(16);
                var domainCheck = Defines.ServerDnsDomainCheckPrefix + ": " + domainCheckValue;

                var serverDns = new ServerDns
                {
                    Id = 0,
                    Tenant = Tenant,
                    User = User,
                    DomainId = Defines.UNUSED_DNS_SETTING_DOMAIN_ID,
                    DomainCheck = domainCheck,
                    DkimSelector = Defines.ServerDnsDkimSelector,
                    DkimPrivateKey = privateKey,
                    DkimPublicKey = publicKey,
                    DkimTtl = Defines.ServerDnsDefaultTtl,
                    DkimVerified = false,
                    DkimDateChecked = null,
                    Spf = Defines.ServerDnsSpfRecordValue,
                    SpfTtl = Defines.ServerDnsDefaultTtl,
                    SpfVerified = false,
                    SpfDateChecked = null,
                    Mx = server.MxRecord,
                    MxTtl = Defines.ServerDnsDefaultTtl,
                    MxVerified = false,
                    MxDateChecked = null,
                    TimeModified = DateTime.UtcNow
                };

                serverDns.Id = serverDnsDao.Save(serverDns);

                dnsSettings = serverDns;
            }

            var dnsData = new ServerDomainDnsData
            {
                Id = dnsSettings.Id,
                MxRecord = new ServerDomainMxRecordData
                {
                    Host = dnsSettings.Mx,
                    IsVerified = false,
                    Priority = Defines.ServerDnsMxRecordPriority
                },
                DkimRecord = new ServerDomainDkimRecordData
                {
                    Selector = dnsSettings.DkimSelector,
                    IsVerified = false,
                    PublicKey = dnsSettings.DkimPublicKey
                },
                DomainCheckRecord = new ServerDomainDnsRecordData
                {
                    Name = Defines.DNS_DEFAULT_ORIGIN,
                    IsVerified = false,
                    Value = dnsSettings.DomainCheck
                },
                SpfRecord = new ServerDomainDnsRecordData
                {
                    Name = Defines.DNS_DEFAULT_ORIGIN,
                    IsVerified = false,
                    Value = dnsSettings.Spf
                }
            };

            return dnsData;
        }

        public bool CheckDomainOwnership(string domain)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (string.IsNullOrEmpty(domain))
                throw new ArgumentException(@"Invalid domain name.", "domain");

            if (domain.Length > 255)
                throw new ArgumentException(@"Domain name exceed limitation of 255 characters.", "domain");

            if (!Parser.IsDomainValid(domain))
                throw new ArgumentException(@"Incorrect domain name.", "domain");

            var domainName = domain.ToLowerInvariant();

            var dns = GetOrCreateUnusedDnsData();

            var dnsLookup = new DnsLookup();

            return dnsLookup.IsDomainTxtRecordExists(domainName, dns.DomainCheckRecord.Value);
        }

        public ServerNotificationAddressData CreateNotificationAddress(string localPart, string password, int domainId)
        {
            if (!CoreContext.Configuration.Standalone)
                throw new SecurityException("Only for standalone");

            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (string.IsNullOrEmpty(localPart))
                throw new ArgumentNullException("localPart", @"Invalid address username.");

            localPart = localPart.ToLowerInvariant().Trim();

            if (localPart.Length > 64)
                throw new ArgumentException(@"Local part of address exceed limitation of 64 characters.", "localPart");

            if (!Parser.IsEmailLocalPartValid(localPart))
                throw new ArgumentException(@"Incorrect address username.", "localPart");

            var trimPwd = Parser.GetValidPassword(password);

            if (domainId < 0)
                throw new ArgumentException(@"Invalid domain id.", "domainId");

            var notificationAddressSettings = ServerNotificationAddressSettings.LoadForTenant(Tenant);

            if (!string.IsNullOrEmpty(notificationAddressSettings.NotificationAddress))
            {
                RemoveNotificationAddress(notificationAddressSettings.NotificationAddress);
            }

            var utcNow = DateTime.UtcNow;

            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);
                var serverDomain = serverDomainDao.GetDomain(domainId);

                if (localPart.Length + serverDomain.Name.Length > 318) // 318 because of @ sign
                    throw new ArgumentException(@"Address of mailbox exceed limitation of 319 characters.", "localPart");

                var login = string.Format("{0}@{1}", localPart, serverDomain.Name);

                var serverDao = daoFactory.CreateServerDao();
                var server = serverDao.Get(Tenant);

                if (server == null)
                    throw new ArgumentException("Server not configured");

                var engine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);

                var maildir = PostfixMaildirUtil.GenerateMaildirPath(serverDomain.Name, localPart, utcNow);

                var serverMailbox = new Server.Core.Entities.Mailbox
                {
                    Name = localPart,
                    Password = <PASSWORD>,
                    Login = login,
                    LocalPart = localPart,
                    Domain = serverDomain.Name,
                    Active = true,
                    Quota = 0,
                    Maldir = maildir,
                    Modified = utcNow,
                    Created = utcNow,
                };

                var serverAddress = new Alias
                {
                    Name = localPart,
                    Address = login,
                    GoTo = login,
                    Domain = serverDomain.Name,
                    IsActive = true,
                    IsGroup = false,
                    Modified = utcNow,
                    Created = utcNow
                };

                engine.SaveMailbox(serverMailbox, serverAddress, false);

                notificationAddressSettings = new ServerNotificationAddressSettings { NotificationAddress = login };

                notificationAddressSettings.SaveForTenant(Tenant);

                var mailboxServerDao = daoFactory.CreateMailboxServerDao();

                var smtpSettings = mailboxServerDao.GetServer(server.SmtpSettingsId);

                var address = new MailAddress(login);

                var notifyAddress = new ServerNotificationAddressData
                {
                    Email = address.ToString(),
                    SmtpPort = smtpSettings.Port,
                    SmtpServer = smtpSettings.Hostname,
                    SmtpAccount = address.ToLogin(smtpSettings.Username),
                    SmptEncryptionType = smtpSettings.SocketType,
                    SmtpAuth = true,
                    SmtpAuthenticationType = smtpSettings.Authentication
                };

                return notifyAddress;
            }
        }

        public void RemoveNotificationAddress(string address)
        {
            if (!CoreContext.Configuration.Standalone)
                throw new SecurityException("Only for standalone");

            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (string.IsNullOrEmpty(address))
                throw new ArgumentNullException("address");

            var deleteAddress = address.ToLowerInvariant().Trim();
            var notificationAddressSettings = ServerNotificationAddressSettings.LoadForTenant(Tenant);

            if (notificationAddressSettings.NotificationAddress != deleteAddress)
                throw new ArgumentException("Mailbox not exists");

            var mailAddress = new MailAddress(deleteAddress);

            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);
                var serverDomain = serverDomainDao.GetDomains().FirstOrDefault(d => d.Name == mailAddress.Host);

                if (serverDomain == null)
                    throw new ArgumentException("Domain not exists");

                var serverDao = daoFactory.CreateServerDao();
                var server = serverDao.Get(Tenant);

                if (server == null)
                    throw new ArgumentException("Server not configured");

                var engine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);

                engine.RemoveMailbox(deleteAddress);
            }

            var addressSettings = notificationAddressSettings.GetDefault() as ServerNotificationAddressSettings;
            if (addressSettings != null && !addressSettings.SaveForTenant(Tenant))
            {
                throw new Exception("Could not delete notification address setting.");
            }
        }

        public ServerFullData GetMailServerFullInfo()
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            var fullServerInfo = new ServerFullData();
            var mailboxDataList = new List<ServerMailboxData>();
            var mailgroupDataList = new List<ServerDomainGroupData>();

            var domainEngine = new ServerDomainEngine(Tenant, User);

            using (var daoFactory = new DaoFactory())
            {
                var server = GetMailServer(daoFactory);

                var domains = domainEngine.GetDomains(daoFactory);

                var mailboxDao = daoFactory.CreateMailboxDao();

                var mailboxes = mailboxDao.GetMailBoxes(new TenantServerMailboxesExp(Tenant));

                var serverAddressDao = daoFactory.CreateServerAddressDao(Tenant);

                var addresses = serverAddressDao.GetList();

                foreach (var mailbox in mailboxes)
                {
                    var address =
                        addresses.FirstOrDefault(
                            a => a.MailboxId == mailbox.Id && a.IsAlias == false && a.IsMailGroup == false);

                    if (address == null)
                        continue;

                    var domain = domains.FirstOrDefault(d => d.Id == address.DomainId);

                    if (domain == null)
                        continue;

                    var serverAddressData = ServerMailboxEngine.ToServerDomainAddressData(address, domain);

                    var aliases =
                        addresses.Where(a => a.MailboxId == mailbox.Id && a.IsAlias && !a.IsMailGroup)
                            .ToList()
                            .ConvertAll(a => ServerMailboxEngine.ToServerDomainAddressData(a, domain));

                    mailboxDataList.Add(ServerMailboxEngine.ToMailboxData(mailbox, serverAddressData, aliases));
                }

                var serverGroupDao = daoFactory.CreateServerGroupDao(Tenant);

                var groups = serverGroupDao.GetList();

                foreach (var serverGroup in groups)
                {
                    var address =
                        addresses.FirstOrDefault(
                            a => a.Id == serverGroup.AddressId && !a.IsAlias && a.IsMailGroup);

                    if (address == null)
                        continue;

                    var domain = domains.FirstOrDefault(d => d.Id == address.DomainId);

                    if (domain == null)
                        continue;

                    var email = string.Format("{0}@{1}", address.AddressName, domain.Name);

                    var serverGroupAddress = ServerMailboxEngine.ToServerDomainAddressData(address, email);

                    var serverGroupAddresses =
                        serverAddressDao.GetGroupAddresses(serverGroup.Id)
                            .ConvertAll(a => ServerMailboxEngine.ToServerDomainAddressData(a,
                                string.Format("{0}@{1}", a.AddressName, domain.Name)));

                    mailgroupDataList.Add(ServerMailgroupEngine.ToServerDomainGroupData(serverGroup.Id, serverGroupAddress, serverGroupAddresses));
                }

                fullServerInfo.Server = server;
                fullServerInfo.Domains = domains;
                fullServerInfo.Mailboxes = mailboxDataList;
                fullServerInfo.Mailgroups = mailgroupDataList;
            }

            return fullServerInfo;
        }

        public string GetServerVersion()
        {
            using (var daoFactory = new DaoFactory())
            {
                var serverDao = daoFactory.CreateServerDao();
                var server = serverDao.Get(Tenant);

                if (server == null)
                    return null;

                var engine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);
                var version = engine.GetVersion();
                return version;
            }
        }

        private static bool IsAdmin
        {
            get
            {
                return WebItemSecurity.IsProductAdministrator(WebItemManager.MailProductID, SecurityContext.CurrentAccount.ID);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/VoipClient.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web;

using ASC.Core;
using ASC.VoipService;
using ASC.VoipService.Dao;
using ASC.Web.Core;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.UserControls.Common;

namespace ASC.Web.Studio
{
    public partial class VoipClient : MainPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Master.DisabledSidePanel = true;
            Master.DisabledTopStudioPanel = true;

            if (VoipNumberData.CanMakeOrReceiveCall)
            {
                PhoneControl.Controls.Add(LoadControl(VoipPhoneControl.Location));
            }
        }
    }

    public class VoipNumberData : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Resources.Master"; }
        }

        protected override string GetCacheHash()
        {
            return SecurityContext.CurrentAccount.ID + CurrentNumber.Number +
                   (SecurityContext.IsAuthenticated && !CoreContext.Configuration.Personal
                        ? (CoreContext.UserManager.GetMaxUsersLastModified().Ticks.ToString(CultureInfo.InvariantCulture) +
                           CoreContext.UserManager.GetMaxGroupsLastModified().Ticks.ToString(CultureInfo.InvariantCulture))
                        : string.Empty);
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            yield return RegisterObject(new { numberId = CurrentNumber.Number });
        }

        public static VoipPhone CurrentNumber
        {
            get { return new CachedVoipDao(CoreContext.TenantManager.GetCurrentTenant().TenantId).GetCurrentNumber(); }
        }

        public static bool CanMakeOrReceiveCall
        {
            get { return Allowed && CurrentNumber != null; }
        }

        public static bool Allowed
        {
            get
            {
                return SetupInfo.VoipEnabled &&
                       VoipDao.ConfigSettingsExist &&
                       !WebItemManager.Instance[WebItemManager.CRMProductID].IsDisabled();
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Core/Notify/StudioWhatsNewNotify.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Threading;

using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Feed;
using ASC.Feed.Data;
using ASC.Notify;
using ASC.Notify.Patterns;
using ASC.Web.Core;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Core.Notify
{
    public class StudioWhatsNewNotify
    {
        public static void SendMsgWhatsNew(DateTime scheduleDate, INotifyClient client)
        {
            var log = LogManager.GetLogger("ASC.Notify.WhatsNew");

            if (WebItemManager.Instance.GetItemsAll<IProduct>().Count == 0)
            {
                log.Info("No products. Return from function");
                return;
            }

            log.Info("Start send whats new.");

            var products = WebItemManager.Instance.GetItemsAll().ToDictionary(p => p.GetSysName());

            foreach (var tenantid in GetChangedTenants(scheduleDate))
            {
                try
                {
                    var tenant = CoreContext.TenantManager.GetTenant(tenantid);
                    if (tenant == null ||
                        tenant.Status != TenantStatus.Active ||
                        !TimeToSendWhatsNew(TenantUtil.DateTimeFromUtc(tenant.TimeZone, scheduleDate)) ||
                        TariffState.NotPaid <= CoreContext.PaymentManager.GetTariff(tenantid).State)
                    {
                        continue;
                    }

                    CoreContext.TenantManager.SetCurrentTenant(tenant);

                    log.InfoFormat("Start send whats new in {0} ({1}).", tenant.TenantDomain, tenantid);
                    foreach (var user in CoreContext.UserManager.GetUsers())
                    {
                        if (!StudioNotifyHelper.IsSubscribedToNotify(user, Actions.SendWhatsNew))
                        {
                            continue;
                        }

                        SecurityContext.AuthenticateMe(CoreContext.Authentication.GetAccountByID(user.ID));

                        var culture = string.IsNullOrEmpty(user.CultureName) ? tenant.GetCulture() : user.GetCulture();

                        Thread.CurrentThread.CurrentCulture = culture;
                        Thread.CurrentThread.CurrentUICulture = culture;

                        var feeds = FeedAggregateDataProvider.GetFeeds(new FeedApiFilter
                        {
                            From = scheduleDate.Date.AddDays(-1),
                            To = scheduleDate.Date.AddSeconds(-1),
                            Max = 100,
                        });

                        var feedMinWrappers = feeds.ConvertAll(f => f.ToFeedMin());

                        var feedMinGroupedWrappers = feedMinWrappers
                            .Where(f =>
                                (f.CreatedDate == DateTime.MaxValue || f.CreatedDate >= scheduleDate.Date.AddDays(-1)) && //'cause here may be old posts with new comments
                                products.ContainsKey(f.Product) &&
                                !f.Id.StartsWith("participant")
                            )
                            .GroupBy(f => products[f.Product]);

                        var ProjectsProductName = products["projects"].Name; //from ASC.Feed.Aggregator.Modules.ModulesHelper.ProjectsProductName

                        var activities = feedMinGroupedWrappers
                            .Where(f => f.Key.Name != ProjectsProductName) //not for project product
                            .ToDictionary(
                            g => g.Key.Name,
                            g => g.Select(f => new WhatsNewUserActivity
                            {
                                Date = f.CreatedDate,
                                UserName = f.Author != null && f.Author.UserInfo != null ? f.Author.UserInfo.DisplayUserName() : string.Empty,
                                UserAbsoluteURL = f.Author != null && f.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(f.Author.UserInfo.GetUserProfilePageURL()) : string.Empty,
                                Title = HtmlUtil.GetText(f.Title, 512),
                                URL = CommonLinkUtility.GetFullAbsolutePath(f.ItemUrl),
                                BreadCrumbs = new string[0],
                                Action = getWhatsNewActionText(f)
                            }).ToList());


                        var projectActivities = feedMinGroupedWrappers
                            .Where(f => f.Key.Name == ProjectsProductName) // for project product
                            .SelectMany(f => f);

                        var projectActivitiesWithoutBreadCrumbs = projectActivities.Where(p => String.IsNullOrEmpty(p.ExtraLocation));

                        var whatsNewUserActivityGroupByPrjs = new List<WhatsNewUserActivity>();

                        foreach (var prawbc in projectActivitiesWithoutBreadCrumbs)
                        {
                            whatsNewUserActivityGroupByPrjs.Add(
                                        new WhatsNewUserActivity
                                        {
                                            Date = prawbc.CreatedDate,
                                            UserName = prawbc.Author != null && prawbc.Author.UserInfo != null ? prawbc.Author.UserInfo.DisplayUserName() : string.Empty,
                                            UserAbsoluteURL = prawbc.Author != null && prawbc.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(prawbc.Author.UserInfo.GetUserProfilePageURL()) : string.Empty,
                                            Title = HtmlUtil.GetText(prawbc.Title, 512),
                                            URL = CommonLinkUtility.GetFullAbsolutePath(prawbc.ItemUrl),
                                            BreadCrumbs = new string[0],
                                            Action = getWhatsNewActionText(prawbc)
                                        });
                        }

                        var groupByPrjs = projectActivities.Where(p => !String.IsNullOrEmpty(p.ExtraLocation)).GroupBy(f => f.ExtraLocation);
                        foreach (var gr in groupByPrjs)
                        {
                            var grlist = gr.ToList();
                            for (var i = 0; i < grlist.Count(); i++)
                            {
                                var ls = grlist[i];
                                whatsNewUserActivityGroupByPrjs.Add(
                                    new WhatsNewUserActivity
                                    {
                                        Date = ls.CreatedDate,
                                        UserName = ls.Author != null && ls.Author.UserInfo != null ? ls.Author.UserInfo.DisplayUserName() : string.Empty,
                                        UserAbsoluteURL = ls.Author != null && ls.Author.UserInfo != null ? CommonLinkUtility.GetFullAbsolutePath(ls.Author.UserInfo.GetUserProfilePageURL()) : string.Empty,
                                        Title = HtmlUtil.GetText(ls.Title, 512),
                                        URL = CommonLinkUtility.GetFullAbsolutePath(ls.ItemUrl),
                                        BreadCrumbs = i == 0 ? new string[1] { gr.Key } : new string[0],
                                        Action = getWhatsNewActionText(ls)
                                    });
                            }
                        }

                        if (whatsNewUserActivityGroupByPrjs.Count > 0)
                        {
                            activities.Add(ProjectsProductName, whatsNewUserActivityGroupByPrjs);
                        }

                        if (0 < activities.Count)
                        {
                            log.InfoFormat("Send whats new to {0}", user.Email);
                            client.SendNoticeAsync(
                                Actions.SendWhatsNew, null, user, null,
                                new TagValue(Tags.Activities, activities),
                                new TagValue(Tags.Date, DateToString(scheduleDate.AddDays(-1), culture)),
                                new TagValue(CommonTags.Priority, 1)
                            );
                        }
                    }
                }
                catch (Exception error)
                {
                    log.Error(error);
                }
            }
        }

        private static string getWhatsNewActionText(FeedMin feed)
        {

            if (feed.Module == ASC.Feed.Constants.BookmarksModule)
                return WebstudioNotifyPatternResource.ActionCreateBookmark;
            else if (feed.Module == ASC.Feed.Constants.BlogsModule)
                return WebstudioNotifyPatternResource.ActionCreateBlog;
            else if (feed.Module == ASC.Feed.Constants.ForumsModule)
            {
                if (feed.Item == "forumTopic")
                    return WebstudioNotifyPatternResource.ActionCreateForum;
                if (feed.Item == "forumPost")
                    return WebstudioNotifyPatternResource.ActionCreateForumPost;
                if (feed.Item == "forumPoll")
                    return WebstudioNotifyPatternResource.ActionCreateForumPoll;
            }
            else if (feed.Module == ASC.Feed.Constants.EventsModule)
                return WebstudioNotifyPatternResource.ActionCreateEvent;
            else if (feed.Module == ASC.Feed.Constants.ProjectsModule)
                return WebstudioNotifyPatternResource.ActionCreateProject;
            else if (feed.Module == ASC.Feed.Constants.MilestonesModule)
                return WebstudioNotifyPatternResource.ActionCreateMilestone;
            else if (feed.Module == ASC.Feed.Constants.DiscussionsModule)
                return WebstudioNotifyPatternResource.ActionCreateDiscussion;
            else if (feed.Module == ASC.Feed.Constants.TasksModule)
                return WebstudioNotifyPatternResource.ActionCreateTask;
            else if (feed.Module == ASC.Feed.Constants.CommentsModule)
                return WebstudioNotifyPatternResource.ActionCreateComment;
            else if (feed.Module == ASC.Feed.Constants.CrmTasksModule)
                return WebstudioNotifyPatternResource.ActionCreateTask;
            else if (feed.Module == ASC.Feed.Constants.ContactsModule)
                return WebstudioNotifyPatternResource.ActionCreateContact;
            else if (feed.Module == ASC.Feed.Constants.DealsModule)
                return WebstudioNotifyPatternResource.ActionCreateDeal;
            else if (feed.Module == ASC.Feed.Constants.CasesModule)
                return WebstudioNotifyPatternResource.ActionCreateCase;
            else if (feed.Module == ASC.Feed.Constants.FilesModule)
                return WebstudioNotifyPatternResource.ActionCreateFile;
            else if (feed.Module == ASC.Feed.Constants.FoldersModule)
                return WebstudioNotifyPatternResource.ActionCreateFolder;

            return "";
        }

        private static IEnumerable<int> GetChangedTenants(DateTime date)
        {
            return new FeedAggregateDataProvider().GetTenants(new TimeInterval(date.Date.AddDays(-1), date.Date.AddSeconds(-1)));
        }

        private static bool TimeToSendWhatsNew(DateTime currentTime)
        {
            var hourToSend = 7;
            if (!string.IsNullOrEmpty(ConfigurationManagerExtension.AppSettings["web.whatsnew-time"]))
            {
                var hour = 0;
                if (int.TryParse(ConfigurationManagerExtension.AppSettings["web.whatsnew-time"], out hour))
                {
                    hourToSend = hour;
                }
            }
            return currentTime.Hour == hourToSend;
        }

        private static string DateToString(DateTime d, CultureInfo c)
        {
            return d.ToString(c.TwoLetterISOLanguageName == "ru" ? "d MMMM" : "M", c);
        }

        class WhatsNewUserActivity
        {
            public IList<string> BreadCrumbs { get; set; }
            public string Title { get; set; }
            public string URL { get; set; }
            public string UserName { get; set; }
            public string UserAbsoluteURL { get; set; }
            public DateTime Date { get; set; }
            public string Action { get; set; }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/Wrappers/MessageWrapperFull.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Api.Documents;
using ASC.Api.Employee;
using ASC.Core;
using ASC.Core.Users;
using ASC.Projects.Core.Domain;
using ASC.Web.Studio.UserControls.Common.Comments;
using ASC.Web.Studio.Utility.HtmlUtility;

namespace ASC.Api.Projects.Wrappers
{
    [DataContract(Name = "message", Namespace = "")]
    public class MessageWrapperFull : MessageWrapper
    {
        [DataMember]
        public bool CanEditFiles { get; set; }

        [DataMember]
        public bool CanReadFiles { get; set; }

        [DataMember]
        public List<EmployeeWraperFull> Subscribers { get; set; }

        [DataMember]
        public List<FileWrapper> Files { get; set; }

        [DataMember]
        public List<CommentInfo> Comments { get; set; }

        [DataMember]
        public ProjectWrapperFull Project { get; set; }

        public MessageWrapperFull(ProjectApiBase projectApiBase, Message message, ProjectWrapperFull project, IEnumerable<EmployeeWraperFull> subscribers)
            : base(projectApiBase, message)
        {
            CanEditFiles = projectApiBase.ProjectSecurity.CanEditFiles(message);
            CanReadFiles = projectApiBase.ProjectSecurity.CanReadFiles(message.Project);
            Text = HtmlUtility.GetFull(Text);
            Project = project;
            Subscribers = subscribers.ToList();
        }

        public MessageWrapperFull(ProjectApiBase projectApiBase, Message message, ProjectWrapperFull project, IEnumerable<EmployeeWraperFull> subscribers, IEnumerable<FileWrapper> files, IEnumerable<CommentInfo> comments) :
            this(projectApiBase, message, project, subscribers)
        {
            Files = files.ToList();
            var creator = CoreContext.UserManager.GetUsers(message.CreateBy);
            Comments = new List<CommentInfo>(comments.Count() + 1)
            {
                new CommentInfo
                {
                    TimeStamp = message.CreateOn,
                    TimeStampStr = message.CreateOn.Ago(),
                    CommentBody = HtmlUtility.GetFull(message.Description),
                    CommentID = SecurityContext.CurrentAccount.ID.ToString() + "1",
                    UserID = message.CreateBy,
                    UserFullName = creator.DisplayUserName(),
                    UserProfileLink = creator.GetUserProfilePageURL(),
                    Inactive = false,
                    IsEditPermissions = false,
                    IsResponsePermissions = false,
                    IsRead = true,
                    UserAvatarPath = creator.GetBigPhotoURL(),
                    UserPost = creator.Title,
                    CommentList = new List<CommentInfo>()
                }
            };
            Comments.AddRange(comments);

        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/ReportEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;

using ASC.Core;
using ASC.Core.Users;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Domain.Reports;
using ASC.Web.Core.Users;

using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Projects.Engine
{
    public class ReportEngine
    {
        public IDaoFactory DaoFactory { get; set; }
        public ProjectSecurity ProjectSecurity { get; set; }
        public EngineFactory EngineFactory { get; set; }

        public ProjectEngine ProjectEngine { get { return EngineFactory.ProjectEngine; } }
        public TaskEngine TaskEngine { get { return EngineFactory.TaskEngine; } }
        public MilestoneEngine MilestoneEngine { get { return EngineFactory.MilestoneEngine; } }
        public MessageEngine MessageEngine { get { return EngineFactory.MessageEngine; } }
        public FileEngine FileEngine { get { return EngineFactory.FileEngine; } }

        public List<ReportTemplate> GetTemplates(Guid userId)
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            return DaoFactory.ReportDao.GetTemplates(userId);
        }

        public List<ReportTemplate> GetAutoTemplates()
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            return DaoFactory.ReportDao.GetAutoTemplates();
        }

        public ReportTemplate GetTemplate(int id)
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            return DaoFactory.ReportDao.GetTemplate(id);
        }

        public ReportTemplate SaveTemplate(ReportTemplate template)
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            return DaoFactory.ReportDao.SaveTemplate(template);
        }

        public ReportFile Save(ReportFile reportFile)
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            return DaoFactory.ReportDao.Save(reportFile);
        }

        public void DeleteTemplate(int id)
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            DaoFactory.ReportDao.DeleteTemplate(id);
        }

        public IEnumerable<ReportFile> Get()
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            return DaoFactory.ReportDao.Get();
        }

        public ReportFile GetByFileId(int fileid)
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            return DaoFactory.ReportDao.GetByFileId(fileid);
        }

        public void Remove(ReportFile report)
        {
            if (ProjectSecurity.IsVisitor(SecurityContext.CurrentAccount.ID)) throw new SecurityException("Access denied.");

            DaoFactory.ReportDao.Remove(report);

            FileEngine.MoveToTrash(report.FileId);
        }

        public IList<object[]> BuildUsersWithoutActiveTasks(TaskFilter filter)
        {
            var result = new List<object[]>();

            var users = new List<Guid>();
            if (filter.UserId != Guid.Empty) users.Add(filter.UserId);
            else if (filter.DepartmentId != Guid.Empty)
            {
                users.AddRange(CoreContext.UserManager.GetUsersByGroup(filter.DepartmentId).Select(u => u.ID));
            }
            else if (filter.HasProjectIds)
            {
                users.AddRange(ProjectEngine.GetTeam(filter.ProjectIds).Select(r => r.ID).Distinct());
            }
            else if (!filter.HasProjectIds)
            {
                users.AddRange(ProjectEngine.GetTeam(ProjectEngine.GetAll().Select(r => r.ID).ToList()).Select(r => r.ID).Distinct());
            }

            var data = TaskEngine.GetByFilterCountForStatistic(filter);

            foreach (var row in data)
            {
                users.Remove(row.UserId);
                if (row.TasksOpen == 0)
                {
                    result.Add(new object[]
                    {
                        row.UserId, 0, row.TasksOpen, row.TasksClosed
                    });
                }
            }
            result.AddRange(users.Select(u => new object[] { u, 0, 0, 0 }));

            return result.Select(x => new[] { DisplayUserSettings.GetFullUserName(CoreContext.UserManager.GetUsers((Guid)x[0]), false), x[2], x[3] }).ToList();
        }

        public IList<object[]> BuildUsersWorkload(TaskFilter filter)
        {
            if (filter.ViewType == 0)
            {
                return TaskEngine.GetByFilterCountForStatistic(filter).Select(r => new object[]
                {
                    DisplayUserSettings.GetFullUserName(CoreContext.UserManager.GetUsers(r.UserId), false), r.TasksOpen, r.TasksClosed, r.TasksTotal,
                    CoreContext.UserManager.GetUserGroups(r.UserId).Select(x=>x.Name)
                }).ToList();
            }

            var tasks = TaskEngine.GetByFilter(filter).FilterResult;
            var projects = tasks.Select(r => r.Project).Distinct();

            var result = new List<object[]>();

            foreach (var pr in projects)
            {
                var prTasks = tasks.Where(r => r.Project.ID == pr.ID && r.Responsibles.Count > 0).ToList();
                if (!prTasks.Any())
                {
                    continue;
                }

                var users = filter.ParticipantId.HasValue ? new List<Guid> { filter.ParticipantId.Value } : prTasks.SelectMany(r => r.Responsibles).Distinct();

                var usersResult = new List<object[]>();
                foreach (var user in users)
                {
                    var tasksOpened = prTasks.Count(r => r.Responsibles.Contains(user) && r.Status == TaskStatus.Open);
                    var tasksClosed = prTasks.Count(r => r.Responsibles.Contains(user) && r.Status == TaskStatus.Closed);

                    usersResult.Add(new object[] {
                        DisplayUserSettings.GetFullUserName(CoreContext.UserManager.GetUsers(user), false),
                        tasksOpened,
                        tasksClosed,
                        tasksOpened + tasksClosed
                    });
                }

                result.Add(new object[] { pr.Title, usersResult });
            }

            return result;
        }

        public IList<object[]> BuildUsersActivity(TaskFilter filter)
        {
            var result = new List<object[]>();
            var tasks = TaskEngine.GetByFilterCountForReport(filter);
            var milestones = MilestoneEngine.GetByFilterCountForReport(filter);
            var messages = MessageEngine.GetByFilterCountForReport(filter);

            if (filter.ViewType == 1)
            {
                var projectIds = GetProjects(tasks, milestones, messages);
                var projects = ProjectEngine.GetByID(projectIds).ToList();

                foreach (var p in projects)
                {
                    var userIds = GetUsers(p.ID, tasks, milestones, messages);

                    foreach (var userId in userIds)
                    {
                        var userName = CoreContext.UserManager.GetUsers(userId).DisplayUserName();
                        var tasksCount = GetCount(tasks, p.ID, userId);
                        var milestonesCount = GetCount(milestones, p.ID, userId);
                        var messagesCount = GetCount(messages, p.ID, userId);

                        result.Add(new object[]
                        {
                            p.ID, p.Title, userName, tasksCount, milestonesCount, messagesCount,
                            tasksCount + milestonesCount + messagesCount
                        });
                    }
                }
            }
            else
            {
                var userIds = GetUsers(-1, tasks, milestones, messages);

                foreach (var userId in userIds)
                {
                    var group = CoreContext.UserManager.GetUserGroups(userId).FirstOrDefault();
                    var userName = CoreContext.UserManager.GetUsers(userId).DisplayUserName();

                    var tasksCount = GetCount(tasks, userId);
                    var milestonesCount = GetCount(milestones, userId);
                    var messagesCount = GetCount(messages, userId);

                    result.Add(new object[]
                        {
                            group != null ? group.ID : Guid.Empty,
                            group != null ? group.Name : "", userName,
                            tasksCount,
                            milestonesCount,
                            messagesCount,
                            tasksCount + milestonesCount + messagesCount
                        });
                }
            }

            return result;
        }

        private static List<int> GetProjects(params IEnumerable<Tuple<Guid, int, int>>[] data)
        {
            var result = new List<int>();

            foreach (var item in data)
            {
                result.AddRange(item.Select(r => r.Item2));
            }

            return result.Distinct().ToList();
        }

        private static List<Guid> GetUsers(int pId, params IEnumerable<Tuple<Guid, int, int>>[] data)
        {
            var result = new List<Guid>();

            foreach (var item in data)
            {
                result.AddRange(item.Where(r => pId == -1 || r.Item2 == pId).Select(r => r.Item1));
            }

            return result.Distinct().ToList();
        }

        private static int GetCount(IEnumerable<Tuple<Guid, int, int>> data, Guid userId)
        {
            return data.Where(r => r.Item1 == userId).Sum(r => r.Item3);
        }
        private static int GetCount(IEnumerable<Tuple<Guid, int, int>> data, int pId, Guid userId)
        {
            var count = 0;
            var item = data.FirstOrDefault(r => r.Item2 == pId && r.Item1 == userId);
            if (item != null)
            {
                count = item.Item3;
            }

            return count;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Projects/ProjectApi.Milestones.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.Exceptions;
using ASC.Api.Projects.Wrappers;
using ASC.Api.Utils;
using ASC.MessagingSystem;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Specific;

namespace ASC.Api.Projects
{
    public partial class ProjectApi
    {
        #region milestone

        ///<summary>
        ///Returns the list of all upcoming milestones within all portal projects
        ///</summary>
        ///<short>
        ///Upcoming milestones
        ///</short>
        ///<category>Milestones</category>
        ///<returns>List of milestones</returns>
        [Read(@"milestone")]
        public IEnumerable<MilestoneWrapper> GetMilestones()
        {
            return EngineFactory.MilestoneEngine.GetUpcomingMilestones((int)Count).Select(MilestoneWrapperSelector).ToList();
        }

        ///<summary>
        ///Returns the list of all milestones matching the filter with the parameters specified in the request
        ///</summary>
        ///<short>
        ///Milestones by filter
        ///</short>
        ///<category>Milestones</category>
        ///<param name="projectid" optional="true">Project ID</param>
        ///<param name="tag" optional="true">Project tag</param>
        ///<param name="status" optional="true">Milstone status/ Can be open or closed</param>
        ///<param name="deadlineStart" optional="true">Minimum value of task deadline</param>
        ///<param name="deadlineStop" optional="true">Maximum value of task deadline</param>
        ///<param name="taskResponsible" optional="true">Responsible for the task in milestone GUID</param>
        ///<param name="lastId">Last milestone ID</param>
        ///<param name="myProjects">Miletone in my Projects</param>
        ///<param name="milestoneResponsible">Responsible for the milestone GUID</param>
        ///<returns>List of milestones</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"milestone/filter")]
        public IEnumerable<MilestoneWrapper> GetMilestonesByFilter(
            int projectid,
            int tag,
            MilestoneStatus? status,
            ApiDateTime deadlineStart,
            ApiDateTime deadlineStop, Guid? taskResponsible,
            int lastId,
            bool myProjects,
            Guid milestoneResponsible)
        {
            var milestoneEngine = EngineFactory.MilestoneEngine;

            var filter = CreateFilter(EntityType.Milestone);
            filter.UserId = milestoneResponsible;
            filter.ParticipantId = taskResponsible;
            filter.TagId = tag;
            filter.FromDate = deadlineStart;
            filter.ToDate = deadlineStop;
            filter.LastId = lastId;
            filter.MyProjects = myProjects;

            if (projectid != 0)
            {
                filter.ProjectIds.Add(projectid);
            }

            if (status != null)
            {
                filter.MilestoneStatuses.Add((MilestoneStatus)status);
            }

            SetTotalCount(milestoneEngine.GetByFilterCount(filter));

            return milestoneEngine.GetByFilter(filter).NotFoundIfNull().Select(MilestoneWrapperSelector).ToList();
        }

        ///<summary>
        ///Returns the list of all overdue milestones in the portal projects
        ///</summary>
        ///<short>
        ///Overdue milestones
        ///</short>
        ///<category>Milestones</category>
        ///<returns>List of milestones</returns>
        [Read(@"milestone/late")]
        public IEnumerable<MilestoneWrapper> GetLateMilestones()
        {
            return EngineFactory.MilestoneEngine.GetLateMilestones((int)Count).Select(MilestoneWrapperSelector).ToList();
        }

        ///<summary>
        ///Returns the list of all milestones due on the date specified in the request
        ///</summary>
        ///<short>
        ///Milestones by full date
        ///</short>
        ///<category>Milestones</category>
        ///<param name="year">Deadline year</param>
        ///<param name="month">Deadline month</param>
        ///<param name="day">Deadline day</param>
        ///<returns>List of milestones</returns>
        [Read(@"milestone/{year}/{month}/{day}")]
        public IEnumerable<MilestoneWrapper> GetMilestonesByDeadLineFull(int year, int month, int day)
        {
            var milestones = EngineFactory.MilestoneEngine.GetByDeadLine(new DateTime(year, month, day));
            return milestones.Select(MilestoneWrapperSelector).ToList();
        }

        ///<summary>
        ///Returns the list of all milestones due in the month specified in the request
        ///</summary>
        ///<short>
        ///Milestones by month
        ///</short>
        ///<category>Milestones</category>
        ///<param name="year">Deadline year</param>
        ///<param name="month">Deadline month</param>
        ///<returns>List of milestones</returns>
        [Read(@"milestone/{year}/{month}")]
        public IEnumerable<MilestoneWrapper> GetMilestonesByDeadLineMonth(int year, int month)
        {
            var milestones = EngineFactory.MilestoneEngine.GetByDeadLine(new DateTime(year, month, DateTime.DaysInMonth(year, month)));
            return milestones.Select(MilestoneWrapperSelector).ToList();
        }

        ///<summary>
        ///Returns the list with the detailed information about the milestone with the ID specified in the request
        ///</summary>
        ///<short>
        ///Get milestone
        ///</short>
        ///<category>Milestones</category>
        ///<param name="id">Milestone ID</param>
        ///<returns>Milestone</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"milestone/{id:[0-9]+}")]
        public MilestoneWrapper GetMilestoneById(int id)
        {
            var milestoneEngine = EngineFactory.MilestoneEngine;
            if (!milestoneEngine.IsExists(id)) throw new ItemNotFoundException();
            return MilestoneWrapperSelector(milestoneEngine.GetByID(id));
        }

        ///<summary>
        ///Returns the list of all tasks within the milestone with the ID specified in the request
        ///</summary>
        ///<short>
        ///Get milestone tasks 
        ///</short>
        ///<category>Milestones</category>
        ///<param name="id">Milestone ID </param>
        ///<returns>Tasks list</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"milestone/{id:[0-9]+}/task")]
        public IEnumerable<TaskWrapper> GetMilestoneTasks(int id)
        {
            if (!EngineFactory.MilestoneEngine.IsExists(id)) throw new ItemNotFoundException();
            return EngineFactory.TaskEngine.GetMilestoneTasks(id).Select(TaskWrapperSelector).ToList();
        }

        ///<summary>
        ///Updates the selected milestone changing the milestone parameters (title, deadline, status, etc.) specified in the request
        ///</summary>
        ///<short>
        ///Update milestone
        ///</short>
        ///<category>Milestones</category>
        ///<param name="id">Milestone ID</param>
        ///<param name="title">Title</param>
        ///<param name="deadline">Deadline</param>
        ///<param name="isKey">Is key or not</param>
        ///<param name="status">Status</param>
        ///<param name="isNotify">Remind me 48 hours before the due date</param>
        ///<param name="description">Milestone description</param>
        ///<param name="projectID">Project ID</param>
        ///<param name="responsible">Milestone responsible</param>
        ///<param name="notifyResponsible">Notify responsible</param>
        ///<returns>Updated milestone</returns>
        ///<exception cref="ArgumentNullException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        ///<example>
        ///<![CDATA[
        ///Sending data in application/json:
        ///
        ///{
        ///    title:"New title",
        ///    deadline:"2011-03-23T14:27:14",
        ///    isKey:false,
        ///    status:"Open"
        ///}
        ///]]>
        ///</example>
        [Update(@"milestone/{id:[0-9]+}")]
        public MilestoneWrapper UpdateMilestone(int id, string title, ApiDateTime deadline, bool? isKey, MilestoneStatus status, bool? isNotify, string description, int projectID, Guid responsible, bool notifyResponsible)
        {
            var milestoneEngine = EngineFactory.MilestoneEngine;

            var milestone = milestoneEngine.GetByID(id).NotFoundIfNull();
            ProjectSecurity.DemandEdit(milestone);

            milestone.Description = Update.IfNotEmptyAndNotEquals(milestone.Description, description);
            milestone.Title = Update.IfNotEmptyAndNotEquals(milestone.Title, title);
            milestone.DeadLine = Update.IfNotEmptyAndNotEquals(milestone.DeadLine, deadline);
            milestone.Responsible = Update.IfNotEmptyAndNotEquals(milestone.Responsible, responsible);

            if (isKey.HasValue)
                milestone.IsKey = isKey.Value;

            if (isNotify.HasValue)
                milestone.IsNotify = isNotify.Value;

            if (projectID != 0)
            {
                var project = EngineFactory.ProjectEngine.GetByID(projectID).NotFoundIfNull();
                milestone.Project = project;
            }

            milestoneEngine.SaveOrUpdate(milestone, notifyResponsible);
            MessageService.Send(Request, MessageAction.MilestoneUpdated, MessageTarget.Create(milestone.ID), milestone.Project.Title, milestone.Title);

            return MilestoneWrapperSelector(milestone);
        }

        ///<summary>
        ///Updates the status of the milestone with the ID specified in the request
        ///</summary>
        ///<short>
        ///Update milestone status
        ///</short>
        ///<category>Milestones</category>
        ///<param name="id">Milestone ID</param>
        ///<param name="status">Status</param>
        ///<returns>Updated milestone</returns>
        ///<exception cref="ArgumentNullException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        ///<example>
        ///<![CDATA[
        ///Sending data in application/json:
        ///
        ///{
        ///    status:"Open"
        ///}
        ///]]>
        ///</example>
        [Update(@"milestone/{id:[0-9]+}/status")]
        public MilestoneWrapper UpdateMilestone(int id, MilestoneStatus status)
        {
            var milestoneEngine = EngineFactory.MilestoneEngine;

            var milestone = milestoneEngine.GetByID(id).NotFoundIfNull();

            milestoneEngine.ChangeStatus(milestone, status);
            MessageService.Send(Request, MessageAction.MilestoneUpdatedStatus, MessageTarget.Create(milestone.ID), milestone.Project.Title, milestone.Title, LocalizedEnumConverter.ConvertToString(milestone.Status));

            return MilestoneWrapperSelector(milestone);
        }

        ///<summary>
        ///Deletes the milestone with the ID specified in the request
        ///</summary>
        ///<short>
        ///Delete milestone
        ///</short>
        ///<category>Milestones</category>
        ///<param name="id">Milestone ID</param>
        ///<returns>Deleted milestone</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Delete(@"milestone/{id:[0-9]+}")]
        public MilestoneWrapper DeleteMilestone(int id)
        {
            var milestoneEngine = EngineFactory.MilestoneEngine;

            var milestone = milestoneEngine.GetByID(id).NotFoundIfNull();

            milestoneEngine.Delete(milestone);
            MessageService.Send(Request, MessageAction.MilestoneDeleted, MessageTarget.Create(milestone.ID), milestone.Project.Title, milestone.Title);

            return MilestoneWrapperSelector(milestone);
        }

        ///<summary>
        ///Deletes milestones with the IDs specified in the request
        ///</summary>
        ///<short>
        ///Delete milestones
        ///</short>
        ///<category>Milestones</category>
        ///<param name="ids">Milestones ID</param>
        ///<returns>Deleted milestones</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Delete(@"milestone")]
        public IEnumerable<MilestoneWrapper> DeleteMilestones(int[] ids)
        {
            var result = new List<MilestoneWrapper>(ids.Length);

            foreach (var id in ids)
            {
                try
                {
                    result.Add(DeleteMilestone(id));
                }
                catch (Exception)
                {

                }
            }

            return result;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/App_Themes/default/style.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.forums-row:hover
{
   background-color: #E6E6E6;
}
.forums-row.view-content:hover
{
   background-color:transparent;
}
.forums-row:hover .link
{
    text-decoration: underline;
}

.forum_thrCategBox
{       
    display:block; 
    padding:5px;
    margin:0px;    
}

.forum_mesBox
{
    display:block;
    padding:5px 5px 15px 5px;  
    height: expression( this.scrollHeight < 100 ? "100px" : "auto" ); /* sets max-height for IE */
    min-height:100px;
    overflow:auto; 
    overflow-x:auto;
    overflow-y:hidden;     
}
.forum_mesBoxPreview
{
    display:block;
    padding:5px 5px 15px 5px;    
    height: expression( this.scrollHeight < 100 ? "100px" : "auto" ); /* sets max-height for IE */
    min-height:100px;
    overflow:auto; 
    overflow-x:auto;
    overflow-y:hidden;    
}
.forum_postBoxUserSection
{
	width:150px;
	overflow:hidden;
}

.forum_attachmentsBox
{   
    margin:5px;    
    padding:5px;
}
.forum_attachItem
{   
    border-right:none;
    border-left:none;
    border-top:none;   
    margin:2px 0px; padding:2px;
}

.forum_upItemBox
{   
	margin-top:3px;
    padding:2px 0px;
    border-top:none;
    border-left:none;
    border-right:none;
}

.forum_sh_item
{    
    border-top:none;
    cursor:pointer; 
    padding:0px;
    margin:0px;
    border:solid 1px #c7c7c7;
    border-top:none;
    background-color:#ffffff;
}
.forum_sh_itemselect
{
    border-top:none;
    cursor:pointer;
    padding:0px;
    margin:0px;
    border:solid 1px #c7c7c7;
    border-top:none;
    background-color:#edf6fd;
}
.forum_uploader
{       
    padding:5px;
}
.forum_columnHeader
{
	color: #82878D;
	font-size:12px;
	border-bottom:solid 1px #D1D1D1;
	padding-bottom:5px;
}


.postClass
{
    
}

/* File Uploader*/

.forum_uploadContainer
{
	margin: 10px 0 0 0; 
	max-height: 150px;
	width: 100%; 
	overflow: auto;
}

*+html .forum_uploadContainer table
{
	width:507px !important;
	z-index:290;	
}
*+html div.studioFileUploaderProgressBar
{
	z-index:190;
	max-width:507px;
}
.files_uploadIcon
{
	background: url(images/upload.png) no-repeat;
	height:32px;
	width:32px;
}
.forum_deleteLinkCSSClass
{
	background:url("images/trash.png") no-repeat scroll center center transparent;
	cursor:pointer;
	height:12px;
	width:12px;
	display:inline-block;
	margin-top:2px;
	text-decoration:none !important;
}
.forum_loadingCSSClass
{
	background:url("images/loader_small.gif") no-repeat scroll center center transparent;
	cursor:default;
	height:24px;
	width:24px;
	display:inline-block;
	margin-top:2px;
	margin-left:-5px;
	text-decoration:none !important;
}
.forum_completeCSSClass
{
	background:url("images/complete.png") no-repeat scroll center center transparent;
	cursor:default;
	height:12px;
	width:12px;
	display:inline-block;
	margin-top:2px;
	text-decoration:none !important;
}


#forum_uploadDialogContainer
{
    padding: 15px; border: 1px solid #d1d1d1
}

#forum_uploadDialogContainer #forum_uploadContainer
{
    margin: 10px 0 0 0; 
	max-height: 120px;
	width: 100%; 
	overflow: auto;
}

#forum_uploadDialogContainer #forum_uploadContainer div.fu_item
{
    margin:0;
    padding:0;
}
#forum_uploadDialogContainer #forum_uploadContainer div.fu_item:first-child
{
    border-top:1px solid #d1d1d1;
}

#forum_uploadDialogContainer #forum_upload_pnl
{
    padding: 15px 0 10px;
    position: relative;
    height: 22px;
}


#forum_uploadDialogContainer #forum_upload_pnl #switcher
{
    float:right;
}

#forum_uploadDialogContainer .forum_overAllProcessBarCssClass
{
	height:8px;
	width:100%;
	border: 1px solid #d1d1d1;
	-moz-border-radius:2px;
	-webkit-border-radius:2px;
	border-radius:2px;
	margin-top:10px;
}
#forum_uploadDialogContainer .forum_overAllProcessBarCssClass div
{
	height:8px;
	background:url("images/back-progress.png") repeat-x !important;
}

#forum_uploadDialogContainer .forum_uploadIcon
{
	background: url(images/upload.png) no-repeat;
	height:32px;
	width:32px;
}

a.forum_uploadButton
{
	float:left;
	cursor:pointer;
	position: absolute !important;
}
*html a.forum_uploadButton {margin-left:0px !important}
*+html a.forum_uploadButton {margin-left:0px !important}

#tableForNavigation {
    height: 24px;
    width: 100%;
}

.navigationLinkBox .tl-combobox {
    background: url("images/comboarrow_bottom.png") no-repeat scroll right center transparent;
    margin-bottom: 1px;
    vertical-align: middle;
}

.navigationLinkBox .tl-combobox .combobox-title .inner-text {
    border-bottom: 1px dotted #666666;
    color: #666666;
}

.text11px {
    font-size: 11px;
}

.forum-page-parent {
    color: #666666;
    font-size: 12px;
    padding-bottom:8px;
    text-align: right;
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/Core/Business/Permissions/BookmarkingPermissionsCheck.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using ASC.Bookmarking.Common;
using ASC.Bookmarking.Pojo;
using ASC.Web.Community.Product;

#endregion

namespace ASC.Bookmarking.Business.Permissions
{
    public static class BookmarkingPermissionsCheck
    {
        public static bool PermissionCheckCreateBookmark()
        {
            return CommunitySecurity.CheckPermissions(BookmarkingBusinessConstants.BookmarkCreateAction);
        }

        public static bool PermissionCheckAddToFavourite()
        {
            return CommunitySecurity.CheckPermissions(BookmarkingBusinessConstants.BookmarkAddToFavouriteAction);
        }

        public static bool PermissionCheckRemoveFromFavourite(UserBookmark b)
        {
            return CommunitySecurity.CheckPermissions(new BookmarkPermissionSecurityObject(b.UserID), BookmarkingBusinessConstants.BookmarkRemoveFromFavouriteAction);
        }

        public static bool PermissionCheckCreateComment()
        {
            return CommunitySecurity.CheckPermissions(BookmarkingBusinessConstants.BookmarkCreateCommentAction);
        }

        public static bool PermissionCheckEditComment()
        {
            return CommunitySecurity.CheckPermissions(BookmarkingBusinessConstants.BookmarkEditCommentAction);
        }

        public static bool PermissionCheckEditComment(Comment c)
        {
            return CommunitySecurity.CheckPermissions(new BookmarkPermissionSecurityObject(c.UserID, c.ID), BookmarkingBusinessConstants.BookmarkEditCommentAction);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Core/Notify/NotifyConfiguration.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text.RegularExpressions;
using System.Threading;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Notify;
using ASC.Notify.Engine;
using ASC.Notify.Messages;
using ASC.Notify.Patterns;
using ASC.Web.Core;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Utility;

using MimeKit.Utils;

namespace ASC.Web.Studio.Core.Notify
{
    public static class NotifyConfiguration
    {
        private static bool configured;
        private static readonly object locker = new object();
        private static readonly Regex urlReplacer = new Regex(@"(<a [^>]*href=(('(?<url>[^>']*)')|(""(?<url>[^>""]*)""))[^>]*>)|(<img [^>]*src=(('(?<url>(?![data:|cid:])[^>']*)')|(""(?<url>(?![data:|cid:])[^>""]*)""))[^/>]*/?>)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        private static readonly Regex textileLinkReplacer = new Regex(@"""(?<text>[\w\W]+?)"":""(?<link>[^""]+)""", RegexOptions.Singleline | RegexOptions.Compiled);

        public static void Configure()
        {
            lock (locker)
            {
                if (!configured)
                {
                    configured = true;

                    WorkContext.NotifyContext.NotifyClientRegistration += NotifyClientRegisterCallback;
                    WorkContext.NotifyContext.NotifyEngine.BeforeTransferRequest += BeforeTransferRequest;
                }
            }
        }

        public static void RegisterSendMethods()
        {
            StudioNotifyService.Instance.RegisterSendMethod();
        }


        private static void NotifyClientRegisterCallback(Context context, INotifyClient client)
        {
            #region url correction

            var absoluteUrl = new SendInterceptorSkeleton(
                "Web.UrlAbsoluter",
                InterceptorPlace.MessageSend,
                InterceptorLifetime.Global,
                (r, p) =>
                {
                    if (r != null && r.CurrentMessage != null && r.CurrentMessage.ContentType == Pattern.HTMLContentType)
                    {
                        var body = r.CurrentMessage.Body;

                        body = urlReplacer.Replace(body, m =>
                        {
                            var url = m.Groups["url"].Value;
                            var ind = m.Groups["url"].Index - m.Index;
                            return string.IsNullOrEmpty(url) && ind > 0 ?
                                m.Value.Insert(ind, CommonLinkUtility.GetFullAbsolutePath(string.Empty)) :
                                m.Value.Replace(url, CommonLinkUtility.GetFullAbsolutePath(url));
                        });

                        body = textileLinkReplacer.Replace(body, m =>
                        {
                            var url = m.Groups["link"].Value;
                            var ind = m.Groups["link"].Index - m.Index;
                            return string.IsNullOrEmpty(url) && ind > 0 ?
                                m.Value.Insert(ind, CommonLinkUtility.GetFullAbsolutePath(string.Empty)) :
                                m.Value.Replace(url, CommonLinkUtility.GetFullAbsolutePath(url));
                        });

                        r.CurrentMessage.Body = body;
                    }
                    return false;
                });
            client.AddInterceptor(absoluteUrl);

            #endregion

            #region security and culture

            var securityAndCulture = new SendInterceptorSkeleton(
                "ProductSecurityInterceptor",
                 InterceptorPlace.DirectSend,
                 InterceptorLifetime.Global,
                 (r, p) =>
                 {
                     try
                     {
                         // culture
                         var u = Constants.LostUser;

                         if (!(CoreContext.Configuration.Personal && r.NotifyAction.ID == Actions.PersonalConfirmation.ID))
                         {
                             if (32 <= r.Recipient.ID.Length)
                             {
                                 var guid = default(Guid);
                                 try
                                 {
                                     guid = new Guid(r.Recipient.ID);
                                 }
                                 catch (FormatException) { }
                                 catch (OverflowException) { }

                                 if (guid != default(Guid))
                                 {
                                     u = CoreContext.UserManager.GetUsers(guid);
                                 }
                             }

                             if (Constants.LostUser.Equals(u))
                             {
                                 u = CoreContext.UserManager.GetUserByEmail(r.Recipient.ID);
                             }

                             if (Constants.LostUser.Equals(u))
                             {
                                 u = CoreContext.UserManager.GetUserByUserName(r.Recipient.ID);
                             }

                             if (!Constants.LostUser.Equals(u))
                             {
                                 var culture = !string.IsNullOrEmpty(u.CultureName) ? u.GetCulture() : CoreContext.TenantManager.GetCurrentTenant().GetCulture();
                                 Thread.CurrentThread.CurrentCulture = culture;
                                 Thread.CurrentThread.CurrentUICulture = culture;

                                 // security
                                 var tag = r.Arguments.Find(a => a.Tag == CommonTags.ModuleID);
                                 var productId = tag != null ? (Guid)tag.Value : Guid.Empty;
                                 if (productId == Guid.Empty)
                                 {
                                     tag = r.Arguments.Find(a => a.Tag == CommonTags.ProductID);
                                     productId = tag != null ? (Guid)tag.Value : Guid.Empty;
                                 }
                                 if (productId == Guid.Empty)
                                 {
                                     productId = (Guid)(CallContext.GetData("asc.web.product_id") ?? Guid.Empty);
                                 }
                                 if (productId != Guid.Empty && productId != new Guid("f4d98afdd336433287783c6945c81ea0") /* ignore people product */)
                                 {
                                     return !WebItemSecurity.IsAvailableForUser(productId, u.ID);
                                 }
                             }
                         }

                         var tagCulture = r.Arguments.FirstOrDefault(a => a.Tag == CommonTags.Culture);
                         if (tagCulture != null)
                         {
                             var culture = CultureInfo.GetCultureInfo((string)tagCulture.Value);
                             Thread.CurrentThread.CurrentCulture = culture;
                             Thread.CurrentThread.CurrentUICulture = culture;
                         }
                     }
                     catch (Exception error)
                     {
                         LogManager.GetLogger("ASC").Error(error);
                     }
                     return false;
                 });
            client.AddInterceptor(securityAndCulture);

            #endregion

            #region white label correction

            var whiteLabel = new SendInterceptorSkeleton(
                "WhiteLabelInterceptor",
                 InterceptorPlace.MessageSend,
                 InterceptorLifetime.Global,
                 (r, p) =>
                 {
                     try
                     {
                         var tags = r.Arguments;

                         var logoTextTag = tags.FirstOrDefault(a => a.Tag == CommonTags.LetterLogoText);
                         var logoText = logoTextTag != null ? (String)logoTextTag.Value : string.Empty;

                         if (!string.IsNullOrEmpty(logoText))
                         {
                             r.CurrentMessage.Body = r.CurrentMessage.Body
                                 .Replace(string.Format("${{{0}}}", CommonTags.LetterLogoText), logoText);
                         }
                     }
                     catch (Exception error)
                     {
                         LogManager.GetLogger("ASC").Error(error);
                     }
                     return false;
                 });
            client.AddInterceptor(whiteLabel);

            #endregion
        }


        private static void BeforeTransferRequest(NotifyEngine sender, NotifyRequest request)
        {
            var aid = Guid.Empty;
            var aname = string.Empty;
            if (SecurityContext.IsAuthenticated)
            {
                aid = SecurityContext.CurrentAccount.ID;
                if (CoreContext.UserManager.UserExists(aid))
                {
                    aname = CoreContext.UserManager.GetUsers(aid).DisplayUserName(false)
                        .Replace(">", "&#62")
                        .Replace("<", "&#60");
                }
            }

            IProduct product;
            IModule module;
            CommonLinkUtility.GetLocationByRequest(out product, out module);
            if (product == null && CallContext.GetData("asc.web.product_id") != null)
            {
                product = WebItemManager.Instance[(Guid)CallContext.GetData("asc.web.product_id")] as IProduct;
            }

            var logoText = TenantWhiteLabelSettings.DefaultLogoText;
            if ((TenantExtra.Enterprise || CoreContext.Configuration.CustomMode) && !MailWhiteLabelSettings.Instance.IsDefault)
            {
                logoText = TenantLogoManager.GetLogoText();
            }

            request.Arguments.Add(new TagValue(CommonTags.AuthorID, aid));
            request.Arguments.Add(new TagValue(CommonTags.AuthorName, aname));
            request.Arguments.Add(new TagValue(CommonTags.AuthorUrl, CommonLinkUtility.GetFullAbsolutePath(CommonLinkUtility.GetUserProfile(aid))));
            request.Arguments.Add(new TagValue(CommonTags.VirtualRootPath, CommonLinkUtility.GetFullAbsolutePath("~").TrimEnd('/')));
            request.Arguments.Add(new TagValue(CommonTags.ProductID, product != null ? product.ID : Guid.Empty));
            request.Arguments.Add(new TagValue(CommonTags.ModuleID, module != null ? module.ID : Guid.Empty));
            request.Arguments.Add(new TagValue(CommonTags.ProductUrl, CommonLinkUtility.GetFullAbsolutePath(product != null ? product.StartURL : "~")));
            request.Arguments.Add(new TagValue(CommonTags.DateTime, TenantUtil.DateTimeNow()));
            request.Arguments.Add(new TagValue(CommonTags.RecipientID, Context.SYS_RECIPIENT_ID));
            request.Arguments.Add(new TagValue(CommonTags.ProfileUrl, CommonLinkUtility.GetFullAbsolutePath(CommonLinkUtility.GetMyStaff())));
            request.Arguments.Add(new TagValue(CommonTags.RecipientSubscriptionConfigURL, CommonLinkUtility.GetMyStaff()));
            request.Arguments.Add(new TagValue(CommonTags.HelpLink, CommonLinkUtility.GetHelpLink(false)));
            request.Arguments.Add(new TagValue(CommonTags.LetterLogoText, logoText));
            request.Arguments.Add(new TagValue(CommonTags.MailWhiteLabelSettings, MailWhiteLabelSettings.Instance));
            request.Arguments.Add(new TagValue(CommonTags.SendFrom, CoreContext.TenantManager.GetCurrentTenant().Name));
            request.Arguments.Add(new TagValue(CommonTags.ImagePath, StudioNotifyHelper.GetNotificationImageUrl("").TrimEnd('/')));

            AddLetterLogo(request);
        }

        private static void AddLetterLogo(NotifyRequest request)
        {
            if (TenantExtra.Enterprise || CoreContext.Configuration.CustomMode)
            {
                try
                {
                    var logoData = TenantLogoManager.GetMailLogoDataFromCache();

                    if (logoData == null)
                    {
                        var logoStream = TenantLogoManager.GetWhitelabelMailLogo();
                        logoData = ReadStreamToByteArray(logoStream) ?? GetDefaultMailLogo();

                        if (logoData != null)
                            TenantLogoManager.InsertMailLogoDataToCache(logoData);
                    }

                    if (logoData != null)
                    {
                        var attachment = new NotifyMessageAttachment
                        {
                            FileName = "logo.png",
                            Content = logoData,
                            ContentId = MimeUtils.GenerateMessageId()
                        };

                        request.Arguments.Add(new TagValue(CommonTags.LetterLogo, "cid:" + attachment.ContentId));
                        request.Arguments.Add(new TagValue(CommonTags.EmbeddedAttachments, new[] { attachment }));
                        return;
                    }
                }
                catch (Exception error)
                {
                    LogManager.GetLogger("ASC").Error(error);
                }
            }

            var logoUrl = CommonLinkUtility.GetFullAbsolutePath(TenantLogoManager.GetLogoDark(true));

            request.Arguments.Add(new TagValue(CommonTags.LetterLogo, logoUrl));
        }

        private static byte[] ReadStreamToByteArray(Stream inputStream)
        {
            if (inputStream == null) return null;

            using (inputStream)
            {
                using (var memoryStream = new MemoryStream())
                {
                    inputStream.CopyTo(memoryStream);
                    return memoryStream.ToArray();
                }
            }
        }

        public static byte[] GetDefaultMailLogo()
        {
            var filePath = Path.Combine(Environment.CurrentDirectory, "skins", "default", "images", "logo", "dark_general.png");

            return File.Exists(filePath) ? File.ReadAllBytes(filePath) : null;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/Impl/Serializers/SerializerResponder.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Api.Interfaces;

using Autofac;

namespace ASC.Api.Impl.Serializers
{
    public class SerializerResponder : IApiResponder
    {
        private readonly ICollection<IApiSerializer> _serializers;


        public SerializerResponder(IComponentContext container)
        {
            var serializers = container.Resolve<IEnumerable<IApiSerializer>>();
            if (serializers == null)
                throw new ArgumentException("No serializers resolved");

            _serializers = new List<IApiSerializer>(serializers);
            if (!_serializers.Any())
                throw new ArgumentException("No serializers defined");
        }

        public string Name
        {
            get { return "serializer"; }
        }

        public IEnumerable<string> GetSupportedExtensions()
        {
            return _serializers.SelectMany(x => x.GetSupportedExtensions());
        }

        public bool CanSerializeType(Type type)
        {
            if (type == null) throw new ArgumentNullException("type");
            return _serializers.Any(x => x.CanSerializeType(type));
        }

        public bool CanRespondTo(IApiStandartResponce responce, HttpContextBase context)
        {
            if (responce == null) throw new ArgumentNullException("responce");
            if (context == null) throw new ArgumentNullException("context");
            return true;
        }

        public void RespondTo(IApiStandartResponce responce, HttpContextBase httpContext)
        {
            if (responce == null) throw new ArgumentNullException("responce");
            if (httpContext == null) throw new ArgumentNullException("httpContext");

            foreach (var apiSerializer in _serializers)
            {
                var contentType = apiSerializer.RespondTo(responce, httpContext.Response.Output,
                                                                  httpContext.Request.Path, httpContext.Request.ContentType, false, false);
                if (contentType != null)
                {
                    httpContext.Response.ContentType = contentType.ToString();
#if (DEBUG)
                    httpContext.Response.AddHeader("X-Responded", string.Format("{0}", contentType));
#endif
                    return;
                }
            }
#if (DEBUG)
            httpContext.Response.AddHeader("X-Responded", "No");
#endif

        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/TCP/TCP_Server.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.TCP
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;
    using System.Timers;
    using Log;

    #endregion

    /// <summary>
    /// This class implements generic TCP session based server.
    /// </summary>
    public class TCP_Server<T> : IDisposable where T : TCP_ServerSession, new()
    {
        #region Events

        /// <summary>
        /// This event is raised when TCP server has disposed.
        /// </summary>
        public event EventHandler Disposed = null;

        /// <summary>
        /// This event is raised when TCP server has unknown unhandled error.
        /// </summary>
        public event ErrorEventHandler Error = null;

        /// <summary>
        /// This event is raised when TCP server creates new session.
        /// </summary>
        public event EventHandler<TCP_ServerSessionEventArgs<T>> SessionCreated = null;

        /// <summary>
        /// This event is raised when TCP server has started.
        /// </summary>
        public event EventHandler Started = null;

        /// <summary>
        /// This event is raised when TCP server has stopped.
        /// </summary>
        public event EventHandler Stopped = null;

        #endregion

        #region Members

        private readonly List<ListeningPoint> m_pListeningPoints;
        private long m_ConnectionsProcessed;

        private bool m_IsDisposed;
        private bool m_IsRunning;
        private long m_MaxConnections;
        private long m_MaxConnectionsPerIP;
        private IPBindInfo[] m_pBindings = new IPBindInfo[0];
        private Logger m_pLogger;
        private TCP_SessionCollection<T> m_pSessions;
        private TimerEx m_pTimer_IdleTimeout;
        private int m_SessionIdleTimeout = 100;
        private DateTime m_StartTime;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public TCP_Server()
        {
            m_pListeningPoints = new List<ListeningPoint>();
            m_pSessions = new TCP_SessionCollection<T>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets TCP server IP bindings.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public IPBindInfo[] Bindings
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pBindings;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (value == null)
                {
                    value = new IPBindInfo[0];
                }

                //--- See binds has changed --------------
                bool changed = false;
                if (m_pBindings.Length != value.Length)
                {
                    changed = true;
                }
                else
                {
                    for (int i = 0; i < m_pBindings.Length; i++)
                    {
                        if (!m_pBindings[i].Equals(value[i]))
                        {
                            changed = true;
                            break;
                        }
                    }
                }

                if (changed)
                {
                    m_pBindings = value;

                    if (m_IsRunning)
                    {
                        StartListen();
                    }
                }
            }
        }

        /// <summary>
        /// Gets how many connections this TCP server has processed.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when TCP server is not running and this property is accesed.</exception>
        public long ConnectionsProcessed
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }
                if (!m_IsRunning)
                {
                    throw new InvalidOperationException("TCP server is not running.");
                }

                return m_ConnectionsProcessed;
            }
        }

        /// <summary>
        /// Gets if server is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get { return m_IsDisposed; }
        }

        /// <summary>
        /// Gets if server is running.
        /// </summary>
        public bool IsRunning
        {
            get { return m_IsRunning; }
        }

        /// <summary>
        /// Gets local listening IP end points.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public IPEndPoint[] LocalEndPoints
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                List<IPEndPoint> retVal = new List<IPEndPoint>();
                foreach (IPBindInfo bind in Bindings)
                {
                    if (bind.IP.Equals(IPAddress.Any))
                    {
                        foreach (IPAddress ip in Dns.GetHostAddresses(""))
                        {
                            if (ip.AddressFamily == AddressFamily.InterNetwork &&
                                !retVal.Contains(new IPEndPoint(ip, bind.Port)))
                            {
                                retVal.Add(new IPEndPoint(ip, bind.Port));
                            }
                        }
                    }
                    else if (bind.IP.Equals(IPAddress.IPv6Any))
                    {
                        foreach (IPAddress ip in Dns.GetHostAddresses(""))
                        {
                            if (ip.AddressFamily == AddressFamily.InterNetworkV6 &&
                                !retVal.Contains(new IPEndPoint(ip, bind.Port)))
                            {
                                retVal.Add(new IPEndPoint(ip, bind.Port));
                            }
                        }
                    }
                    else
                    {
                        if (!retVal.Contains(bind.EndPoint))
                        {
                            retVal.Add(bind.EndPoint);
                        }
                    }
                }

                return retVal.ToArray();
            }
        }

        /// <summary>
        /// Gets or sets logger. Value null means no logging.
        /// </summary>
        public Logger Logger
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pLogger;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                m_pLogger = value;
            }
        }

        /// <summary>
        /// Gets or sets maximum allowed concurent connections. Value 0 means unlimited.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentException">Is raised when negative value is passed.</exception>
        public long MaxConnections
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }

                return m_MaxConnections;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }
                if (value < 0)
                {
                    throw new ArgumentException("Property 'MaxConnections' value must be >= 0.");
                }

                m_MaxConnections = value;
            }
        }

        /// <summary>
        /// Gets or sets maximum allowed connections for 1 IP address. Value 0 means unlimited.
        /// </summary>
        public long MaxConnectionsPerIP
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }

                return m_MaxConnectionsPerIP;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }
                if (m_MaxConnectionsPerIP < 0)
                {
                    throw new ArgumentException("Property 'MaxConnectionsPerIP' value must be >= 0.");
                }

                m_MaxConnectionsPerIP = value;
            }
        }

        /// <summary>
        /// Gets or sets maximum allowed session idle time in seconds, after what session will be terminated. Value 0 means unlimited,
        /// but this is strongly not recommened.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentException">Is raised when negative value is passed.</exception>
        public int SessionIdleTimeout
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }

                return m_SessionIdleTimeout;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }
                if (m_SessionIdleTimeout < 0)
                {
                    throw new ArgumentException("Property 'SessionIdleTimeout' value must be >= 0.");
                }

                m_SessionIdleTimeout = value;
            }
        }

        /// <summary>
        /// Gets TCP server active sessions.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when TCP server is not running and this property is accesed.</exception>
        public TCP_SessionCollection<T> Sessions
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }
                if (!m_IsRunning)
                {
                    throw new InvalidOperationException("TCP server is not running.");
                }

                return m_pSessions;
            }
        }

        /// <summary>
        /// Gets the time when server was started.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when TCP server is not running and this property is accesed.</exception>
        public DateTime StartTime
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("TCP_Server");
                }
                if (!m_IsRunning)
                {
                    throw new InvalidOperationException("TCP server is not running.");
                }

                return m_StartTime;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            if (m_IsRunning)
            {
                try
                {
                    Stop();
                }
                catch {}
            }
            m_IsDisposed = true;

            // We must call disposed event before we release events.
            try
            {
                OnDisposed();
            }
            catch
            {
                // We never should get exception here, user should handle it, just skip it.
            }

            m_pSessions = null;

            // Release all events.
            Started = null;
            Stopped = null;
            Disposed = null;
            Error = null;
        }

        /// <summary>
        /// Starts TCP server.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public void Start()
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("TCP_Server");
            }
            if (m_IsRunning)
            {
                return;
            }
            m_IsRunning = true;

            m_StartTime = DateTime.Now;
            m_ConnectionsProcessed = 0;

            ThreadPool.QueueUserWorkItem(delegate { StartListen(); });

            m_pTimer_IdleTimeout = new TimerEx(30000, true);
            m_pTimer_IdleTimeout.Elapsed += m_pTimer_IdleTimeout_Elapsed;
            m_pTimer_IdleTimeout.Enabled = true;

            OnStarted();
        }

        /// <summary>
        /// Stops TCP server, all active connections will be terminated.
        /// </summary>
        public void Stop()
        {
            if (!m_IsRunning)
            {
                return;
            }
            m_IsRunning = false;

            // Dispose all old binds.
            foreach (ListeningPoint listeningPoint in m_pListeningPoints.ToArray())
            {
                try
                {
                    listeningPoint.Socket.Close();
                }
                catch (Exception x)
                {
                    OnError(x);
                }
            }
            m_pListeningPoints.Clear();

            m_pTimer_IdleTimeout.Dispose();
            m_pTimer_IdleTimeout = null;

            OnStopped();
        }

        /// <summary>
        /// Restarts TCP server.
        /// </summary>
        public void Restart()
        {
            Stop();
            Start();
        }

        #endregion

        #region Virtual methods

        /// <summary>
        /// Is called when new incoming session and server maximum allowed connections exceeded.
        /// </summary>
        /// <param name="session">Incoming session.</param>
        /// <remarks>This method allows inhereted classes to report error message to connected client.
        /// Session will be disconnected after this method completes.
        /// </remarks>
        protected virtual void OnMaxConnectionsExceeded(T session) {}

        /// <summary>
        /// Is called when new incoming session and server maximum allowed connections per connected IP exceeded.
        /// </summary>
        /// <param name="session">Incoming session.</param>
        /// <remarks>This method allows inhereted classes to report error message to connected client.
        /// Session will be disconnected after this method completes.
        /// </remarks>
        protected virtual void OnMaxConnectionsPerIPExceeded(T session) {}

        #endregion

        #region Utility methods

        /// <summary>
        /// Is called when session idle check timer triggered.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimer_IdleTimeout_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                foreach (T session in Sessions.ToArray())
                {
                    try
                    {
                        if (DateTime.Now > session.TcpStream.LastActivity.AddSeconds(m_SessionIdleTimeout))
                        {
                            
                            session.OnTimeoutI();
                            // Session didn't dispose itself, so dispose it.
                            if (!session.IsDisposed)
                            {
                                session.Disconnect();
                                session.Dispose();
                            }
                        }
                    }
                    catch {}
                }
            }
            catch (Exception x)
            {
                OnError(x);
            }
        }

        /// <summary>
        /// Starts listening incoming connections. NOTE: All active listening points will be disposed.
        /// </summary>
        private void StartListen()
        {
            try
            {
                // Dispose all old binds.
                foreach (ListeningPoint listeningPoint in m_pListeningPoints.ToArray())
                {
                    try
                    {
                        listeningPoint.Socket.Close();
                    }
                    catch (Exception x)
                    {
                        OnError(x);
                    }
                }
                m_pListeningPoints.Clear();

                // Create new listening points and start accepting connections.
                bool ioCompletion_asyncSockets = Net_Utils.IsIoCompletionPortsSupported();
                foreach (IPBindInfo bind in m_pBindings)
                {
                    try
                    {
                        Socket socket = null;
                        if (bind.IP.AddressFamily == AddressFamily.InterNetwork)
                        {
                            socket = new Socket(AddressFamily.InterNetwork,
                                                SocketType.Stream,
                                                ProtocolType.Tcp);
                        }
                        else if (bind.IP.AddressFamily == AddressFamily.InterNetworkV6)
                        {
                            socket = new Socket(AddressFamily.InterNetworkV6,
                                                SocketType.Stream,
                                                ProtocolType.Tcp);
                        }
                        else
                        {
                            // Invalid address family, just skip it.
                            continue;
                        }
                        socket.Bind(new IPEndPoint(bind.IP, bind.Port));
                        socket.Listen(100);

                        ListeningPoint listeningPoint = new ListeningPoint(socket, bind);
                        m_pListeningPoints.Add(listeningPoint);

                        // Begin accept.
                        //   We MUST use socket.AcceptAsync method, this consume all threading power in Windows paltform(IO completion ports).
                        //   For other platforms we need to use BeginAccept.

                        #region IO completion ports

                        if (ioCompletion_asyncSockets)
                        {
                            SocketAsyncEventArgs eArgs = new SocketAsyncEventArgs();
                            eArgs.Completed += delegate(object s, SocketAsyncEventArgs e)
                                                   {
                                                       if (e.SocketError == SocketError.Success)
                                                       {
                                                           ProcessConnection(e.AcceptSocket, bind);
                                                       }

                                                       // Start accepting new connection.
                                                       IOCompletionBeginAccept(e, socket, bind);
                                                   };

                            // Move processing to thread-pool, because IOCompletionBeginAccept keeps using calling thread as loang as there is work todo.
                            ThreadPool.QueueUserWorkItem(delegate
                                                             {
                                                                 // Start accepting new connection.
                                                                 IOCompletionBeginAccept(eArgs, socket, bind);
                                                             });
                        }

                            #endregion

                            #region Async sockets

                        else
                        {
                            // Begin accepting connection.
                            socket.BeginAccept(new AsyncCallback(AsynSocketsAcceptCompleted), listeningPoint);
                        }

                        #endregion
                    }
                    catch (Exception x)
                    {
                        // The only exception what we should get there is if socket is in use.
                        OnError(x);
                    }
                }
            }
            catch (Exception x)
            {
                OnError(x);
            }
        }

        /// <summary>
        /// Starts accepting connection(s).
        /// </summary>
        /// <param name="socketArgs">AcceptAsync method data.</param>
        /// <param name="listeningSocket">Local listening socket.</param>
        /// <param name="bindInfo">Local listening socket bind info.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>socketArgs</b>,<b>listeningSocket</b> or <b>bindInfo</b> is null reference.</exception>
        private void IOCompletionBeginAccept(SocketAsyncEventArgs socketArgs,
                                             Socket listeningSocket,
                                             IPBindInfo bindInfo)
        {
            if (socketArgs == null)
            {
                throw new ArgumentNullException("socketArgs");
            }
            if (listeningSocket == null)
            {
                throw new ArgumentNullException("listeningSocket");
            }
            if (bindInfo == null)
            {
                throw new ArgumentNullException("bindInfo");
            }

            try
            {
                // We need to clear it, before reuse.
                socketArgs.AcceptSocket = null;

                // Use active worker thread as long as AcceptAsync completes synchronously.
                // (With this approeach we don't have thread context switches while AcceptAsync completes synchronously)
                while (m_IsRunning && !listeningSocket.AcceptAsync(socketArgs))
                {
                    // Operation completed synchronously.

                    if (socketArgs.SocketError == SocketError.Success)
                    {
                        ProcessConnection(socketArgs.AcceptSocket, bindInfo);
                    }

                    // We need to clear it, before reuse.
                    socketArgs.AcceptSocket = null;
                }
            }
            catch (ObjectDisposedException x)
            {
                string dummy = x.Message;
                // Listening socket closed, so skip that error.
            }
        }

        /// <summary>
        /// This method is called when BeginAccept ha completed.
        /// </summary>
        /// <param name="ar">The result of the asynchronous operation.</param>
        private void AsynSocketsAcceptCompleted(IAsyncResult ar)
        {
            ListeningPoint lPoint = (ListeningPoint) ar.AsyncState;
            try
            {
                ProcessConnection(lPoint.Socket.EndAccept(ar), lPoint.BindInfo);
            }
            catch
            {
                // Skip accept errors.
            }

            // Begin accepting connection.
            lPoint.Socket.BeginAccept(new AsyncCallback(AsynSocketsAcceptCompleted), lPoint);
        }

        /// <summary>
        /// Processes specified connection.
        /// </summary>
        /// <param name="socket">Accpeted socket.</param>
        /// <param name="bindInfo">Local bind info what accpeted connection.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>socket</b> or <b>bindInfo</b> is null reference.</exception>
        private void ProcessConnection(Socket socket, IPBindInfo bindInfo)
        {
            if (socket == null)
            {
                throw new ArgumentNullException("socket");
            }
            if (bindInfo == null)
            {
                throw new ArgumentNullException("bindInfo");
            }

            m_ConnectionsProcessed++;

            try
            {
                T session = new T();
                session.Init(this,
                             socket,
                             bindInfo.HostName,
                             bindInfo.SslMode == SslMode.SSL,
                             bindInfo.Certificate);

                // Maximum allowed connections exceeded, reject connection.
                if (m_MaxConnections != 0 && m_pSessions.Count > m_MaxConnections)
                {
                    OnMaxConnectionsExceeded(session);
                    session.Dispose();
                }
                    // Maximum allowed connections per IP exceeded, reject connection.
                else if (m_MaxConnectionsPerIP != 0)
                {
                    OnMaxConnectionsPerIPExceeded(session);
                    session.Dispose();
                }
                    // Start processing new session.
                else
                {
                    session.Disonnected +=
                        delegate(object sender, EventArgs e) { m_pSessions.Remove((T)sender); };
                    m_pSessions.Add(session);

                    OnSessionCreated(session);

                    session.Start();
                }
            }
            catch (Exception x)
            {
                OnError(x);
            }
        }

        /// <summary>
        /// Raises <b>SessionCreated</b> event.
        /// </summary>
        /// <param name="session">TCP server session that was created.</param>
        private void OnSessionCreated(T session)
        {
            if (SessionCreated != null)
            {
                SessionCreated(this, new TCP_ServerSessionEventArgs<T>(this, session));
            }
        }

        /// <summary>
        /// Raises <b>Error</b> event.
        /// </summary>
        /// <param name="x">Exception happened.</param>
        protected void OnError(Exception x)
        {
            if (Error != null)
            {
                Error(this, new Error_EventArgs(x, new StackTrace()));
            }
        }

        #endregion

        /// <summary>
        /// Raises <b>Started</b> event.
        /// </summary>
        protected void OnStarted()
        {
            if (Started != null)
            {
                Started(this, new EventArgs());
            }
        }

        /// <summary>
        /// Raises <b>Stopped</b> event.
        /// </summary>
        protected void OnStopped()
        {
            if (Stopped != null)
            {
                Stopped(this, new EventArgs());
            }
        }

        /// <summary>
        /// Raises <b>Disposed</b> event.
        /// </summary>
        protected void OnDisposed()
        {
            if (Disposed != null)
            {
                Disposed(this, new EventArgs());
            }
        }

        #region Nested type: ListeningPoint

        /// <summary>
        /// This class holds listening point info.
        /// </summary>
        private class ListeningPoint
        {
            #region Members

            private readonly IPBindInfo m_pBindInfo;
            private readonly Socket m_pSocket;

            #endregion

            #region Constructor

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="socket">Listening socket.</param>
            /// <param name="bind">Bind info what acceped socket.</param>
            public ListeningPoint(Socket socket, IPBindInfo bind)
            {
                m_pSocket = socket;
                m_pBindInfo = bind;
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets bind info.
            /// </summary>
            public IPBindInfo BindInfo
            {
                get { return m_pBindInfo; }
            }

            /// <summary>
            /// Gets socket.
            /// </summary>
            public Socket Socket
            {
                get { return m_pSocket; }
            }

            #endregion
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Core/HelpClasses/ForumPresenterFactory.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

namespace ASC.Forum
{
    public class ForumPresenterFactory : IPresenterFactory
    {
        public IPresenter GetPresenter<T>() where T : class
        {
            IPresenter presenter = null;

            if (typeof(T).Equals(typeof(ISecurityActionView)))
                presenter = new SecurityActionPresenter();

            else if (typeof(T).Equals(typeof(INotifierView)))
                presenter = new NotifierPresenter();

            else if (typeof(T).Equals(typeof(ISubscriberView)))
                presenter = new SubscriberPresenter();

            else if (typeof(T).Equals(typeof(ISubscriptionGetcherView)))
                presenter = new SubscriptionGetcherPresenter();

            return presenter;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Calendar/BusinessObjects/ColumnCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Utils;
using ASC.Web.Core.Calendars;

namespace ASC.Api.Calendar.BusinessObjects
{
    internal class ColumnCollection
    {
        private readonly List<SelectColumnInfo> _columns = new List<SelectColumnInfo>();

        public class SelectColumnInfo
        {

            public string Name { get; set; }
            public int Ind { get; set; }

            public T Parse<T>(object[] row)
            {
                if (typeof(T).Equals(typeof(int)))
                    return (T)((object)Convert.ToInt32(row[this.Ind]));

                if (typeof(T).Equals(typeof(Guid)))
                    return (T)((object)new Guid(Convert.ToString(row[this.Ind])));

                if (typeof(T).Equals(typeof(Boolean)))
                    return (T)((object)(Convert.ToBoolean(row[this.Ind])));

                if (typeof(T).Equals(typeof(DateTime)))
                    return (T)((object)Convert.ToDateTime(row[this.Ind]));

                if (typeof(T).Equals(typeof(RecurrenceRule)))
                {
                    return (T)((object)RecurrenceRule.Parse(Convert.ToString(row[this.Ind])));
                }

                if (typeof(T).Equals(typeof(TimeZoneInfo)))
                {
                    if (IsNull(row))
                        return (T)(object)null;

                    var timeZoneId = Convert.ToString(row[this.Ind]);

                    return (T)((object)TimeZoneConverter.GetTimeZone(timeZoneId));
                }

                return (T)(object)(Convert.ToString(row[this.Ind]) ?? "");
            }

            public bool IsNull(object[] row)
            {
                return row[this.Ind] == null || row[this.Ind] == DBNull.Value;
            }
        }

        public SelectColumnInfo RegistryColumn(string selectName)
        {
            var c = new SelectColumnInfo() { Name = selectName, Ind = _columns.Count };
            _columns.Add(c);
            return c;
        }

        public string[] SelectQuery
        {
            get
            {
                return _columns.Select(c => c.Name).ToArray();
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Services/WhatsNew/feed.ashx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.ServiceModel.Syndication;
using System.Text;
using System.Web;
using System.Web.Services;
using System.Xml;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Feed;
using ASC.Feed.Data;
using ASC.Web.Core;
using ASC.Web.Core.Helpers;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Services.WhatsNew
{
    [WebService(Namespace = "http://www.teamlab.com/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.None)]
    public class feed : IHttpHandler
    {
        public const string HandlerBasePath = "~/services/whatsnew/";
        public const string HandlerPath = "~/services/whatsnew/feed.ashx";
        private const string TitleParam = "c";
        private const string ProductParam = "pid";


        public void ProcessRequest(HttpContext context)
        {
            if (!ProcessAuthorization(context))
            {
                AccessDenied(context);
                return;
            }

            var productId = ParseGuid(context.Request[ProductParam]);
            var product = WebItemManager.Instance[productId.GetValueOrDefault()];
            var products = WebItemManager.Instance.GetItemsAll<IProduct>().ToDictionary(p => p.GetSysName());
            var lastModified = GetLastModified(context);

            var feeds = FeedAggregateDataProvider.GetFeeds(new FeedApiFilter
            {
                Product = product != null ? product.GetSysName() : null,
                From = lastModified ?? DateTime.UtcNow.AddDays(-14),
                To = DateTime.UtcNow,
                OnlyNew = true
            })
                .OrderByDescending(f => f.CreatedDate)
                .Take(100)
                .Select(f => f.ToFeedMin())
                .ToList();

            if (lastModified != null && feeds.Count == 0)
            {
                context.Response.StatusCode = (int)HttpStatusCode.NotModified;
                context.Response.StatusDescription = "Not Modified";
            }

            var feedItems = feeds.Select(f =>
            {
                var item = new SyndicationItem(
                    HttpUtility.HtmlDecode((products.ContainsKey(f.Product) ? products[f.Product].Name + ": " : string.Empty) + f.Title),
                    string.Empty,
                    new Uri(CommonLinkUtility.GetFullAbsolutePath(f.ItemUrl)),
                    f.Id,
                    new DateTimeOffset(TenantUtil.DateTimeToUtc(f.CreatedDate)))
                {
                    PublishDate = f.CreatedDate,
                };
                if (f.Author != null && f.Author.UserInfo != null)
                {
                    var u = f.Author.UserInfo;
                    item.Authors.Add(new SyndicationPerson(u.Email, u.DisplayUserName(false), CommonLinkUtility.GetUserProfile(u.ID)));
                }
                return item;
            });

            var lastUpdate = DateTime.UtcNow;
            if (feeds.Count > 0)
            {
                lastUpdate = feeds.Max(x => x.ModifiedDate);
            }

            var feed = new SyndicationFeed(
                CoreContext.TenantManager.GetCurrentTenant().Name,
                string.Empty,
                new Uri(context.Request.GetUrlRewriter(), VirtualPathUtility.ToAbsolute("~/Feed.aspx")),
                TenantProvider.CurrentTenantID.ToString(),
                new DateTimeOffset(lastUpdate),
                feedItems);

            var rssFormatter = new Atom10FeedFormatter(feed);
            var settings = new XmlWriterSettings
            {
                CheckCharacters = false,
                ConformanceLevel = ConformanceLevel.Document,
                Encoding = Encoding.UTF8,
                Indent = true,
            };
            using (var writer = XmlWriter.Create(context.Response.Output, settings))
            {
                rssFormatter.WriteTo(writer);
            }
            context.Response.Charset = Encoding.UTF8.WebName;
            context.Response.ContentType = "application/atom+xml";
            context.Response.AddHeader("ETag", DateTime.UtcNow.ToString("yyyyMMddHHmmss"));
            context.Response.AddHeader("Last-Modified", DateTime.UtcNow.ToString("R"));
        }

        public static string RenderRssMeta(string title, string productId)
        {
            var urlparams = new Dictionary<string, string>();
            if (!String.IsNullOrEmpty(productId))
            {
                urlparams.Add(ProductParam, productId);
            }
            if (!String.IsNullOrEmpty(title))
            {
                urlparams.Add(TitleParam, title);
            }

            var queryString = new StringBuilder("?");
            foreach (var urlparam in urlparams)
            {
                queryString.AppendFormat("{0}={1}&", HttpUtility.UrlEncode(urlparam.Key), HttpUtility.UrlEncode(urlparam.Value));
            }

            return string.Format(@"<link rel=""alternate"" type=""application/atom+xml"" title=""{0}"" href=""{1}"" />",
                title, CommonLinkUtility.GetFullAbsolutePath(HandlerPath) + queryString.ToString().TrimEnd('&'));
        }

        private static bool ProcessAuthorization(HttpContext context)
        {
            if (!SecurityContext.IsAuthenticated)
            {
                try
                {
                    var cookiesKey = CookiesManager.GetCookies(CookiesType.AuthKey);
                    if (!SecurityContext.AuthenticateMe(cookiesKey))
                    {
                        throw new UnauthorizedAccessException();
                    }
                }
                catch (Exception)
                {
                    return AuthorizationHelper.ProcessBasicAuthorization(context);
                }
            }
            return SecurityContext.IsAuthenticated;
        }

        private static void AccessDenied(HttpContext context)
        {
            context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            context.Response.StatusDescription = "Access Denied";
            string realm = String.Format("Basic Realm=\"{0}\"", context.Request.GetUrlRewriter().Host);
            context.Response.AppendHeader("WWW-Authenticate", realm);
            context.Response.Write("401 Access Denied");
        }

        private static Guid? ParseGuid(string guid)
        {
            try
            {
                return new Guid(guid);
            }
            catch
            {
                return null;
            }
        }

        private DateTime? GetLastModified(HttpContext context)
        {
            if (context.Request.Headers["If-Modified-Since"] != null)
            {
                try
                {
                    return DateTime.ParseExact(context.Request.Headers["If-Modified-Since"], "R", null);
                }
                catch { }
            }
            if (context.Request.Headers["If-None-Match"] != null)
            {
                try
                {
                    return DateTime.ParseExact(context.Request.Headers["If-None-Match"], "yyyyMMddHHmmss", null);
                }
                catch { }
            }
            return null;
        }


        public bool IsReusable
        {
            get { return false; }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/STUN/Message/STUN_t_ErrorCode.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.STUN.Message
{
    /// <summary>
    /// This class implements STUN ERROR-CODE. Defined in RFC 3489 11.2.9.
    /// </summary>
    public class STUN_t_ErrorCode
    {
        #region Members

        private string m_ReasonText = "";

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="code">Error code.</param>
        /// <param name="reasonText">Reason text.</param>
        public STUN_t_ErrorCode(int code, string reasonText)
        {
            Code = code;
            m_ReasonText = reasonText;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets error code.
        /// </summary>
        public int Code { get; set; }

        /// <summary>
        /// Gets reason text.
        /// </summary>
        public string ReasonText
        {
            get { return m_ReasonText; }

            set { m_ReasonText = value; }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Utils/FileHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.IO;
using System.Reflection;

namespace ASC.Web.CRM.Classes
{
    public class FileHelper
    {
        public static void WriteTextToFile(string path, string text)
        {
            File.WriteAllText(path, text);
        }

        public static string ReadTextFromFile(string path)
        {
            return File.Exists(path) ? File.ReadAllText(path) : null;
        }

        public static string ReadTextFromEmbeddedResource(string resourceName)
        {
            var result = string.Empty;
            var assembly = Assembly.GetExecutingAssembly();

            using (var stream = assembly.GetManifestResourceStream(resourceName))
            {
                if (stream != null)
                {
                    using (var sr = new StreamReader(stream))
                    {
                        result = sr.ReadToEnd();
                    }
                }
            }

            return result;
        }

        public static byte[] ReadBytesFromFile(string path)
        {
            return File.Exists(path) ? File.ReadAllBytes(path) : null;
        }

        public static byte[] ReadBytesFromEmbeddedResource(string resourceName)
        {
            byte[] result = null;
            var assembly = Assembly.GetExecutingAssembly();

            using (var stream = assembly.GetManifestResourceStream(resourceName))
            {
                if (stream != null)
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        stream.CopyTo(memoryStream);
                        result = memoryStream.ToArray();
                    }
                }
            }

            return result;
        }

        public static void DeleteFile(string path)
        {
            if (File.Exists(path))
                File.Delete(path);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/core/collaborators.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/*
 * Welcome Collaborators popup Manager
 */
window.WelcomeCollaboratorsManager = new function () {

    function closeWelcomePopup () {
        Teamlab.closeWelcomePopup();
        javascript: jq.unblockUI();
    }

    function init () {
        var regPath = /(^\/$)|(\/feed\.aspx)|(\/products\/community\/)|(\/products\/projects\/)|(\/products\/files\/)/g;
        if (location.pathname.match(regPath) == null) {
            return;
        }

        jq.tmpl("template-blockUIPanel", {
            id: "studio_welcomeCollaboratorContainer",
            headerTest: ASC.Resources.Master.ResourceJS.WelcomeCollaboratorPopupHeader,

            innerHtmlText: ["<div class=\"welcome-to-teamlab-with-logo\">",
                "<p class=\"welcome\">",
                Encoder.XSSEncode(ASC.Resources.Master.ResourceJS.WelcomeToTeamlab),
                "</p>",
                "<p>",
                ASC.Resources.Master.ResourceJS.WelcomeCollaboratorRole,
                "</p>",
                jq.format(ASC.Resources.Master.ResourceJS.WelcomeCollaboratorCan,
                    "<p>", "</p><ul class='welcome-collaborator-can'><li>", "</li><li>", "</li><li>", "</li></ul>"),
                "<p>",
                ASC.Resources.Master.ResourceJS.WelcomeCollaboratorOtherActions,
                "</p>",
                "</div>"].join(''),
            OKBtn: ASC.Resources.Master.ResourceJS.WelcomeCollaboratorStartWork
        }).appendTo("#studioPageContent .mainPageContent:first");

        jq("#studio_welcomeCollaboratorContainer").on("click", ".button.blue, .cancelButton", function () {
            window.WelcomeCollaboratorsManager.closeWelcomePopup();
        });

        StudioBlockUIManager.blockUI('#studio_welcomeCollaboratorContainer', 500);
    }

    return {
        init: init,
        closeWelcomePopup: closeWelcomePopup
    };
};
jq(document).ready(function () {
    WelcomeCollaboratorsManager.init();
});

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Data/Map.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Data;

using ASC.Blogs.Core.Domain;
using ASC.Common.Data;

#endregion

namespace ASC.Blogs.Core.Data
{
    static class RowMappers
    {
        public static Blog ToBlog(IDataRecord row)
        {
            return new Blog
            {
                BlogID = row.Get<int>("id"),
                Name = row.Get<string>("name"),
                UserID = row.Get<Guid>("user_id"),
                GroupID = row.Get<Guid>("group_id"),
            };
        }

        public static string ToString(IDataRecord row)
        {
            return row.Get<string>("name");
        }

        public static Tag ToTag(IDataRecord row)
        {
            return new Tag
            {
                Content = row.Get<string>("name"),
                PostId = row.Get<Guid>("post_id"),
            };
        }

        public static Comment ToComment(IDataRecord row)
        {
            return new Comment
            {
                ID = row.Get<Guid>("id"),
                PostId = row.Get<Guid>("post_id"),
                Content = row.Get<string>("content"),
                UserID = row.Get<Guid>("created_by"),
                Datetime = ASC.Core.Tenants.TenantUtil.DateTimeFromUtc(row.Get<DateTime>("created_when")),
                ParentId = row.Get<Guid>("parent_id"),
                Inactive = row.Get<int>("inactive") > 0
            };
        }

        public static Post ToPost(IDataRecord row, bool withContent)
        {
            return new Post
            {
                ID = row.Get<Guid>("id"),
                Title = row.Get<string>("title"),
                Content = withContent ? row.Get<string>("content") : null,
                UserID = row.Get<Guid>("created_by"),
                Datetime = ASC.Core.Tenants.TenantUtil.DateTimeFromUtc(row.Get<DateTime>("created_when")),
                BlogId = row.Get<int>("blog_id"),
                AutoIncrementID = row.Get<int>("post_id")
            };
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Stack/SIP_ServerTransaction.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Stack
{
    #region usings

    using System;
    using System.Timers;
    using Message;

    #endregion

    /// <summary>
    /// Implements SIP server transaction. Defined in rfc 3261 17.2.
    /// </summary>
    public class SIP_ServerTransaction : SIP_Transaction
    {
        #region Events

        /// <summary>
        /// Is raised when transaction has canceled.
        /// </summary>
        public event EventHandler Canceled = null;

        /// <summary>
        /// Is raised when transaction has sent response to remote party.
        /// </summary>
        public event EventHandler<SIP_ResponseSentEventArgs> ResponseSent = null;

        #endregion

        #region Members

        private TimerEx m_pTimer100;
        private TimerEx m_pTimerG;
        private TimerEx m_pTimerH;
        private TimerEx m_pTimerI;
        private TimerEx m_pTimerJ;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stack">Owner SIP stack.</param>
        /// <param name="flow">SIP data flow which received request.</param>
        /// <param name="request">SIP request that transaction will handle.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stack</b>,<b>flow</b> or <b>request</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public SIP_ServerTransaction(SIP_Stack stack, SIP_Flow flow, SIP_Request request)
            : base(stack, flow, request)
        {
            // Log
            if (Stack.Logger != null)
            {
                Stack.Logger.AddText(ID,
                                     "Transaction [branch='" + ID + "';method='" + Method +
                                     "';IsServer=true] created.");
            }

            Start();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public override void Dispose()
        {
            lock (SyncRoot)
            {
                if (m_pTimer100 != null)
                {
                    m_pTimer100.Dispose();
                    m_pTimer100 = null;
                }
                if (m_pTimerG != null)
                {
                    m_pTimerG.Dispose();
                    m_pTimerG = null;
                }
                if (m_pTimerH != null)
                {
                    m_pTimerH.Dispose();
                    m_pTimerH = null;
                }
                if (m_pTimerI != null)
                {
                    m_pTimerI.Dispose();
                    m_pTimerI = null;
                }
                if (m_pTimerJ != null)
                {
                    m_pTimerJ.Dispose();
                    m_pTimerJ = null;
                }
            }
        }

        /// <summary>
        /// Sends specified response to remote party.
        /// </summary>
        /// <param name="response">SIP response to send.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public void SendResponse(SIP_Response response)
        {
            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                try
                {
                    #region INVITE

                    /* RFC 3261 17.2.1.
                                           |INVITE
                                           |pass INV to TU
                        INVITE             V send 100 if TU won't in 200ms
                        send response+-----------+
                            +--------|           |--------+101-199 from TU
                            |        | Proceeding|        |send response
                            +------->|           |<-------+
                                     |           |          Transport Err.
                                     |           |          Inform TU
                                     |           |--------------->+
                                     +-----------+                |
                        300-699 from TU |     |2xx from TU        |
                        send response   |     |send response      |
                                        |     +------------------>+
                                        |                         |
                        INVITE          V          Timer G fires  |
                        send response+-----------+ send response  |
                            +--------|           |--------+       |
                            |        | Completed |        |       |
                            +------->|           |<-------+       |
                                     +-----------+                |
                                        |     |                   |
                                    ACK |     |                   |
                                    -   |     +------------------>+
                                        |        Timer H fires    |
                                        V        or Transport Err.|
                                     +-----------+  Inform TU     |
                                     |           |                |
                                     | Confirmed |                |
                                     |           |                |
                                     +-----------+                |
                                           |                      |
                                           |Timer I fires         |
                                           |-                     |
                                           |                      |
                                           V                      |
                                     +-----------+                |
                                     |           |                |
                                     | Terminated|<---------------+
                                     |           |
                                     +-----------+
                    */

                    if (Method == SIP_Methods.INVITE)
                    {
                        #region Proceeding

                        if (State == SIP_TransactionState.Proceeding)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                            }
                                // 2xx
                            else if (response.StatusCodeType == SIP_StatusCodeType.Success)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Terminated);
                            }
                                // 3xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.1.
                                    For unreliable transports, timer G is set to fire in T1 seconds, and is not set to fire for reliable transports.
                                */
                                if (!Flow.IsReliable)
                                {
                                    m_pTimerG = new TimerEx(SIP_TimerConstants.T1, false);
                                    m_pTimerG.Elapsed += m_pTimerG_Elapsed;
                                    m_pTimerG.Enabled = true;

                                    // Log
                                    if (Stack.Logger != null)
                                    {
                                        Stack.Logger.AddText(ID,
                                                             "Transaction [branch='" + ID + "';method='" +
                                                             Method +
                                                             "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) started, will triger after " +
                                                             m_pTimerG.Interval + ".");
                                    }
                                }

                                /* RFC 3261 17.2.1.
                                    When the "Completed" state is entered, timer H MUST be set to fire in 64*T1 seconds for all transports.
                                */
                                m_pTimerH = new TimerEx(64*SIP_TimerConstants.T1);
                                m_pTimerH.Elapsed += m_pTimerH_Elapsed;
                                m_pTimerH.Enabled = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer H(INVITE ACK wait) started, will triger after " +
                                                         m_pTimerH.Interval + ".");
                                }
                            }
                        }

                            #endregion

                            #region Completed

                        else if (State == SIP_TransactionState.Completed)
                        {
                            // We do nothing here, we just wait ACK to arrive.
                        }

                            #endregion

                            #region Confirmed

                        else if (State == SIP_TransactionState.Confirmed)
                        {
                            // We do nothing, just wait ACK retransmissions.
                        }

                            #endregion

                            #region Terminated

                        else if (State == SIP_TransactionState.Terminated)
                        {
                            // We should never rreach here, but if so, skip it.
                        }

                        #endregion
                    }

                        #endregion

                        #region Non-INVITE

                        /* RFC 3261 17.2.2.
                                              |Request received
                                              |pass to TU
                                              V
                                        +-----------+
                                        |           |
                                        | Trying    |-------------+
                                        |           |             |
                                        +-----------+             |200-699 from TU
                                              |                   |send response
                                              |1xx from TU        |
                                              |send response      |
                                              |                   |
                           Request            V      1xx from TU  |
                           send response+-----------+send response|
                               +--------|           |--------+    |
                               |        | Proceeding|        |    |
                               +------->|           |<-------+    |
                        +<--------------|           |             |
                        |Trnsprt Err    +-----------+             |
                        |Inform TU            |                   |
                        |                     |                   |
                        |                     |200-699 from TU    |
                        |                     |send response      |
                        |  Request            V                   |
                        |  send response+-----------+             |
                        |      +--------|           |             |
                        |      |        | Completed |<------------+
                        |      +------->|           |
                        +<--------------|           |
                        |Trnsprt Err    +-----------+
                        |Inform TU            |
                        |                     |Timer J fires
                        |                     |-
                        |                     |
                        |                     V
                        |               +-----------+
                        |               |           |
                        +-------------->| Terminated|
                                        |           |
                                        +-----------+
                    */

                    else
                    {
                        #region Trying

                        if (State == SIP_TransactionState.Trying)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Proceeding);
                            }
                                // 2xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.2.
                                    When the server transaction enters the "Completed" state, it MUST set
                                    Timer J to fire in 64*T1 seconds for unreliable transports, and zero
                                    seconds for reliable transports.
                                */
                                m_pTimerJ = new TimerEx(64*SIP_TimerConstants.T1, false);
                                m_pTimerJ.Elapsed += m_pTimerJ_Elapsed;
                                m_pTimerJ.Enabled = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will triger after " +
                                                         m_pTimerJ.Interval + ".");
                                }
                            }
                        }

                            #endregion

                            #region Proceeding

                        else if (State == SIP_TransactionState.Proceeding)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                            }
                                // 2xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.2.
                                    When the server transaction enters the "Completed" state, it MUST set
                                    Timer J to fire in 64*T1 seconds for unreliable transports, and zero
                                    seconds for reliable transports.
                                */
                                m_pTimerJ = new TimerEx(64*SIP_TimerConstants.T1, false);
                                m_pTimerJ.Elapsed += m_pTimerJ_Elapsed;
                                m_pTimerJ.Enabled = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will triger after " +
                                                         m_pTimerJ.Interval + ".");
                                }
                            }
                        }

                            #endregion

                            #region Completed

                        else if (State == SIP_TransactionState.Completed)
                        {
                            // Do nothing.
                        }

                            #endregion

                            #region Terminated

                        else if (State == SIP_TransactionState.Terminated)
                        {
                            // Do nothing.
                        }

                        #endregion
                    }

                    #endregion
                }
                catch (SIP_TransportException x)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] transport exception: " + x.Message);
                    }

                    OnTransportError(x);
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }

        /// <summary>
        /// Cancels current transaction processing and sends '487 Request Terminated'.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when final response is sent and Cancel method is called after it.</exception>
        public override void Cancel()
        {
            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (FinalResponse != null)
                {
                    throw new InvalidOperationException("Final response is already sent, CANCEL not allowed.");
                }

                try
                {
                    SIP_Response response = Stack.CreateResponse(SIP_ResponseCodes.x487_Request_Terminated,
                                                                 Request);
                    Stack.TransportLayer.SendResponse(this, response);

                    OnCanceled();
                }
                catch (SIP_TransportException x)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] transport exception: " + x.Message);
                    }

                    OnTransportError(x);
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Processes specified request through this transaction.
        /// </summary>
        /// <param name="flow">SIP data flow.</param>
        /// <param name="request">SIP request.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        internal void ProcessRequest(SIP_Flow flow, SIP_Request request)
        {
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    return;
                }

                try
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        byte[] requestData = request.ToByteData();

                        Stack.Logger.AddRead(Guid.NewGuid().ToString(),
                                             null,
                                             0,
                                             "Request [transactionID='" + ID + "'; method='" +
                                             request.RequestLine.Method + "'; cseq='" +
                                             request.CSeq.SequenceNumber + "'; " + "transport='" +
                                             flow.Transport + "'; size='" + requestData.Length +
                                             "'; received '" + flow.LocalEP + "' <- '" + flow.RemoteEP + "'.",
                                             flow.LocalEP,
                                             flow.RemoteEP,
                                             requestData);
                    }

                    #region INVITE

                    if (Method == SIP_Methods.INVITE)
                    {
                        #region INVITE

                        if (request.RequestLine.Method == SIP_Methods.INVITE)
                        {
                            if (State == SIP_TransactionState.Proceeding)
                            {
                                /* RFC 3261 17.2.1.
                                    If a request retransmission is received while in the "Proceeding" state, the most recent provisional 
                                    response that was received from the TU MUST be passed to the transport layer for retransmission.
                                */
                                SIP_Response response = LastProvisionalResponse;
                                if (response != null)
                                {
                                    Stack.TransportLayer.SendResponse(this, response);
                                }
                            }
                            else if (State == SIP_TransactionState.Completed)
                            {
                                /* RFC 3261 17.2.1.
                                    While in the "Completed" state, if a request retransmission is received, the server SHOULD 
                                    pass the response to the transport for retransmission.
                                */
                                Stack.TransportLayer.SendResponse(this, FinalResponse);
                            }
                        }

                            #endregion

                            #region ACK

                        else if (request.RequestLine.Method == SIP_Methods.ACK)
                        {
                            /* RFC 3261 17.2.1
                                If an ACK is received while the server transaction is in the "Completed" state, the server transaction 
                                MUST transition to the "Confirmed" state.  As Timer G is ignored in this state, any retransmissions of the 
                                response will cease.
                         
                                When this state is entered, timer I is set to fire in T4 seconds for unreliable transports, 
                                and zero seconds for reliable transports.
                            */

                            if (State == SIP_TransactionState.Completed)
                            {
                                SetState(SIP_TransactionState.Confirmed);

                                // Stop timers G,H
                                if (m_pTimerG != null)
                                {
                                    m_pTimerG.Dispose();
                                    m_pTimerG = null;

                                    // Log
                                    if (Stack.Logger != null)
                                    {
                                        Stack.Logger.AddText(ID,
                                                             "Transaction [branch='" + ID + "';method='" +
                                                             Method +
                                                             "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) stoped.");
                                    }
                                }
                                if (m_pTimerH != null)
                                {
                                    m_pTimerH.Dispose();
                                    m_pTimerH = null;

                                    // Log
                                    if (Stack.Logger != null)
                                    {
                                        Stack.Logger.AddText(ID,
                                                             "Transaction [branch='" + ID + "';method='" +
                                                             Method +
                                                             "';IsServer=true] timer H(INVITE ACK wait) stoped.");
                                    }
                                }

                                // Start timer I.
                                m_pTimerI = new TimerEx((flow.IsReliable ? 0 : SIP_TimerConstants.T4), false);
                                m_pTimerI.Elapsed += m_pTimerI_Elapsed;
                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer I(INVITE ACK retransission wait) started, will triger after " +
                                                         m_pTimerI.Interval + ".");
                                }
                                m_pTimerI.Enabled = true;
                            }
                        }

                        #endregion
                    }

                        #endregion

                        #region Non-INVITE

                    else
                    {
                        // Non-INVITE transaction may have only request retransmission requests.
                        if (Method == request.RequestLine.Method)
                        {
                            if (State == SIP_TransactionState.Proceeding)
                            {
                                /* RFC 3261 17.2.2.
                                    If a retransmission of the request is received while in the "Proceeding" state, the most
                                    recently sent provisional response MUST be passed to the transport layer for retransmission.
                                */
                                Stack.TransportLayer.SendResponse(this, LastProvisionalResponse);
                            }
                            else if (State == SIP_TransactionState.Completed)
                            {
                                /* RFC 3261 17.2.2.
                                    While in the "Completed" state, the server transaction MUST pass the final response to the transport
                                    layer for retransmission whenever a retransmission of the request is received.
                                */
                                Stack.TransportLayer.SendResponse(this, FinalResponse);
                            }
                        }
                    }

                    #endregion
                }
                catch (SIP_TransportException x)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] transport exception: " + x.Message);
                    }

                    OnTransportError(x);
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Is raised when INVITE 100 (Trying) response must be sent if no response sent by transaction user.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimer100_Elapsed(object sender, ElapsedEventArgs e)
        {
            lock (SyncRoot)
            {
                // RFC 3261 17.2.1. TU didn't generate response in 200 ms, send '100 Trying' to stop request retransmission.
                if (State == SIP_TransactionState.Proceeding && Responses.Length == 0)
                {
                    /* RFC 3261 17.2.1.
                        The 100 (Trying) response is constructed according to the procedures in Section 8.2.6, except that the
                        insertion of tags in the To header field of the response (when none was present in the request) 
                        is downgraded from MAY to SHOULD NOT.
                     * 
                       RFC 3261 8.2.6.
                        When a 100 (Trying) response is generated, any Timestamp header field present in the request MUST 
                        be copied into this 100 (Trying) response. If there is a delay in generating the response, the UAS
                        SHOULD add a delay value into the Timestamp value in the response. This value MUST contain the difference 
                        between the time of sending of the response and receipt of the request, measured in seconds.
                    */

                    SIP_Response tryingResponse = Stack.CreateResponse(SIP_ResponseCodes.x100_Trying, Request);
                    if (Request.Timestamp != null)
                    {
                        tryingResponse.Timestamp = new SIP_t_Timestamp(Request.Timestamp.Time,
                                                                       (DateTime.Now - CreateTime).Seconds);
                    }

                    try
                    {
                        Stack.TransportLayer.SendResponse(this, tryingResponse);
                    }
                    catch (Exception x)
                    {
                        OnTransportError(x);
                        SetState(SIP_TransactionState.Terminated);
                        return;
                    }
                }

                if (m_pTimer100 != null)
                {
                    m_pTimer100.Dispose();
                    m_pTimer100 = null;
                }
            }
        }

        /// <summary>
        /// Is raised when INVITE timer G triggered.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimerG_Elapsed(object sender, ElapsedEventArgs e)
        {
            /* RFC 3261 17.2.1.
                If timer G fires, the response is passed to the transport layer once more for retransmission, and
                timer G is set to fire in MIN(2*T1, T2) seconds.  From then on, when timer G fires, the response is 
                passed to the transport again for transmission, and timer G is reset with a value that doubles, unless
                that value exceeds T2, in which case it is reset with the value of T2.
            */

            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Completed)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) triggered.");
                    }

                    try
                    {
                        Stack.TransportLayer.SendResponse(this, FinalResponse);

                        // Update(double current) next transmit time.
                        m_pTimerG.Interval *= Math.Min(m_pTimerG.Interval*2, SIP_TimerConstants.T2);
                        m_pTimerG.Enabled = true;

                        // Log
                        if (Stack.Logger != null)
                        {
                            Stack.Logger.AddText(ID,
                                                 "Transaction [branch='" + ID + "';method='" + Method +
                                                 "';IsServer=false] timer G(INVITE response(3xx - 6xx) retransmission) updated, will triger after " +
                                                 m_pTimerG.Interval + ".");
                        }
                    }
                    catch (Exception x)
                    {
                        OnTransportError(x);
                        SetState(SIP_TransactionState.Terminated);
                    }
                }
            }
        }

        /// <summary>
        /// Is raised when INVITE timer H triggered.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimerH_Elapsed(object sender, ElapsedEventArgs e)
        {
            /* RFC 3261 17.2.1.
                If timer H fires while in the "Completed" state, it implies that the
                ACK was never received.  In this case, the server transaction MUST
                transition to the "Terminated" state, and MUST indicate to the TU
                that a transaction failure has occurred.
            */

            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Completed)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] timer H(INVITE ACK wait) triggered.");
                    }

                    OnTransactionError("ACK was never received.");
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }

        /// <summary>
        /// Is raised when INVITE timer I triggered.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimerI_Elapsed(object sender, ElapsedEventArgs e)
        {
            /* RFC 3261 17.2.1.
                Once timer I fires, the server MUST transition to the "Terminated" state.
            */

            lock (SyncRoot)
            {
                // Log
                if (Stack.Logger != null)
                {
                    Stack.Logger.AddText(ID,
                                         "Transaction [branch='" + ID + "';method='" + Method +
                                         "';IsServer=true] timer I(INVITE ACK retransmission wait) triggered.");
                }

                SetState(SIP_TransactionState.Terminated);
            }
        }

        /// <summary>
        /// Is raised when INVITE timer J triggered.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimerJ_Elapsed(object sender, ElapsedEventArgs e)
        {
            /* RFC 3261 172.2.2.
                Timer J fires, at which point it MUST transition to the "Terminated" state.
            */

            lock (SyncRoot)
            {
                // Log
                if (Stack.Logger != null)
                {
                    Stack.Logger.AddText(ID,
                                         "Transaction [branch='" + ID + "';method='" + Method +
                                         "';IsServer=true] timer I(Non-INVITE request retransmission wait) triggered.");
                }

                SetState(SIP_TransactionState.Terminated);
            }
        }

        /// <summary>
        /// Starts transaction processing.
        /// </summary>
        private void Start()
        {
            #region INVITE

            if (Method == SIP_Methods.INVITE)
            {
                /* RFC 3261 17.2.1.
                    When a server transaction is constructed for a request, it enters the "Proceeding" state. The server 
                    transaction MUST generate a 100 (Trying) response unless it knows that the TU will generate a provisional 
                    or final response within 200 ms, in which case it MAY generate a 100 (Trying) response.
                */

                SetState(SIP_TransactionState.Proceeding);

                m_pTimer100 = new TimerEx(200, false);
                m_pTimer100.Elapsed += m_pTimer100_Elapsed;
                m_pTimer100.Enabled = true;
            }

                #endregion

                #region Non-INVITE

            else
            {
                // RFC 3261 17.2.2. The state machine is initialized in the "Trying" state.
                SetState(SIP_TransactionState.Trying);
            }

            #endregion
        }

        /// <summary>
        /// Raises <b>ResponseSent</b> event.
        /// </summary>
        /// <param name="response">SIP response.</param>
        private void OnResponseSent(SIP_Response response)
        {
            if (ResponseSent != null)
            {
                ResponseSent(this, new SIP_ResponseSentEventArgs(this, response));
            }
        }

        /// <summary>
        /// Raises <b>Canceled</b> event.
        /// </summary>
        private void OnCanceled()
        {
            if (Canceled != null)
            {
                Canceled(this, new EventArgs());
            }
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/ContactEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Mail.Core.Dao.Expressions.Contact;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Search;
using ASC.Mail.Enums;
using ASC.Mail.Utils;
using ASC.Web.Core;

namespace ASC.Mail.Core.Engine
{
    public class ContactEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ILog Log { get; private set; }

        public ContactEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.ContactEngine");
        }

        public List<ContactCard> GetContactCards(IContactsExp exp)
        {
            if (exp == null)
                throw new ArgumentNullException("exp");

            using (var daoFactory = new DaoFactory())
            {
                var daoContacts = daoFactory.CreateContactCardDao(Tenant, User);

                var list = daoContacts.GetContactCards(exp);

                return list;
            }
        }

        public int GetContactCardsCount(IContactsExp exp)
        {
            if (exp == null)
                throw new ArgumentNullException("exp");

            using (var daoFactory = new DaoFactory())
            {
                var daoContacts = daoFactory.CreateContactCardDao(Tenant, User);

                var count = daoContacts.GetContactCardsCount(exp);

                return count;
            }
        }

        public ContactCard GetContactCard(int id)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoContacts = daoFactory.CreateContactCardDao(Tenant, User);

                var contactCard = daoContacts.GetContactCard(id);

                return contactCard;
            }
        }

        public ContactCard SaveContactCard(ContactCard contactCard)
        {
            using (var daoFactory = new DaoFactory())
            {
                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    var daoContact = daoFactory.CreateContactDao(Tenant, User);
                    var daoContactInfo = daoFactory.CreateContactInfoDao(Tenant, User);

                    var contactId = daoContact.SaveContact(contactCard.ContactInfo);

                    contactCard.ContactInfo.Id = contactId;

                    foreach (var contactItem in contactCard.ContactItems)
                    {
                        contactItem.ContactId = contactId;

                        var contactItemId = daoContactInfo.SaveContactInfo(contactItem);

                        contactItem.Id = contactItemId;
                    }

                    tx.Commit();
                }
            }

            var factory = new EngineFactory(Tenant, User, Log);

            Log.Debug("IndexEngine->SaveContactCard()");

            factory.IndexEngine.Add(contactCard.ToMailContactWrapper());

            return contactCard;
        }

        public ContactCard UpdateContactCard(ContactCard newContactCard)
        {
            var contactId = newContactCard.ContactInfo.Id;

            if (contactId < 0)
                throw new ArgumentException("Invalid contact id");

            var contactCard = GetContactCard(contactId);

            if (null == contactCard)
                throw new ArgumentException("Contact not found");

            var contactChanged = !contactCard.ContactInfo.Equals(newContactCard.ContactInfo);

            var newContactItems = newContactCard.ContactItems.Where(c => !contactCard.ContactItems.Contains(c)).ToList();

            var removedContactItems = contactCard.ContactItems.Where(c => !newContactCard.ContactItems.Contains(c)).ToList();

            if (!contactChanged && !newContactItems.Any() && !removedContactItems.Any())
                return contactCard;

            using (var daoFactory = new DaoFactory())
            {
                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    if (contactChanged)
                    {
                        var daoContact = daoFactory.CreateContactDao(Tenant, User);

                        daoContact.SaveContact(newContactCard.ContactInfo);

                        contactCard.ContactInfo = newContactCard.ContactInfo;
                    }

                    var daoContactInfo = daoFactory.CreateContactInfoDao(Tenant, User);

                    if (newContactItems.Any())
                    {
                        foreach (var contactItem in newContactItems)
                        {
                            contactItem.ContactId = contactId;

                            var contactItemId = daoContactInfo.SaveContactInfo(contactItem);

                            contactItem.Id = contactItemId;

                            contactCard.ContactItems.Add(contactItem);
                        }
                    }

                    if (removedContactItems.Any())
                    {
                        foreach (var contactItem in removedContactItems)
                        {
                            daoContactInfo.RemoveContactInfo(contactItem.Id);

                            contactCard.ContactItems.Remove(contactItem);
                        }
                    }

                    tx.Commit();
                }
            }

            var factory = new EngineFactory(Tenant, User, Log);

            Log.Debug("IndexEngine->UpdateContactCard()");

            factory.IndexEngine.Update(new List<MailContactWrapper> { contactCard.ToMailContactWrapper() });

            return contactCard;
        }

        public void RemoveContacts(List<int> ids)
        {
            if (!ids.Any())
                throw new ArgumentNullException("ids");

            using (var daoFactory = new DaoFactory())
            {
                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var daoContact = daoFactory.CreateContactDao(Tenant, User);

                    daoContact.RemoveContacts(ids);

                    var daoContactInfo = daoFactory.CreateContactInfoDao(Tenant, User);

                    daoContactInfo.RemoveByContactIds(ids);

                    tx.Commit();
                }
            }

            var factory = new EngineFactory(Tenant, User, Log);

            Log.Debug("IndexEngine->RemoveContacts()");

            factory.IndexEngine.RemoveContacts(ids, Tenant, new Guid(User));
        }

        /// <summary>
        /// Search emails in Accounts, Mail, CRM, Peaople Contact System
        /// </summary>
        /// <param name="tenant">Tenant id</param>
        /// <param name="userName">User id</param>
        /// <param name="term">Search word</param>
        /// <param name="maxCountPerSystem">limit result per Contact System</param>
        /// <param name="timeout">Timeout in milliseconds</param>
        /// <param name="httpContextScheme"></param>
        /// <returns></returns>
        public List<string> SearchEmails(int tenant, string userName, string term, int maxCountPerSystem, string httpContextScheme, int timeout = -1)
        {
            var equality = new ContactEqualityComparer();
            var contacts = new List<string>();
            var userGuid = new Guid(userName);

            var watch = new Stopwatch();

            watch.Start();

            var apiHelper = new ApiHelper(httpContextScheme, Log);

            var taskList = new List<Task<List<string>>>()
            {
                Task.Run(() =>
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant);
                    SecurityContext.AuthenticateMe(userGuid);

                    var engine = new EngineFactory(tenant, userName);

                    var exp = new FullFilterContactsExp(tenant, userName, term, infoType: ContactInfoType.Email, orderAsc: true, limit: maxCountPerSystem);

                    var contactCards = engine.ContactEngine.GetContactCards(exp);

                    return (from contactCard in contactCards
                        from contactItem in contactCard.ContactItems
                        select
                            string.IsNullOrEmpty(contactCard.ContactInfo.ContactName)
                                ? contactItem.Data
                                : MailUtil.CreateFullEmail(contactCard.ContactInfo.ContactName, contactItem.Data))
                        .ToList();
                }),

                Task.Run(() =>
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant);
                    SecurityContext.AuthenticateMe(userGuid);

                    var engine = new EngineFactory(tenant, userGuid.ToString());
                    return engine.AccountEngine.SearchAccountEmails(term);
                }),

                Task.Run(() =>
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant);
                    SecurityContext.AuthenticateMe(userGuid);

                    return WebItemSecurity.IsAvailableForMe(WebItemManager.CRMProductID)
                        ? apiHelper.SearchCrmEmails(term, maxCountPerSystem)
                        : new List<string>();
                }),

                Task.Run(() =>
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant);
                    SecurityContext.AuthenticateMe(userGuid);

                    return WebItemSecurity.IsAvailableForMe(WebItemManager.PeopleProductID)
                        ? apiHelper.SearchPeopleEmails(term, 0, maxCountPerSystem)
                        : new List<string>();
                })
            };

            try
            {
                var taskArray = taskList.ToArray<Task>();

                Task.WaitAll(taskArray, timeout);

                watch.Stop();
            }
            catch (AggregateException e)
            {
                watch.Stop();

                var errorText =
                    new StringBuilder("SearchEmails: \nThe following exceptions have been thrown by WaitAll():");

                foreach (var t in e.InnerExceptions)
                {
                    errorText
                        .AppendFormat("\n-------------------------------------------------\n{0}", t);
                }

                Log.Error(errorText.ToString());
            }

            contacts =
                taskList.Aggregate(contacts,
                    (current, task) => !task.IsFaulted
                                       && task.IsCompleted
                                       && !task.IsCanceled
                        ? current.Concat(task.Result).ToList()
                        : current)
                    .Distinct(equality)
                    .ToList();

            Log.DebugFormat("SearchEmails (term = '{0}'): {1} sec / {2} items", term, watch.Elapsed.TotalSeconds, contacts.Count);

            return contacts;
        }

        public class ContactEqualityComparer : IEqualityComparer<string>
        {
            public bool Equals(string contact1, string contact2)
            {
                if (contact1 == null && contact2 == null)
                    return true;

                if (contact1 == null || contact2 == null)
                    return false;

                var contact1Parts = contact1.Split('<');
                var contact2Parts = contact2.Split('<');

                return contact1Parts.Last().Replace(">", "") == contact2Parts.Last().Replace(">", "");
            }

            public int GetHashCode(string str)
            {
                var strParts = str.Split('<');
                return strParts.Last().Replace(">", "").GetHashCode();
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Core/Notify/StudioNotifyHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Users;
using ASC.Notify.Model;
using ASC.Notify.Recipients;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Core.Notify
{
    class StudioNotifyHelper
    {
        public static readonly string Helplink;

        public static readonly StudioNotifySource NotifySource;

        public static readonly ISubscriptionProvider SubscriptionProvider;

        public static readonly IRecipientProvider RecipientsProvider;

        private static readonly int CountMailsToNotActivated;

        private static readonly string NotificationImagePath;

        static StudioNotifyHelper()
        {
            Helplink = CommonLinkUtility.GetHelpLink(false);
            NotifySource = new StudioNotifySource();
            SubscriptionProvider = NotifySource.GetSubscriptionProvider();
            RecipientsProvider = NotifySource.GetRecipientsProvider();

            int.TryParse(ConfigurationManagerExtension.AppSettings["core.notify.countspam"], out CountMailsToNotActivated);
            NotificationImagePath = ConfigurationManagerExtension.AppSettings["web.notification.image.path"];
        }


        public static IEnumerable<UserInfo> GetRecipients(bool toadmins, bool tousers, bool toguests)
        {
            if (toadmins)
            {
                if (tousers)
                {
                    if (toguests)
                        return CoreContext.UserManager.GetUsers();

                    return CoreContext.UserManager.GetUsers(EmployeeStatus.Default, EmployeeType.User);
                }

                if (toguests)
                    return
                        CoreContext.UserManager.GetUsersByGroup(Constants.GroupAdmin.ID)
                                   .Concat(CoreContext.UserManager.GetUsers(EmployeeStatus.Default, EmployeeType.Visitor));

                return CoreContext.UserManager.GetUsersByGroup(Constants.GroupAdmin.ID);
            }

            if (tousers)
            {
                if (toguests)
                    return CoreContext.UserManager.GetUsers()
                                      .Where(u => !CoreContext.UserManager.IsUserInGroup(u.ID, Constants.GroupAdmin.ID));

                return CoreContext.UserManager.GetUsers(EmployeeStatus.Default, EmployeeType.User)
                                  .Where(u => !CoreContext.UserManager.IsUserInGroup(u.ID, Constants.GroupAdmin.ID));
            }

            if (toguests)
                return CoreContext.UserManager.GetUsers(EmployeeStatus.Default, EmployeeType.Visitor);

            return new List<UserInfo>();
        }

        public static IRecipient ToRecipient(Guid userId)
        {
            return RecipientsProvider.GetRecipient(userId.ToString());
        }

        public static IRecipient[] RecipientFromEmail(string email, bool checkActivation)
        {
            return RecipientFromEmail(new List<string> { email }, checkActivation);
        }

        public static IRecipient[] RecipientFromEmail(List<string> emails, bool checkActivation)
        {
            var res = new List<IRecipient>();

            if (emails == null) return res.ToArray();

            res.AddRange(emails.
                             Select(email => email.ToLower()).
                             Select(e => new DirectRecipient(e, null, new[] { e }, checkActivation)));

            if (!checkActivation
                && CountMailsToNotActivated > 0
                && TenantExtra.Saas && !CoreContext.Configuration.Personal)
            {
                var tenant = CoreContext.TenantManager.GetCurrentTenant();
                var tariff = CoreContext.TenantManager.GetTenantQuota(tenant.TenantId);
                if (tariff.Free || tariff.Trial)
                {
                    var sended = SpamEmailSettings.MailsSended;

                    var mayTake = Math.Max(0, CountMailsToNotActivated - sended);
                    var tryCount = res.Count();
                    if (mayTake < tryCount)
                    {
                        res = res.Take(mayTake).ToList();

                        LogManager.GetLogger("ASC.Notify")
                                  .Warn(string.Format("Free tenant {0} for today is trying to send {1} more letters without checking activation. Sent {2}",
                                                      tenant.TenantId, tryCount, mayTake));
                    }
                    SpamEmailSettings.MailsSended = sended + tryCount;
                }
            }

            return res.ToArray();
        }


        public static string GetNotificationImageUrl(string imageFileName)
        {
            if (string.IsNullOrEmpty(NotificationImagePath))
            {
                return
                    CommonLinkUtility.GetFullAbsolutePath(
                        WebImageSupplier.GetAbsoluteWebPath("notification/" + imageFileName));
            }

            return NotificationImagePath.TrimEnd('/') + "/" + imageFileName;
        }


        public static bool IsSubscribedToNotify(Guid userId, INotifyAction notifyAction)
        {
            return IsSubscribedToNotify(ToRecipient(userId), notifyAction);
        }

        public static bool IsSubscribedToNotify(IRecipient recipient, INotifyAction notifyAction)
        {
            return recipient != null && SubscriptionProvider.IsSubscribed(notifyAction, recipient, null);
        }

        public static void SubscribeToNotify(Guid userId, INotifyAction notifyAction, bool subscribe)
        {
            SubscribeToNotify(ToRecipient(userId), notifyAction, subscribe);
        }

        public static void SubscribeToNotify(IRecipient recipient, INotifyAction notifyAction, bool subscribe)
        {
            if (recipient == null) return;

            if (subscribe)
            {
                SubscriptionProvider.Subscribe(notifyAction, null, recipient);
            }
            else
            {
                SubscriptionProvider.UnSubscribe(notifyAction, null, recipient);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Classes/SocialMedia/SocialMediaUI.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.Thrdparty;
using ASC.Thrdparty.Twitter;
using ASC.Web.CRM.Classes.SocialMedia;
using ASC.Web.CRM.Resources;


namespace ASC.Web.CRM.SocialMedia
{
    public class SocialMediaUI
    {
        private readonly ILog _logger = LogManager.GetLogger("ASC");
        private DaoFactory DaoFactory { get; set; }

        public SocialMediaUI(DaoFactory factory)
        {
            DaoFactory = factory;
        }

        public List<SocialMediaImageDescription> GetContactSMImages(int contactID)
        {
            var contact = DaoFactory.ContactDao.GetByID(contactID);

            var images = new List<SocialMediaImageDescription>();


            var socialNetworks = DaoFactory.ContactInfoDao.GetList(contact.ID, null, null, null);

            var twitterAccounts = socialNetworks.Where(sn => sn.InfoType == ContactInfoType.Twitter).Select(sn => sn.Data.Trim()).ToList();

            Func<List<String>, Tenant, List<SocialMediaImageDescription>> dlgGetTwitterImageDescriptionList = GetTwitterImageDescriptionList;

            // Parallelizing

            var waitHandles = new List<WaitHandle>();

            var currentTenant = CoreContext.TenantManager.GetCurrentTenant();

            var arGetAvatarsFromTwitter = dlgGetTwitterImageDescriptionList.BeginInvoke(twitterAccounts, currentTenant, null, null);
            waitHandles.Add(arGetAvatarsFromTwitter.AsyncWaitHandle);

            WaitHandle.WaitAll(waitHandles.ToArray());

            images.AddRange(dlgGetTwitterImageDescriptionList.EndInvoke(arGetAvatarsFromTwitter));

            return images;
        }

        public List<SocialMediaImageDescription> GetContactSMImages(List<String> twitter)
        {
            var images = new List<SocialMediaImageDescription>();

            Func<List<String>, Tenant, List<SocialMediaImageDescription>> dlgGetTwitterImageDescriptionList = GetTwitterImageDescriptionList;

            // Parallelizing

            var waitHandles = new List<WaitHandle>();

            var currentTenant = CoreContext.TenantManager.GetCurrentTenant();

            var arGetAvatarsFromTwitter = dlgGetTwitterImageDescriptionList.BeginInvoke(twitter, currentTenant, null, null);
            waitHandles.Add(arGetAvatarsFromTwitter.AsyncWaitHandle);

            WaitHandle.WaitAll(waitHandles.ToArray());

            images.AddRange(dlgGetTwitterImageDescriptionList.EndInvoke(arGetAvatarsFromTwitter));

            return images;
        }

        private List<SocialMediaImageDescription> GetTwitterImageDescriptionList(List<String> twitterAccounts, Tenant tenant)
        {
            var images = new List<SocialMediaImageDescription>();

            if (twitterAccounts.Count == 0)
                return images;

            try
            {
                CoreContext.TenantManager.SetCurrentTenant(tenant);

                var provider = new TwitterDataProvider(TwitterApiHelper.GetTwitterApiInfoForCurrentUser());

                twitterAccounts = twitterAccounts.Distinct().ToList();
                images.AddRange(from twitterAccount in twitterAccounts
                                let imageUrl = provider.GetUrlOfUserImage(twitterAccount, TwitterDataProvider.ImageSize.Small)
                                where imageUrl != null
                                select new SocialMediaImageDescription
                                {
                                    Identity = twitterAccount,
                                    ImageUrl = imageUrl,
                                    SocialNetwork = SocialNetworks.Twitter
                                });
            }
            catch (Exception ex)
            {
                _logger.Error(ex);
            }

            return images;
        }

        public Exception ProcessError(Exception exception, string methodName)
        {
            if (exception is ConnectionFailureException)
                return new Exception(CRMSocialMediaResource.ErrorTwitterConnectionFailure);

            if (exception is RateLimitException)
                return new Exception(CRMSocialMediaResource.ErrorTwitterRateLimit);

            if (exception is ResourceNotFoundException)
                return new Exception(CRMSocialMediaResource.ErrorTwitterAccountNotFound);

            if (exception is UnauthorizedException)
                return new Exception(CRMSocialMediaResource.ErrorTwitterUnauthorized);

            if (exception is SocialMediaException)
                return new Exception(CRMSocialMediaResource.ErrorInternalServer);

            if (exception is SocialMediaAccountNotFound)
                return exception;

            var unknownErrorText = String.Format("{0} error: Unknown exception:", methodName);
            _logger.Error(unknownErrorText, exception);
            return new Exception(CRMSocialMediaResource.ErrorInternalServer);
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailSignatureData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

namespace ASC.Mail.Data.Contracts
{
    [DataContract(Namespace = "")]
    public class MailSignatureData
    {
        public MailSignatureData(int mailboxId, int tenant, string html, bool isActive)
        {
            Tenant = tenant;
            MailboxId = mailboxId;
            Html = html;
            IsActive = isActive;
        }

        public int Tenant { get; private set; }

        [DataMember(Name = "mailboxId")]
        public int MailboxId { get; private set; }

        [DataMember(Name = "html")]
        public string Html { get; private set; }

        [DataMember(Name = "isActive")]
        public bool IsActive { get; private set; }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/ServerDomainEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Security;

using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.Engine.Operations;
using ASC.Mail.Core.Engine.Operations.Base;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Extensions;
using ASC.Mail.Utils;
using ASC.Web.Core;

using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Mail.Core.Engine
{
    public class ServerDomainEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ILog Log { get; private set; }

        public ServerDomainEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.ServerDomainEngine");
        }

        public ServerDomainData GetDomain(int id)
        {
            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                var serverDomain = serverDomainDao.GetDomain(id);

                if (serverDomain == null)
                    throw new Exception("Domain not found");

                var serverDnsDao = daoFactory.CreateServerDnsDao(Tenant, User);

                var dnsData = UpdateDnsStatus(serverDomain, serverDnsDao, serverDomainDao);

                return ToServerDomainData(serverDomain, dnsData);
            }
        }

        public List<ServerDomainData> GetDomains()
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            using (var daoFactory = new DaoFactory())
            {
                return GetDomains(daoFactory);
            }
        }

        public List<ServerDomain> GetAllDomains()
        {
            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                var domains = serverDomainDao.GetAllDomains();

                return domains;
            }
        }

        public List<ServerDomainData> GetDomains(IDaoFactory daoFactory)
        {
            var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

            var listDomains = serverDomainDao.GetDomains();

            if (!listDomains.Any())
                return new List<ServerDomainData>();

            var serverDnsDao = daoFactory.CreateServerDnsDao(Tenant, User);

            var list = new List<ServerDomainData>();

            foreach (var domain in listDomains)
            {
                var dnsData = UpdateDnsStatus(domain, serverDnsDao, serverDomainDao);

                var serverDomain = ToServerDomainData(domain, dnsData);

                list.Add(serverDomain);
            }

            return list;
        }

        public ServerDomainData GetCommonDomain()
        {
            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                var domainCommon = serverDomainDao.GetDomains()
                    .SingleOrDefault(x => x.Tenant == Defines.SHARED_TENANT_ID);

                if (domainCommon == null)
                    return null;

                var serverDomain = ToServerDomainData(domainCommon, null);

                return serverDomain;
            }
        }

        public ServerDomainDnsData GetDnsData(int domainId)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (domainId < 0)
                throw new ArgumentException(@"Invalid domain id.", "domainId");

            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                var domain = serverDomainDao.GetDomain(domainId);

                if (domain == null)
                    return null;

                var serverDnsDao = daoFactory.CreateServerDnsDao(Tenant, User);

                var dnsData = UpdateDnsStatus(domain, serverDnsDao, serverDomainDao, true);

                return dnsData;
            }
        }

        public bool IsDomainExists(string name)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (string.IsNullOrEmpty(name))
                throw new ArgumentException(@"Invalid domain name.", "name");

            if (name.Length > 255)
                throw new ArgumentException(@"Domain name exceed limitation of 255 characters.", "name");

            if (!Parser.IsDomainValid(name))
                throw new ArgumentException(@"Incorrect domain name.", "name");

            var domainName = name.ToLowerInvariant();

            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);
                return serverDomainDao.IsDomainExists(domainName);
            }
        }

        public ServerDomainData AddDomain(string domain, int dnsId)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (string.IsNullOrEmpty(domain))
                throw new ArgumentException(@"Invalid domain name.", "domain");

            if (domain.Length > 255)
                throw new ArgumentException(@"Domain name exceed limitation of 255 characters.", "domain");

            if (!Parser.IsDomainValid(domain))
                throw new ArgumentException(@"Incorrect domain name.", "domain");

            var domainName = domain.ToLowerInvariant();

            var engine = new EngineFactory(Tenant, User);

            var dnsLookup = new DnsLookup();

            using (var daoFactory = new DaoFactory())
            {
                var serverDao = daoFactory.CreateServerDao();

                var server = serverDao.Get(Tenant);

                var freeDns = engine.ServerEngine.GetOrCreateUnusedDnsData(daoFactory, server);

                if (freeDns.Id != dnsId)
                    throw new InvalidDataException("This dkim public key is already in use. Please reopen wizard again.");

                if (!CoreContext.Configuration.Standalone &&
                    !dnsLookup.IsDomainTxtRecordExists(domainName, freeDns.DomainCheckRecord.Value))
                {
                    throw new InvalidOperationException("txt record is not correct.");
                }

                var isVerified = freeDns.CheckDnsStatus(domainName);

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                    var utcNow = DateTime.UtcNow;

                    var mailServerEngine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);

                    var mailServerDomain = new Server.Core.Entities.Domain
                    {
                        Name = domainName,
                        Active = true,
                        Description = string.Format("Domain created in UtcTime: {0}, for tenant: {1}", utcNow, Tenant),
                        Created = utcNow,
                        Modified = utcNow
                    };

                    mailServerEngine.SaveDomain(mailServerDomain);

                    var serverDomain = new ServerDomain
                    {
                        Id = 0,
                        Tenant = Tenant,
                        Name = domainName,
                        IsVerified = isVerified,
                        DateAdded = utcNow,
                        DateChecked = utcNow
                    };

                    serverDomain.Id = serverDomainDao.Save(serverDomain);

                    var serverDnsDao = daoFactory.CreateServerDnsDao(Tenant, User);
                    var serverDns = serverDnsDao.GetById(freeDns.Id);

                    var mailServerDkim = new Server.Core.Entities.Dkim
                    {
                        DomainName = domainName,
                        Selector = serverDns.DkimSelector,
                        PrivateKey = serverDns.DkimPrivateKey,
                        PublicKey = serverDns.DkimPublicKey
                    };

                    mailServerEngine.SaveDkim(mailServerDkim);

                    serverDns.DomainId = serverDomain.Id;
                    serverDns.TimeModified = utcNow;
                    serverDnsDao.Save(serverDns);

                    tx.Commit();

                    return ToServerDomainData(serverDomain, freeDns);
                }
            }
        }

        public MailOperationStatus RemoveDomain(int id)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (id < 0)
                throw new ArgumentException(@"Invalid domain id.", "id");

            var domain = GetDomain(id);

            if (domain.IsSharedDomain)
                throw new SecurityException("Can not remove shared domain.");

            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var user = SecurityContext.CurrentAccount;

            var operationEngine = new OperationEngine();

            var operations = operationEngine.MailOperations.GetTasks()
                .Where(o =>
                {
                    var oTenant = o.GetProperty<int>(MailOperation.TENANT);
                    var oUser = o.GetProperty<string>(MailOperation.OWNER);
                    var oType = o.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
                    return oTenant == tenant.TenantId &&
                           oUser == user.ID.ToString() &&
                           oType == MailOperationType.RemoveDomain;
                })
                .ToList();

            var sameOperation = operations.FirstOrDefault(o =>
            {
                var oSource = o.GetProperty<string>(MailOperation.SOURCE);
                return oSource == domain.Id.ToString();
            });

            if (sameOperation != null)
            {
                return operationEngine.GetMailOperationStatus(sameOperation.Id);
            }

            var runningOperation = operations.FirstOrDefault(o => o.Status <= DistributedTaskStatus.Running);

            if (runningOperation != null)
                throw new MailOperationAlreadyRunningException("Remove mailbox operation already running.");

            var op = new MailRemoveMailserverDomainOperation(tenant, user, domain);

            return operationEngine.QueueTask(op);
        }

        private ServerDomainDnsData UpdateDnsStatus(ServerDomain domain,
            IServerDnsDao serverDnsDao, IServerDomainDao serverDomainDao, bool force = false)
        {
            var serverDns = serverDnsDao.Get(domain.Id);

            if (serverDns.UpdateRecords(domain.Name, force))
            {
                serverDnsDao.Save(serverDns);
            }

            var dnsData = ToServerDomainDnsData(serverDns);

            if (dnsData != null && domain.IsVerified != dnsData.IsVerified)
            {
                serverDomainDao.SetVerified(domain.Id, dnsData.IsVerified);
            }

            return dnsData;
        }

        protected ServerDomainData ToServerDomainData(ServerDomain domain, ServerDomainDnsData dns)
        {
            var serverDomain = new ServerDomainData
            {
                Id = domain.Id,
                Name = domain.Name,
                Dns = dns,
                IsSharedDomain = domain.Tenant == Defines.SHARED_TENANT_ID
            };

            return serverDomain;
        }

        protected ServerDomainDnsData ToServerDomainDnsData(ServerDns serverDns)
        {
            if (serverDns == null)
                return null;

            var dnsData = new ServerDomainDnsData
            {
                Id = serverDns.Id,
                MxRecord = new ServerDomainMxRecordData
                {
                    Host = serverDns.Mx,
                    IsVerified = serverDns.MxVerified,
                    Priority = Defines.ServerDnsMxRecordPriority
                },
                SpfRecord = new ServerDomainDnsRecordData
                {
                    Name = Defines.DNS_DEFAULT_ORIGIN,
                    IsVerified = serverDns.SpfVerified,
                    Value = serverDns.Spf
                },
                DkimRecord = new ServerDomainDkimRecordData
                {
                    Selector = serverDns.DkimSelector,
                    IsVerified = serverDns.DkimVerified,
                    PublicKey = serverDns.DkimPublicKey
                },
                DomainCheckRecord = new ServerDomainDnsRecordData
                {
                    Name = Defines.DNS_DEFAULT_ORIGIN,
                    IsVerified = true,
                    Value = serverDns.DomainCheck
                }
            };

            return dnsData;
        }

        private static bool IsAdmin
        {
            get
            {
                return WebItemSecurity.IsProductAdministrator(WebItemManager.MailProductID, SecurityContext.CurrentAccount.ID);
            }
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/Impl/Constraints/ApiHttpMethodConstraint.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;

using ASC.Api.Impl.Routing;

namespace ASC.Api.Impl.Constraints
{
    public class ApiHttpMethodConstraint : HttpMethodConstraint
    {
        private static readonly Dictionary<string, ApiHttpMethodConstraint> Methods = new Dictionary<string, ApiHttpMethodConstraint>(5);

        public static ApiHttpMethodConstraint GetInstance(string method)
        {
            method = method.ToUpperInvariant();
            if (Methods.ContainsKey(method)) return Methods[method];

            var result = new ApiHttpMethodConstraint(method);
            Methods.Add(method, result);
            return result;
        }

        public ApiHttpMethodConstraint(params string[] allowedMethods) : base(allowedMethods)
        {

        }

        protected override bool Match(System.Web.HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            var baseMatch = base.Match(httpContext, route, parameterName, values, routeDirection);
            if (!baseMatch && routeDirection == RouteDirection.IncomingRequest)
            {
                baseMatch = AllowedMethods.Any(method => string.Equals(method, httpContext.Request.RequestType, StringComparison.OrdinalIgnoreCase));
            }
            return baseMatch;
        }
    }

    public class ApiExtensionConstraint : IRouteConstraint
    {
        private readonly List<string> extensions;

        public ApiExtensionConstraint(List<string> extensions)
        {
            this.extensions = extensions;
        }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
            RouteDirection routeDirection)
        {
            if (!route.Url.EndsWith(ApiRouteRegistrator.ExtensionBrace)) return true;
            if (!values.Any()) return false;
            var extension = (string)values.First(r => r.Key == ApiRouteRegistrator.Extension).Value;
            extension = extension.TrimStart('.');

            if (extensions.Contains("." + extension)) return true;

            return false;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/ReportDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;

using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.CRM.Core.Entities;
using ASC.VoipService;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Resources;
using ASC.Web.Files.Api;


#endregion

namespace ASC.CRM.Core.Dao
{
    public class ReportDao : AbstractDao
    {
        const string TimeFormat = "[h]:mm:ss;@";
        const string ShortDateFormat = "M/d/yyyy";

        private DaoFactory DaoFactory { get; set; }

        #region Constructor

        public ReportDao(int tenantID, DaoFactory daoFactory)
            : base(tenantID)
        {
            this.DaoFactory = daoFactory;
        }

        #endregion


        #region Common Methods

        private static void GetTimePeriod(ReportTimePeriod timePeriod, out DateTime fromDate, out DateTime toDate)
        {
            var now = TenantUtil.DateTimeNow().Date;

            var diff = (int)now.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek;
            if (diff < 0)
            {
                diff += 7;
            }

            var quarter = (now.Month + 2) / 3;

            var year = now.Year;

            switch (timePeriod)
            {
                case ReportTimePeriod.Today:
                    fromDate = now;
                    toDate = now.AddDays(1).AddSeconds(-1);
                    break;
                case ReportTimePeriod.Yesterday:
                    fromDate = now.AddDays(-1);
                    toDate = now.AddSeconds(-1);
                    break;
                case ReportTimePeriod.Tomorrow:
                    fromDate = now.AddDays(1);
                    toDate = now.AddDays(2).AddSeconds(-1);
                    break;
                case ReportTimePeriod.CurrentWeek:
                    fromDate = now.AddDays(-1 * diff);
                    toDate = now.AddDays(-1 * diff + 7).AddSeconds(-1);
                    break;
                case ReportTimePeriod.PreviousWeek:
                    fromDate = now.AddDays(-1 * diff - 7);
                    toDate = now.AddDays(-1 * diff).AddSeconds(-1);
                    break;
                case ReportTimePeriod.NextWeek:
                    fromDate = now.AddDays(-1 * diff + 7);
                    toDate = now.AddDays(-1 * diff + 14).AddSeconds(-1);
                    break;
                case ReportTimePeriod.CurrentMonth:
                    fromDate = new DateTime(now.Year, now.Month, 1);
                    toDate = new DateTime(now.Year, now.Month, 1).AddMonths(1).AddSeconds(-1);
                    break;
                case ReportTimePeriod.PreviousMonth:
                    toDate = new DateTime(now.Year, now.Month, 1).AddSeconds(-1);
                    fromDate = new DateTime(toDate.Year, toDate.Month, 1);
                    break;
                case ReportTimePeriod.NextMonth:
                    fromDate = new DateTime(now.Year, now.Month, 1).AddMonths(1);
                    toDate = new DateTime(now.Year, now.Month, 1).AddMonths(2).AddSeconds(-1);
                    break;
                case ReportTimePeriod.CurrentQuarter:
                    fromDate = new DateTime(now.Year, quarter * 3 - 2, 1);
                    toDate = new DateTime(now.Year, fromDate.Month, 1).AddMonths(3).AddSeconds(-1);
                    break;
                case ReportTimePeriod.PreviousQuarter:
                    quarter--;
                    if (quarter == 0)
                    {
                        year--;
                        quarter = 4;
                    }
                    fromDate = new DateTime(year, quarter * 3 - 2, 1);
                    toDate = new DateTime(year, fromDate.Month, 1).AddMonths(3).AddSeconds(-1);
                    break;
                case ReportTimePeriod.NextQuarter:
                    quarter++;
                    if (quarter == 5)
                    {
                        year++;
                        quarter = 1;
                    }
                    fromDate = new DateTime(year, quarter * 3 - 2, 1);
                    toDate = new DateTime(year, fromDate.Month, 1).AddMonths(3).AddSeconds(-1);
                    break;
                case ReportTimePeriod.CurrentYear:
                    fromDate = new DateTime(now.Year, 1, 1);
                    toDate = new DateTime(now.Year, 1, 1).AddYears(1).AddSeconds(-1);
                    break;
                case ReportTimePeriod.PreviousYear:
                    toDate = new DateTime(now.Year, 1, 1).AddSeconds(-1);
                    fromDate = new DateTime(toDate.Year, 1, 1);
                    break;
                case ReportTimePeriod.NextYear:
                    fromDate = new DateTime(now.Year, 1, 1).AddYears(1);
                    toDate = new DateTime(now.Year, 1, 1).AddYears(2).AddSeconds(-1);
                    break;
                case ReportTimePeriod.DuringAllTime:
                    fromDate = DateTime.MinValue;
                    toDate = DateTime.MaxValue;
                    break;
                default:
                    fromDate = DateTime.MinValue;
                    toDate = DateTime.MinValue;
                    break;
            }
        }

        private static string GetTimePeriodText(ReportTimePeriod timePeriod)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            switch (timePeriod)
            {
                case ReportTimePeriod.Today:
                case ReportTimePeriod.Yesterday:
                case ReportTimePeriod.Tomorrow:
                    return fromDate.ToShortDateString();
                case ReportTimePeriod.CurrentWeek:
                case ReportTimePeriod.PreviousWeek:
                case ReportTimePeriod.NextWeek:
                    return string.Format("{0}-{1}", fromDate.ToShortDateString(), toDate.ToShortDateString());
                case ReportTimePeriod.CurrentMonth:
                case ReportTimePeriod.PreviousMonth:
                case ReportTimePeriod.NextMonth:
                    return fromDate.ToString("Y");
                case ReportTimePeriod.CurrentQuarter:
                case ReportTimePeriod.PreviousQuarter:
                case ReportTimePeriod.NextQuarter:
                    return string.Format("{0}-{1}", fromDate.ToString("Y"), toDate.ToString("Y"));
                case ReportTimePeriod.CurrentYear:
                case ReportTimePeriod.PreviousYear:
                case ReportTimePeriod.NextYear:
                    return fromDate.Year.ToString(CultureInfo.InvariantCulture);
                case ReportTimePeriod.DuringAllTime:
                    return CRMReportResource.DuringAllTime;
                default:
                    return string.Empty;
            }
        }

        public List<string> GetMissingRates(string defaultCurrency)
        {
            var existingRatesQuery = Query("crm_currency_rate r")
                .Select("distinct r.from_currency")
                .Where("r.to_currency", defaultCurrency);

            var missingRatesQuery = Query("crm_deal d")
                .Select("distinct d.bid_currency")
                .Where(!Exp.Eq("d.bid_currency", defaultCurrency))
                .Where(!Exp.In("d.bid_currency", existingRatesQuery));


            return Db.ExecuteList(missingRatesQuery).ConvertAll(row => row[0].ToString());
        }

        #endregion


        #region Report Files

        public List<Files.Core.File> SaveSampleReportFiles()
        {
            var result = new List<Files.Core.File>();

            var storeTemplate = Global.GetStoreTemplate();

            if (storeTemplate == null) return result;

            var culture = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).GetCulture() ??
                          CoreContext.TenantManager.GetCurrentTenant().GetCulture();

            var path = culture + "/";

            if (!storeTemplate.IsDirectory(path))
            {
                path = "default/";
                if (!storeTemplate.IsDirectory(path)) return result;
            }

            foreach (var filePath in storeTemplate.ListFilesRelative("", path, "*", false).Select(x => path + x))
            {
                using (var stream = storeTemplate.GetReadStream("", filePath))
                {
                    var document = new Files.Core.File
                    {
                        Title = Path.GetFileName(filePath),
                        FolderID = DaoFactory.FileDao.GetRoot(),
                        ContentLength = stream.Length,
                        ThumbnailStatus = Files.Core.Thumbnail.NotRequired,
                    };

                    var file = DaoFactory.FileDao.SaveFile(document, stream);

                    SaveFile((int)file.ID, -1);

                    result.Add(file);
                }
            }

            return result;
        }

        public List<Files.Core.File> GetFiles()
        {
            return GetFiles(SecurityContext.CurrentAccount.ID);
        }

        public List<Files.Core.File> GetFiles(Guid userId)
        {
            var query = Query("crm_report_file")
                .Select("file_id")
                .Where("create_by", userId);

            using (var filedao = FilesIntegration.GetFileDao())
            {
                var fileIds = Db.ExecuteList(query).ConvertAll(row => row[0]).ToArray();
                return fileIds.Length > 0 ? filedao.GetFiles(fileIds) : new List<Files.Core.File>();
            }
        }

        public List<int> GetFileIds(Guid userId)
        {
            var query = Query("crm_report_file")
                .Select("file_id")
                .Where("create_by", userId);

            return Db.ExecuteList(query).ConvertAll(row => Convert.ToInt32(row[0]));
        }

        public Files.Core.File GetFile(int fileid)
        {
            return GetFile(fileid, SecurityContext.CurrentAccount.ID);
        }

        public Files.Core.File GetFile(int fileid, Guid userId)
        {
            var query = Query("crm_report_file")
                .SelectCount()
                .Where("file_id", fileid)
                .Where("create_by", userId);

            using (var filedao = FilesIntegration.GetFileDao())
            {
                return Db.ExecuteScalar<int>(query) > 0 ? filedao.GetFile(fileid) : null;
            }
        }

        public void DeleteFile(int fileid)
        {
            var query = Delete("crm_report_file")
                .Where("file_id", fileid)
                .Where("create_by", SecurityContext.CurrentAccount.ID);

            using (var filedao = FilesIntegration.GetFileDao())
            {
                Db.ExecuteNonQuery(query);
                filedao.DeleteFile(fileid);
            }
        }

        public void DeleteFiles(Guid userId)
        {
            var fileIds = GetFileIds(userId);

            var query = Delete("crm_report_file")
                .Where("create_by", userId);

            using (var filedao = FilesIntegration.GetFileDao())
            {
                Db.ExecuteNonQuery(query);

                foreach (var fileId in fileIds)
                {
                    filedao.DeleteFile(fileId);
                }
            }
        }

        public void SaveFile(int fileId, int reportType)
        {
            Db.ExecuteScalar<int>(
                Insert("crm_report_file")
                .InColumnValue("file_id", fileId)
                .InColumnValue("report_type", reportType)
                .InColumnValue("create_on", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()))
                .InColumnValue("create_by", SecurityContext.CurrentAccount.ID)
                .Identity(1, 0, true));
        }

        #endregion


        #region SalesByManagersReport

        public bool CheckSalesByManagersReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_deal d")
                .Select("d.id")
                .LeftOuterJoin("crm_deal_milestone m", Exp.EqColumns("m.id", "d.deal_milestone_id") & Exp.EqColumns("m.tenant_id", "d.tenant_id"))
                .Where("m.status", (int)DealMilestoneStatus.ClosedAndWon)
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.actual_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            return Db.ExecuteList(sqlQuery).Any();
        }

        public object GetSalesByManagersReportData(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            var reportData = BuildSalesByManagersReport(timePeriod, managers, defaultCurrency);

            return reportData == null || !reportData.Any() ? null : GenerateReportData(timePeriod, reportData);
        }

        private List<SalesByManager> BuildSalesByManagersReport(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            string dateSelector;

            switch (timePeriod)
            {
                case ReportTimePeriod.Today:
                case ReportTimePeriod.Yesterday:
                    dateSelector = "date_add(date(d.actual_close_date), interval extract(hour from d.actual_close_date) hour) as close_date";
                    break;
                case ReportTimePeriod.CurrentWeek:
                case ReportTimePeriod.PreviousWeek:
                case ReportTimePeriod.CurrentMonth:
                case ReportTimePeriod.PreviousMonth:
                    dateSelector = "date(d.actual_close_date) as close_date";
                    break;
                case ReportTimePeriod.CurrentQuarter:
                case ReportTimePeriod.PreviousQuarter:
                case ReportTimePeriod.CurrentYear:
                case ReportTimePeriod.PreviousYear:
                    dateSelector = "date_sub(date(d.actual_close_date), interval (extract(day from d.actual_close_date) - 1) day) as close_date";
                    break;
                default:
                    return null;
            }

            var sqlQuery = Query("crm_deal d")
                .Select("d.responsible_id",
                        "concat(u.firstname, ' ', u.lastname) as full_name",
                        string.Format(@"sum((case d.bid_type
                        when 0 then
                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                        else
                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                        end)) as bid_value", defaultCurrency),
                        dateSelector)
                .LeftOuterJoin("crm_deal_milestone m", Exp.EqColumns("m.id", "d.deal_milestone_id") & Exp.EqColumns("m.tenant_id", "d.tenant_id"))
                .LeftOuterJoin("crm_currency_rate r", Exp.EqColumns("r.tenant_id", "d.tenant_id") & Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "d.tenant_id") & Exp.EqColumns("u.id", "d.responsible_id"))
                .Where("m.status", (int)DealMilestoneStatus.ClosedAndWon)
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.actual_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("responsible_id", "close_date");


            return Db.ExecuteList(sqlQuery).ConvertAll(ToSalesByManagers);
        }

        private static SalesByManager ToSalesByManagers(object[] row)
        {
            return new SalesByManager
            {
                UserId = string.IsNullOrEmpty(Convert.ToString(row[0])) ? Guid.Empty : new Guid(Convert.ToString(row[0])),
                UserName = Convert.ToString(row[1]),
                Value = Convert.ToDecimal(row[2]),
                Date = Convert.ToDateTime(row[3]) == DateTime.MinValue ? DateTime.MinValue : TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[3]))
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, List<SalesByManager> data)
        {
            switch (timePeriod)
            {
                case ReportTimePeriod.Today:
                case ReportTimePeriod.Yesterday:
                    return GenerateReportDataByHours(timePeriod, data);
                case ReportTimePeriod.CurrentWeek:
                case ReportTimePeriod.PreviousWeek:
                case ReportTimePeriod.CurrentMonth:
                case ReportTimePeriod.PreviousMonth:
                    return GenerateReportDataByDays(timePeriod, data);
                case ReportTimePeriod.CurrentQuarter:
                case ReportTimePeriod.PreviousQuarter:
                case ReportTimePeriod.CurrentYear:
                case ReportTimePeriod.PreviousYear:
                    return GenerateReportByMonths(timePeriod, data);
                default:
                    return null;
            }
        }

        private static object GenerateReportDataByHours(ReportTimePeriod timePeriod, List<SalesByManager> data)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var res = new Dictionary<Guid, Dictionary<DateTime, decimal>>();

            var users = data.Select(x => x.UserId).Distinct().ToList();

            foreach (var userId in users)
            {
                var date = fromDate;

                while (date < toDate)
                {
                    if (res.ContainsKey(userId))
                    {
                        res[userId].Add(date, 0);
                    }
                    else
                    {
                        res.Add(userId, new Dictionary<DateTime, decimal> { { date, 0 } });
                    }

                    date = date.AddHours(1);
                }
            }

            foreach (var item in data)
            {
                var itemDate = new DateTime(item.Date.Year, item.Date.Month, item.Date.Day, item.Date.Hour, 0, 0);

                if (itemDate < res[item.UserId].First().Key)
                    itemDate = res[item.UserId].First().Key;

                if (itemDate > res[item.UserId].Last().Key)
                    itemDate = res[item.UserId].Last().Key;

                res[item.UserId][itemDate] += item.Value;
            }

            var body = new List<List<object>>();

            foreach (var resItem in res)
            {
                var bodyItem = new List<object>
                    {
                        data.First(x => x.UserId == resItem.Key).UserName
                    };

                bodyItem.AddRange(resItem.Value.Select(x => new { format = "0.00", value = x.Value.ToString(CultureInfo.InvariantCulture) }));

                body.Add(bodyItem);
            }

            var head = new List<object>();

            foreach (var key in res.First().Value.Keys)
            {
                head.Add(new { format = "H:mm", value = key.ToShortTimeString() });
            }

            return new
            {
                resource = new
                {
                    manager = CRMReportResource.Manager,
                    summary = CRMReportResource.Sum,
                    total = CRMReportResource.Total,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),
                    sheetName = CRMReportResource.SalesByManagersReport,
                    header = CRMReportResource.SalesByManagersReport,
                    header1 = CRMReportResource.SalesByHour + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    header2 = CRMReportResource.TotalSalesByManagers + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName1 = CRMReportResource.SalesByHour + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName2 = CRMReportResource.TotalSalesByManagers + ", " + Global.TenantSettings.DefaultCurrency.Symbol
                },
                thead = head,
                tbody = body
            };
        }

        private static object GenerateReportDataByDays(ReportTimePeriod timePeriod, List<SalesByManager> data)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var res = new Dictionary<Guid, Dictionary<DateTime, decimal>>();

            var users = data.Select(x => x.UserId).Distinct().ToList();

            foreach (var userId in users)
            {
                var date = fromDate;

                while (date < toDate)
                {
                    if (res.ContainsKey(userId))
                    {
                        res[userId].Add(date, 0);
                    }
                    else
                    {
                        res.Add(userId, new Dictionary<DateTime, decimal> { { date, 0 } });
                    }

                    date = date.AddDays(1);
                }
            }

            foreach (var item in data)
            {
                var itemDate = new DateTime(item.Date.Year, item.Date.Month, item.Date.Day);

                if (itemDate < res[item.UserId].First().Key)
                    itemDate = res[item.UserId].First().Key;

                if (itemDate > res[item.UserId].Last().Key)
                    itemDate = res[item.UserId].Last().Key;

                res[item.UserId][itemDate] += item.Value;
            }

            var body = new List<List<object>>();

            foreach (var resItem in res)
            {
                var bodyItem = new List<object>
                    {
                        data.First(x => x.UserId == resItem.Key).UserName
                    };

                bodyItem.AddRange(resItem.Value.Select(x => new { format = "0.00", value = x.Value.ToString(CultureInfo.InvariantCulture) }));

                body.Add(bodyItem);
            }

            var head = new List<object>();
            var separator = CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator.ToCharArray();
            var pattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern.Replace("yyyy", string.Empty).Trim(separator);

            foreach (var key in res.First().Value.Keys)
            {
                head.Add(new { format = pattern, value = key.ToString(ShortDateFormat, CultureInfo.InvariantCulture) });
            }

            return new
            {
                resource = new
                {
                    manager = CRMReportResource.Manager,
                    summary = CRMReportResource.Sum,
                    total = CRMReportResource.Total,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),
                    sheetName = CRMReportResource.SalesByManagersReport,
                    header = CRMReportResource.SalesByManagersReport,
                    header1 = CRMReportResource.SalesByDay + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    header2 = CRMReportResource.TotalSalesByManagers + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName1 = CRMReportResource.SalesByDay + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName2 = CRMReportResource.TotalSalesByManagers + ", " + Global.TenantSettings.DefaultCurrency.Symbol
                },
                thead = head,
                tbody = body
            };
        }

        private static object GenerateReportByMonths(ReportTimePeriod timePeriod, List<SalesByManager> data)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var res = new Dictionary<Guid, Dictionary<DateTime, decimal>>();

            var users = data.Select(x => x.UserId).Distinct().ToList();

            foreach (var userId in users)
            {
                var date = fromDate;

                while (date < toDate)
                {
                    if (res.ContainsKey(userId))
                    {
                        res[userId].Add(date, 0);
                    }
                    else
                    {
                        res.Add(userId, new Dictionary<DateTime, decimal> { { date, 0 } });
                    }

                    date = date.AddMonths(1);
                }
            }

            foreach (var item in data)
            {
                var itemDate = new DateTime(item.Date.Year, item.Date.Month, 1);

                if (itemDate < res[item.UserId].First().Key)
                    itemDate = res[item.UserId].First().Key;

                if (itemDate > res[item.UserId].Last().Key)
                    itemDate = res[item.UserId].Last().Key;

                res[item.UserId][itemDate] += item.Value;
            }

            var body = new List<List<object>>();

            foreach (var resItem in res)
            {
                var bodyItem = new List<object>
                    {
                        data.First(x => x.UserId == resItem.Key).UserName
                    };

                bodyItem.AddRange(resItem.Value.Select(x => new { format = "0.00", value = x.Value.ToString(CultureInfo.InvariantCulture) }));

                body.Add(bodyItem);
            }

            var head = new List<object>();

            foreach (var key in res.First().Value.Keys)
            {
                head.Add(new { format = "MMM-yy", value = key.ToString(ShortDateFormat, CultureInfo.InvariantCulture) });
            }

            return new
            {
                resource = new
                {
                    manager = CRMReportResource.Manager,
                    summary = CRMReportResource.Sum,
                    total = CRMReportResource.Total,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),
                    sheetName = CRMReportResource.SalesByManagersReport,
                    header = CRMReportResource.SalesByManagersReport,
                    header1 = CRMReportResource.SalesByMonth + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    header2 = CRMReportResource.TotalSalesByManagers + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName1 = CRMReportResource.SalesByMonth + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName2 = CRMReportResource.TotalSalesByManagers + ", " + Global.TenantSettings.DefaultCurrency.Symbol
                },
                thead = head,
                tbody = body
            };
        }

        #endregion


        #region SalesForecastReport

        public bool CheckSalesForecastReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_deal d")
                .Select("d.id")
                .LeftOuterJoin("crm_deal_milestone m", Exp.EqColumns("m.tenant_id", "d.tenant_id") & Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where("m.status", (int)DealMilestoneStatus.Open)
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.expected_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            return Db.ExecuteList(sqlQuery).Any();
        }

        public object GetSalesForecastReportData(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            var reportData = BuildSalesForecastReport(timePeriod, managers, defaultCurrency);

            return reportData == null || !reportData.Any() ? null : GenerateReportData(timePeriod, reportData);
        }

        private List<SalesForecast> BuildSalesForecastReport(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            string dateSelector;

            switch (timePeriod)
            {
                case ReportTimePeriod.CurrentWeek:
                case ReportTimePeriod.NextWeek:
                case ReportTimePeriod.CurrentMonth:
                case ReportTimePeriod.NextMonth:
                    dateSelector = "d.expected_close_date as close_date";
                    break;
                case ReportTimePeriod.CurrentQuarter:
                case ReportTimePeriod.NextQuarter:
                case ReportTimePeriod.CurrentYear:
                case ReportTimePeriod.NextYear:
                    dateSelector = "date_sub(date(d.expected_close_date), interval (extract(day from d.expected_close_date) - 1) day) as close_date";
                    break;
                default:
                    return null;
            }

            var sqlQuery = Query("crm_deal d")
                .Select(string.Format(@"sum(case d.bid_type
                        when 0 then
                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                        else
                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                        end) as value", defaultCurrency),
                        string.Format(@"sum(case d.bid_type
                        when 0 then
                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate)) * d.deal_milestone_probability / 100
                        else
                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate)) * d.deal_milestone_probability / 100
                        end) as value_with_probability", defaultCurrency),
                        dateSelector)
                .LeftOuterJoin("crm_deal_milestone m", Exp.EqColumns("m.tenant_id", "d.tenant_id") & Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .LeftOuterJoin("crm_currency_rate r", Exp.EqColumns("r.tenant_id", "d.tenant_id") & Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .Where("m.status", (int)DealMilestoneStatus.Open)
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.expected_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("close_date");

            return Db.ExecuteList(sqlQuery).ConvertAll(ToSalesForecast);
        }

        private static SalesForecast ToSalesForecast(object[] row)
        {
            return new SalesForecast
            {
                Value = Convert.ToDecimal(row[0]),
                ValueWithProbability = Convert.ToDecimal(row[1]),
                Date = Convert.ToDateTime(row[2]) == DateTime.MinValue ? DateTime.MinValue : TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[2]))
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, List<SalesForecast> data)
        {
            switch (timePeriod)
            {
                case ReportTimePeriod.CurrentWeek:
                case ReportTimePeriod.NextWeek:
                case ReportTimePeriod.CurrentMonth:
                case ReportTimePeriod.NextMonth:
                    return GenerateReportDataByDays(timePeriod, data);
                case ReportTimePeriod.CurrentQuarter:
                case ReportTimePeriod.NextQuarter:
                case ReportTimePeriod.CurrentYear:
                case ReportTimePeriod.NextYear:
                    return GenerateReportByMonths(timePeriod, data);
                default:
                    return null;
            }
        }

        private static object GenerateReportDataByDays(ReportTimePeriod timePeriod, List<SalesForecast> data)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var res = new Dictionary<DateTime, Tuple<decimal, decimal>>();

            var date = fromDate;

            while (date < toDate)
            {
                res.Add(date, new Tuple<decimal, decimal>(0, 0));
                date = date.AddDays(1);
            }

            foreach (var item in data)
            {
                var key = new DateTime(item.Date.Year, item.Date.Month, item.Date.Day);

                if (key < res.First().Key)
                    key = res.First().Key;

                if (key > res.Last().Key)
                    key = res.Last().Key;

                res[key] = new Tuple<decimal, decimal>(res[key].Item1 + item.ValueWithProbability,
                                                       res[key].Item2 + item.Value);
            }

            var body = new List<List<object>>();
            var separator = CultureInfo.CurrentCulture.DateTimeFormat.DateSeparator.ToCharArray();
            var pattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern.Replace("yyyy", string.Empty).Trim(separator);

            foreach (var resItem in res)
            {
                var bodyItem = new List<object>
                    {
                        new {format = pattern, value = resItem.Key.ToString(ShortDateFormat, CultureInfo.InvariantCulture)},
                        new {format = "0.00", value = resItem.Value.Item1.ToString(CultureInfo.InvariantCulture)},
                        new {format = "0.00", value = resItem.Value.Item2.ToString(CultureInfo.InvariantCulture)}
                    };

                body.Add(bodyItem);
            }

            var head = new List<object>
                {
                    CRMReportResource.Day,
                    CRMReportResource.WithRespectToProbability,
                    CRMReportResource.IfAllOpportunitiesWon
                };

            return new
            {
                resource = new
                {
                    total = CRMReportResource.Total,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),
                    sheetName = CRMReportResource.SalesForecastReport,
                    header = CRMReportResource.SalesForecastReport,
                    header1 = CRMReportResource.SalesForecastReport + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName = CRMReportResource.SalesForecastReport + ", " + Global.TenantSettings.DefaultCurrency.Symbol
                },
                thead = head,
                tbody = body
            };
        }

        private static object GenerateReportByMonths(ReportTimePeriod timePeriod, List<SalesForecast> data)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var res = new Dictionary<DateTime, Tuple<decimal, decimal>>();

            var date = fromDate;

            while (date < toDate)
            {
                res.Add(date, new Tuple<decimal, decimal>(0, 0));
                date = date.AddMonths(1);
            }

            foreach (var item in data)
            {
                var key = new DateTime(item.Date.Year, item.Date.Month, 1);

                if (key < res.First().Key)
                    key = res.First().Key;

                if (key > res.Last().Key)
                    key = res.Last().Key;

                res[key] = new Tuple<decimal, decimal>(res[key].Item1 + item.ValueWithProbability,
                                                       res[key].Item2 + item.Value);
            }

            var body = new List<List<object>>();

            foreach (var resItem in res)
            {
                var bodyItem = new List<object>
                    {
                        new {format = "MMM-yy", value = resItem.Key.ToString(ShortDateFormat, CultureInfo.InvariantCulture)},
                        new {format = "0.00", value = resItem.Value.Item1.ToString(CultureInfo.InvariantCulture)},
                        new {format = "0.00", value = resItem.Value.Item2.ToString(CultureInfo.InvariantCulture)}
                    };

                body.Add(bodyItem);
            }

            var head = new List<object>
                {
                    CRMReportResource.Month,
                    CRMReportResource.WithRespectToProbability,
                    CRMReportResource.IfAllOpportunitiesWon
                };

            return new
            {
                resource = new
                {
                    total = CRMReportResource.Total,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),
                    sheetName = CRMReportResource.SalesForecastReport,
                    header = CRMReportResource.SalesForecastReport,
                    header1 = CRMReportResource.SalesForecastReport + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName = CRMReportResource.SalesForecastReport + ", " + Global.TenantSettings.DefaultCurrency.Symbol
                },
                thead = head,
                tbody = body
            };
        }

        #endregion


        #region SalesFunnelReport

        public bool CheckSalesFunnelReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_deal d")
                .Select("d.id")
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            return Db.ExecuteList(sqlQuery).Any();
        }

        public object GetSalesFunnelReportData(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            var reportData = BuildSalesFunnelReport(timePeriod, managers, defaultCurrency);

            return reportData == null || !reportData.Any() ? null : GenerateReportData(timePeriod, reportData);
        }

        private List<SalesFunnel> BuildSalesFunnelReport(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_deal_milestone m")
                .Select("m.status", "m.title",
                        "count(d.id) as deals_count",
                        string.Format(@"sum(case d.bid_type
                        when 0 then
                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                        else
                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                        end) as deals_value", defaultCurrency),
                        "avg(if(m.status = 1, datediff(d.actual_close_date, d.create_on), 0)) as deals_duration")
                .LeftOuterJoin("crm_deal d", Exp.EqColumns("d.tenant_id", "m.tenant_id") &
                                             Exp.EqColumns("d.deal_milestone_id", "m.id") &
                                             (managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty) &
                                             Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "m.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .GroupBy("m.id")
                .OrderBy("m.sort_order", true);


            return Db.ExecuteList(sqlQuery).ConvertAll(ToSalesFunnel);
        }

        private static SalesFunnel ToSalesFunnel(object[] row)
        {
            return new SalesFunnel
            {
                Status = (DealMilestoneStatus)Convert.ToInt32(row[0]),
                Title = Convert.ToString(row[1]),
                Count = Convert.ToInt32(row[2]),
                Value = Convert.ToDecimal(row[3]),
                Duration = Convert.ToInt32(row[4])
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, List<SalesFunnel> data)
        {
            var totalCount = data.Sum(x => x.Count);

            if (totalCount == 0) return null;

            var totalBudget = data.Sum(x => x.Value);

            var closed = data.Where(x => x.Status == DealMilestoneStatus.ClosedAndWon).ToList();

            var reportData = data.Select(item => new List<object>
                {
                    item.Title,
                    item.Status,
                    item.Count,
                    item.Value
                }).ToList();

            return new
            {
                resource = new
                {
                    header = CRMReportResource.SalesFunnelReport,
                    sheetName = CRMReportResource.SalesFunnelReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),

                    chartName = CRMReportResource.SalesFunnelByCount,
                    chartName1 = CRMReportResource.SalesFunnelByBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName2 = CRMReportResource.DealsCount,
                    chartName3 = CRMReportResource.DealsBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,

                    totalCountLabel = CRMReportResource.TotalDealsCount,
                    totalCountValue = totalCount,

                    totalBudgetLabel = CRMReportResource.TotalDealsBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    totalBudgetValue = totalBudget,

                    averageBidLabel = CRMReportResource.AverageDealsBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    averageBidValue = totalBudget / totalCount,

                    averageDurationLabel = CRMReportResource.AverageDealsDuration,
                    averageDurationValue = closed.Sum(x => x.Duration) / closed.Count,

                    header1 = CRMReportResource.ByCount,
                    header2 = CRMReportResource.ByBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,

                    stage = CRMReportResource.Stage,
                    count = CRMReportResource.Count,
                    budget = CRMReportResource.Budget,
                    conversion = CRMReportResource.Conversion,

                    deals = CRMDealResource.Deals,
                    status0 = DealMilestoneStatus.Open.ToLocalizedString(),
                    status1 = DealMilestoneStatus.ClosedAndWon.ToLocalizedString(),
                    status2 = DealMilestoneStatus.ClosedAndLost.ToLocalizedString()
                },
                data = reportData
            };
        }

        #endregion


        #region WorkloadByContactsReport

        public bool CheckWorkloadByContactsReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_contact c")
                .Select("c.id")
                .Where(managers != null && managers.Any() ? Exp.In("c.create_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("c.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            return Db.ExecuteList(sqlQuery).Any();

        }

        public object GetWorkloadByContactsReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            var reportData = BuildWorkloadByContactsReport(timePeriod, managers);

            return reportData == null || !reportData.Any() ? null : GenerateReportData(timePeriod, reportData);
        }

        private List<WorkloadByContacts> BuildWorkloadByContactsReport(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_contact c")
                .Select("c.create_by",
                        "concat(u.firstname, ' ', u.lastname) as full_name",
                        "i.id",
                        "i.title",
                        "count(c.id) as total",
                        "count(d.id) as `with deals`")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "c.tenant_id") & Exp.EqColumns("i.id", "c.contact_type_id") & Exp.Eq("i.list_type", (int)ListType.ContactType))
                .LeftOuterJoin("crm_deal d", Exp.EqColumns("d.tenant_id", "c.tenant_id") & Exp.EqColumns("d.contact_id", "c.id"))
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "c.tenant_id") & Exp.EqColumns("u.id", "c.create_by"))
                .Where(managers != null && managers.Any() ? Exp.In("c.create_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("c.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("c.create_by", "i.id")
                .OrderBy("i.sort_order, i.title", true);

            return Db.ExecuteList(sqlQuery).ConvertAll(ToWorkloadByContacts);
        }

        private static WorkloadByContacts ToWorkloadByContacts(object[] row)
        {
            return new WorkloadByContacts
            {
                UserId = string.IsNullOrEmpty(Convert.ToString(row[0])) ? Guid.Empty : new Guid(Convert.ToString(row[0])),
                UserName = Convert.ToString(row[1]),
                CategoryId = Convert.ToInt32(row[2]),
                CategoryName = Convert.ToString(row[3]),
                Count = Convert.ToInt32(row[4]),
                WithDeals = Convert.ToInt32(row[5])
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, List<WorkloadByContacts> reportData)
        {
            return new
            {
                resource = new
                {
                    header = CRMReportResource.WorkloadByContactsReport,
                    sheetName = CRMReportResource.WorkloadByContactsReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),

                    header1 = CRMReportResource.NewContacts,
                    header2 = CRMReportResource.NewContactsWithAndWithoutDeals,

                    manager = CRMReportResource.Manager,
                    total = CRMReportResource.Total,

                    noSet = CRMCommonResource.NoSet,
                    withDeals = CRMReportResource.ContactsWithDeals,
                    withouthDeals = CRMReportResource.ContactsWithoutDeals,
                },
                data = reportData
            };
        }

        #endregion


        #region WorkloadByTasksReport

        public bool CheckWorkloadByTasksReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlNewTasksQuery = Query("crm_task t")
                .Select("t.id")
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var sqlClosedTasksQuery = Query("crm_task t")
                .Select("t.id")
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Eq("t.is_closed", 1))
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.last_modifed_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var sqlOverdueTasksQuery = Query("crm_task t")
                .Select("t.id")
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.deadline", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where(Exp.Or(Exp.Eq("t.is_closed", 0) & Exp.Lt("t.deadline", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())), (Exp.Eq("t.is_closed", 1) & Exp.Sql("t.last_modifed_on > t.deadline"))))
                .SetMaxResults(1);

            bool res;

            using (var tx = Db.BeginTransaction())
            {
                res = Db.ExecuteList(sqlNewTasksQuery).Any() ||
                      Db.ExecuteList(sqlClosedTasksQuery).Any() ||
                      Db.ExecuteList(sqlOverdueTasksQuery).Any();

                tx.Commit();
            }

            return res;
        }

        public object GetWorkloadByTasksReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            var reportData = BuildWorkloadByTasksReport(timePeriod, managers);

            if (reportData == null || !reportData.Any()) return null;

            var hasData = reportData.Any(item => item.Value.Count > 0);

            return hasData ? GenerateReportData(timePeriod, reportData) : null;
        }

        private Dictionary<string, List<WorkloadByTasks>> BuildWorkloadByTasksReport(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlNewTasksQuery = Query("crm_task t")
                .Select("i.id",
                        "i.title",
                        "t.responsible_id",
                        "concat(u.firstname, ' ', u.lastname) as full_name",
                        "count(t.id) as count")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "t.tenant_id") & Exp.EqColumns("i.id", "t.category_id") & Exp.Eq("i.list_type", (int)ListType.TaskCategory))
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "t.tenant_id") & Exp.EqColumns("u.id", "t.responsible_id"))
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("i.id", "t.responsible_id")
                .OrderBy("i.sort_order", true);

            var sqlClosedTasksQuery = Query("crm_task t")
                .Select("i.id",
                        "i.title",
                        "t.responsible_id",
                        "concat(u.firstname, ' ', u.lastname) as full_name",
                        "count(t.id) as count")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "t.tenant_id") & Exp.EqColumns("i.id", "t.category_id") & Exp.Eq("i.list_type", (int)ListType.TaskCategory))
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "t.tenant_id") & Exp.EqColumns("u.id", "t.responsible_id"))
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Eq("t.is_closed", 1))
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.last_modifed_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("i.id", "t.responsible_id")
                .OrderBy("i.sort_order", true);

            var sqlOverdueTasksQuery = Query("crm_task t")
                .Select("i.id",
                        "i.title",
                        "t.responsible_id",
                        "concat(u.firstname, ' ', u.lastname) as full_name",
                        "count(t.id) as count")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "t.tenant_id") & Exp.EqColumns("i.id", "t.category_id") & Exp.Eq("i.list_type", (int)ListType.TaskCategory))
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "t.tenant_id") & Exp.EqColumns("u.id", "t.responsible_id"))
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.deadline", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where(Exp.Or(Exp.Eq("t.is_closed", 0) & Exp.Lt("t.deadline", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())), (Exp.Eq("t.is_closed", 1) & Exp.Sql("t.last_modifed_on > t.deadline"))))
                .GroupBy("i.id", "t.responsible_id")
                .OrderBy("i.sort_order", true);

            Dictionary<string, List<WorkloadByTasks>> res;

            using (var tx = Db.BeginTransaction())
            {
                res = new Dictionary<string, List<WorkloadByTasks>>
                    {
                        {"Created", Db.ExecuteList(sqlNewTasksQuery).ConvertAll(ToWorkloadByTasks)},
                        {"Closed", Db.ExecuteList(sqlClosedTasksQuery).ConvertAll(ToWorkloadByTasks)},
                        {"Overdue", Db.ExecuteList(sqlOverdueTasksQuery).ConvertAll(ToWorkloadByTasks)}
                    };

                tx.Commit();
            }

            return res;
        }

        private static WorkloadByTasks ToWorkloadByTasks(object[] row)
        {
            return new WorkloadByTasks
            {
                CategoryId = Convert.ToInt32(row[0]),
                CategoryName = Convert.ToString(row[1]),
                UserId = string.IsNullOrEmpty(Convert.ToString(row[2])) ? Guid.Empty : new Guid(Convert.ToString(row[2])),
                UserName = Convert.ToString(row[3]),
                Count = Convert.ToInt32(row[4])
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, Dictionary<string, List<WorkloadByTasks>> reportData)
        {
            return new
            {
                resource = new
                {
                    header = CRMReportResource.WorkloadByTasksReport,
                    sheetName = CRMReportResource.WorkloadByTasksReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),

                    header1 = CRMReportResource.ClosedTasks,
                    header2 = CRMReportResource.NewTasks,
                    header3 = CRMReportResource.OverdueTasks,

                    manager = CRMReportResource.Manager,
                    total = CRMReportResource.Total
                },
                data = reportData
            };
        }

        #endregion


        #region WorkloadByDealsReport

        public bool CheckWorkloadByDealsReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_deal d")
                .Select("d.id")
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ?
                        Exp.Empty :
                        Exp.Or(Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)),
                                Exp.Between("d.actual_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))))
                .SetMaxResults(1);

            return Db.ExecuteList(sqlQuery).Any();
        }

        public object GetWorkloadByDealsReportData(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            var reportData = BuildWorkloadByDealsReport(timePeriod, managers, defaultCurrency);

            return reportData == null || !reportData.Any() ? null : GenerateReportData(timePeriod, reportData);
        }

        private List<WorkloadByDeals> BuildWorkloadByDealsReport(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_deal d")
                .Select("d.responsible_id",
                        "concat(u.firstname, ' ', u.lastname) as full_name",
                        "m.status",
                        "count(d.id) as deals_count",
                        string.Format(@"sum(case d.bid_type
                        when 0 then
                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                        else
                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_deal_milestone m", Exp.EqColumns("m.tenant_id", "d.tenant_id") & Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "d.tenant_id") & Exp.EqColumns("u.id", "d.responsible_id"))
                .LeftOuterJoin("crm_currency_rate r", Exp.EqColumns("r.tenant_id", "d.tenant_id") & Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ?
                        Exp.Empty :
                        Exp.Or(Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)),
                                Exp.Between("d.actual_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))))
                .GroupBy("d.responsible_id", "m.status");


            return Db.ExecuteList(sqlQuery).ConvertAll(ToWorkloadByDeals);
        }

        private static WorkloadByDeals ToWorkloadByDeals(object[] row)
        {
            return new WorkloadByDeals
            {
                UserId = string.IsNullOrEmpty(Convert.ToString(row[0])) ? Guid.Empty : new Guid(Convert.ToString(row[0])),
                UserName = Convert.ToString(row[1]),
                Status = (DealMilestoneStatus)Convert.ToInt32(row[2]),
                Count = Convert.ToInt32(row[3]),
                Value = Convert.ToDecimal(row[4])
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, List<WorkloadByDeals> data)
        {
            var reportData = data.Select(item => new List<object>
                {
                    item.UserId,
                    item.UserName,
                    (int)item.Status,
                    item.Count,
                    item.Value
                }).ToList();

            return new
            {
                resource = new
                {
                    header = CRMReportResource.WorkloadByDealsReport,
                    sheetName = CRMReportResource.WorkloadByDealsReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),

                    chartName = CRMReportResource.DealsCount,
                    chartName1 = CRMReportResource.DealsBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,

                    header1 = CRMReportResource.ByCount,
                    header2 = CRMReportResource.ByBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,

                    manager = CRMReportResource.Manager,
                    total = CRMReportResource.Total,

                    status0 = CRMReportResource.New,
                    status1 = CRMReportResource.Won,
                    status2 = CRMReportResource.Lost
                },
                data = reportData
            };
        }

        #endregion


        #region WorkloadByInvoicesReport

        public bool CheckWorkloadByInvoicesReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sent = !Exp.Eq("i.status", (int)InvoiceStatus.Draft) & (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.issue_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)));
            var paid = Exp.Eq("i.status", (int)InvoiceStatus.Paid) & (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.last_modifed_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)));
            var rejected = Exp.Eq("i.status", (int)InvoiceStatus.Rejected) & (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.last_modifed_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)));
            var overdue = (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.due_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))) & Exp.Or(Exp.Eq("i.status", (int)InvoiceStatus.Sent) & Exp.Lt("i.due_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())), Exp.Eq("i.status", (int)InvoiceStatus.Paid) & Exp.Sql("i.last_modifed_on > i.due_date"));

            var sqlQuery = Query("crm_invoice i")
                .Select("i.id")
                .Where(managers != null && managers.Any() ? Exp.In("i.create_by", managers) : Exp.Empty)
                .Where(Exp.Or(Exp.Or(sent, paid), Exp.Or(rejected, overdue)))
                .SetMaxResults(1);

            return Db.ExecuteList(sqlQuery).Any();
        }

        public object GetWorkloadByInvoicesReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            var reportData = BuildWorkloadByInvoicesReport(timePeriod, managers);

            if (reportData == null || !reportData.Any()) return null;

            var hasData = reportData.Any(item => item.SentCount > 0 || item.PaidCount > 0 || item.RejectedCount > 0 || item.OverdueCount > 0);

            return hasData ? GenerateReportData(timePeriod, reportData) : null;
        }

        private List<WorkloadByInvoices> BuildWorkloadByInvoicesReport(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sent = Exp.Sum(Exp.If(!Exp.Eq("i.status", (int)InvoiceStatus.Draft) & (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.issue_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))), 1, 0));
            var paid = Exp.Sum(Exp.If(Exp.Eq("i.status", (int)InvoiceStatus.Paid) & (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.last_modifed_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))), 1, 0));
            var rejected = Exp.Sum(Exp.If(Exp.Eq("i.status", (int)InvoiceStatus.Rejected) & (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.last_modifed_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))), 1, 0));
            var overdue = Exp.Sum(Exp.If((timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.due_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))) & Exp.Or(Exp.Eq("i.status", (int)InvoiceStatus.Sent) & Exp.Lt("i.due_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())), Exp.Eq("i.status", (int)InvoiceStatus.Paid) & Exp.Sql("i.last_modifed_on > i.due_date")), 1, 0));

            var sqlQuery = Query("crm_invoice i")
                .Select("i.create_by", "concat(u.firstname, ' ', u.lastname) as full_name")
                .Select(sent)
                .Select(paid)
                .Select(rejected)
                .Select(overdue)
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "i.tenant_id") & Exp.EqColumns("u.id", "i.create_by"))
                .Where(managers != null && managers.Any() ? Exp.In("i.create_by", managers) : Exp.Empty)
                .GroupBy("i.create_by");


            return Db.ExecuteList(sqlQuery).ConvertAll(ToWorkloadByInvoices);
        }

        private static WorkloadByInvoices ToWorkloadByInvoices(object[] row)
        {
            return new WorkloadByInvoices
            {
                UserId = string.IsNullOrEmpty(Convert.ToString(row[0])) ? Guid.Empty : new Guid(Convert.ToString(row[0])),
                UserName = Convert.ToString(row[1]),
                SentCount = Convert.ToInt32(row[2]),
                PaidCount = Convert.ToInt32(row[3]),
                RejectedCount = Convert.ToInt32(row[4]),
                OverdueCount = Convert.ToInt32(row[5])
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, List<WorkloadByInvoices> reportData)
        {
            return new
            {
                resource = new
                {
                    header = CRMReportResource.WorkloadByInvoicesReport,
                    sheetName = CRMReportResource.WorkloadByInvoicesReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),

                    chartName = CRMReportResource.BilledInvoices,
                    chartName1 = CRMInvoiceResource.Invoices,

                    header1 = CRMInvoiceResource.Invoices,

                    manager = CRMReportResource.Manager,
                    total = CRMReportResource.Total,

                    billed = CRMReportResource.Billed,
                    paid = CRMReportResource.Paid,
                    rejected = CRMReportResource.Rejected,
                    overdue = CRMReportResource.Overdue
                },
                data = reportData
            };
        }

        #endregion


        #region GetWorkloadByViopReport

        public bool CheckWorkloadByViopReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_voip_calls c")
                .Select("c.id")
                .Where(Exp.EqColumns("c.parent_call_id", "''"))
                .Where(managers != null && managers.Any() ? Exp.In("c.answered_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ?
                        Exp.Empty :
                        Exp.Between("c.dial_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            return Db.ExecuteList(sqlQuery).Any();
        }

        public object GetWorkloadByViopReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            var reportData = BuildWorkloadByViopReport(timePeriod, managers);

            return reportData == null || !reportData.Any() ? null : GenerateReportData(timePeriod, reportData);
        }

        private List<WorkloadByViop> BuildWorkloadByViopReport(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var sqlQuery = Query("crm_voip_calls c")
                .Select("c.answered_by",
                        "concat(u.firstname, ' ', u.lastname) as full_name",
                        "c.status",
                        "count(c.id) as calls_count",
                        "sum(c.dial_duration) as duration")
                .LeftOuterJoin("core_user u", Exp.EqColumns("u.tenant", "c.tenant_id") & Exp.EqColumns("u.id", "c.answered_by"))
                .Where(Exp.EqColumns("c.parent_call_id", "''"))
                .Where(managers != null && managers.Any() ? Exp.In("c.answered_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ?
                        Exp.Empty :
                        Exp.Between("c.dial_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("c.answered_by", "c.status");


            return Db.ExecuteList(sqlQuery).ConvertAll(ToWorkloadByViop);
        }

        private static WorkloadByViop ToWorkloadByViop(object[] row)
        {
            return new WorkloadByViop
            {
                UserId = string.IsNullOrEmpty(Convert.ToString(row[0])) ? Guid.Empty : new Guid(Convert.ToString(row[0])),
                UserName = Convert.ToString(row[1] ?? string.Empty),
                Status = (VoipCallStatus)Convert.ToInt32(row[2] ?? 0),
                Count = Convert.ToInt32(row[3]),
                Duration = Convert.ToInt32(row[4])
            };
        }

        private static object GenerateReportData(ReportTimePeriod timePeriod, List<WorkloadByViop> data)
        {
            var reportData = data.Select(item => new List<object>
                {
                    item.UserId,
                    item.UserName,
                    (int) item.Status,
                    item.Count,
                    new {format = TimeFormat, value = SecondsToTimeFormat(item.Duration)}
                }).ToList();

            return new
            {
                resource = new
                {
                    header = CRMReportResource.WorkloadByVoipReport,
                    sheetName = CRMReportResource.WorkloadByVoipReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),

                    chartName = CRMReportResource.CallsCount,
                    chartName1 = CRMReportResource.CallsDuration,

                    header1 = CRMReportResource.CallsCount,
                    header2 = CRMReportResource.CallsDuration,

                    manager = CRMReportResource.Manager,
                    total = CRMReportResource.Total,

                    incoming = CRMReportResource.Incoming,
                    outcoming = CRMReportResource.Outcoming,

                    timeFormat = TimeFormat
                },
                data = reportData
            };
        }

        private static string SecondsToTimeFormat(int duration)
        {
            var timeSpan = TimeSpan.FromSeconds(duration);

            return string.Format("{0}:{1}:{2}",
                ((timeSpan.TotalHours < 10 ? "0" : "") + (int)timeSpan.TotalHours),
                ((timeSpan.Minutes < 10 ? "0" : "") + timeSpan.Minutes),
                ((timeSpan.Seconds < 10 ? "0" : "") + timeSpan.Seconds));
        }

        #endregion


        #region SummaryForThePeriodReport

        public bool CheckSummaryForThePeriodReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var newDealsSqlQuery = Query("crm_deal d")
                .Select("d.id")
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var closedDealsSqlQuery = Query("crm_deal d")
                .Select("d.id")
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.actual_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where(!Exp.Eq("m.status", (int)DealMilestoneStatus.Open))
                .SetMaxResults(1);

            var overdueDealsSqlQuery = Query("crm_deal d")
                .Select("d.id")
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(
                    Exp.And(
                        Exp.Between("d.expected_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)),
                        Exp.Or(Exp.Eq("m.status", (int)DealMilestoneStatus.Open) & Exp.Lt("d.expected_close_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())),
                               Exp.Eq("m.status", (int)DealMilestoneStatus.ClosedAndWon) & Exp.Sql("d.actual_close_date > d.expected_close_date"))));

            var invoicesSqlQuery = Query("crm_invoice i")
                .Select("i.id")
                .Where(managers != null && managers.Any() ? Exp.In("i.create_by", managers) : Exp.Empty)
                .Where(Exp.Between("i.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var contactsSqlQuery = Query("crm_contact c")
                .Select("c.id")
                .Where(managers != null && managers.Any() ? Exp.In("c.create_by", managers) : Exp.Empty)
                .Where(Exp.Between("c.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var tasksSqlQuery = Query("crm_task t")
                .Select("t.id")
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("t.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var voipSqlQuery = Query("crm_voip_calls c")
                .Select("c.id")
                .Where(Exp.EqColumns("c.parent_call_id", "''"))
                .Where(managers != null && managers.Any() ? Exp.In("c.answered_by", managers) : Exp.Empty)
                .Where(Exp.Between("c.dial_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("c.status");

            bool res;

            using (var tx = Db.BeginTransaction())
            {
                res = Db.ExecuteList(newDealsSqlQuery).Any() ||
                      Db.ExecuteList(closedDealsSqlQuery).Any() ||
                      Db.ExecuteList(overdueDealsSqlQuery).Any() ||
                      Db.ExecuteList(invoicesSqlQuery).Any() ||
                      Db.ExecuteList(contactsSqlQuery).Any() ||
                      Db.ExecuteList(tasksSqlQuery).Any() ||
                      Db.ExecuteList(voipSqlQuery).Any();

                tx.Commit();
            }

            return res;
        }

        public object GetSummaryForThePeriodReportData(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            var reportData = BuildSummaryForThePeriodReport(timePeriod, managers, defaultCurrency);

            if (reportData == null) return null;

            return GenerateSummaryForThePeriodReportData(timePeriod, reportData);
        }

        private object BuildSummaryForThePeriodReport(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var newDealsSqlQuery = Query("crm_deal d")
                .Select("count(d.id) as count",
                        string.Format(@"sum(case d.bid_type
                                        when 0 then
                                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                                        else
                                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)));

            var wonDealsSqlQuery = Query("crm_deal d")
                .Select("count(d.id) as count",
                        string.Format(@"sum(case d.bid_type
                                        when 0 then
                                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                                        else
                                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.actual_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where("m.status", (int)DealMilestoneStatus.ClosedAndWon);

            var lostDealsSqlQuery = Query("crm_deal d")
                .Select("count(d.id) as count",
                        string.Format(@"sum(case d.bid_type
                                        when 0 then
                                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                                        else
                                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("d.actual_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where("m.status", (int)DealMilestoneStatus.ClosedAndLost);

            var overdueDealsSqlQuery = Query("crm_deal d")
                .Select("count(d.id) as count",
                        string.Format(@"sum(case d.bid_type
                                        when 0 then
                                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                                        else
                                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(
                    Exp.And(
                        Exp.Between("d.expected_close_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)),
                        Exp.Or(Exp.Eq("m.status", (int)DealMilestoneStatus.Open) & Exp.Lt("d.expected_close_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())),
                               Exp.Eq("m.status", (int)DealMilestoneStatus.ClosedAndWon) & Exp.Sql("d.actual_close_date > d.expected_close_date"))));

            var sent = Exp.Sum(Exp.If(!Exp.Eq("i.status", (int)InvoiceStatus.Draft), 1, 0));
            var paid = Exp.Sum(Exp.If(Exp.Eq("i.status", (int)InvoiceStatus.Paid), 1, 0));
            var rejected = Exp.Sum(Exp.If(Exp.Eq("i.status", (int)InvoiceStatus.Rejected), 1, 0));
            var overdue = Exp.Sum(Exp.If(Exp.Or(Exp.Eq("i.status", (int)InvoiceStatus.Sent) & Exp.Lt("i.due_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())),
                                                Exp.Eq("i.status", (int)InvoiceStatus.Paid) & Exp.Sql("i.last_modifed_on > i.due_date")), 1, 0));

            var invoicesSqlQuery = Query("crm_invoice i")
                .Select(sent)
                .Select(paid)
                .Select(rejected)
                .Select(overdue)
                .Where(managers != null && managers.Any() ? Exp.In("i.create_by", managers) : Exp.Empty)
                .Where(Exp.Between("i.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)));


            var contactsSqlQuery = Query("crm_contact c")
                .Select("i.title",
                        "count(c.id)")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "c.tenant_id") &
                                                  Exp.EqColumns("i.id", "c.contact_type_id") &
                                                  Exp.Eq("i.list_type", (int)ListType.ContactType))
                .Where(managers != null && managers.Any() ? Exp.In("c.create_by", managers) : Exp.Empty)
                .Where(Exp.Between("c.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("i.id")
                .OrderBy("i.sort_order, i.title", true);

            var tasksSqlQuery = Query("crm_task t")
                .Select("i.title")
                .Select(Exp.Sum(Exp.If(Exp.Eq("t.is_closed", 1) & Exp.Between("t.last_modifed_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)), 1, 0)))
                .Select(Exp.Sum(Exp.If(Exp.Or(Exp.Eq("t.is_closed", 0) & Exp.Lt("t.deadline", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())), Exp.Eq("t.is_closed", 1) & Exp.Sql("t.last_modifed_on > t.deadline")), 1, 0)))
                .Select("count(t.id)")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "t.tenant_id") & Exp.EqColumns("i.id", "t.category_id") & Exp.Eq("i.list_type", (int)ListType.TaskCategory))
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(Exp.Between("t.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("i.id")
                .OrderBy("i.sort_order, i.title", true);

            var voipSqlQuery = Query("crm_voip_calls c")
                .Select("c.status",
                        "count(c.id) as calls_count",
                        "sum(c.dial_duration) as duration")
                .Where(Exp.EqColumns("c.parent_call_id", "''"))
                .Where(managers != null && managers.Any() ? Exp.In("c.answered_by", managers) : Exp.Empty)
                .Where(Exp.Between("c.dial_date", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("c.status");

            object res;

            using (var tx = Db.BeginTransaction())
            {
                res = new
                {
                    DealsInfo = new
                    {
                        Created = Db.ExecuteList(newDealsSqlQuery),
                        Won = Db.ExecuteList(wonDealsSqlQuery),
                        Lost = Db.ExecuteList(lostDealsSqlQuery),
                        Overdue = Db.ExecuteList(overdueDealsSqlQuery),
                    },
                    InvoicesInfo = Db.ExecuteList(invoicesSqlQuery),
                    ContactsInfo = Db.ExecuteList(contactsSqlQuery),
                    TasksInfo = Db.ExecuteList(tasksSqlQuery),
                    VoipInfo = Db.ExecuteList(voipSqlQuery)
                };

                tx.Commit();
            }

            return res;
        }

        private static object GenerateSummaryForThePeriodReportData(ReportTimePeriod timePeriod, object reportData)
        {
            return new
            {
                resource = new
                {
                    header = CRMReportResource.SummaryForThePeriodReport,
                    sheetName = CRMReportResource.SummaryForThePeriodReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),
                    chartName = CRMReportResource.DealsByBudget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName1 = CRMReportResource.DealsByCount,
                    chartName2 = CRMReportResource.ContactsByType,
                    chartName3 = CRMReportResource.TasksForThePeriod,
                    chartName4 = CRMReportResource.InvoicesForThePeriod,
                    chartName5 = CRMReportResource.CallsForThePeriod,
                    header1 = CRMDealResource.Deals,
                    header2 = CRMContactResource.Contacts,
                    header3 = CRMTaskResource.Tasks,
                    header4 = CRMInvoiceResource.Invoices,
                    header5 = CRMReportResource.Calls,
                    byBudget = CRMReportResource.ByBudget,
                    currency = Global.TenantSettings.DefaultCurrency.Symbol,
                    byCount = CRMReportResource.ByCount,
                    item = CRMReportResource.Item,
                    type = CRMReportResource.Type,
                    won = CRMReportResource.Won,
                    lost = CRMReportResource.Lost,
                    created = CRMReportResource.Created,
                    closed = CRMReportResource.Closed,
                    overdue = CRMReportResource.Overdue,
                    notSpecified = CRMCommonResource.NoSet,
                    total = CRMReportResource.Total,
                    status = CRMReportResource.Status,
                    billed = CRMReportResource.Billed,
                    paid = CRMReportResource.Paid,
                    rejected = CRMReportResource.Rejected,
                    count = CRMReportResource.Count,
                    duration = CRMReportResource.Duration,
                    incoming = CRMReportResource.Incoming,
                    outcoming = CRMReportResource.Outcoming,
                    missed = CRMReportResource.MissedCount,
                    timeFormat = TimeFormat
                },
                data = reportData
            };
        }

        #endregion


        #region SummaryAtThisMomentReport

        public bool CheckSummaryAtThisMomentReportData(ReportTimePeriod timePeriod, Guid[] managers)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var dealsSqlQuery = Query("crm_deal d")
                .Select("d.id")
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where("m.status", (int)DealMilestoneStatus.Open)
                .SetMaxResults(1);

            var contactsSqlQuery = Query("crm_contact c")
                .Select("c.id")
                .Where(managers != null && managers.Any() ? Exp.In("c.create_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("c.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var tasksSqlQuery = Query("crm_task t")
                .Select("t.id")
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            var invoicesSqlQuery = Query("crm_invoice i")
                .Select("i.id")
                .Where(managers != null && managers.Any() ? Exp.In("i.create_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .SetMaxResults(1);

            bool res;

            using (var tx = Db.BeginTransaction())
            {
                res = Db.ExecuteList(dealsSqlQuery).Any() ||
                      Db.ExecuteList(contactsSqlQuery).Any() ||
                      Db.ExecuteList(tasksSqlQuery).Any() ||
                      Db.ExecuteList(invoicesSqlQuery).Any();

                tx.Commit();
            }

            return res;
        }

        public object GetSummaryAtThisMomentReportData(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            var reportData = BuildSummaryAtThisMomentReport(timePeriod, managers, defaultCurrency);

            if (reportData == null) return null;

            return GenerateSummaryAtThisMomentReportData(timePeriod, reportData);
        }

        private object BuildSummaryAtThisMomentReport(ReportTimePeriod timePeriod, Guid[] managers, string defaultCurrency)
        {
            DateTime fromDate;
            DateTime toDate;

            GetTimePeriod(timePeriod, out fromDate, out toDate);

            var openDealsSqlQuery = Query("crm_deal d")
                .Select("count(d.id) as count",
                        string.Format(@"sum(case d.bid_type
                                        when 0 then
                                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                                        else
                                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where("m.status", (int)DealMilestoneStatus.Open);

            var overdueDealsSqlQuery = Query("crm_deal d")
                .Select("count(d.id) as count",
                        string.Format(@"sum(case d.bid_type
                                        when 0 then
                                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                                        else
                                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where("m.status", (int)DealMilestoneStatus.Open)
                .Where(Exp.Lt("d.expected_close_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())));

            var nearDealsSqlQuery = Query("crm_deal d")
                .Select("count(d.id) as count",
                        string.Format(@"sum(case d.bid_type
                                        when 0 then
                                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                                        else
                                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_currency_rate r",
                               Exp.EqColumns("r.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .LeftOuterJoin("crm_deal_milestone m",
                               Exp.EqColumns("m.tenant_id", "d.tenant_id") &
                               Exp.EqColumns("m.id", "d.deal_milestone_id"))
                .Where(managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .Where("m.status", (int)DealMilestoneStatus.Open)
                .Where(Exp.Between("d.expected_close_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()), TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow().AddDays(30))));

            var dealsByStageSqlQuery = Query("crm_deal_milestone m")
                .Select("m.title",
                        "count(d.id) as deals_count",
                        string.Format(@"sum(case d.bid_type
                        when 0 then
                            d.bid_value * (if(d.bid_currency = '{0}', 1, r.rate))
                        else
                            d.bid_value * (if(d.per_period_value = 0, 1, d.per_period_value)) * (if(d.bid_currency = '{0}', 1, r.rate))
                        end) as deals_value", defaultCurrency))
                .LeftOuterJoin("crm_deal d", Exp.EqColumns("d.tenant_id", "m.tenant_id") &
                    Exp.EqColumns("d.deal_milestone_id", "m.id") &
                    (managers != null && managers.Any() ? Exp.In("d.responsible_id", managers) : Exp.Empty) &
                    (timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("d.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate))))
                .LeftOuterJoin("crm_currency_rate r", Exp.EqColumns("r.tenant_id", "m.tenant_id") & Exp.EqColumns("r.from_currency", "d.bid_currency"))
                .Where("m.status", (int)DealMilestoneStatus.Open)
                .GroupBy("m.id")
                .OrderBy("m.sort_order, m.title", true);

            var contactsByTypeSqlQuery = Query("crm_contact c")
                .Select("i.title",
                        "count(c.id) as count")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "c.tenant_id") &
                                                  Exp.EqColumns("i.id", "c.contact_type_id") &
                                                  Exp.Eq("i.list_type", (int)ListType.ContactType))
                .Where(managers != null && managers.Any() ? Exp.In("c.create_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("c.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("i.id")
                .OrderBy("i.sort_order, i.title", true);

            var contactsByStageSqlQuery = Query("crm_contact c")
                .Select("i.title",
                        "count(c.id) as count")
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "c.tenant_id") &
                                                  Exp.EqColumns("i.id", "c.status_id") &
                                                  Exp.Eq("i.list_type", (int)ListType.ContactStatus))
                .Where(managers != null && managers.Any() ? Exp.In("c.create_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("c.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("i.id")
                .OrderBy("i.sort_order, i.title", true);

            var tasksSqlQuery = Query("crm_task t")
                .Select("i.title")
                .Select(Exp.Sum(Exp.If(Exp.Eq("t.is_closed", 0), 1, 0)))
                .Select(Exp.Sum(Exp.If(Exp.Eq("t.is_closed", 0) & Exp.Lt("t.deadline", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())), 1, 0)))
                .LeftOuterJoin("crm_list_item i", Exp.EqColumns("i.tenant_id", "t.tenant_id") & Exp.EqColumns("i.id", "t.category_id") & Exp.Eq("i.list_type", (int)ListType.TaskCategory))
                .Where(managers != null && managers.Any() ? Exp.In("t.responsible_id", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("t.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)))
                .GroupBy("i.id")
                .OrderBy("i.sort_order, i.title", true);

            var sent = Exp.Sum(Exp.If(Exp.Eq("i.status", (int)InvoiceStatus.Sent), 1, 0));
            var overdue = Exp.Sum(Exp.If(Exp.Eq("i.status", (int)InvoiceStatus.Sent) & Exp.Lt("i.due_date", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow())), 1, 0));

            var invoicesSqlQuery = Query("crm_invoice i")
                .Select(sent)
                .Select(overdue)
                .Where(managers != null && managers.Any() ? Exp.In("i.create_by", managers) : Exp.Empty)
                .Where(timePeriod == ReportTimePeriod.DuringAllTime ? Exp.Empty : Exp.Between("i.create_on", TenantUtil.DateTimeToUtc(fromDate), TenantUtil.DateTimeToUtc(toDate)));

            object res;

            using (var tx = Db.BeginTransaction())
            {
                res = new
                {
                    DealsInfo = new
                    {
                        Open = Db.ExecuteList(openDealsSqlQuery),
                        Overdue = Db.ExecuteList(overdueDealsSqlQuery),
                        Near = Db.ExecuteList(nearDealsSqlQuery),
                        ByStage = Db.ExecuteList(dealsByStageSqlQuery)
                    },
                    ContactsInfo = new
                    {
                        ByType = Db.ExecuteList(contactsByTypeSqlQuery),
                        ByStage = Db.ExecuteList(contactsByStageSqlQuery)
                    },
                    TasksInfo = Db.ExecuteList(tasksSqlQuery),
                    InvoicesInfo = Db.ExecuteList(invoicesSqlQuery),
                };

                tx.Commit();
            }

            return res;
        }

        private static object GenerateSummaryAtThisMomentReportData(ReportTimePeriod timePeriod, object reportData)
        {
            return new
            {
                resource = new
                {
                    header = CRMReportResource.SummaryAtThisMomentReport,
                    sheetName = CRMReportResource.SummaryAtThisMomentReport,
                    dateRangeLabel = CRMReportResource.TimePeriod + ":",
                    dateRangeValue = GetTimePeriodText(timePeriod),
                    chartName = CRMReportResource.DealsByStatus + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName1 = CRMReportResource.DealsByStage + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    chartName2 = CRMReportResource.ContactsByType,
                    chartName3 = CRMReportResource.ContactsByStage,
                    chartName4 = CRMReportResource.TasksByStatus,
                    chartName5 = CRMReportResource.InvoicesByStatus,
                    header1 = CRMDealResource.Deals,
                    header2 = CRMContactResource.Contacts,
                    header3 = CRMTaskResource.Tasks,
                    header4 = CRMInvoiceResource.Invoices,
                    budget = CRMReportResource.Budget + ", " + Global.TenantSettings.DefaultCurrency.Symbol,
                    count = CRMReportResource.Count,
                    open = CRMReportResource.Opened,
                    overdue = CRMReportResource.Overdue,
                    near = CRMReportResource.Near,
                    stage = CRMReportResource.Stage,
                    temperature = CRMContactResource.ContactStage,
                    type = CRMReportResource.Type,
                    total = CRMReportResource.Total,
                    billed = CRMReportResource.Billed,
                    notSpecified = CRMCommonResource.NoSet,
                    status = CRMReportResource.Status,
                },
                data = reportData
            };
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Services/NotifyService/NotifyConstants.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using ASC.Notify.Model;

#endregion

namespace ASC.Web.CRM.Services.NotifyService
{
    public static class NotifyConstants
    {

        public static readonly INotifyAction Event_SetAccess = new NotifyAction("SetAccess", "set access for users");

        public static readonly INotifyAction Event_ResponsibleForTask = new NotifyAction("ResponsibleForTask", "responsible for task");

        public static readonly INotifyAction Event_TaskReminder = new NotifyAction("TaskReminder", "auto reminder about task");

        public static readonly INotifyAction Event_ResponsibleForOpportunity = new NotifyAction("ResponsibleForOpportunity", "responsible for opportunity");

        public static readonly INotifyAction Event_AddRelationshipEvent = new NotifyAction("AddRelationshipEvent", "add relationship event");

        public static readonly INotifyAction Event_ExportCompleted = new NotifyAction("ExportCompleted", "export is completed");

        public static readonly INotifyAction Event_ExportCompletedCustomMode = new NotifyAction("ExportCompletedCustomMode", "export is completed");

        public static readonly INotifyAction Event_ImportCompleted = new NotifyAction("ImportCompleted", "import is completed");

        public static readonly INotifyAction Event_ImportCompletedCustomMode = new NotifyAction("ImportCompletedCustomMode", "import is completed");

        public static readonly INotifyAction Event_CreateNewContact = new NotifyAction("CreateNewContact", "create new contact");

        public static readonly string Tag_AdditionalData = "AdditionalData";

        public static readonly string Tag_EntityID = "EntityID";

        public static readonly string Tag_EntityTitle = "EntityTitle";

        public static readonly string Tag_EntityRelativeURL = "EntityRelativeURL";

        public static readonly string Tag_EntityListRelativeURL = "EntityListRelativeURL";

        public static readonly string Tag_EntityListTitle = "EntityListTitle";

    }
}

<|start_filename|>common/ASC.ActiveDirectory/Novell/Extensions/NovellLdapEntryExtension.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

using ASC.ActiveDirectory.Base;
using ASC.ActiveDirectory.Base.Data;
using ASC.ActiveDirectory.Novell.Data;

using Novell.Directory.Ldap;

namespace ASC.ActiveDirectory.Novell.Extensions
{
    public static class NovellLdapEntryExtension
    {
        public static object GetAttributeValue(this LdapEntry ldapEntry, string attributeName, bool getBytes = false)
        {
            var attribute = ldapEntry.getAttribute(attributeName);

            if (attribute == null)
                return null;

            if (!(string.Equals(attributeName, LdapConstants.ADSchemaAttributes.OBJECT_SID,
                StringComparison.OrdinalIgnoreCase) || getBytes))
            {
                return attribute.StringValue;
            }

            if (attribute.ByteValue == null)
                return null;

            var value = new byte[attribute.ByteValue.Length];

            Buffer.BlockCopy(attribute.ByteValue, 0, value, 0, attribute.ByteValue.Length);

            if (getBytes)
            {
                return value;
            }

            return DecodeSid(value);
        }

        public static string[] GetAttributeArrayValue(this LdapEntry ldapEntry, string attributeName)
        {
            var attribute = ldapEntry.getAttribute(attributeName);
            return attribute == null ? null : attribute.StringValueArray;
        }

        private static string DecodeSid(byte[] sid)
        {
            var strSid = new StringBuilder("S-");

            // get version
            int revision = sid[0];
            strSid.Append(revision.ToString(CultureInfo.InvariantCulture));

            //next byte is the count of sub-authorities
            var countSubAuths = sid[1] & 0xFF;

            //get the authority
            long authority = 0;

            //String rid = "";
            for (var i = 2; i <= 7; i++)
            {
                authority |= ((long)sid[i]) << (8 * (5 - (i - 2)));
            }

            strSid.Append("-");
            strSid.Append(authority);

            //iterate all the sub-auths
            var offset = 8;
            const int size = 4; //4 bytes for each sub auth

            for (var j = 0; j < countSubAuths; j++)
            {
                long subAuthority = 0;
                for (var k = 0; k < size; k++)
                {
                    subAuthority |= (long)(sid[offset + k] & 0xFF) << (8 * k);
                }

                strSid.Append("-");
                strSid.Append(subAuthority);

                offset += size;
            }

            return strSid.ToString();
        }

        /// <summary>
        /// Create LDAPObject by LdapEntry
        /// </summary>
        /// <param name="ldapEntry">init ldapEntry</param>
        /// <param name="ldapUniqueIdAttribute"></param>
        /// <returns>LDAPObject</returns>
        public static LdapObject ToLdapObject(this LdapEntry ldapEntry, string ldapUniqueIdAttribute = null)
        {
            if (ldapEntry == null)
                throw new ArgumentNullException("ldapEntry");

            return new NovellLdapObject(ldapEntry, ldapUniqueIdAttribute);
        }

        /// <summary>
        /// Create lis of LDAPObject by LdapEntry list
        /// </summary>
        /// <param name="entries">list of LdapEntry</param>
        /// <param name="ldapUniqueIdAttribute"></param>
        /// <returns>list of LDAPObjects</returns>
        public static List<LdapObject> ToLdapObjects(this IEnumerable<LdapEntry> entries, string ldapUniqueIdAttribute = null)
        {
            return entries.Select(e => ToLdapObject(e, ldapUniqueIdAttribute)).ToList();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/ProjectEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Services.NotifyService;
using ASC.Web.Files.Api;
using ASC.Web.Projects.Core.Search;

namespace ASC.Projects.Engine
{
    public class ProjectEngine
    {
        public TaskEngine TaskEngine { get { return EngineFactory.TaskEngine; } }
        public MilestoneEngine MilestoneEngine { get { return EngineFactory.MilestoneEngine; } }
        public MessageEngine MessageEngine { get { return EngineFactory.MessageEngine; } }
        public FileEngine FileEngine { get { return EngineFactory.FileEngine; } }
        public TimeTrackingEngine TimeTrackingEngine { get { return EngineFactory.TimeTrackingEngine; } }

        public EngineFactory EngineFactory { get; set; }
        public IDaoFactory DaoFactory { get; set; }
        public ProjectSecurity ProjectSecurity { get; set; }
        public bool DisableNotifications { get; set; }

        public Func<Project, bool> CanReadDelegate;

        public ProjectEngine(bool disableNotificationParameter)
        {
            CanReadDelegate = CanRead;
            DisableNotifications = disableNotificationParameter;
        }

        #region Get Projects

        public IEnumerable<Project> GetAll()
        {
            return DaoFactory.ProjectDao.GetAll(null, 0).Where(CanReadDelegate);
        }

        public IEnumerable<Project> GetAll(ProjectStatus status, int max)
        {
            return DaoFactory.ProjectDao.GetAll(status, max)
                .Where(CanReadDelegate);
        }

        public IEnumerable<Project> GetLast(ProjectStatus status, int max)
        {
            var offset = 0;
            var lastProjects = new List<Project>();

            do
            {
                var projects = DaoFactory.ProjectDao.GetLast(status, offset, max);

                if (!projects.Any())
                    return lastProjects;

                lastProjects.AddRange(projects.Where(CanReadDelegate));
                offset = offset + max;
            } while (lastProjects.Count < max);

            return lastProjects.Count == max ? lastProjects : lastProjects.GetRange(0, max);
        }

        public IEnumerable<Project> GetOpenProjectsWithTasks(Guid participantId)
        {
            return DaoFactory.ProjectDao.GetOpenProjectsWithTasks(participantId).Where(CanReadDelegate).ToList();
        }

        public IEnumerable<Project> GetByParticipant(Guid participant)
        {
            return DaoFactory.ProjectDao.GetByParticipiant(participant, ProjectStatus.Open).Where(CanReadDelegate).ToList();
        }

        public IEnumerable<Project> GetByFilter(TaskFilter filter)
        {
            return DaoFactory.ProjectDao.GetByFilter(filter, ProjectSecurity.CurrentUserAdministrator, ProjectSecurity.IsPrivateDisabled);
        }

        public int GetByFilterCount(TaskFilter filter)
        {
            return DaoFactory.ProjectDao.GetByFilterCount(filter, ProjectSecurity.CurrentUserAdministrator, ProjectSecurity.IsPrivateDisabled);
        }

        public IEnumerable<Project> GetFollowing(Guid participant)
        {
            return DaoFactory.ProjectDao.GetFollowing(participant).Where(CanReadDelegate).ToList();
        }

        public Project GetByID(int projectID)
        {
            return GetByID(projectID, true);
        }

        public Project GetByID(int projectID, bool checkSecurity)
        {
            var project = DaoFactory.ProjectDao.GetById(projectID);

            if (!checkSecurity)
                return project;

            return CanRead(project) ? project : null;
        }

        public Project GetFullProjectByID(int projectID)
        {
            var project = DaoFactory.ProjectDao.GetById(projectID);

            if (!CanRead(project)) return null;

            var filter = new TaskFilter
            {
                ProjectIds = new List<int> { projectID },
                MilestoneStatuses = new List<MilestoneStatus> { MilestoneStatus.Open }
            };
            var taskCount = TaskEngine.GetByFilterCount(filter);

            project.MilestoneCount = MilestoneEngine.GetByFilterCount(filter);
            project.TaskCount = taskCount.TasksOpen;
            project.TaskCountTotal = taskCount.TasksTotal;
            project.DiscussionCount = MessageEngine.GetByFilterCount(filter);

            using (var folderDao = FilesIntegration.GetFolderDao())
            {
                var folderId = FileEngine.GetRoot(projectID);
                project.DocumentsCount = folderDao.GetItemsCount(folderId);
            }

            project.TimeTrackingTotal = TimeTrackingEngine.GetTotalByProject(projectID);
            project.ParticipantCount = GetTeam(projectID).Count();


            return project;
        }

        public IEnumerable<Project> GetByID(ICollection projectIDs, bool checkSecurity = true)
        {
            var projects = DaoFactory.ProjectDao.GetById(projectIDs);
            if (checkSecurity)
            {
                projects = projects.Where(CanReadDelegate).ToList();
            }
            return projects;
        }

        public bool IsExists(int projectID)
        {
            return DaoFactory.ProjectDao.IsExists(projectID);
        }

        private bool CanRead(Project project)
        {
            return ProjectSecurity.CanRead(project);
        }

        public DateTime GetMaxLastModified()
        {
            return DaoFactory.ProjectDao.GetMaxLastModified();
        }

        #endregion

        #region Order

        public void SetTaskOrder(Project project, string order)
        {
            DaoFactory.ProjectDao.SetTaskOrder(project.ID, order);
        }

        public string GetTaskOrder(Project project)
        {
            return DaoFactory.ProjectDao.GetTaskOrder(project.ID);
        }

        #endregion

        #region Get Counts

        public virtual int CountOpen()
        {
            return Count(ProjectStatus.Open);
        }

        public int Count(ProjectStatus? status = null)
        {
            var filter = new TaskFilter();

            if (status.HasValue)
            {
                filter.ProjectStatuses = new List<ProjectStatus> { status.Value };
            }

            return GetByFilterCount(filter);
        }

        public int GetTaskCount(int projectId, TaskStatus? taskStatus)
        {
            return GetTaskCount(new List<int> { projectId }, taskStatus).First();
        }

        public IEnumerable<int> GetTaskCount(List<int> projectId, TaskStatus? taskStatus)
        {
            return DaoFactory.ProjectDao.GetTaskCount(projectId, taskStatus, ProjectSecurity.CurrentUserAdministrator);
        }

        public int GetMilestoneCount(int projectId, params MilestoneStatus[] milestoneStatus)
        {
            return DaoFactory.ProjectDao.GetMilestoneCount(projectId, milestoneStatus);
        }

        public int GetMessageCount(int projectId)
        {
            return DaoFactory.ProjectDao.GetMessageCount(projectId);
        }

        #endregion

        #region Save, Delete

        public Project SaveOrUpdate(Project project, bool notifyManager)
        {
            return SaveOrUpdate(project, notifyManager, false);
        }

        public virtual Project SaveOrUpdate(Project project, bool notifyManager, bool isImport)
        {
            if (project == null) throw new ArgumentNullException("project");

            // check guest responsible
            if (ProjectSecurity.IsVisitor(project.Responsible))
            {
                ProjectSecurity.CreateGuestSecurityException();
            }

            project.LastModifiedBy = SecurityContext.CurrentAccount.ID;
            project.LastModifiedOn = TenantUtil.DateTimeNow();

            if (project.ID == 0)
            {
                if (project.CreateBy == default(Guid)) project.CreateBy = SecurityContext.CurrentAccount.ID;
                if (project.CreateOn == default(DateTime)) project.CreateOn = TenantUtil.DateTimeNow();

                ProjectSecurity.DemandCreate<Project>(null);

                DaoFactory.ProjectDao.Create(project);

                FactoryIndexer<ProjectsWrapper>.IndexAsync(project);
            }
            else
            {
                var oldProject = DaoFactory.ProjectDao.GetById(new[] { project.ID }).FirstOrDefault();
                ProjectSecurity.DemandEdit(oldProject);

                DaoFactory.ProjectDao.Update(project);

                if (!project.Private) ResetTeamSecurity(oldProject);

                FactoryIndexer<ProjectsWrapper>.UpdateAsync(project);
            }

            if (notifyManager && !DisableNotifications && !project.Responsible.Equals(SecurityContext.CurrentAccount.ID))
                NotifyClient.Instance.SendAboutResponsibleByProject(project.Responsible, project);

            return project;
        }

        public Project ChangeStatus(Project project, ProjectStatus status)
        {
            if (project == null) throw new ArgumentNullException("project");
            ProjectSecurity.DemandEdit(project);

            project.LastModifiedBy = SecurityContext.CurrentAccount.ID;
            project.LastModifiedOn = TenantUtil.DateTimeNow();
            project.StatusChangedOn = DateTime.Now;
            project.Status = status;

            DaoFactory.ProjectDao.Update(project);

            return project;
        }

        public virtual void Delete(int projectId)
        {
            var project = GetByID(projectId);
            if (project == null) return;

            ProjectSecurity.DemandEdit(project);

            FileEngine.RemoveRoot(projectId);

            List<int> messages, tasks;
            DaoFactory.ProjectDao.Delete(projectId, out messages, out tasks);

            NotifyClient.Instance.SendAboutProjectDeleting(new HashSet<Guid> { project.Responsible }, project);

            MessageEngine.UnSubscribeAll(messages.Select(r => new Message { Project = project, ID = r }).ToList());
            TaskEngine.UnSubscribeAll(tasks.Select(r => new Task { Project = project, ID = r }).ToList());

            FactoryIndexer<ProjectsWrapper>.DeleteAsync(project);
        }

        #endregion

        #region Contacts

        public IEnumerable<Project> GetProjectsByContactID(int contactId)
        {
            return DaoFactory.ProjectDao.GetByContactID(contactId).Where(CanReadDelegate);
        }

        public void AddProjectContact(int projectId, int contactId)
        {
            DaoFactory.ProjectDao.AddProjectContact(projectId, contactId);
        }

        public void DeleteProjectContact(int projectId, int contactId)
        {
            DaoFactory.ProjectDao.DeleteProjectContact(projectId, contactId);
        }

        #endregion

        #region Team

        public IEnumerable<Participant> GetTeam(int projectId)
        {
            var project = GetByID(projectId);
            return DaoFactory.ProjectDao.GetTeam(project).Where(r => !r.UserInfo.Equals(ASC.Core.Users.Constants.LostUser)).ToList();
        }

        public IEnumerable<Participant> GetProjectTeamExcluded(int projectId)
        {
            var project = GetByID(projectId);
            return DaoFactory.ProjectDao.GetTeam(project, true).Where(r => !r.UserInfo.Equals(ASC.Core.Users.Constants.LostUser)).ToList();
        }

        public IEnumerable<Participant> GetTeam(List<int> projectIds)
        {
            var projects = GetByID(projectIds);
            return DaoFactory.ProjectDao.GetTeam(projects).Where(r => !r.UserInfo.Equals(ASC.Core.Users.Constants.LostUser)).ToList();
        }

        public bool IsInTeam(int project, Guid participant)
        {
            return DaoFactory.ProjectDao.IsInTeam(project, participant);
        }

        public bool IsFollow(int project, Guid participant)
        {
            return DaoFactory.ProjectDao.IsFollow(project, participant);
        }

        public void AddToTeam(Project project, Participant participant, bool sendNotification)
        {
            if (participant == null) throw new ArgumentNullException("participant");

            AddToTeam(project, participant.ID, sendNotification);
        }

        public void AddToTeam(Project project, Guid participant, bool sendNotification)
        {
            if (project == null) throw new ArgumentNullException("project");

            ProjectSecurity.DemandEditTeam(project);
            DaoFactory.ProjectDao.AddToTeam(project.ID, participant);

            if (!DisableNotifications && sendNotification && !project.Responsible.Equals(participant) && participant != SecurityContext.CurrentAccount.ID)
                NotifyClient.Instance.SendInvaiteToProjectTeam(participant, project);
        }

        public void RemoveFromTeam(Project project, Participant participant, bool sendNotification)
        {
            if (participant == null) throw new ArgumentNullException("participant");

            RemoveFromTeam(project, participant.ID, sendNotification);
        }

        public void RemoveFromTeam(Project project, Guid participant, bool sendNotification)
        {
            if (project == null) throw new ArgumentNullException("project");
            if (participant == null) throw new ArgumentNullException("participant");

            ProjectSecurity.DemandEditTeam(project);
            DaoFactory.ProjectDao.RemoveFromTeam(project.ID, participant);

            if (!DisableNotifications && sendNotification)
                NotifyClient.Instance.SendRemovingFromProjectTeam(participant, project);
        }

        public void UpdateTeam(Project project, IEnumerable<Guid> participants, bool notify)
        {
            if (project == null) throw new ArgumentNullException("project");
            if (participants == null) throw new ArgumentNullException("participants");

            ProjectSecurity.DemandEditTeam(project);

            var newTeam = participants.Select(p => new Participant(p)).ToList();
            var oldTeam = GetTeam(project.ID);

            var removeFromTeam = oldTeam.Where(p => !newTeam.Contains(p) && p.ID != project.Responsible).ToList();
            var inviteToTeam = new List<Participant>();

            foreach (var participant in newTeam.Where(participant => !oldTeam.Contains(participant)))
            {
                DaoFactory.ParticipantDao.RemoveFromFollowingProjects(project.ID, participant.ID);
                inviteToTeam.Add(participant);
            }

            foreach (var participant in inviteToTeam)
            {
                AddToTeam(project, participant, notify);
            }

            foreach (var participant in removeFromTeam)
            {
                RemoveFromTeam(project, participant, notify);
            }
        }

        public void SetTeamSecurity(Project project, Participant participant, ProjectTeamSecurity teamSecurity, bool visible)
        {
            if (participant == null) throw new ArgumentNullException("participant");

            SetTeamSecurity(project, participant.ID, teamSecurity, visible);
        }

        public void SetTeamSecurity(Project project, Guid participant, ProjectTeamSecurity teamSecurity, bool visible)
        {
            if (project == null) throw new ArgumentNullException("project");

            ProjectSecurity.DemandEditTeam(project);

            var security = DaoFactory.ProjectDao.GetTeamSecurity(project.ID, participant);
            if (visible)
            {
                if (security != ProjectTeamSecurity.None) security ^= teamSecurity;
            }
            else
            {
                security |= teamSecurity;
            }
            DaoFactory.ProjectDao.SetTeamSecurity(project.ID, participant, security);
        }

        public void SetTeamSecurity(Project project, Guid participant, ProjectTeamSecurity teamSecurity)
        {
            if (project == null) throw new ArgumentNullException("project");

            ProjectSecurity.DemandEditTeam(project);

            DaoFactory.ProjectDao.SetTeamSecurity(project.ID, participant, teamSecurity);
        }

        public void SetTeamSecurity(int projectId, Participant participant)
        {
            DaoFactory.ProjectDao.SetTeamSecurity(projectId, participant.ID, participant.ProjectTeamSecurity);
        }

        public void ResetTeamSecurity(Project project)
        {
            if (project == null) throw new ArgumentNullException("project");

            ProjectSecurity.DemandEditTeam(project);

            var participant = GetTeam(project.ID);

            foreach (var part in participant)
            {
                DaoFactory.ProjectDao.SetTeamSecurity(project.ID, part.ID, ProjectTeamSecurity.None);
            }

        }

        public bool GetTeamSecurity(Project project, Participant participant, ProjectTeamSecurity teamSecurity)
        {
            if (project == null) throw new ArgumentNullException("project");
            if (participant == null) throw new ArgumentNullException("participant");

            var security = DaoFactory.ProjectDao.GetTeamSecurity(project.ID, participant.ID);
            return (security & teamSecurity) != teamSecurity;
        }

        public ProjectTeamSecurity GetTeamSecurity(Project project, Guid participant)
        {
            if (project == null) throw new ArgumentNullException("project");

            return DaoFactory.ProjectDao.GetTeamSecurity(project.ID, participant);
        }

        public IEnumerable<ParticipantFull> GetTeamUpdates(DateTime from, DateTime to)
        {
            return DaoFactory.ProjectDao.GetTeamUpdates(from, to).Where(x => CanRead(x.Project));
        }

        public DateTime GetTeamMaxLastModified()
        {
            return DaoFactory.ProjectDao.GetTeamMaxLastModified();
        }

        #endregion
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Test/MilestonesTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Web.Projects.Test
{
    using NUnit.Framework;

    [TestFixture]
    public class MilestonesTest : BaseTest
    {
        [Test]
        public void Milestone()
        {
            var newMilestone = GenerateMilestone();

            SaveOrUpdate(newMilestone);

            Assert.AreNotEqual(newMilestone.ID, 0);


            var result = Get(newMilestone);

            Assert.AreEqual(newMilestone.ID, result.ID);


            newMilestone.Title = "NewTitle";

            SaveOrUpdate(newMilestone);

            var updatedMilestone = Get(newMilestone);

            Assert.AreEqual(updatedMilestone.Title, newMilestone.Title);


            Delete(newMilestone);

            var deletedMilestone = Get(newMilestone);

            Assert.IsNull(deletedMilestone);
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/POP3/Server/POP3_eArgs_GetMessageStream.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.POP3.Server
{
    #region usings

    using System;
    using System.IO;

    #endregion

    /// <summary>
    /// Provides data to POP3 server event GetMessageStream.
    /// </summary>
    public class POP3_eArgs_GetMessageStream
    {
        #region Members

        private readonly POP3_Message m_pMessageInfo;
        private readonly POP3_Session m_pSession;
        private bool m_CloseMessageStream = true;
        private bool m_MessageExists = true;
        private long m_MessageStartOffset;
        private Stream m_MessageStream;

        #endregion

        #region Properties

        /// <summary>
        /// Gets reference to current POP3 session.
        /// </summary>
        public POP3_Session Session
        {
            get { return m_pSession; }
        }

        /// <summary>
        /// Gets message info what message stream to get.
        /// </summary>
        public POP3_Message MessageInfo
        {
            get { return m_pMessageInfo; }
        }

        /// <summary>
        /// Gets or sets if message stream is closed automatically if all actions on it are completed.
        /// Default value is true.
        /// </summary>
        public bool CloseMessageStream
        {
            get { return m_CloseMessageStream; }

            set { m_CloseMessageStream = value; }
        }

        /// <summary>
        /// Gets or sets message stream. When setting this property Stream position must be where message begins.
        /// </summary>
        public Stream MessageStream
        {
            get
            {
                if (m_MessageStream != null)
                {
                    m_MessageStream.Position = m_MessageStartOffset;
                }
                return m_MessageStream;
            }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("Property MessageStream value can't be null !");
                }
                if (!value.CanSeek)
                {
                    throw new Exception("Stream must support seeking !");
                }

                m_MessageStream = value;
                m_MessageStartOffset = m_MessageStream.Position;
            }
        }

        /// <summary>
        /// Gets message size in bytes.
        /// </summary>
        public long MessageSize
        {
            get
            {
                if (m_MessageStream == null)
                {
                    throw new Exception("You must set MessageStream property first to use this property !");
                }
                else
                {
                    return m_MessageStream.Length - m_MessageStream.Position;
                }
            }
        }

        /// <summary>
        /// Gets or sets if message exists. Set this false, if message actually doesn't exist any more.
        /// </summary>
        public bool MessageExists
        {
            get { return m_MessageExists; }

            set { m_MessageExists = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="session">Reference to current POP3 session.</param>
        /// <param name="messageInfo">Message info what message items to get.</param>
        public POP3_eArgs_GetMessageStream(POP3_Session session, POP3_Message messageInfo)
        {
            m_pSession = session;
            m_pMessageInfo = messageInfo;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/Services/ASC.Mail.Aggregator.CollectionService/Program.Options.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using CommandLine;
using CommandLine.Text;

namespace ASC.Mail.Aggregator.CollectionService
{
    public class Options
    {
        [OptionList('u', "users", MetaValue = "STRING ARRAY", Required = false, HelpText = "An array of users for which the aggregator will take tasks. " +
                                                                                           "Separator = ';' " +
                                                                                           "Example: -u\"{tl_userId_1}\";\"{tl_userId_2}\";\"{tl_userId_3}\"", Separator = ';')]
        public IList<string> OnlyUsers { get; set; }

        [Option("console", Required = false, HelpText = "Console state")]
        public bool IsConsole { get; set; }

        [Option("unlimit", Required = false, HelpText = "Unlimit messages per mailbox session")]
        public bool NoMessagesLimit { get; set; }

        [HelpOption]
        public string GetUsage()
        {
            return HelpText.AutoBuild(this, current => HelpText.DefaultParsingErrorsHandler(this, current));
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_SVGroupHFCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// Implements same single value header fields group. Group can contain one type header fields only.
    /// This is class is used by Authorization:,Proxy-Authorization:, ... .
    /// </summary>
    public class SIP_SVGroupHFCollection<T> where T : SIP_t_Value
    {
        #region Members

        private readonly string m_FieldName = "";
        private readonly List<SIP_SingleValueHF<T>> m_pFields;
        private readonly SIP_Message m_pMessage;

        #endregion

        #region Properties

        /// <summary>
        /// Gets header field name what this group holds.
        /// </summary>
        public string FieldName
        {
            get { return m_FieldName; }
        }

        /// <summary>
        /// Gets number of header fields in this group.
        /// </summary>
        public int Count
        {
            get { return m_pFields.Count; }
        }

        /// <summary>
        /// Gets header fields what are in this group.
        /// </summary>
        public SIP_SingleValueHF<T>[] HeaderFields
        {
            get { return m_pFields.ToArray(); }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner message that owns this group.</param>
        /// <param name="fieldName">Header field name what group holds.</param>
        public SIP_SVGroupHFCollection(SIP_Message owner, string fieldName)
        {
            m_pMessage = owner;
            m_FieldName = fieldName;

            m_pFields = new List<SIP_SingleValueHF<T>>();

            Refresh();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Adds specified header field value to the end of header.
        /// </summary>
        /// <param name="value">Header field value.</param>
        public void Add(string value)
        {
            m_pMessage.Header.Add(m_FieldName, value);
            Refresh();
        }

        /// <summary>
        /// Removes header field from specified index.
        /// </summary>
        /// <param name="index">Index of the header field what to remove. Index is relative ths group.</param>
        public void Remove(int index)
        {
            m_pMessage.Header.Remove(m_pFields[index]);
            m_pFields.RemoveAt(index);
        }

        /// <summary>
        /// Removes specified header field from header.
        /// </summary>
        /// <param name="field">Header field to remove.</param>
        public void Remove(SIP_SingleValueHF<T> field)
        {
            m_pMessage.Header.Remove(field);
            m_pFields.Remove(field);
        }

        /// <summary>
        /// Removes all this gorup header fields from header.
        /// </summary>
        public void RemoveAll()
        {
            foreach (SIP_SingleValueHF<T> h in m_pFields)
            {
                m_pMessage.Header.Remove(h);
            }
            m_pFields.Clear();
        }

        /// <summary>
        /// Gets the first(Top-Most) header field. Returns null if no header fields.
        /// </summary>
        /// <returns>Returns first header field or null if no header fields.</returns>
        public SIP_SingleValueHF<T> GetFirst()
        {
            if (m_pFields.Count > 0)
            {
                return m_pFields[0];
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Gets all header field values.
        /// </summary>
        /// <returns></returns>
        public T[] GetAllValues()
        {
            List<T> retVal = new List<T>();
            foreach (SIP_SingleValueHF<T> hf in m_pFields)
            {
                retVal.Add(hf.ValueX);
            }

            return retVal.ToArray();
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Refreshes header fields in group from actual header.
        /// </summary>
        private void Refresh()
        {
            m_pFields.Clear();

            foreach (SIP_HeaderField h in m_pMessage.Header)
            {
                if (h.Name.ToLower() == m_FieldName.ToLower())
                {
                    m_pFields.Add((SIP_SingleValueHF<T>) h);
                }
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Utils/PdfQueueWorker.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Common.Logging;
using ASC.Common.Threading.Progress;
using ASC.Common.Web;
using ASC.Core;
using ASC.CRM.Core;

namespace ASC.Web.CRM.Classes
{
    public class PdfQueueWorker
    {
        private static readonly ProgressQueue Queue = new ProgressQueue(Global.GetQueueWorkerCount("pdf"), Global.GetQueueWaitInterval("pdf"), true);

        public static string GetTaskId(int tenantId, int invoiceId)
        {
            return string.Format("{0}_{1}", tenantId, invoiceId);
        }

        public static PdfProgressItem GetTaskStatus(int tenantId, int invoiceId)
        {
            var id = GetTaskId(tenantId, invoiceId);
            return Queue.GetStatus(id) as PdfProgressItem;
        }

        public static void TerminateTask(int tenantId, int invoiceId)
        {
            var item = GetTaskStatus(tenantId, invoiceId);

            if (item != null)
                Queue.Remove(item);
        }

        public static PdfProgressItem StartTask(HttpContext context, int tenantId, Guid userId, int invoiceId)
        {
            lock (Queue.SynchRoot)
            {
                var task = GetTaskStatus(tenantId, invoiceId);

                if (task != null && task.IsCompleted)
                {
                    Queue.Remove(task);
                    task = null;
                }

                if (task == null)
                {
                    task = new PdfProgressItem(context, tenantId, userId, invoiceId);
                    Queue.Add(task);
                }

                if (!Queue.IsStarted)
                    Queue.Start(x => x.RunJob());

                return task;
            }
        }
    }

    public class PdfProgressItem : IProgressItem
    {
        private readonly string _contextUrl;
        private readonly int _tenantId;
        private readonly int _invoiceId;
        private readonly Guid _userId;

        public object Id { get; set; }
        public object Status { get; set; }
        public object Error { get; set; }
        public double Percentage { get; set; }
        public bool IsCompleted { get; set; }

        public PdfProgressItem(HttpContext context, int tenantId, Guid userId, int invoiceId)
        {
            _contextUrl = context != null ? context.Request.GetUrlRewriter().ToString() : null;
            _tenantId = tenantId;
            _invoiceId = invoiceId;
            _userId = userId;

            Id = PdfQueueWorker.GetTaskId(tenantId, invoiceId);
            Status = ProgressStatus.Queued;
            Error = null;
            Percentage = 0;
            IsCompleted = false;
        }

        public void RunJob()
        {
            try
            {
                Percentage = 0;
                Status = ProgressStatus.Started;

                CoreContext.TenantManager.SetCurrentTenant(_tenantId);

                SecurityContext.AuthenticateMe(_userId);

                if (HttpContext.Current == null && !WorkContext.IsMono)
                {
                    HttpContext.Current = new HttpContext(
                        new HttpRequest("hack", _contextUrl, string.Empty),
                        new HttpResponse(new System.IO.StringWriter()));
                }

                PdfCreator.CreateAndSaveFile(_invoiceId);

                Percentage = 100;
                Status = ProgressStatus.Done;
            }
            catch (Exception ex)
            {
                LogManager.GetLogger("ASC.Web").Error(ex);
                Percentage = 0;
                Status = ProgressStatus.Failed;
                Error = ex.Message;
            }
            finally
            {
                // fake httpcontext break configuration manager for mono
                if (!WorkContext.IsMono)
                {
                    if (HttpContext.Current != null)
                    {
                        new DisposableHttpContext(HttpContext.Current).Dispose();
                        HttpContext.Current = null;
                    }
                }

                IsCompleted = true;
            }
        }

        public object Clone()
        {
            return MemberwiseClone();
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/Multilang/tagMLDETECTCP.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Text;

namespace MultiLanguage
{
    public enum MLDETECTCP {
        // Default setting will be used. 
        MLDETECTCP_NONE = 0,

        // Input stream consists of 7-bit data. 
        MLDETECTCP_7BIT = 1,

        // Input stream consists of 8-bit data. 
        MLDETECTCP_8BIT = 2,

        // Input stream consists of double-byte data. 
        MLDETECTCP_DBCS = 4,

        // Input stream is an HTML page. 
        MLDETECTCP_HTML = 8,

        //Not currently supported. 
        MLDETECTCP_NUMBER = 16
    } 
}


<|start_filename|>module/ASC.Api/ASC.Api.Community/Wiki/FileWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

using ASC.Api.Employee;
using ASC.Specific;
using ASC.Web.UserControls.Wiki;
using ASC.Web.UserControls.Wiki.Data;

namespace ASC.Api.Wiki.Wrappers
{
    [DataContract(Name = "file", Namespace = "")]
    public class FileWrapper
    {
        [DataMember(Order = 0)]
        public string Name { get; set; }

        [DataMember(Order = 1)]
        public EmployeeWraper UpdatedBy { get; set; }

        [DataMember(Order = 2)]
        public ApiDateTime Updated { get; set; }

        [DataMember(Order = 3)]
        public string Location { get; set; }

        public FileWrapper(File file)
        {
            Name = file.FileName;
            UpdatedBy = EmployeeWraper.Get(Core.CoreContext.UserManager.GetUsers(file.UserID));
            Updated = (ApiDateTime)file.Date;
            Location = file.FileLocation;
        }

        public FileWrapper()
        {

        }

        public static FileWrapper GetSample()
        {
            return new FileWrapper
            {
                Name = "File name",
                Location = WikiEngine.GetFileLocation("File name"),
                Updated = ApiDateTime.GetSample(),
                UpdatedBy = EmployeeWraper.GetSample()
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/People/Core/Import/ContactInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using ASC.Web.People.Resources;

namespace ASC.Web.People.Core.Import
{
    public class ContactInfo
    {
        private string firstName;
        private string lastName;
        private string email;

        [Resource("FirstName")]
        public string FirstName
        {
            get { return (firstName ?? "").Trim(); }
            set { firstName = value; }
        }

        [Resource("LastName")]
        public string LastName
        {
            get { return (lastName ?? "").Trim(); }
            set { lastName = value; }
        }

        [Resource("Email")]
        public string Email
        {
            get { return (email ?? "").Trim(); }
            set { email = value; }
        }

        public static List<KeyValuePair<string, string>> GetColumns()
        {
            return typeof(ContactInfo).GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Select(r =>
                {
                    var attr = r.GetCustomAttribute<ResourceAttribute>();
                    return new KeyValuePair<string, string>(attr.Title,
                        PeopleResource.ResourceManager.GetString(attr.Title));
                }).ToList();
        }

        public override bool Equals(object obj)
        {
            try
            {
                if (obj is ContactInfo)
                {
                    var o = obj as ContactInfo;
                    return Email.Equals(o.Email);
                }
            }
            catch
            {
            }

            return false;
        }

        public override int GetHashCode()
        {
            return Email.GetHashCode();
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class ResourceAttribute : Attribute
    {
        public string Title { get; private set; }

        public ResourceAttribute(string title)
        {
            Title = title;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/LdapSettings/js/ldapsettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var LdapSettings = new function () {
    var alreadyChecking = false,
        already = false,
        previousSettings = null,
        progressBarIntervalId = null,
        objectSettings = null,
        isRestoreDefault = jq(".ldap-settings-main-container").hasClass("ldap-settings-is-default"),

        currentCron = null,
        currentSettings = null,

        syncInProgress = false,
        constants = {
            NULL_PERCENT: 0,
            SSL_LDAP_PORT: 636,
            DEFAULT_LDAP_PORT: 389,
            GET_STATUS_TIMEOUT: 1000
        },

        ldapCertificateProblem = {
            CertExpired: -2146762495,
            CertValidityPeriodNesting: -2146762494,
            CertRole: -2146762493,
            CertPathLenConst: -2146762492,
            CertCritical: -2146762491,
            CertPurpose: -2146762490,
            CertIssuerChaining: -2146762489,
            CertMalformed: -2146762488,
            CertUntrustedRoot: -2146762487,
            CertChainnig: -2146762486,
            CertRevoked: -2146762484,
            CertUntrustedTestRoot: -2146762483,
            CertRevocationFailure: -2146762482,
            CertCnNoMatch: -2146762481,
            CertWrongUsage: -2146762480,
            CertUntrustedCa: -2146762478,
            CertUnrecognizedError: -2146762477
        },

        ldapSecurityRes = {
            fullAccess: ASC.Resources.Master.ResourceJS.SecurityMappingFullAccess,
            documents: ASC.Resources.Master.ResourceJS.SecurityMappingDocuments,
            projects: ASC.Resources.Master.ResourceJS.SecurityMappingProjects,
            crm: ASC.Resources.Master.ResourceJS.SecurityMappingCrm,
            community: ASC.Resources.Master.ResourceJS.SecurityMappingCommunity,
            people: ASC.Resources.Master.ResourceJS.SecurityMappingPeople,
            mail: ASC.Resources.Master.ResourceJS.SecurityMappingMail
        },

        ldapMappingRes = {
            FirstNameAttribute: ASC.Resources.Master.ResourceJS.MappingFirstNameAttribute,
            SecondNameAttribute: ASC.Resources.Master.ResourceJS.MappingSecondNameAttribute,
            BirthDayAttribute: ASC.Resources.Master.ResourceJS.MappingBirthDayAttribute,
            GenderAttribute: ASC.Resources.Master.ResourceJS.MappingGenderAttribute,
            MobilePhoneAttribute: ASC.Resources.Master.ResourceJS.MappingMobilePhoneAttribute,
            MailAttribute: ASC.Resources.Master.ResourceJS.MappingMailAttribute,
            TitleAttribute: ASC.Resources.Master.ResourceJS.MappingTitleAttribute,
            LocationAttribute: ASC.Resources.Master.ResourceJS.MappingLocationAttribute,
            AvatarAttribute: ASC.Resources.Master.ResourceJS.MappingAvatarAttribute,
            AdditionalPhone: ASC.Resources.Master.ResourceJS.MappingAdditionalPhone,
            AdditionalMobilePhone: ASC.Resources.Master.ResourceJS.MappingAdditionalMobilePhone,
            AdditionalMail: ASC.Resources.Master.ResourceJS.MappingAdditionalMail,
            Skype: ASC.Resources.Master.ResourceJS.MappingSkype
        },

        $ldapSettingsServer = jq("#ldapSettingsServer"),
        $ldapSettingsUserDN = jq("#ldapSettingsUserDN"),
        $ldapSettingsPortNumber = jq("#ldapSettingsPortNumber"),
        $ldapSettingsUserFilter = jq("#ldapSettingsUserFilter"),
        $ldapSettingsLoginAttribute = jq("#ldapSettingsLoginAttribute"),
        $ldapSettingsGroupDN = jq("#ldapSettingsGroupDN"),
        $ldapSettingsUserAttribute = jq("#ldapSettingsUserAttribute"),
        $ldapSettingsGroupFilter = jq("#ldapSettingsGroupFilter"),
        $ldapSettingsGroupAttribute = jq("#ldapSettingsGroupAttribute"),
        $ldapSettingsGroupNameAttribute = jq("#ldapSettingsGroupNameAttribute"),
        $ldapSettingsLogin = jq("#ldapSettingsLogin"),
        $ldapSettingsPassword = jq("#ldapSettingsPassword"),

        $ldapSettingsError = jq("#ldapSettingsError"),
        $ldapSettingsSyncError = jq("#ldapSettingsSyncError"),

        $ldapSettingsSyncBtn = jq("#ldapSettingsSyncBtn"),
        $ldapSettingsRestoreBtn = jq("#ldapSettingsRestoreBtn"),


        $ldapSettingsSaveBtn = jq(".ldap-settings-save"),
        $ldapSettingsMainContainer = jq(".ldap-settings-main-container"),

        $ldapSettingsSyncSource = jq("#ldapSettingsSyncSource"),
        $ldapSettingsSource = jq("#ldapSettingsSource"),
        $ldapSettingsStatus = jq("#ldapSettingsStatus"),
        $ldapSettingsPercent = jq("#ldapSettingsPercent"),

        $ldapSettingsProgressbarContainer = jq(".ldap-settings-progressbar-container"),
        $ldapSettingsProgressValue = $ldapSettingsProgressbarContainer.find(".asc-progress-value"),

        $ldapSettingsSyncProgressbarContainer = jq(".ldap-settings-sync-progressbar-container"),
        $ldapSettingsSyncProgressValue = $ldapSettingsSyncProgressbarContainer.find(".asc-progress-value"),

        $ldapSettingsCronContainer = jq("#ldapSettingsCronContainer"),
        $ldapSettingsAutoSyncBtn = jq("#ldapSettingsAutoSyncBtn"),

        $ldapSettingsUserContainer = jq(".ldap-settings-user-container"),
        $ldapSettingsGroupContainer = jq(".ldap-settings-group-container"),
        $ldapSettingsAuthContainer = jq(".ldap-settings-auth-container"),
        $ldapSettingsSecurityContainer = jq(".ldap-settings-security-container"),
        $ldapSettingsAdvancedContainer = jq(".ldap-settings-advanced-container"),

        $ldapSettingsStartTlsCheckbox = jq("#ldapSettingsStartTLSCheckbox"),
        $ldapSettingsSslCheckbox = jq("#ldapSettingsSslCheckbox"),

        $ldapSettingsAuthBtn = jq("#ldapSettingsAuthenticationCheckbox"),
        $ldapSettingsBtn = jq("#ldapSettingsCheckbox"),

        $ldapSettingsSyncStatus = jq("#ldapSettingsSyncStatus"),
        $ldapSettingsSyncPercent = jq("#ldapSettingsSyncPercent"),

        $ldapSettingsGroupBtn = jq("#ldapSettingsGroupCheckbox"),

        $ldapSettingsAutoSync = jq("#ldapAutoSyncCont"),
        $ldapSettingsCron = jq("#ldapSettingsAutoSyncCron"),
        $ldapSettingsCronInput = jq("#ldapSettingsAutoSyncCronInput"),
        $ldapCronEditLink = jq("#ldapCronEditLink, #ldapCronHumanText"),
        $ldapSettingsAutoSyncDialog = jq("#ldapSettingsCronDialog"),
        $ldapNextSyncFields = jq(".cronHumanReadable"),

        $ldapSettingsSendWelcomeEmailCheckbox = jq("#ldapSettingsSendWelcomeEmail"),

        $ldapSettingsInviteDialog = jq("#ldapSettingsInviteDialog"),
        $ldapSettingsCertificateValidationDialog = jq("#ldapSettingsCertificateValidationDialog"),
        $ldapSettingsTurnOffDialog = jq("#ldapSettingsTurnOffDialog"),
        $ldapSettingsCronTurnOffDialog = jq("#ldapSettingsCronTurnOffDialog"),
        $ldapSettingsSpoilerLink = jq(".ldap-settings-spoiler-link"),
        $ldapSettingsSpoiler = jq("#ldapSettingsSpoiler"),

        $ldapMappingSecurity = jq("#ldapMappingSecurity"),
        $ldapMappingAddAccess = jq("#ldapMappingAddAccess"),

        $ldapMappingAddBtn = jq("#ldapMappingAddBtn"),
        $ldapMappingSettings = jq("#ldapMappingSettings"),
        $studioPageContent = jq('#studioPageContent'),
        ldapMappingOptions,
        ldapMappingRequiredOptions = ["FirstNameAttribute", "SecondNameAttribute", "MailAttribute"],

        $ldapSettingsImportUserLimitPanel = jq("#ldapSettingsImportUserLimitPanel"),

        $ldapSettingsRestoreDefaultSettings = jq(".ldap-settings-restore-default-settings"),
        $view = jq('.studio-container');


    var init = function () {


        function buildMappingOptions(collection) {
            var htmlMappingOptions = "";

            for (var key in collection) {
                htmlMappingOptions += "<div class=\"option\" data-value=\"" + key + "\">" + Encoder.htmlEncode(collection[key]) + "</div>";
            }

            return htmlMappingOptions;
        }

        if (jq("#ldapBlock").hasClass("disable")) {
            jq("#ldapBlock").find("input").prop("disabled", true);
            jq("#ldapSettingsSyncBtn").addClass("disable");
            return;
        }

        Teamlab.getLdapCronSettings({}, {
            success: onGetLdapCronSettings,
            error: onFailApi
        });

        $ldapSettingsSpoilerLink.on('click', function () {
            spoiler.toggle('#ldapSettingsSpoiler', jq(this));
        });

        if (!$ldapSettingsSyncBtn.hasClass("disable")) {
            enableSync(true);
        }

        ldapMappingOptions = buildMappingOptions(ldapMappingRes);
        ldapSecurityOptions = buildMappingOptions(ldapSecurityRes);

        parseMappings($ldapMappingSettings, ldapMappingRes, ldapMappingOptions, ASC.Resources.Master.ResourceJS.LdapAttributeOrigin, ldapMappingRequiredOptions);
        parseMappings($ldapMappingSecurity, ldapSecurityRes, ldapSecurityOptions, ASC.Resources.Master.ResourceJS.LdapSecurityPlaceholder);

        currentSettings = getSettings();

        $studioPageContent.on('click', '.selectBox', showSelectOptions);
        $studioPageContent.on('click', '.selectBox .option', selectOption);

        if ($ldapSettingsBtn.hasClass("off")) {
            $ldapSettingsMainContainer.find("input").attr("disabled", true);
            $ldapSettingsMainContainer.find("textarea").attr("disabled", true);
            $ldapSettingsMainContainer.find(".selectBox:not(.locked)").addClass("disabled");
            $ldapMappingAddBtn.addClass("disable");
            $ldapMappingAddAccess.addClass("disabled");
            $ldapMappingSettings.find(".ldap-mapping-remove-row").addClass("disable");
            $ldapMappingSecurity.find(".ldap-mapping-remove-row").addClass("disable");

            $ldapSettingsGroupBtn.addClass("disable");

            $ldapSettingsAuthBtn.addClass("disable")

        } else {
            $ldapSettingsUserContainer.find("input").attr("disabled", false);
            $ldapSettingsUserContainer.find("textarea").attr("disabled", false);
            if ($ldapSettingsGroupContainer.hasClass("ldap-settings-disabled")) {
                $ldapSettingsGroupContainer.find("input").attr("disabled", true);
                $ldapSettingsGroupContainer.find("textarea").attr("disabled", true);
                $ldapMappingAddAccess.addClass("disabled");
                $ldapMappingSecurity.find(".ldap-mapping-remove-row").addClass("disable");
            } else {
                $ldapSettingsGroupContainer.find("input").attr("disabled", false);
                $ldapSettingsGroupContainer.find("textarea").attr("disabled", false);
                $ldapMappingAddAccess.removeClass("disabled");
                $ldapMappingSecurity.find(".ldap-mapping-remove-row").removeClass("disable");
            }

            if ($ldapSettingsAuthContainer.hasClass("ldap-settings-disabled")) {
                $ldapSettingsAuthContainer.find("input").attr("disabled", true);
            } else {
                $ldapSettingsAuthContainer.find("input").attr("disabled", false);
            }
        }

        if (!$ldapSettingsSaveBtn.hasClass("disable")) {
            enableSave(true);
        }

        if (!$ldapSettingsRestoreBtn.hasClass("disable")) {
            enableRestoreDefault(true);
        }

        if (!$ldapSettingsSyncBtn.hasClass("disable")) {
            enableSync(true);
        }

        jq("body").on("click", function (event) {
            var $selectors = $view.find('.selectBox');
            var target = (event.target) ? event.target : event.srcElement,
                element = jq(target);

            if (!element.is('.selectBox') && !element.is('.selectBoxValue') && !element.is('.selectBoxSwitch')) {
                $selectors.find('.selectOptionsBox').hide();
            } else {
                var curBox = element.is('.selectBox') ? element : element.parents('.selectBox:first');
                $selectors.not(curBox).find('.selectOptionsBox').hide();
            }
        });

        $ldapMappingAddBtn.click(function () {
            if (jq(this).hasClass("disable")) return;
            addMappingRow($ldapMappingSettings, "", "", "", ldapMappingOptions, ASC.Resources.Master.ResourceJS.LdapAttributeOrigin);
        });

        $ldapMappingAddAccess.click(function () {
            if (jq(this).hasClass("disable")) return;
            addMappingRow($ldapMappingSecurity, "", "", "", ldapSecurityOptions, ASC.Resources.Master.ResourceJS.LdapSecurityPlaceholder);
        });

        $ldapSettingsTurnOffDialog.on("click", ".ldap-settings-ok", function () {
            if (jq(this).hasClass("disabled"))
                return;

            enableLdap(false);
            closeDialog();
            saveSettings();

            if ($ldapSettingsSpoiler.hasClass("display-none")) {
                spoiler.toggle('#ldapSettingsSpoiler', $ldapSettingsSpoilerLink);
            }

            jq('html, body').animate({
                scrollTop: $ldapSettingsProgressbarContainer.offset().top
            }, 2000);
        });
        $ldapSettingsTurnOffDialog.on("click", ".ldap-settings-cancel", closeDialog);

        $ldapSettingsCronTurnOffDialog.on("click", ".ldap-settings-ok", function () {
            if (jq(this).hasClass("disabled"))
                return;

            $ldapSettingsAutoSyncBtn.addClass("off").removeClass("on");
            showCronEdit(false);
            saveCronSettings(true);
            closeDialog();
        });
        $ldapSettingsCronTurnOffDialog.on("click", ".ldap-settings-cancel", closeDialog);



        $ldapSettingsSslCheckbox.click(function () {
            var self = jq(this);

            if (self.is(":checked")) {
                $ldapSettingsStartTlsCheckbox.prop('checked', false);
                $ldapSettingsPortNumber.val(constants.SSL_LDAP_PORT);
            }
            else {
                $ldapSettingsPortNumber.val(constants.DEFAULT_LDAP_PORT);
            }
            refreshButtons();
        });

        $ldapSettingsStartTlsCheckbox.click(function () {
            var self = jq(this);
            if (self.hasClass("disabled"))
                return;

            if (self.is(":checked")) {
                $ldapSettingsSslCheckbox.prop('checked', false);
                $ldapSettingsPortNumber.val(constants.DEFAULT_LDAP_PORT);
            }
            refreshButtons();
        });

        $ldapSettingsBtn.on("click", onLdapEnabled);
        $ldapSettingsAutoSyncBtn.on("click", onAutoSyncEnabled);
        jq("#ldapCronEditLink").on("click", function (e) { onAutoSyncEnabled(e, true); });

        $ldapSettingsSendWelcomeEmailCheckbox.click(function () {
            if (jq(this).is(":checked")) {
                jq(this).removeClass("off").addClass("on");
            } else {
                jq(this).removeClass("on").addClass("off");
            }
        });
        $ldapSettingsGroupBtn.click(function () {

            if (jq(this).hasClass("disable")) return;

            if (jq(this).hasClass("off")) {
                jq(this).removeClass("off").addClass("on");
                $ldapSettingsGroupContainer.find("input").removeAttr("disabled");
                $ldapSettingsGroupContainer.removeClass("ldap-settings-disabled");
            } else {
                jq(this).removeClass("on").addClass("off");
                $ldapSettingsGroupContainer.find("input").attr("disabled", "");
                $ldapSettingsGroupContainer.addClass("ldap-settings-disabled");
            }
        });

        $ldapSettingsAuthBtn.click(function () {

            var $ldapSettingsAuthContainer = jq(".ldap-settings-auth-container");

            if (jq(this).hasClass("disable")) return;

            if (jq(this).hasClass("off")) {
                jq(this).removeClass("off").addClass("on");
                $ldapSettingsAuthContainer.find("input").removeAttr("disabled");
                $ldapSettingsAuthContainer.removeClass("ldap-settings-disabled");
            } else {
                jq(this).removeClass("on").addClass("off");
                $ldapSettingsAuthContainer.find("input").attr("disabled", "");
                $ldapSettingsAuthContainer.addClass("ldap-settings-disabled");
            }
        });

        $ldapSettingsCertificateValidationDialog.on("click",
            ".ldap-settings-ok",
            function () { continueSaveSettings(null, true); });
        $ldapSettingsCertificateValidationDialog.on("click",
            ".ldap-settings-cancel",
            function () {
                closeDialog();
            });

        $ldapSettingsAutoSyncDialog.on("click", ".ldap-sync-save", function () {
            if (jq(this).hasClass("disabled"))
                return;

            $ldapSettingsAutoSyncBtn.addClass("on").removeClass("off");
            showCronEdit(true);
            saveCronSettings();
            closeDialog();
            $ldapNextSyncFields.text(getNextValidDateFromCron($ldapSettingsCron.jqCronGetInstance().getCron()));
        });
        $ldapSettingsAutoSyncDialog.on("click", ".ldap-settings-cancel", function () {
            closeDialog();
            if (currentCron) {
                setTimeout(function () { $ldapSettingsCron.jqCronGetInstance().setCron(currentCron); }, 500);
            }
        });
        $ldapSettingsMainContainer.on("click", ".ldap-settings-restore-default-settings", restoreDefault);

        $ldapSettingsInviteDialog.on("click", ".ldap-settings-ok", restoreDefaultSettings);
        $ldapSettingsInviteDialog.on("click", ".ldap-settings-cancel", cancelDialog);
        $ldapSettingsImportUserLimitPanel.on("click", ".ldap-settings-ok", continueSaveSettings);
        $ldapSettingsImportUserLimitPanel.on("click", ".ldap-settings-cancel", cancelDialog);
        $ldapSettingsImportUserLimitPanel.on("click", ".cancelButton", cancelDialog);
        jq(document).keyup(function (e) {
            /* Escape Key */
            if (!$ldapSettingsImportUserLimitPanel.is(":hidden") && e.keyCode == 27) {
                cancelDialog();
            }
        });
        jq(".ldap-settings-main-container input").change(function () {
            isRestoreDefault = false;
            if ($ldapSettingsSaveBtn.hasClass("disable")) {
                $ldapSettingsSaveBtn.removeClass("disable");
                $ldapSettingsMainContainer.on("click", ".ldap-settings-save", saveSettings);
            }
            if ($ldapSettingsRestoreDefaultSettings.hasClass("disable")) {
                $ldapSettingsRestoreDefaultSettings.removeClass("disable");
                $ldapSettingsMainContainer.on("click", ".ldap-settings-restore-default-settings", restoreDefault);
            }
        });
        jq(".ldap-settings-main-container .textEdit").keyup(function () {
            isRestoreDefault = false;
            if ($ldapSettingsSaveBtn.hasClass("disable")) {
                $ldapSettingsSaveBtn.removeClass("disable");
                $ldapSettingsMainContainer.on("click", ".ldap-settings-save", saveSettings);
            }
            if ($ldapSettingsRestoreDefaultSettings.hasClass("disable")) {
                $ldapSettingsRestoreDefaultSettings.removeClass("disable");
                $ldapSettingsMainContainer.on("click", ".ldap-settings-restore-default-settings", restoreDefault);
            }
        });
    }

    function onGetLdapCronSettings(params, cron) {

        currentCron = Object.keys(cron).length === 0 ? "" : cron;
        if (currentCron === "") {
            $ldapSettingsAutoSyncBtn.removeClass("on").addClass("off");
            showCronEdit(false);
        } else {
            $ldapSettingsAutoSyncBtn.removeClass("off").addClass("on");
            showCronEdit(true);
        }

        $ldapSettingsCron.jqCron({
            enabled_year: false,
            texts: {
                en: {
                    empty: ASC.Resources.Master.ResourceJS.CronEmpty,
                    empty_minutes: ASC.Resources.Master.ResourceJS.CronEmptyMinutes,
                    empty_time_hours: ASC.Resources.Master.ResourceJS.CronEmptyTimeHours,
                    empty_time_minutes: ASC.Resources.Master.ResourceJS.CronEmptyTimeMinutes,
                    empty_day_of_week: ASC.Resources.Master.ResourceJS.CronEmptyDayOfWeek,
                    empty_day_of_month: ASC.Resources.Master.ResourceJS.CronEmptyDayOfMonth,
                    empty_month: ASC.Resources.Master.ResourceJS.CronEmptyMonth,
                    name_minute: ASC.Resources.Master.ResourceJS.CronNameMinute,
                    name_hour: ASC.Resources.Master.ResourceJS.CronNameHour,
                    name_day: ASC.Resources.Master.ResourceJS.CronNameDay,
                    name_week: ASC.Resources.Master.ResourceJS.CronNameWeek,
                    name_month: ASC.Resources.Master.ResourceJS.CronNameMonth,
                    name_year: ASC.Resources.Master.ResourceJS.CronNameYear,
                    text_period: ASC.Resources.Master.ResourceJS.CronTextPeriod,
                    text_mins: ASC.Resources.Master.ResourceJS.CronTextMins,
                    text_time: ASC.Resources.Master.ResourceJS.CronTextTime,
                    text_dow: ASC.Resources.Master.ResourceJS.CronTextDow,
                    text_month: ASC.Resources.Master.ResourceJS.CronTextMonth,
                    text_dom: ASC.Resources.Master.ResourceJS.CronTextDom,
                    error1: ASC.Resources.Master.ResourceJS.CronError1,
                    error2: ASC.Resources.Master.ResourceJS.CronError2,
                    error3: ASC.Resources.Master.ResourceJS.CronError3,
                    error4: ASC.Resources.Master.ResourceJS.CronError4,
                    first_last: [ASC.Resources.Master.ResourceJS.CronFirst, ASC.Resources.Master.ResourceJS.CronLast],
                    weekdays: [ASC.Resources.Master.ResourceJS.CronMonday, ASC.Resources.Master.ResourceJS.CronTuesday, ASC.Resources.Master.ResourceJS.CronWednesday, ASC.Resources.Master.ResourceJS.CronThursday, ASC.Resources.Master.ResourceJS.CronFriday, ASC.Resources.Master.ResourceJS.CronSaturday, ASC.Resources.Master.ResourceJS.CronSunday],
                    months: [ASC.Resources.Master.ResourceJS.CronJanuary, ASC.Resources.Master.ResourceJS.CronFebruary, ASC.Resources.Master.ResourceJS.CronMarch, ASC.Resources.Master.ResourceJS.CronApril, ASC.Resources.Master.ResourceJS.CronMay, ASC.Resources.Master.ResourceJS.CronJune, ASC.Resources.Master.ResourceJS.CronJuly, ASC.Resources.Master.ResourceJS.CronAugust, ASC.Resources.Master.ResourceJS.CronSeptember, ASC.Resources.Master.ResourceJS.CronOctober, ASC.Resources.Master.ResourceJS.CronNovember, ASC.Resources.Master.ResourceJS.CronDecember]
                }
            },
            default_value: currentCron || "0 0 0 ? * *",
            bind_to: $ldapSettingsCronInput,
            bind_method: {
                set: function ($element, value) {
                    var el;
                    if ($ldapSettingsAutoSyncDialog.is(":visible")) {
                        el = $ldapSettingsAutoSyncDialog.find(".cronHumanReadable");
                    } else {
                        el = $ldapNextSyncFields;
                    }
                    el = $ldapNextSyncFields;
                    el.text(getNextValidDateFromCron(value));
                    $element.val(value);
                }
            }
        }).children().first().on("cron:change", refreshButtons);
    }

    function enableInputs(on) {
        if (on) {
            $ldapSettingsBtn.removeClass("off").addClass("on");
            $ldapMappingAddBtn.removeClass("disable");

            $ldapMappingAddAccess.addClass("disabled");
            $ldapSettingsUserContainer.find("input").attr("disabled", false);

            $ldapSettingsUserContainer.find("textarea").attr("disabled", false);
            $ldapSettingsUserContainer.find(".selectBox:not(.locked)").removeClass("disabled");
            $ldapMappingSettings.find(".ldap-mapping-remove-row").removeClass("disable");
            $ldapMappingSecurity.find(".ldap-mapping-remove-row").addClass("disable");

            $ldapSettingsGroupBtn.removeClass("disable");

            $ldapSettingsUserContainer.removeClass("ldap-settings-disabled");
            $ldapSettingsSecurityContainer.removeClass("ldap-settings-disabled");
            $ldapSettingsAdvancedContainer.removeClass("ldap-settings-disabled");

            $ldapSettingsStartTlsCheckbox.attr("disabled", false);
            $ldapSettingsSslCheckbox.attr("disabled", false);

            $ldapSettingsSendWelcomeEmailCheckbox.attr("disabled", false);

            $ldapSettingsAutoSyncBtn.addClass("disable");

            if ($ldapSettingsGroupBtn.hasClass("on")) {
                $ldapSettingsGroupContainer.find("input").removeAttr("disabled");
                $ldapSettingsGroupContainer.find("textarea").removeAttr("disabled");
                $ldapSettingsGroupContainer.removeClass("ldap-settings-disabled");
                $ldapMappingAddAccess.removeClass("disabled");
                $ldapMappingSecurity.find(".ldap-mapping-remove-row").removeClass("disable");
            }
            $ldapSettingsAuthBtn.removeClass("disable");

            if ($ldapSettingsAuthBtn.hasClass("on")) {
                $ldapSettingsAuthContainer.find("input").attr("disabled", false);
                $ldapSettingsAuthContainer.removeClass("ldap-settings-disabled");
            }
        } else {
            $ldapSettingsBtn.removeClass("on").addClass("off");
            $ldapMappingAddBtn.addClass("disable");

            $ldapSettingsCronContainer.find("input").attr("disabled", true);
            $ldapSettingsCronContainer.find(".on_off_button").addClass("disabled");

            $ldapMappingAddAccess.addClass("disabled");

            $ldapSettingsGroupBtn.addClass("disable");

            $ldapSettingsAuthBtn.addClass("disable");

            $ldapSettingsMainContainer.find("input").attr("disabled", true);
            $ldapSettingsMainContainer.find("textarea").attr("disabled", true);
            $ldapSettingsUserContainer.find(".selectBox:not(.locked)").addClass("disabled");
            $ldapMappingSettings.find(".ldap-mapping-remove-row").addClass("disable");
            $ldapMappingSecurity.find(".ldap-mapping-remove-row").addClass("disable");
            $ldapSettingsStartTlsCheckbox.addClass("disabled");
            $ldapSettingsSslCheckbox.addClass("disabled");

            $ldapSettingsSendWelcomeEmailCheckbox.attr("disabled", true);

            $ldapSettingsAutoSyncBtn.removeClass("disable");
            $ldapSettingsUserContainer.addClass("ldap-settings-disabled");
            $ldapSettingsSecurityContainer.addClass("ldap-settings-disabled");
            $ldapSettingsAdvancedContainer.addClass("ldap-settings-disabled");
            $ldapSettingsGroupContainer.addClass("ldap-settings-disabled");
            $ldapSettingsAuthContainer.addClass("ldap-settings-disabled");
        }
    }

    function getNextValidDateFromCron(cron) {
        var now, m = moment();

        var parts = cron.split(" ");

        var mins = parts[1],
            hrs = parts[2],
            dow = parts[5];

        var offset = m.utcOffset();
        m.utc(offset);
        m.milliseconds(0).subtract(offset, "minutes");
        now = moment(m);

        m.seconds(0);
        m.minutes(mins);

        if (hrs !== "*") {
            m.hours(hrs);

            if (dow === "*") {
                if (m < now) {
                    m.add(1, "days");
                }
            } else {
                if (dow.length === 1) {
                    m.isoWeekday(parseInt(dow));

                    if (m < now) {
                        m.add(7, "days");
                    }
                } else {
                    if (dow[1] === "L") {
                        m.date(m.daysInMonth());

                        while (m.isoWeekday() != dow[0]) {
                            m.subtract(1, "days");
                        }

                        if (m < now) {
                            m.add(7, "days");

                            var month = m.month();

                            while (month === m.month()) {
                                m.add(7, "days");
                            }

                            m.subtract(7, "days");
                        }
                    } else {
                        m.date(1);
                        var month = m.month();
                        m.isoWeekday(parseInt(dow[0]));

                        if (month !== m.month()) {
                            m.add(7, "days");
                        }

                        if (m < now) {
                            m.add(1, "month");
                            m.date(1);

                            month = m.month();
                            m.isoWeekday(parseInt(dow[0]));

                            if (month !== m.month()) {
                                m.add(7, "days");
                            }
                        }
                    }
                }
            }
        } else {
            if (m < now) {
                m.add(1, "hours");
            }
        }

        return m.add(offset, "minutes").format("LLLL");
    }

    function refreshButtons() {
        isRestoreDefault = false;
        var settingsChanged = hasChanges();
        enableSave(settingsChanged);
        enableSync(!settingsChanged && currentSettings.EnableLdapAuthentication);
        enableRestoreDefault($ldapSettingsBtn.hasClass("on"));
        enableCron(currentSettings.EnableLdapAuthentication);
        enableMailCheckboxes($ldapSettingsBtn.hasClass("on") && jq(".ldap-mapping-row .selectBox[data-value=MailAttribute]").nextAll("input").val());
    }

    function enableProgress(enabled) {
        if (enabled) {
            if (syncInProgress) {
                $ldapSettingsProgressbarContainer.css({ "visibility": "hidden" });
                $ldapSettingsSyncProgressbarContainer.css({ "visibility": "visible" });
            } else {
                $ldapSettingsProgressbarContainer.css({ "visibility": "visible" });
                $ldapSettingsSyncProgressbarContainer.css({ "visibility": "hidden" });
            }
        } else {
            $ldapSettingsProgressbarContainer.css({ "visibility": "hidden" });
            $ldapSettingsSyncProgressbarContainer.css({ "visibility": "hidden" });
        }
    }
    
    function enableSave(enabled) {
        $ldapSettingsSaveBtn.toggleClass("disable", !enabled);

        if (enabled) {
            $ldapSettingsSaveBtn.off("click").on("click", saveSettings);
        } else {
            $ldapSettingsSaveBtn.off("click");
        }
    }

    function enableSync(enabled) {
        $ldapSettingsSyncBtn.toggleClass("disable", !enabled);

        if (enabled) {
            $ldapSettingsSyncBtn.off("click").on("click", syncUsersLDAP);
        } else {
            $ldapSettingsSyncBtn.off("click");
        }
    }

    function enableRestoreDefault(enabled) {
        $ldapSettingsRestoreBtn.toggleClass("disable", !enabled);

        if (enabled) {
            $ldapSettingsRestoreBtn.off("click").on("click", restoreDefault);
        } else {
            $ldapSettingsRestoreBtn.off("click");
        }
    }

    function enableCron(on) {

        $ldapSettingsAutoSyncBtn.toggleClass("disable", !on);
        if (!on) {
            $ldapSettingsAutoSyncBtn.removeClass("on").addClass("off");
        }

        showCronEdit($ldapSettingsAutoSyncBtn.hasClass("on"));
    }

    function showCronEdit(on) {
        if (on) {
            $ldapCronEditLink.show();
        } else {
            $ldapCronEditLink.hide();
        }
    }

    function enableMailCheckboxes(on) {
        if (on) {
            $ldapSettingsSendWelcomeEmailCheckbox.attr("disabled", false);
        } else {
            $ldapSettingsSendWelcomeEmailCheckbox.prop('checked', false).attr("disabled", true); 
        }
    }

    function enableLdap(on) {
        $ldapSettingsBtn.toggleClass("off", !on).toggleClass("on", on);

        if (on && $ldapSettingsSpoiler.hasClass("display-none")) {
            $ldapSettingsSpoilerLink.click();
        }

        enableInputs(on);

        HideRequiredError();

        onSettingsChanged();

    }

    function onLdapEnabled() {
        var $this = jq(this);

        if ($this.hasClass("disabled"))
            return;

        var on = $this.hasClass("off");

        if (currentSettings.EnableLdapAuthentication) {
            StudioBlockUIManager.blockUI("#ldapSettingsTurnOffDialog", 500);
        }
        else {
            enableLdap(on);
        }
    }

    function getSettings() {
        var enableLdapAuthentication = $ldapSettingsBtn.hasClass("on"),
            startTls = $ldapSettingsStartTlsCheckbox.is(":checked"),
            ssl = $ldapSettingsSslCheckbox.is(":checked"),
            sendWelcomeEmail = $ldapSettingsSendWelcomeEmailCheckbox.is(":checked"),
            server = $ldapSettingsServer.val(),
            userDN = $ldapSettingsUserDN.val(),
            portNumber = $ldapSettingsPortNumber.val(),
            userFilter = $ldapSettingsUserFilter.val(),
            loginAttribute = $ldapSettingsLoginAttribute.val(),
            ldapMapping = {},
            accessRights = {},
            groupMembership = $ldapSettingsGroupBtn.hasClass("on"),
            groupDN = $ldapSettingsGroupDN.val(),
            userAttribute = $ldapSettingsUserAttribute.val(),
            groupFilter = $ldapSettingsGroupFilter.val(),
            groupAttribute = $ldapSettingsGroupAttribute.val(),
            groupNameAttribute = $ldapSettingsGroupNameAttribute.val(),
            authentication = $ldapSettingsAuthBtn.hasClass("on"),
            login = $ldapSettingsLogin.val(),
            password = $ldapSettingsPassword.val();


        $ldapMappingSettings.children().each(function () {
            var select = (jq(this).children("div").attr("data-value") || "").trim();
            var input = (jq(this).children("input").val() || "").trim();

            if (!select || !input) return;

            if (ldapMapping[select] && !select.endsWith("Attribute")) {
                ldapMapping[select] += "," + input;
            } else {
                ldapMapping[select] = input;
            }
        });

        $ldapMappingSecurity.children().each(function () {
            var select = (jq(this).children("div").attr("data-value") || "").trim();
            var input = (jq(this).children("input").val() || "").trim();

            if (!select || !input) return;

            if (accessRights[select]) {
                accessRights[select] += "," + input;
            } else {
                accessRights[select] = input;
            }
        });

        var settings = {
            EnableLdapAuthentication: enableLdapAuthentication,
            StartTls: startTls,
            Ssl: ssl,
            SendWelcomeEmail: sendWelcomeEmail,
            Server: server,
            UserDN: userDN,
            PortNumber: portNumber,
            UserFilter: userFilter,
            LoginAttribute: loginAttribute,
            LdapMapping: ldapMapping,
            AccessRights: accessRights,
            GroupMembership: groupMembership,
            GroupDN: groupDN,
            UserAttribute: userAttribute,
            GroupFilter: groupFilter,
            GroupAttribute: groupAttribute,
            GroupNameAttribute: groupNameAttribute,
            Authentication: authentication,
            Login: login,
            Password: password
        };

        return settings;
    }


    function parseMappings(elem, res, options, placeholder, required) {
        var data_val = elem.attr("data-value");
        if (!data_val) return;
        var data = JSON.parse(data_val);
        elem.removeAttr("data-value");

        if (required) {
            for (var i = 0; i < required.length; i++) {
                var value = data[required[i]];
                addMappingRow(elem, required[i], value ? value : "", res[required[i]], options, placeholder, true);
            }
        }

        if (data) {
            for (var key in data) {
                if (required && required.includes(key)) {
                    continue;
                }

                if (data[key].includes(",")) {
                    var split = data[key].split(",");
                    for (var i = 0; i < split.length; i++) {
                        addMappingRow(elem, key, split[i], res[key], options, placeholder);
                    }
                } else {
                    addMappingRow(elem, key, data[key], res[key], options, placeholder);
                }
            }
        }
    }

    function refreshMappingOptions(el, options) {

        var uniqueKeys = [];
        var selects = el.find(".selectBox");
        selects.each(function () {
            var val = jq(this).attr("data-value");
            if (val.endsWith("Attribute"))
                uniqueKeys.push(val);
        }).each(function () {
            var sel = jq(this).attr("data-value");

            var currentOptions = jq(this).find(".selectOptionsInnerBox").html(options).children();
            currentOptions.filter(function () { return jq(this).attr("data-value") === sel }).addClass("selected");
            currentOptions.filter(function () {
                return !(uniqueKeys.indexOf(jq(this).attr("data-value")) < 0) && jq(this).attr("data-value") !== sel;
            }).remove();
        });
    }

    function addMappingRow(el, key, value, humanKey, options, placeholder, required) {
        key = key || "";
        value = value || "";

        jq("#ldapMappingFieldTmpl")
            .tmpl({ key: key, value: value, humanKey: humanKey, options: options, placeholder: placeholder, required: required }).appendTo(el);

        el.find(".ldap-mapping-remove-row").last().click(function () { removeMappingRow(el, jq(this), options); });
        var select = el.find(".selectBox").last();
        select.on("valueChanged", onSettingsChanged);
        select.on("valueChanged", function () { refreshMappingOptions(el, options); });

        if (required) {
            select.addClass("locked").addClass("disabled");
        }

        var input = el.find("input").last();
        input.change(refreshButtons)
            .keyup(refreshButtons)
            .on("paste", refreshButtons);

        refreshMappingOptions(el, options);
        if (!key) {
            var val = select.find(".selectOptionsInnerBox").children().first();
            select.attr("data-value", val.attr("data-value"));
            select.children(".selectBoxValue").text(val.text());
            refreshMappingOptions(el, options);
        }
    }

    function removeMappingRow(el, self, options) {
        if (self.hasClass("disable")) return;

        var row = self.parent();
        if (row.length && row.hasClass("ldap-mapping-row"))
            row.remove();
        refreshMappingOptions(el, options);
        refreshButtons();
    }

    function onSettingsChanged() {
        refreshButtons();
    }

    function hasChanges() {
        var nextSettings = getSettings();

        if (!currentSettings && !!nextSettings ||
            !!currentSettings && !nextSettings) {
            return true;
        }

        if (currentSettings.EnableLdapAuthentication !== nextSettings.EnableLdapAuthentication ||
            currentSettings.StartTls !== nextSettings.StartTls ||
            currentSettings.SendWelcomeEmail !== nextSettings.SendWelcomeEmail ||
            currentSettings.Server !== nextSettings.Server ||
            currentSettings.UserDN !== nextSettings.UserDN ||
            currentSettings.PortNumber !== nextSettings.PortNumber ||
            currentSettings.UserFilter !== nextSettings.UserFilter ||
            currentSettings.LoginAttribute !== nextSettings.LoginAttribute ||
            currentSettings.GroupMembership !== nextSettings.GroupMembership ||
            currentSettings.GroupDN !== nextSettings.GroupDN ||
            currentSettings.UserAttribute !== nextSettings.UserAttribute ||
            currentSettings.GroupFilter !== nextSettings.GroupFilter ||
            currentSettings.GroupAttribute !== nextSettings.GroupAttribute ||
            currentSettings.GroupNameAttribute !== nextSettings.GroupNameAttribute ||
            currentSettings.Authentication !== nextSettings.Authentication ||
            currentSettings.Login !== nextSettings.Login ||
            currentSettings.Password !== nextSettings.Password) {
            return true;
        }


        if (!isObjectsEqual(currentSettings.LdapMapping, nextSettings.LdapMapping)) {
            return true;
        }

        if (!isObjectsEqual(currentSettings.AccessRights, nextSettings.AccessRights)) {
            return true;
        }

        return false;
    }

    function showSelectOptions() {
        var $selector = jq(this);

        if ($selector.attr("disabled") || $selector.hasClass("disabled"))
            return;

        var $options = $selector.find('.selectOptionsBox');

        if ($options.is(':visible')) {
            $options.hide();
            $options.css('top', 0);
            $options.css('left', 0);
        } else {
            var offset = $selector.position();

            if ($options.is('.top')) {
                $options.css('top', offset.top - $options.outerHeight() - 3 + 'px');
                $options.css('left', offset.left + $selector.outerWidth() - $options.outerWidth() + 'px');
            } else {
                $options.css('top', offset.top + $selector.outerHeight() + 3 + 'px');
                $options.css('left', offset.left + $selector.outerWidth() - $options.outerWidth() + 'px');
            }

            $options.show();
        }
    }

    function selectOption() {

        var $option = jq(this),
            $select = $option.closest('.selectBox'),
            value = $option.attr('data-value');

        $select.find('.selectBoxValue').text($option.text());
        $select.attr('data-value', value);

        $option.closest('.selectOptionsBox').hide();
        $option.siblings('.option').removeClass('selected');
        $option.addClass('selected');

        $select.trigger("valueChanged", value);
    }

    function onAutoSyncEnabled(ev, edit) {

        var $this = jq(this);

        if ($this.hasClass("disable")) return;

        var on = $ldapSettingsAutoSyncBtn.hasClass("on");

        if (on && currentCron && !edit) {
            StudioBlockUIManager.blockUI("#ldapSettingsCronTurnOffDialog", 500);
            return;
        } else {
            if (currentCron) {
                $ldapSettingsCron.jqCronGetInstance().setCron(currentCron);
            }
            StudioBlockUIManager.blockUI("#ldapSettingsCronDialog", 500);
            return;
        }
    }

    function restoreDefaultSettings() {

        PopupKeyUpActionProvider.CloseDialog();
        HideRequiredError();
        setStatus("");
        setSource("");
        setPercents(constants.NULL_PERCENT);

        Teamlab.getLdapDefaultSettings({},
            {
                success: function (params, result) {

                    try {
                        if (result) {
                            loadSettings(result);
                            continueSaveSettings(null, true);
                        } else {
                            throw ASC.Resources.Master.ResourceJS.OperationFailedError;
                        }
                    } catch (error) {
                        showError(error);
                        currentSettings = previousSettings;
                        endProcess();
                    }
                },
                error: onFailApi
            });
    }

    function closeDialog() {
        PopupKeyUpActionProvider.CloseDialog();
        enableInterface(true);
        $ldapSettingsError.hide();
        $ldapSettingsSyncError.hide();
        enableProgress(false);
        refreshButtons();
        already = false;
    }

    function saveCronSettings(remove) {
        var newCron;

        if (remove) {
            newCron = null;
        } else {
            newCron = $ldapSettingsCronInput.val();
        }

        Teamlab.setLdapCronSettings({}, { cron: newCron }, {
            success: function () {
                currentCron = newCron;
            },
            error: onFailApi
        });
    }

    function syncUsersLDAP() {
        if (already) {
            return;
        }

        syncInProgress = true;
        disableInterface();
        previousSettings = currentSettings;
        setStatus("");
        setSource("");
        setPercents(constants.NULL_PERCENT);

        already = true;
        HideRequiredError();

        $ldapSettingsError.addClass("display-none");

        PopupKeyUpActionProvider.CloseDialog();
        disableInterface();

        Teamlab.syncLdap({},
            {
                success: function () {
                    setProgress(status);
                    progressBarIntervalId = setInterval(checkStatus, 600);
                },
                error: onFailApi
            });
    }

    function cancelDialog() {
        PopupKeyUpActionProvider.CloseDialog();
        already = false;
    }

    function isInt(str) {
        var n = ~~Number(str);
        return String(n) === str && n >= 0;
    }

    function restoreDefault() {
        var $this = jq(this);

        if ($this.hasClass("disable")) return;

        StudioBlockUIManager.blockUI("#ldapSettingsInviteDialog", 500);
        PopupKeyUpActionProvider.EnterAction = "LdapSettings.restoreDefaultSettings();";
    }

    function disableInterface() {
        setPercentsExactly(constants.NULL_PERCENT);
        $ldapSettingsError.hide();
        $ldapSettingsSyncError.hide();
        $ldapSettingsProgressbarContainer.removeClass("display-none");
        $ldapSettingsSaveBtn.addClass("disable");
        $ldapSettingsRestoreDefaultSettings.addClass("disable");
        jq(".ldap-settings-sync-users").addClass("disable");
        $ldapSettingsMainContainer.addClass("ldap-settings-disabled-all");
        $ldapSettingsMainContainer.find("input").attr("disabled", "");
        $ldapSettingsMainContainer.off("click", ".ldap-settings-save");
        $ldapSettingsMainContainer.off("click", ".ldap-settings-restore-default-settings");
        $ldapSettingsMainContainer.off("click", ".ldap-settings-sync-users");

        $ldapMappingSettings.find(".ldap-mapping-remove-row").addClass("disable");
        $ldapMappingAddBtn.attr("disabled", true).addClass("disable");

        enableRestoreDefault(false);
        enableSave(false);
        enableSync(false);
        enableProgress(true);
    }

    function enableInterface(cancel) {
        if (!cancel) {
            refreshButtons();
        }
        $ldapSettingsMainContainer.removeClass("ldap-settings-disabled-all");
        $ldapSettingsBtn.attr("disabled", false).removeClass("disable");
        if ($ldapSettingsBtn.hasClass("on")) {
            $ldapSettingsStartTlsCheckbox.removeClass("disabled").attr("disabled", false);
            $ldapSettingsSslCheckbox.removeClass("disabled").attr("disabled", false);
            $ldapSettingsUserContainer.find("input").attr("disabled", false);
            $ldapSettingsUserContainer.find("textarea").attr("disabled", false);
            $ldapSettingsUserContainer.find(".selectBox:not(.locked)").removeClass("disabled");
            $ldapSettingsUserContainer.find(".on-off-button").removeClass("disable");
            $ldapSettingsAutoSyncBtn.removeClass("disable");
            $ldapSettingsGroupBtn.removeClass("disable");

            $ldapMappingAddBtn.attr("disable", false).removeClass("disable");
            $ldapMappingSettings.find(".ldap-mapping-remove-row").removeClass("disable");

            if ($ldapSettingsGroupBtn.hasClass("on")) {
                $ldapSettingsGroupContainer.find("input").attr("disabled", false);
                $ldapSettingsGroupContainer.find("textarea").attr("disabled", false);
                $ldapSettingsGroupContainer.find(".selectBox:not(.locked)").removeClass("disabled");
                $ldapSettingsGroupContainer.find(".on-off-button").removeClass("disable");
                $ldapMappingAddAccess.attr("disabled", false).removeClass("disabled");
            }
            $ldapSettingsAuthBtn.removeClass("disable");
            if ($ldapSettingsAuthBtn.hasClass("on")) {
                $ldapSettingsAuthContainer.find("input").attr("disabled", false);
                $ldapSettingsAuthContainer.find(".on-off-button").removeClass("disable");
            }
            if ($ldapSettingsAutoSyncBtn.hasClass("on")) {
                $ldapSettingsAutoSync.find("input").attr("disabled", false);
                $ldapSettingsAutoSync.find(".selectBox:not(.locked)").removeClass("disabled");
            }
        }

    }

    function saveSettings() {
        if (already) {
            return;
        }

        already = true;

        HideRequiredError();

        objectSettings = getSettings();
        $ldapSettingsMainContainer.find(".ldap-settings-empty-field").addClass("display-none");
        $ldapSettingsMainContainer.find(".ldap-settings-incorrect-number").addClass("display-none");

        if (!validateSettings(objectSettings)) {
            already = false;
            return;
        }

        setStatus("");
        setSource("");
        setPercents(constants.NULL_PERCENT);

        if ($ldapSettingsBtn.hasClass("on")) {
            StudioBlockUIManager.blockUI("#ldapSettingsImportUserLimitPanel", 500);
            PopupKeyUpActionProvider.EnableEsc = false;
            PopupKeyUpActionProvider.EnterAction = "LdapSettings.continueSaveSettings();";
        } else {
            continueSaveSettings();
        }
    }

    function validateSettings(settings) {
        var isValid = true;

        var validateKeyValuePairs = function () {
            var $input = jq(this).children("input");
            var select = (jq(this).children("div").attr("data-value") || "").trim();
            var input = ($input.val() || "").trim();
            if (!select || !input) {
                jq(this).children(".requiredErrorText").text(ASC.Resources.Master.ResourceJS.LdapSettingsEmptyField);
                ShowRequiredError($input, !isValid, !isValid);
                isValid = false;
            }
        };

        if (settings.EnableLdapAuthentication) {
            if (settings.Server === "") {
                ShowRequiredError($ldapSettingsServer);
                isValid = false;
            }
            if (settings.UserDN === "") {
                ShowRequiredError($ldapSettingsUserDN, !isValid, !isValid);
                isValid = false;
            }
            if (settings.UserFilter === "") {
                ShowRequiredError($ldapSettingsUserFilter, !isValid, !isValid);
                isValid = false;
            }
            if (settings.PortNumber === "") {
                jq("#ldapSettingsPortNumberError").text(ASC.Resources.Master.ResourceJS.LdapSettingsEmptyField);
                ShowRequiredError($ldapSettingsPortNumber, !isValid, !isValid);
                isValid = false;
            } else if (!isInt(settings.PortNumber)) {
                jq("#ldapSettingsPortNumberError").text(ASC.Resources.Master.ResourceJS.LdapSettingsIncorrectPortNumber);
                ShowRequiredError($ldapSettingsPortNumber, !isValid, !isValid);
                isValid = false;
            }
            if (settings.LoginAttribute === "") {
                ShowRequiredError($ldapSettingsLoginAttribute, !isValid, !isValid);
                isValid = false;
            }

            $ldapMappingSettings.children().each(validateKeyValuePairs);

            var values = {};
            var uniqueErr = false;
            $ldapMappingSettings.children().each(function () {
                var val = jq(this).children("input").val();
                if (!val) return;

                var exist = values[val];
                if (exist) {
                    exist.children(".requiredErrorText").text("");
                    ShowRequiredError(exist.children("input"), !isValid, !isValid);
                    uniqueErr = true;
                    isValid = false;
                    jq(this).children(".requiredErrorText").text("");
                    ShowRequiredError(jq(this).children("input"), !isValid, !isValid);
                } else {
                    values[val] = jq(this);
                }
            });
            if (uniqueErr) toastr.error(ASC.Resources.Master.ResourceJS.ErrorBindingSameAttribute);

            if (settings.GroupMembership) {
                if (settings.GroupDN === "") {
                    ShowRequiredError($ldapSettingsGroupDN, !isValid, !isValid);
                    isValid = false;
                }
                if (settings.GroupFilter === "") {
                    ShowRequiredError($ldapSettingsGroupFilter, !isValid, !isValid);
                    isValid = false;
                }
                if (settings.UserAttribute === "") {
                    ShowRequiredError($ldapSettingsUserAttribute, !isValid, !isValid);
                    isValid = false;
                }
                if (settings.GroupAttribute === "") {
                    ShowRequiredError($ldapSettingsGroupAttribute, !isValid, !isValid);
                    isValid = false;
                }
                if (settings.GroupNameAttribute === "") {
                    ShowRequiredError($ldapSettingsGroupNameAttribute, !isValid, !isValid);
                    isValid = false;
                }

                $ldapMappingSecurity.children().each(validateKeyValuePairs);
            }
            if (settings.Authentication) {
                if (settings.Login === "") {
                    ShowRequiredError($ldapSettingsLogin, !isValid, !isValid);
                    isValid = false;
                }
                if (settings.Password === "") {
                    ShowRequiredError($ldapSettingsPassword, !isValid, !isValid);
                    isValid = false;
                }
            }
        }

        return isValid;
    }

    function continueSaveSettings(e, acceptCertificate) {

        PopupKeyUpActionProvider.CloseDialog();

        syncInProgress = false;

        disableInterface();

        if (!acceptCertificate) {
            acceptCertificate = false;
        }
        previousSettings = currentSettings;
        currentSettings = getSettings();

        Teamlab.saveLdapSettings({},
            {
                settings: JSON.stringify(currentSettings),
                acceptCertificate: acceptCertificate
            },
            {
                success: function (params, data) {
                    try {
                        var status = data;
                        if (status && status.id) {
                            setProgress(status);
                            progressBarIntervalId = setInterval(checkStatus, constants.GET_STATUS_TIMEOUT);
                        } else {
                            throw ASC.Resources.Master.ResourceJS.OperationFailedError;
                        }
                    } catch (error) {
                        showError(error);
                        currentSettings = previousSettings;
                        endProcess();
                    }
                },
                error: onFailApi
            });
    }

    function onFailApi(jqXHR, textStatus) {
        if (textStatus !== null && textStatus === "abort") {
            return;
        }
        showError(ASC.Resources.Master.ResourceJS.OperationFailedError);
        currentSettings = previousSettings;
        endProcess();
    }

    function endProcess() {
        if (progressBarIntervalId) {
            clearInterval(progressBarIntervalId);
        }
        already = false;
        enableInterface(false);
        if (isRestoreDefault) {
            enableRestoreDefault(false);
        }
    }

    function showError(error) {
        var errorMessage;

        if (typeof (error) === "string") {
            errorMessage = error;
        }
        else if (error.message) {
            errorMessage = error.message;
        } else if (error.responseText) {
            try {
                var json = JSON.parse(error.responseText);

                if (typeof (json) === "object") {
                    if (json.ExceptionMessage) {
                        errorMessage = json.ExceptionMessage;
                    }
                    else if (json.Message) {
                        errorMessage = json.Message;
                    }
                }
                else if (typeof (json) === "string") {
                    errorMessage = error.responseText.replace(/(^")|("$)/g, "");

                    if (!errorMessage.length && error.statusText) {
                        errorMessage = error.statusText;
                    }
                }
            } catch (e) {
                errorMessage = error.responseText;
            }
        } else if (error.statusText) {
            errorMessage = error.statusText;
        } else if (error.error) {
            errorMessage = error.error;
        }

        errorMessage = !errorMessage || typeof (errorMessage) !== "string" || !errorMessage.length ?
            ASC.Resources.Master.ResourceJS.OperationFailedError :
            errorMessage.replace(/(^")|("$)/g, "");

        if (!errorMessage.length) {
            console.error('showError failed with ', error);
            return;
        }

        if (syncInProgress) {
            $ldapSettingsSyncError.text(errorMessage);
            $ldapSettingsSyncError.show();
        } else {
            $ldapSettingsError.text(errorMessage);
            $ldapSettingsError.show();
        }
        setStatus("");
        setSource("");
        setPercents(constants.NULL_PERCENT);
        toastr.error(errorMessage);
    }

    function setProgress(status) {
        setPercents(status.percents);

        if (status.completed) {
            if (!status.error) {
                setStatus(ASC.Resources.Master.ResourceJS.LdapSettingsSuccess);
                setSource("");
            }
            else {

            }
        } else {
            setStatus(status.status);
            setSource(status.source);
        }
    }

    function checkStatus() {
        if (alreadyChecking) {
            return;
        }
        alreadyChecking = true;
        Teamlab.getLdapStatus({},
            {
                success: onGetStatus,
                error: function () {
                    alreadyChecking = false;
                }
            });
    }
    
    function mapError(error) {
        switch (error) {
            case ldapCertificateProblem.CertExpired:
                return ASC.Resources.Master.ResourceJS.LdapSettingsCertExpired;
            case ldapCertificateProblem.CertCnNoMatch:
                return ASC.Resources.Master.ResourceJS.LdapSettingsCertCnNoMatch;
            case ldapCertificateProblem.CertIssuerChaining:
                return ASC.Resources.Master.ResourceJS.LdapSettingsCertIssuerChaining;
            case ldapCertificateProblem.CertUntrustedCa:
                return ASC.Resources.Master.ResourceJS.LdapSettingsCertUntrustedCa;
            case ldapCertificateProblem.CertUntrustedRoot:
                return ASC.Resources.Master.ResourceJS.LdapSettingsCertUntrustedRoot;
            case ldapCertificateProblem.CertMalformed:
                return ASC.Resources.Master.ResourceJS.LdapSettingsCertMalformed;
            case ldapCertificateProblem.CertUnrecognizedError:
                return ASC.Resources.Master.ResourceJS.LdapSettingsCertUnrecognizedError;
            case ldapCertificateProblem.CertValidityPeriodNesting:
            case ldapCertificateProblem.CertRole:
            case ldapCertificateProblem.CertPathLenConst:
            case ldapCertificateProblem.CertCritical:
            case ldapCertificateProblem.CertPurpose:
            case ldapCertificateProblem.CertChainnig:
            case ldapCertificateProblem.CertRevoked:
            case ldapCertificateProblem.CertUntrustedTestRoot:
            case ldapCertificateProblem.CertRevocationFailure:
            case ldapCertificateProblem.CertWrongUsage:
                return "";
        }

        return "";
    }

    function onGetStatus(params, data) {
        alreadyChecking = false;
        try {

            if (data.error) {
                if (data.certificateConfirmRequest && data.certificateConfirmRequest.certificateErrors) {
                    var errors = data.certificateConfirmRequest.certificateErrors
                        .map((item) => mapError(item));
                    data.certificateConfirmRequest.certificateErrors = errors;
                }
            }

            var status = data;
            if (jq.isEmptyObject(data)) {
                status = {
                    completed: true,
                    percents: 100,
                    certificateConfirmRequest: null,
                    error: ""
                };
            }

            setProgress(status);

            if (status.warning && lastWarning !== status.warning) {
                lastWarning = status.warning;
                toastr.warning(status.warning, "", { timeOut: 0, extendedTimeOut: 0 });
            }

            if (isCompleted(status)) {
                lastWarning = "";

                if (status.error)
                    throw status.error;

                endProcess();
            }

        } catch (error) {
            showError(error);
            currentSettings = previousSettings;
            endProcess();
        }
    }

    function isCompleted(status) {
        if (!status)
            return true;

        if (!status.completed)
            return false;

        if (status.certificateConfirmRequest &&
            status.certificateConfirmRequest.requested) {
            setCertificateDetails(status.certificateConfirmRequest);
            currentSettings = previousSettings;
            /* popupId, width, height, marginLeft, marginTop */
            StudioBlockUIManager.blockUI("#ldapSettingsCertificateValidationDialog", 500);
            return true;
        }

        if (status.error) {
            return true;
        }

        toastr.success(ASC.Resources.Master.ResourceJS.LdapSettingsSuccess);
        return true;
    }

    function setCertificateDetails(certificateConfirmRequest) {
        $ldapSettingsCertificateValidationDialog.find(".ldap-settings-serial-number").text(certificateConfirmRequest.serialNumber);
        $ldapSettingsCertificateValidationDialog.find(".ldap-settings-issuer-name").text(certificateConfirmRequest.issuerName);
        $ldapSettingsCertificateValidationDialog.find(".ldap-settings-subject-name").text(certificateConfirmRequest.subjectName);
        $ldapSettingsCertificateValidationDialog.find(".ldap-settings-valid-from").text(certificateConfirmRequest.validFrom);
        $ldapSettingsCertificateValidationDialog.find(".ldap-settings-valid-until").text(certificateConfirmRequest.validUntil);
        $ldapSettingsCertificateValidationDialog.find(".ldap-settings-unique-hash").text(certificateConfirmRequest.hash);
        $ldapSettingsCertificateValidationDialog.find(".toast-container").remove();
        var html = jq("#ldapCrtErrorTmpl")
            .tmpl({
                errors: function () {
                    var certificateErrors = certificateConfirmRequest.certificateErrors,
                        errors = [];
                    for (var i = 0; i < certificateErrors.length; i++) {
                        errors[i] = {};
                        errors[i].message = certificateErrors[i];
                    }
                    return errors;
                }
            });
        $ldapSettingsCertificateValidationDialog.find(".ldap-settings-crt-details-last").after(html);
    }

    function setPercentsExactly(percents) {
        jq(".asc-progress-value").css("width", percents + "%");
        jq("#ldapSettingsPercent").text(percents + "% ");
    }

    function setPercents(percent) {
        if (percent === undefined)
            return;

        var value = percent + "%";

        if (syncInProgress) {
            if (percent === constants.NULL_PERCENT || percent <= lastPercent) {
                $ldapSettingsSyncProgressValue.css({ "width": value });
            } else {
                $ldapSettingsSyncProgressValue.animate({ "width": value });
            }
            $ldapSettingsSyncPercent.text(value + " ");
        } else {
            if (percent === constants.NULL_PERCENT || percent <= lastPercent) {
                $ldapSettingsProgressValue.css({ "width": value });
            } else {
                $ldapSettingsProgressValue.animate({ "width": value });
            }
            $ldapSettingsPercent.text(value + " ");
        }

        lastPercent = percent;
    }

    function setStatus(status) {
        if (syncInProgress)
            $ldapSettingsSyncStatus.text(status);
        else
            $ldapSettingsStatus.text(status);
    }

    function setSource(source) {
        if (syncInProgress)
            $ldapSettingsSyncSource.text(source);
        else
            $ldapSettingsSource.text(source);
    }
    function clearAllMappingRows(el) {
        el.find(".ldap-mapping-row").remove();
    }
    function loadSettings(settings) {
        if (settings) {
            if (settings["enableLdapAuthentication"]) {
                $ldapSettingsBtn.removeClass("off").addClass("on");
            } else {

                $ldapSettingsStartTlsCheckbox.prop('checked', false);
                $ldapSettingsSslCheckbox.prop('checked', false);
            }
            if (settings["startTls"]) {
                $ldapSettingsStartTlsCheckbox.prop('checked', true);
            } else {
                $ldapSettingsBtn.removeClass("on").addClass("off");
            }
            if (settings["ssl"]) {
                $ldapSettingsSslCheckbox.prop('checked', true);
            } else {
                $ldapSettingsBtn.removeClass("on").addClass("off");
            }
            if (settings["sendWelcomeEmail"] == "true") {
                $ldapSettingsSendWelcomeEmailCheckbox.prop('checked', true);
            }
            $ldapSettingsServer.val(settings["server"]);
            $ldapSettingsUserDN.val(settings["userDN"]);
            $ldapSettingsPortNumber.val(settings["portNumber"]);
            $ldapSettingsUserFilter.val(settings["userFilter"]);
            $ldapSettingsLoginAttribute.val(settings["loginAttribute"]);

            var ldapMapping = settings["ldapMapping"];
            var accessRights = settings["accessRights"];

            clearAllMappingRows($ldapMappingSettings);
            if (ldapMapping) {
                for (var key in ldapMapping) {
                    addMappingRow($ldapMappingSettings, key, ldapMapping[key], ldapMappingRes[key], ldapMappingOptions, ASC.Resources.Master.ResourceJS.LdapAttributeOrigin, ldapMappingRequiredOptions.indexOf(key) !== -1);
                }
            }

            clearAllMappingRows($ldapMappingSecurity);
            if (accessRights) {
                for (var key in accessRights) {
                    addMappingRow($ldapMappingSecurity, key, ldapMapping[key], ldapSecurityRes[key], ldapSecurityOptions, ASC.Resources.Master.ResourceJS.LdapSecurityPlaceholder);
                }
            }

            if (settings["enableLdapAuthentication"]) {
                $ldapSettingsGroupBtn.removeClass("disable");
                $ldapSettingsAuthBtn.removeClass("disable");
            } else {
                $ldapSettingsGroupBtn.addClass("disable");
                $ldapSettingsAuthBtn.addClass("disable");
            }

            if (settings["groupMembership"]) {
                $ldapSettingsGroupBtn.removeClass("off").addClass("on");
            } else {
                $ldapSettingsGroupBtn.removeClass("on").addClass("off");
            }
            $ldapSettingsGroupDN.val(settings["groupDN"]);
            $ldapSettingsUserAttribute.val(settings["userAttribute"]);
            $ldapSettingsGroupFilter.val(settings["groupFilter"]);
            $ldapSettingsGroupAttribute.val(settings["groupAttribute"]);
            $ldapSettingsGroupNameAttribute.val(settings["groupNameAttribute"]);

            if (settings["authentication"]) {
                $ldapSettingsAuthBtn.removeClass("off").addClass("on");
            } else {
                $ldapSettingsAuthBtn.removeClass("on").addClass("off");
            }
            $ldapSettingsLogin.val(settings["login"]);
            $ldapSettingsPassword.val(settings["password"]);

            disableNeededBlocks(settings["enableLdapAuthentication"],
                settings["groupMembership"],
                settings["authentication"]);
        }
    }

    function disableNeededBlocks(enableLdapAuthentication, groupMembership, authentication) {
        if (!enableLdapAuthentication) {
            $ldapSettingsMainContainer.find("input:not(#ldapSettingsCheckbox)").attr("disabled", "");
            jq(".ldap-settings-label-checkbox:not(.ldap-settings-never-disable)").addClass("ldap-settings-disabled");
            $ldapSettingsUserContainer.addClass("ldap-settings-disabled");
            $ldapSettingsGroupContainer.addClass("ldap-settings-disabled");
            $ldapSettingsAuthContainer.addClass("ldap-settings-disabled");
        } else {
            if (!groupMembership) {
                $ldapSettingsGroupContainer.find("input").attr("disabled", "");
                $ldapSettingsGroupContainer.addClass("ldap-settings-disabled");
            }
            if (!authentication) {
                $ldapSettingsAuthContainer.find("input").attr("disabled", "");
                $ldapSettingsAuthContainer.addClass("ldap-settings-disabled");
            }
        }
    }


    return {
        init: init,
        restoreDefaultSettings: restoreDefaultSettings,
        continueSaveSettings: continueSaveSettings,
        syncUsersLDAP: syncUsersLDAP
    };
};

function isObjectsEqual(obj, secondObj) {
    if (!obj || !secondObj) {
        return false;
    }

    var objKeys = [];
    var secondObjKeys = [];

    for (var key in obj) {
        objKeys.push(key);
    }

    for (var key in secondObj) {
        secondObjKeys.push(key);
    }

    if (objKeys.length !== secondObjKeys.length) {
        return false;
    }

    for (var i in objKeys) {
        var key = objKeys[i];
        if (obj[key] !== secondObj[key]) {
            return false;
        }
    }

    return true;
}

var spoiler = function () {
    var toggle = function (toggleEl, spoilerEl, force, hideLinkText, showLinkText) {
        var el = jq(toggleEl);
        var $this = jq(spoilerEl);
        if (!el)
            return;

        var enabled = typeof force === "boolean" ? force : el.hasClass('display-none');
        var linkText = "";

        if (enabled) {
            el.toggleClass('display-none', false);
            if ($this) {
                linkText = hideLinkText || ASC.Resources.Master.ResourceJS.HideLink;
                $this.text(linkText).prop('title', linkText);
            }
        } else {
            el.toggleClass('display-none', true);
            if ($this) {
                linkText = showLinkText || ASC.Resources.Master.ResourceJS.ShowLink;
                $this.text(linkText).prop('title', linkText);
            }
        }
    };

    return {
        toggle: toggle
    };
}();

jq(function () {
    LdapSettings.init();
});

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Stack/SIP_Hop.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Stack
{
    #region usings

    using System;
    using System.Net;

    #endregion

    /// <summary>
    /// Implements SIP hop(address,port,transport). Defined in RFC 3261.
    /// </summary>
    public class SIP_Hop
    {
        #region Members

        private readonly IPEndPoint m_pEndPoint;
        private readonly string m_Transport = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets target IP end point.
        /// </summary>
        public IPEndPoint EndPoint
        {
            get { return m_pEndPoint; }
        }

        /// <summary>
        /// Gets target IP address.
        /// </summary>
        public IPAddress IP
        {
            get { return m_pEndPoint.Address; }
        }

        /// <summary>
        /// Gets target port.
        /// </summary>
        public int Port
        {
            get { return m_pEndPoint.Port; }
        }

        /// <summary>
        /// Gets target SIP transport.
        /// </summary>
        public string Transport
        {
            get { return m_Transport; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="ep">IP end point.</param>
        /// <param name="transport">SIP transport to use.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>ep</b> or <b>transport</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public SIP_Hop(IPEndPoint ep, string transport)
        {
            if (ep == null)
            {
                throw new ArgumentNullException("ep");
            }
            if (transport == null)
            {
                throw new ArgumentNullException("transport");
            }
            if (transport == "")
            {
                throw new ArgumentException("Argument 'transport' value must be specified.");
            }

            m_pEndPoint = ep;
            m_Transport = transport;
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="ip">IP address.</param>
        /// <param name="port">Destination port.</param>
        /// <param name="transport">SIP transport to use.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>ip</b> or <b>transport</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public SIP_Hop(IPAddress ip, int port, string transport)
        {
            if (ip == null)
            {
                throw new ArgumentNullException("ip");
            }
            if (port < 1)
            {
                throw new ArgumentException("Argument 'port' value must be >= 1.");
            }
            if (transport == null)
            {
                throw new ArgumentNullException("transport");
            }
            if (transport == "")
            {
                throw new ArgumentException("Argument 'transport' value must be specified.");
            }

            m_pEndPoint = new IPEndPoint(ip, port);
            m_Transport = transport;
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Core.Common/Notify/Senders/SmtpSender.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Net;

using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Notify.Messages;
using ASC.Notify.Patterns;

using MailKit.Security;

using MimeKit;

namespace ASC.Core.Notify.Senders
{
    internal class SmtpSender : INotifySender
    {
        private const string HTML_FORMAT =
            @"<!DOCTYPE html PUBLIC ""-//W3C//DTD HTML 4.01 Transitional//EN"">
<html>
<head>
<meta content=""text/html;charset=UTF-8"" http-equiv=""Content-Type"">
</head>
<body>{0}</body>
</html>";

        protected ILog Log { get; private set; }

        private string _host;
        private int _port;
        private bool _ssl;
        private ICredentials _credentials;
        protected bool _useCoreSettings;
        const int NETWORK_TIMEOUT = 30000;

        public SmtpSender()
        {
            Log = LogManager.GetLogger("ASC.Notify");
        }

        public virtual void Init(IDictionary<string, string> properties)
        {
            if (properties.ContainsKey("useCoreSettings") && bool.Parse(properties["useCoreSettings"]))
            {
                _useCoreSettings = true;
            }
            else
            {
                _host = properties["host"];
                _port = properties.ContainsKey("port") ? int.Parse(properties["port"]) : 25;
                _ssl = properties.ContainsKey("enableSsl") && bool.Parse(properties["enableSsl"]);
                if (properties.ContainsKey("userName"))
                {
                    _credentials = new NetworkCredential(
                         properties["userName"],
                         properties["password"]);
                }
            }
        }

        private void InitUseCoreSettings()
        {
            var s = CoreContext.Configuration.SmtpSettings;
            _host = s.Host;
            _port = s.Port;
            _ssl = s.EnableSSL;
            _credentials = !string.IsNullOrEmpty(s.CredentialsUserName)
                ? new NetworkCredential(s.CredentialsUserName, s.CredentialsUserPassword)
                : null;
        }

        public virtual NoticeSendResult Send(NotifyMessage m)
        {
            CoreContext.TenantManager.SetCurrentTenant(m.Tenant);
            var smtpClient = GetSmtpClient();
            var result = NoticeSendResult.TryOnceAgain;
            try
            {
                try
                {
                    if (_useCoreSettings)
                        InitUseCoreSettings();

                    var mail = BuildMailMessage(m);

                    Log.DebugFormat("SmtpSender - host={0}; port={1}; enableSsl={2} enableAuth={3}", _host, _port, _ssl, _credentials != null);

                    smtpClient.Connect(_host, _port,
                        _ssl ? SecureSocketOptions.Auto : SecureSocketOptions.None);

                    if (_credentials != null)
                    {
                        smtpClient.Authenticate(_credentials);
                    }

                    smtpClient.Send(mail);
                    result = NoticeSendResult.OK;
                }
                catch (Exception e)
                {
                    Log.ErrorFormat("Tenant: {0}, To: {1} - {2}", m.Tenant, m.To, e);
                    throw;
                }
            }
            catch (ObjectDisposedException)
            {
                result = NoticeSendResult.SendingImpossible;
            }
            catch (InvalidOperationException)
            {
                result = string.IsNullOrEmpty(_host) || _port == 0
                    ? NoticeSendResult.SendingImpossible
                    : NoticeSendResult.TryOnceAgain;
            }
            catch (IOException)
            {
                result = NoticeSendResult.TryOnceAgain;
            }
            catch (MailKit.Net.Smtp.SmtpProtocolException)
            {
                result = NoticeSendResult.SendingImpossible;
            }
            catch (MailKit.Net.Smtp.SmtpCommandException e)
            {
                switch (e.StatusCode)
                {
                    case MailKit.Net.Smtp.SmtpStatusCode.MailboxBusy:
                    case MailKit.Net.Smtp.SmtpStatusCode.MailboxUnavailable:
                    case MailKit.Net.Smtp.SmtpStatusCode.ExceededStorageAllocation:
                        result = NoticeSendResult.TryOnceAgain;
                        break;
                    case MailKit.Net.Smtp.SmtpStatusCode.MailboxNameNotAllowed:
                    case MailKit.Net.Smtp.SmtpStatusCode.UserNotLocalWillForward:
                    case MailKit.Net.Smtp.SmtpStatusCode.UserNotLocalTryAlternatePath:
                        result = NoticeSendResult.MessageIncorrect;
                        break;
                    default:
                        if (e.StatusCode != MailKit.Net.Smtp.SmtpStatusCode.Ok)
                        {
                            result = NoticeSendResult.TryOnceAgain;
                        }
                        break;
                }
            }
            catch (Exception)
            {
                result = NoticeSendResult.SendingImpossible;
            }
            finally
            {
                if (smtpClient.IsConnected)
                    smtpClient.Disconnect(true);

                smtpClient.Dispose();
            }
            return result;
        }

        private MimeMessage BuildMailMessage(NotifyMessage m)
        {
            var mimeMessage = new MimeMessage
            {
                Subject = m.Subject
            };

            var fromAddress = MailboxAddress.Parse(ParserOptions.Default, m.From);

            mimeMessage.From.Add(fromAddress);

            foreach (var to in m.To.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries))
            {
                mimeMessage.To.Add(MailboxAddress.Parse(ParserOptions.Default, to));
            }

            if (m.ContentType == Pattern.HTMLContentType)
            {
                var textPart = new TextPart("plain")
                {
                    Text = HtmlUtil.GetText(m.Content),
                    ContentTransferEncoding = ContentEncoding.QuotedPrintable
                };

                var multipartAlternative = new MultipartAlternative { textPart };

                var htmlPart = new TextPart("html")
                {
                    Text = GetHtmlView(m.Content),
                    ContentTransferEncoding = ContentEncoding.QuotedPrintable
                };

                if (m.EmbeddedAttachments != null && m.EmbeddedAttachments.Length > 0)
                {
                    var multipartRelated = new MultipartRelated
                    {
                        Root = htmlPart
                    };

                    foreach (var attachment in m.EmbeddedAttachments)
                    {
                        var mimeEntity = ConvertAttachmentToMimePart(attachment);
                        if (mimeEntity != null)
                            multipartRelated.Add(mimeEntity);
                    }

                    multipartAlternative.Add(multipartRelated);
                }
                else
                {
                    multipartAlternative.Add(htmlPart);
                }

                mimeMessage.Body = multipartAlternative;
            }
            else
            {
                mimeMessage.Body = new TextPart("plain")
                {
                    Text = m.Content,
                    ContentTransferEncoding = ContentEncoding.QuotedPrintable
                };
            }

            if (!string.IsNullOrEmpty(m.ReplyTo))
            {
                mimeMessage.ReplyTo.Add(MailboxAddress.Parse(ParserOptions.Default, m.ReplyTo));
            }

            mimeMessage.Headers.Add("Auto-Submitted", string.IsNullOrEmpty(m.AutoSubmitted) ? "auto-generated" : m.AutoSubmitted);

            return mimeMessage;
        }

        protected string GetHtmlView(string body)
        {
            return string.Format(HTML_FORMAT, body);
        }

        private MailKit.Net.Smtp.SmtpClient GetSmtpClient()
        {
            var sslCertificatePermit = ConfigurationManagerExtension.AppSettings["mail.certificate-permit"] != null &&
                                    Convert.ToBoolean(ConfigurationManagerExtension.AppSettings["mail.certificate-permit"]);

            var smtpClient = new MailKit.Net.Smtp.SmtpClient
            {
                Timeout = NETWORK_TIMEOUT
            };

            if (sslCertificatePermit)
                smtpClient.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;

            return smtpClient;
        }

        private static MimePart ConvertAttachmentToMimePart(NotifyMessageAttachment attachment)
        {
            try
            {
                if (attachment == null || string.IsNullOrEmpty(attachment.FileName) || string.IsNullOrEmpty(attachment.ContentId) || attachment.Content == null)
                    return null;

                var extension = Path.GetExtension(attachment.FileName);

                if (string.IsNullOrEmpty(extension))
                    return null;

                return new MimePart("image", extension.TrimStart('.'))
                {
                    ContentId = attachment.ContentId,
                    Content = new MimeContent(new MemoryStream(attachment.Content)),
                    ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
                    ContentTransferEncoding = ContentEncoding.Base64,
                    FileName = attachment.FileName
                };
            }
            catch (Exception)
            {
                return null;
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Expressions/Contact/SimpleFilterContactsExp.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao.Expressions.Contact
{
    public class SimpleFilterContactsExp : IContactsExp
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public bool? OrderAsc { get; private set; }
        public int? StartIndex { get; private set; }
        public int? Limit { get; private set; }

        private const string MAIL_CONTACTS = "mc";

        public SimpleFilterContactsExp(int tenant, string user, bool? orderAsc = null,
            int? startIndex = null, int? limit = null)
        {
            Tenant = tenant;
            User = user;

            OrderAsc = orderAsc;
            StartIndex = startIndex;
            Limit = limit;
        }

        public virtual Exp GetExpression()
        {
            return Exp.Eq(ContactsTable.Columns.Tenant.Prefix(MAIL_CONTACTS), Tenant)
                   & Exp.Eq(ContactsTable.Columns.User.Prefix(MAIL_CONTACTS), User);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Configuration/MailSpaceUsageStatManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Core;
using ASC.Web.Core.Users;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Mail.Configuration
{
    public class MailSpaceUsageStatManager : SpaceUsageStatManager, IUserSpaceUsage
    {
        private const string MailDatabaseId = "mail";

        public override List<UsageSpaceStatItem> GetStatData()
        {
            using (var mail_db = new DbManager(MailDatabaseId))
            {
                var query = new SqlQuery("mail_attachment a")
                    .InnerJoin("mail_mail m", Exp.EqColumns("a.id_mail", "m.id"))
                    .Select("m.id_user")
                    .Select("sum(a.size) as size")
                    .Where("a.tenant", TenantProvider.CurrentTenantID)
                    .Where("a.need_remove", 0)
                    .GroupBy(1)
                    .OrderBy(2, false);

                return mail_db.ExecuteList(query)
                    .Select(r =>
                        {
                            var user_id = new Guid(Convert.ToString(r[0]));
                            var user = CoreContext.UserManager.GetUsers(user_id);
                            var item = new UsageSpaceStatItem
                            {
                                Name = DisplayUserSettings.GetFullUserName(user, false),
                                ImgUrl = UserPhotoManager.GetSmallPhotoURL(user.ID),
                                Url = CommonLinkUtility.GetUserProfile(user.ID),
                                SpaceUsage = Convert.ToInt64(r[1]),
                                Disabled = user.Status == EmployeeStatus.Terminated
                            };
                            return item;
                        })
                    .ToList();
            }
        }

        public long GetUserSpaceUsage(Guid userId)
        {
            using (var mail_db = new DbManager(MailDatabaseId))
            {
                var query = new SqlQuery("mail_attachment a")
                    .InnerJoin("mail_mail m", Exp.EqColumns("a.id_mail", "m.id"))
                    .Select("sum(a.size) as size")
                    .Where("a.tenant", TenantProvider.CurrentTenantID)
                    .Where("m.id_user", userId)
                    .Where("a.need_remove", 0);

                return mail_db.ExecuteScalar<long>(query);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Deals/DealDetailsView.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Web;

using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.Web.CRM.Classes;


#endregion

namespace ASC.Web.CRM.Controls.Deals
{
    public partial class DealDetailsView : BaseUserControl
    {
        #region Property

        public Deal TargetDeal { get; set; }

        public static String Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Deals/DealDetailsView.ascx"); }
        }

        #endregion

        #region Events

        protected void Page_Load(object sender, EventArgs e)
        {
            ExecFullCardView();
            ExecPeopleView();
            ExecFilesView();
            RegisterScript();
        }

        #endregion

        #region Methods

        protected void ExecFullCardView()
        {
            var dealFullCardControl = (DealFullCardView)LoadControl(DealFullCardView.Location);
            dealFullCardControl.TargetDeal = TargetDeal;

            _phProfileView.Controls.Add(dealFullCardControl);
        }

        private void ExecPeopleView()
        {
            RegisterClientScriptHelper.DataListContactTab(Page, TargetDeal.ID, EntityType.Opportunity);
        }

        private void ExecFilesView()
        {
            var filesViewControl = (Studio.UserControls.Common.Attachments.Attachments)LoadControl(Studio.UserControls.Common.Attachments.Attachments.Location);
            filesViewControl.EntityType = "opportunity";
            filesViewControl.ModuleName = "crm";
            _phFilesView.Controls.Add(filesViewControl);

            //var mainContent = (MainContent) LoadControl(MainContent.Location);
            //mainContent.FolderIDCurrentRoot = FilesIntegration.RegisterBunch("crm", "opportunity", TargetDeal.ID.ToString());
            //mainContent.TitlePage = "crm";
            //_phFilesView.Controls.Add(mainContent);

            //if (FileUtility.ExtsImagePreviewed.Count != 0)
            //    _phFilesView.Controls.Add(LoadControl(FileViewer.Location));

            //if (!Core.Mobile.MobileDetector.IsMobile)
            //    _phFilesView.Controls.Add(LoadControl(ChunkUploadDialog.Location));

        }

        private void RegisterScript()
        {
            Page.RegisterInlineScript(@"ASC.CRM.DealDetailsView.init();");
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Server/IMAP_Session.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Security.Principal;
using ASC.Mail.Net.IO;

namespace ASC.Mail.Net.IMAP.Server
{
    #region usings

    using System;
    using System.Collections;
    using System.IO;
    using System.Net.Sockets;
    using System.Text;
    using System.Timers;
    using AUTH;
    using Mime;
    using StringReader = StringReader;
    using ASC.Mail.Net.TCP;

    #endregion

    /// <summary>
    /// IMAP session.
    /// </summary>
    public class IMAP_Session : TCP_ServerSession
    {
        #region Nested type: Command_IDLE

        /// <summary>
        /// This class implements IDLE command. Defined in RFC 2177.
        /// </summary>
        private class Command_IDLE: IDisposable
        {
            #region Members

            private readonly string m_CmdTag = "";
            private readonly string folder;
            private bool m_IsDisposed;
            private IMAP_Session m_pSession;
            private TimerEx m_pTimer;

            #endregion

            #region Constructor

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="session">Owner IMAP session.</param>
            /// <param name="cmdTag">IDLE command command-tag.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>session</b> or <b>cmdTag</b> is null reference.</exception>
            /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
            public Command_IDLE(IMAP_Session session, string cmdTag) : this(session, cmdTag, session.SelectedMailbox) { }

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="session">Owner IMAP session.</param>
            /// <param name="cmdTag">IDLE command command-tag.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>session</b> or <b>cmdTag</b> is null reference.</exception>
            /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
            public Command_IDLE(IMAP_Session session, string cmdTag, string folder)
            {
                if (session == null)
                {
                    throw new ArgumentNullException("session");
                }
                if (cmdTag == null)
                {
                    throw new ArgumentNullException("cmdTag");
                }
                if (cmdTag == string.Empty)
                {
                    throw new ArgumentException("Argument 'cmdTag' value must be specified.", "cmdTag");
                }

                try
                {
                    m_pSession = session;
                    m_CmdTag = cmdTag;
                    this.folder = folder;
                    Start();
                }
                catch (Exception x)
                {
                    m_pSession.OnError(x);   
                }
            }

            void m_pSession_FolderChanged(string folderName, string username)
            {
                //tada
                if (!m_IsDisposed)
                    m_pSession.ProcessMailboxChanges(folder);
            }

            #endregion

            #region Methods

            /// <summary>
            /// Cleans up any resources being used.
            /// </summary>
            /// 
            public void Dispose()
            {
                if (m_IsDisposed)
                {
                    return;
                }
                m_IsDisposed = true;
                try
                {
                    m_pTimer.Stop();
                    m_pSession.FolderChanged -= m_pSession_FolderChanged;
                    m_pSession.m_pIDLE = null;
                    m_pSession = null;
                    m_pTimer.Dispose();
                    m_pTimer = null;

                }
                catch (Exception)
                {
                    
                }
            }

            #endregion

            #region Event handlers

            private void m_pTimer_Elapsed(object sender, ElapsedEventArgs e)
            {
                // If mailbox changes, report them to connected client.
                if (!m_IsDisposed)
                    m_pSession.ProcessMailboxChanges(folder);
            }

            #endregion

            #region Utility methods

            private void ReadLineCompleted(object sender, EventArgs<SmartStream.ReadLineAsyncOP> eventArgs)
            {
                try
                {
                    // Accoridng RFC, we should get only "DONE" here.
                    if (m_IsDisposed)
                        return;

                    if (eventArgs.Value.IsCompleted && eventArgs.Value.Error == null)
                    {
                        if (eventArgs.Value.LineUtf8 ==
                            "DONE")
                        {
                            // Send "cmd-tag OK IDLE terminated" to connected client.
                            m_pSession.WriteLine(m_CmdTag + " OK IDLE terminated");

                            m_pSession.BeginRecieveCmd();

                            Dispose();
                        }
                        // Connected client send illegal stuff us, end session.
                        else
                        {
                            m_pSession.EndSession();

                            Dispose();
                        }
                    }
                    // Receive errors, probably TCP connection broken.
                    else
                    {
                        m_pSession.EndSession();

                        Dispose();
                    }

                }
                catch (Exception)
                {
                    
                }
            }

            /// <summary>
            /// Starts IDLE command processing.
            /// </summary>
            private void Start()
            {
                /* RFC 2177 IDLE command example.
                    C: A004 IDLE
                    S: * 2 EXPUNGE
                    S: * 3 EXISTS
                    S: + idling
                    ...time passes; another client expunges message 3...
                    S: * 3 EXPUNGE
                    S: * 2 EXISTS
                    ...time passes; new mail arrives...
                    S: * 3 EXISTS
                    C: DONE
                    S: A004 OK IDLE terminated
                */

                // Send status reponse to connected client if any.
                m_pSession.ProcessMailboxChanges(folder);

                // Send "+ idling" to connected client.
                m_pSession.WriteLine("+ idling");


                // Start timer to poll mailbox changes.
                m_pSession.FolderChanged += m_pSession_FolderChanged;

                m_pTimer = new TimerEx(5000, true);
                m_pTimer.Elapsed += m_pTimer_Elapsed;
                m_pTimer.Enabled = true;

                // Start waiting DONE command from connected client.
                m_pSession.ReadAsync(ReadLineCompleted);
            }

            #endregion
        }

        #endregion

        #region Members

        private IMAP_Server ImapServer { get { return Server as IMAP_Server; } }
        private Command_IDLE m_pIDLE;
        private IMAP_SelectedFolder m_pSelectedFolder;
        private IMAP_SelectedFolder m_pAdditionalFolder;
        private string m_StatusedMailbox = "";
        private int m_BadCmdCount;
        private GenericIdentity m_pUser;

        public IMAP_Session()
        {
            SelectedMailbox = "";
        }

        public override void Dispose()
        {
            base.Dispose();
            if (!IsDisposed)
            {
                if (m_pIDLE!=null)
                {
                    m_pIDLE.Dispose();
                }
                if (m_pSelectedFolder!=null)
                {
                    m_pSelectedFolder.Dispose();
                }
                if (m_pAdditionalFolder != null)
                {
                    m_pAdditionalFolder.Dispose();
                }
            }
        }

        internal event IMAP_Server.FolderChangedHandler FolderChanged = null;

        public void OnFolderChanged(string folderName, string username)
        {
            if (FolderChanged != null)
            {
                FolderChanged(folderName, username);
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets selected mailbox.
        /// </summary>
        public string SelectedMailbox { get; private set; }

        #endregion

        #region Constructor




        #endregion

        #region Methods


        #endregion

        #region Overrides

        protected override void OnTimeout()
        {
            base.OnTimeout();
            WriteLine("* BYE Session timeout");
            TcpStream.Flush();
        }


        #endregion

        #region Utility methods


        protected internal override void Start()
        {
            base.Start();
            try
            {
                ImapServer.FolderChanged += OnFolderChanged;
                // Check if ip is allowed to connect this computer
                if (ImapServer.OnValidate_IpAddress(LocalEndPoint, RemoteEndPoint))
                {
                    WriteLine(string.Format("* OK {0} IMAP Server ready", LocalHostName));
                    BeginRecieveCmd();
                }
                else
                {
                    EndSession();
                }
            }
            catch (Exception x)
            {
                OnError(x);
            }
        }

        /// <summary>
        /// Ends session, closes socket.
        /// </summary>
        private void EndSession()
        {
            Disconnect();
        }

        /// <summary>
        /// Is called when error occures.
        /// </summary>
        /// <param name="x"></param>
		private new void OnError(Exception x)
        {
            // Session disposed, so we don't care about terminating errors any more.
            if (IsDisposed)
            {
                return;
            }
            try
            {
                ImapServer.OnSysError("ending session", x);
                EndSession();
            }
            catch (Exception)
            {
                
            }
        }


        private void AddLog(string message)
        {
            // Log
            if (ImapServer.Logger != null)
            {
                ImapServer.Logger.AddText(ID, message);
            }
        }

        private void AddReadEntry(string cmd)
        {
            // Log
            if (ImapServer.Logger != null)
            {
                ImapServer.Logger.AddRead(ID, AuthenticatedUserIdentity, cmd.Length, cmd, LocalEndPoint, RemoteEndPoint);
            }
        }

        private void AddWriteEntry(string cmd)
        {
            // Log
            if (ImapServer.Logger != null)
            {
                ImapServer.Logger.AddWrite(ID, AuthenticatedUserIdentity, cmd.Length, cmd, LocalEndPoint, RemoteEndPoint);
            }
        }

        /// <summary>
        /// Starts recieveing command.
        /// </summary>
        private void BeginRecieveCmd()
        {
            SmartStream.ReadLineAsyncOP args = new SmartStream.ReadLineAsyncOP(new byte[Workaround.Definitions.MaxStreamLineLength],
                                                                               SizeExceededAction.
                                                                                   JunkAndThrowException);

            args.Completed += new EventHandler<EventArgs<SmartStream.ReadLineAsyncOP>>(ReciveCmdComleted);
            TcpStream.ReadLine(args, true);
        }

        internal void ReadAsync(EventHandler<EventArgs<SmartStream.ReadLineAsyncOP>> completed)
        {
            SmartStream.ReadLineAsyncOP args = new SmartStream.ReadLineAsyncOP(new byte[Workaround.Definitions.MaxStreamLineLength],
                                                                               SizeExceededAction.
                                                                                   JunkAndThrowException);

            args.Completed += completed;
            TcpStream.ReadLine(args, true);
        }

        protected void WriteLine(string line)
        {
            try
            {
                AddWriteEntry(line);
                TcpStream.WriteLine(line);
            }
            catch (Exception x)
            {
                OnError(x);                
            }
        }


        private void ReciveCmdComleted(object sender, EventArgs<SmartStream.ReadLineAsyncOP> e)
        {
            if (e.Value.IsCompleted && e.Value.Error == null)
            {
                //Call
                bool sessionEnd = false;
                try
                {
                    string cmdLine = e.Value.LineUtf8;
                    AddReadEntry(cmdLine);
                    // Exceute command
                    TcpStream.MemoryBuffer = true;
                    sessionEnd = SwitchCommand(cmdLine);
                    TcpStream.Flush();
                    if (sessionEnd)
                    {
                        // Session end, close session
                        EndSession();
                    }
                }
                catch (Exception ex)
                {
                    OnError(ex);
                }
            }
            else if (e.Value.Error != null)
            {
                OnError(e.Value.Error);
            }
        }

        private void EndSession(string text)
        {
            Disconnect(text);
        }

        /// <summary>
        /// Executes IMAP command.
        /// </summary>
        /// <param name="IMAP_commandTxt">Original command text.</param>
        /// <returns>Returns true if must end session(command loop).</returns>
        private bool SwitchCommand(string IMAP_commandTxt)
        {
            // Parse commandTag + comand + args
            // eg. C: a100 SELECT INBOX<CRLF>
            // a100   - commandTag
            // SELECT - command
            // INBOX  - arg

            //---- Parse command --------------------------------------------------//
            string[] cmdParts = IMAP_commandTxt.TrimStart().Split(new[] { ' ' });
            // For bad command, just return empty cmdTag and command name
            if (cmdParts.Length < 2)
            {
                cmdParts = new[] { "", "" };
            }
            string commandTag = cmdParts[0].Trim().Trim();
            string command = cmdParts[1].ToUpper().Trim();
            string argsText = Core.GetArgsText(IMAP_commandTxt, cmdParts[0] + " " + cmdParts[1]);
            //---------------------------------------------------------------------//

            bool getNextCmd = true;

            switch (command)
            {
                //--- Non-IsAuthenticated State
                case "STARTTLS":
                    STARTTLS(commandTag, argsText);
                    break;

                case "AUTHENTICATE":
                    Authenticate(commandTag, argsText);
                    break;

                case "LOGIN":
                    LogIn(commandTag, argsText);
                    break;
                //--- End of non-IsAuthenticated

                //--- IsAuthenticated State
                case "SELECT":
                    Select(commandTag, argsText);
                    break;

                case "EXAMINE":
                    Examine(commandTag, argsText);
                    break;

                case "CREATE":
                    Create(commandTag, argsText);
                    break;

                case "DELETE":
                    Delete(commandTag, argsText);
                    break;

                case "RENAME":
                    Rename(commandTag, argsText);
                    break;

                case "SUBSCRIBE":
                    Suscribe(commandTag, argsText);
                    break;

                case "UNSUBSCRIBE":
                    UnSuscribe(commandTag, argsText);
                    break;

                case "LIST":
                    List(commandTag, argsText);
                    break;

                case "LSUB":
                    LSub(commandTag, argsText);
                    break;

                case "STATUS":
                    Status(commandTag, argsText);
                    break;

                case "APPEND":
                    getNextCmd = BeginAppendCmd(commandTag, argsText);
                    break;

                case "NAMESPACE":
                    Namespace(commandTag, argsText);
                    break;

                case "GETACL":
                    GETACL(commandTag, argsText);
                    break;

                case "SETACL":
                    SETACL(commandTag, argsText);
                    break;

                case "DELETEACL":
                    DELETEACL(commandTag, argsText);
                    break;

                case "LISTRIGHTS":
                    LISTRIGHTS(commandTag, argsText);
                    break;

                case "MYRIGHTS":
                    MYRIGHTS(commandTag, argsText);
                    break;

                case "GETQUOTA":
                    GETQUOTA(commandTag, argsText);
                    break;

                case "GETQUOTAROOT":
                    GETQUOTAROOT(commandTag, argsText);
                    break;
                //--- End of IsAuthenticated

                //--- Selected State
                case "CHECK":
                    Check(commandTag);
                    break;

                case "CLOSE":
                    Close(commandTag);
                    break;

                case "EXPUNGE":
                    Expunge(commandTag);
                    break;

                case "SEARCH":
                    Search(commandTag, argsText, false);
                    break;

                case "FETCH":
                    Fetch(commandTag, argsText, false);
                    break;

                case "STORE":
                    Store(commandTag, argsText, false);
                    break;

                case "COPY":
                    Copy(commandTag, argsText, false);
                    break;

                case "UID":
                    Uid(commandTag, argsText);
                    break;

                case "IDLE":
                    getNextCmd = !Idle(commandTag, argsText);
                    break;
                //--- End of Selected 

                //--- Any State
                case "CAPABILITY":
                    Capability(commandTag);
                    break;
                case "NOOP":
                    Noop(commandTag);
                    break;

                case "LOGOUT":
                    LogOut(commandTag);
                    return true;
                //--- End of Any

                default:
                    WriteLine(commandTag + " BAD command unrecognized");

                    //---- Check that maximum bad commands count isn't exceeded ---------------//
                    if (m_BadCmdCount > ImapServer.MaxBadCommands - 1)
                    {
                        WriteLine("* BAD Too many bad commands, closing transmission channel");
                        return true;
                    }
                    m_BadCmdCount++;
                    //-------------------------------------------------------------------------//
                    break;
            }

            if (getNextCmd)
            {
                BeginRecieveCmd();
            }

            return false;
        }




        //--- Non-IsAuthenticated State ------

        private void STARTTLS(string cmdTag, string argsText)
        {
            /* RFC 2595 3. IMAP STARTTLS extension.
                3. IMAP STARTTLS extension

                   When the TLS extension is present in IMAP, "STARTTLS" is listed as a
                   capability in response to the CAPABILITY command.  This extension
                   adds a single command, "STARTTLS" to the IMAP protocol which is used
                   to begin a TLS negotiation.

                3.1. STARTTLS Command

                   Arguments:  none

                   Responses:  no specific responses for this command

                   Result:     OK - begin TLS negotiation
                               BAD - command unknown or arguments invalid

                      A TLS negotiation begins immediately after the CRLF at the end of
                      the tagged OK response from the server.  Once a client issues a
                      STARTTLS command, it MUST NOT issue further commands until a
                      server response is seen and the TLS negotiation is complete.

                      The STARTTLS command is only valid in non-authenticated state.
                      The server remains in non-authenticated state, even if client
                      credentials are supplied during the TLS negotiation.  The SASL
                      [SASL] EXTERNAL mechanism MAY be used to authenticate once TLS
                      client credentials are successfully exchanged, but servers
                      supporting the STARTTLS command are not required to support the
                      EXTERNAL mechanism.

                      Once TLS has been started, the client MUST discard cached
                      information about server capabilities and SHOULD re-issue the
                      CAPABILITY command.  This is necessary to protect against
                      man-in-the-middle attacks which alter the capabilities list prior
                      to STARTTLS.  The server MAY advertise different capabilities
                      after STARTTLS.

                      The formal syntax for IMAP is amended as follows:

                        command_any   =/  "STARTTLS"

                   Example:    C: a001 CAPABILITY
                               S: * CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
                               S: a001 OK CAPABILITY completed
                               C: a002 STARTTLS
                               S: a002 OK Begin TLS negotiation now
                               <TLS negotiation, further commands are under TLS layer>
                               C: a003 CAPABILITY
                               S: * CAPABILITY IMAP4rev1 AUTH=EXTERNAL
                               S: a003 OK CAPABILITY completed
                               C: a004 LOGIN joe password
                               S: a004 OK LOGIN completed
            */

            if (IsAuthenticated)
            {
                WriteLine(cmdTag +
                                 " NO The STARTTLS command is only valid in non-authenticated state !");
                return;
            }
            if (IsSecureConnection)
            {
                WriteLine(cmdTag + " NO The STARTTLS already started !");
                return;
            }
            if (Certificate == null)
            {
                WriteLine(cmdTag + " NO TLS not available, SSL certificate isn't specified !");
                return;
            }

            WriteLine(cmdTag + " OK Ready to start TLS");

            try
            {
                SwitchToSecure();
                AddLog("TLS negotiation completed successfully.");
            }
            catch (Exception x)
            {
                WriteLine(cmdTag + " NO TLS handshake failed ! " + x.Message);
            }
        }

        private void Authenticate(string cmdTag, string argsText)
        {
            /* Rfc 3501 6.2.2.  AUTHENTICATE Command

				Arguments:  authentication mechanism name

				Responses:  continuation data can be requested

				Result:     OK  - authenticate completed, now in authenticated state
							NO  - authenticate failure: unsupported authentication
								  mechanism, credentials rejected
							BAD - command unknown or arguments invalid,
								  authentication exchange cancelled
			*/
            if (IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO AUTH you are already logged in", cmdTag));
                return;
            }

            string userName = "";
            //	string password = "";
            AuthUser_EventArgs aArgs = null;

            switch (argsText.ToUpper())
            {
                case "CRAM-MD5":

                    #region CRAM-MDD5 authentication

                    /* Cram-M5
					C: A0001 AUTH CRAM-MD5
					S: + <md5_calculation_hash_in_base64>
					C: base64(decoded:username password_hash)
					S: A0001 OK CRAM authentication successful
					*/

                    string md5Hash = string.Format("<{0}>", Guid.NewGuid().ToString().ToLower());
                    WriteLine(string.Format("+ {0}", Convert.ToBase64String(Encoding.ASCII.GetBytes(md5Hash))));

                    string reply = ReadLine();
                    reply = Encoding.Default.GetString(Convert.FromBase64String(reply));
                    string[] replyArgs = reply.Split(' ');
                    userName = replyArgs[0];

                    aArgs = ImapServer.OnAuthUser(this, userName, replyArgs[1], md5Hash, AuthType.CRAM_MD5);

                    // There is custom error, return it
                    if (aArgs.ErrorText != null)
                    {
                        WriteLine(string.Format("{0} NO {1}", cmdTag, aArgs.ErrorText));
                        return;
                    }

                    if (aArgs.Validated)
                    {
                        WriteLine(string.Format("{0} OK Authentication successful.", cmdTag));

                        SetUserName(userName);
                    }
                    else
                    {
                        WriteLine(string.Format("{0} NO Authentication failed", cmdTag));
                    }

                    #endregion

                    break;

                case "DIGEST-MD5":

                    #region DIGEST-MD5 authentication

                    /* RFC 2831 AUTH DIGEST-MD5
					 * 
					 * Example:
					 * 
					 * C: AUTH DIGEST-MD5
					 * S: + base64(realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",qop="auth",algorithm=md5-sess)
					 * C: base64(username="chris",realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",
					 *    nc=00000001,cnonce="OA6MHXh6VqTrRk",digest-uri="imap/elwood.innosoft.com",
                     *    response=d388dad90d4bbd760a152321f2143af7,qop=auth)
					 * S: + base64(rspauth=ea40f60335c427b5527b84dbabcdfffd)
					 * C:
					 * S: A0001 OK Authentication successful.
					*/

                    string realm = LocalHostName;
                    string nonce = AuthHelper.GenerateNonce();

                    WriteLine("+ " +
                                     AuthHelper.Base64en(AuthHelper.Create_Digest_Md5_ServerResponse(realm,
                                                                                                     nonce)));

                    string clientResponse = AuthHelper.Base64de(ReadLine());
                    // Check that realm and nonce in client response are same as we specified
                    if (clientResponse.IndexOf(string.Format("realm=\"{0}\"", realm)) > -1 &&
                        clientResponse.IndexOf(string.Format("nonce=\"{0}\"", nonce)) > -1)
                    {
                        // Parse user name and password compare value
                        //		string userName  = "";
                        string passwData = "";
                        string cnonce = "";
                        foreach (string clntRespParam in clientResponse.Split(','))
                        {
                            if (clntRespParam.StartsWith("username="))
                            {
                                userName = clntRespParam.Split(new[] { '=' }, 2)[1].Replace("\"", "");
                            }
                            else if (clntRespParam.StartsWith("response="))
                            {
                                passwData = clntRespParam.Split(new[] { '=' }, 2)[1];
                            }
                            else if (clntRespParam.StartsWith("cnonce="))
                            {
                                cnonce = clntRespParam.Split(new[] { '=' }, 2)[1].Replace("\"", "");
                            }
                        }

                        aArgs = ImapServer.OnAuthUser(this,
                                                     userName,
                                                     passwData,
                                                     clientResponse,
                                                     AuthType.DIGEST_MD5);

                        // There is custom error, return it
                        if (aArgs.ErrorText != null)
                        {
                            WriteLine(string.Format("{0} NO {1}", cmdTag, aArgs.ErrorText));
                            return;
                        }

                        if (aArgs.Validated)
                        {
                            // Send server computed password hash
                            WriteLine("+ " + AuthHelper.Base64en("rspauth=" + aArgs.ReturnData));

                            // We must got empty line here
                            clientResponse = ReadLine();
                            if (clientResponse == "")
                            {
                                WriteLine(string.Format("{0} OK Authentication successful.", cmdTag));

                                SetUserName(userName);
                            }
                            else
                            {
                                WriteLine(string.Format("{0} NO Authentication failed", cmdTag));
                            }
                        }
                        else
                        {
                            WriteLine(string.Format("{0} NO Authentication failed", cmdTag));
                        }
                    }
                    else
                    {
                        WriteLine(string.Format("{0} NO Authentication failed", cmdTag));
                    }

                    #endregion

                    break;

                default:
                    WriteLine(string.Format("{0} NO unsupported authentication mechanism", cmdTag));
                    break;
            }
        }

        private void LogIn(string cmdTag, string argsText)
        {
            /* RFC 3501 6.2.3 LOGIN Command
			  
				Arguments:  user name
							password

				Responses:  no specific responses for this command

				Result:     OK  - login completed, now in authenticated state
							NO  - login failure: user name or password rejected
							BAD - command unknown or arguments invalid
			   
				The LOGIN command identifies the client to the server and carries
				the plaintext password authenticating this user.
			
				Example: C: a001 LOGIN SMITH SESAME
					     S: a001 OK LOGIN completed
						 
						 //----
						 C: a001 LOGIN "SMITH" "SESAME"
						 S: a001 OK LOGIN completed
			   
			*/
            /*if (IsAuthenticated)
            {
                WriteLine(cmdTag + " NO Reauthentication error, you are already logged in");
                return;
            }*/

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD Invalid arguments, syntax: {{<command-tag> LOGIN \"<user-name>\" \"<password>\"}}", cmdTag));
                return;
            }

            string userName = args[0];
            string password = args[1];

            // Store start time
            long startTime = DateTime.Now.Ticks;

            AuthUser_EventArgs aArgs = ImapServer.OnAuthUser(this, userName, password, "", AuthType.Plain);
            // There is custom error, return it
            if (aArgs.ErrorText != null)
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, aArgs.ErrorText));
                return;
            }

            if (aArgs.Validated)
            {
                WriteLine(string.Format("{0} OK LOGIN Completed in {1} seconds", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2")));

                SetUserName(userName);
            }
            else
            {
                WriteLine(string.Format("{0} NO LOGIN failed", cmdTag));
            }
        }

        public override GenericIdentity AuthenticatedUserIdentity
        {
            get
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pUser;
            }
        }

        private void SetUserName(string userName)
        {
            UserName = userName;
            m_pUser = new GenericIdentity(UserName);
            
        }

        public string UserName { get; set; }

        //--- End of non-IsAuthenticated State 

        //--- IsAuthenticated State ------

        private void Select(string cmdTag, string argsText)
        {
            /* Rfc 3501 6.3.1 SELECT Command
			 
				Arguments:  mailbox name

				Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
							REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
							UIDNEXT, UIDVALIDITY

				Result:     OK - select completed, now in selected state
							NO - select failure, now in authenticated state: no
									such mailbox, can't access mailbox
							BAD - command unknown or arguments invalid
							
				The SELECT command selects a mailbox so that messages in the
				mailbox can be accessed.  Before returning an OK to the client,
				the server MUST send the following untagged data to the client.
				Note that earlier versions of this protocol only required the
				FLAGS, EXISTS, and RECENT untagged data; consequently, client
				implementations SHOULD implement default behavior for missing data
				as discussed with the individual item.

					FLAGS       Defined flags in the mailbox.  See the description
								of the FLAGS response for more detail.

					<n> EXISTS  The number of messages in the mailbox.  See the
								description of the EXISTS response for more detail.

					<n> RECENT  The number of messages with the \Recent flag set.
								See the description of the RECENT response for more
								detail.

					OK [UNSEEN <n>]
								The message sequence number of the first unseen
								message in the mailbox.  If this is missing, the
								client can not make any assumptions about the first
								unseen message in the mailbox, and needs to issue a
								SEARCH command if it wants to find it.

					OK [PERMANENTFLAGS (<list of flags>)]
								A list of message flags that the client can change
								permanently.  If this is missing, the client should
								assume that all flags can be changed permanently.

					OK [UIDNEXT <n>]
								The next unique identifier value.  Refer to section
								2.3.1.1 for more information.  If this is missing,
								the client can not make any assumptions about the
								next unique identifier value.
								
					OK [UIDVALIDITY <n>]
                     The unique identifier validity value.  Refer to
                     section 2.3.1.1 for more information.  If this is
                     missing, the server does not support unique
                     identifiers.

				Only one mailbox can be selected at a time in a connection;
				simultaneous access to multiple mailboxes requires multiple
				connections.  The SELECT command automatically deselects any
				currently selected mailbox before attempting the new selection.
				Consequently, if a mailbox is selected and a SELECT command that
				fails is attempted, no mailbox is selected.

				If the client is permitted to modify the mailbox, the server
				SHOULD prefix the text of the tagged OK response with the
				"[READ-WRITE]" response code.

				If the client is not permitted to modify the mailbox but is
				permitted read access, the mailbox is selected as read-only, and
				the server MUST prefix the text of the tagged OK response to
				SELECT with the "[READ-ONLY]" response code.  Read-only access
				through SELECT differs from the EXAMINE command in that certain
				read-only mailboxes MAY permit the change of permanent state on a
				per-user (as opposed to global) basis.  Netnews messages marked in
				a server-based .newsrc file are an example of such per-user
				permanent state that can be modified with read-only mailboxes.

				Example:    C: A142 SELECT INBOX
							S: * 172 EXISTS
							S: * 1 RECENT
							S: * OK [UNSEEN 12] Message 12 is first unseen
							S: * OK [UIDVALIDITY 3857529045] UIDs valid
							S: * OK [UIDNEXT 4392] Predicted next UID
							S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
							S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
							S: A142 OK [READ-WRITE] SELECT completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD SELECT invalid arguments. Syntax: {{<command-tag> SELECT \"mailboxName\"}}", cmdTag));
                return;
            }

            // Store start time
            long startTime = DateTime.Now.Ticks;

            IMAP_SelectedFolder selectedFolder = new IMAP_SelectedFolder(Core.Decode_IMAP_UTF7_String(args[0]));
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, selectedFolder);
            if (eArgs.ErrorText == null)
            {
                m_pSelectedFolder = selectedFolder;
                SelectedMailbox = Core.Decode_IMAP_UTF7_String(args[0]);

                string response = "";
                response += "* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n";
                response += string.Format("* {0} EXISTS\r\n", m_pSelectedFolder.Messages.Count);
                response += string.Format("* {0} RECENT\r\n", m_pSelectedFolder.RecentCount);
                response += string.Format("* OK [UNSEEN {0}] Message {1} is first unseen\r\n", m_pSelectedFolder.FirstUnseen, m_pSelectedFolder.FirstUnseen);
                response += string.Format("* OK [UIDVALIDITY {0}] Folder UID\r\n", m_pSelectedFolder.FolderUID);
                response += string.Format("* OK [UIDNEXT {0}] Predicted next message UID\r\n", m_pSelectedFolder.MessageUidNext);
                response +=
                    "* OK [PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)] Available permanent flags\r\n";
                response += string.Format("{0} OK [{1}] SELECT Completed in {2} seconds\r\n", cmdTag, (m_pSelectedFolder.ReadOnly ? "READ-ONLY" : "READ-WRITE"), ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2"));

                TcpStream.Write(response);
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, eArgs.ErrorText));
            }
        }

        private void Examine(string cmdTag, string argsText)
        {
            /* Rfc 3501 6.3.2 EXAMINE Command
			
				Arguments:  mailbox name

				Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
							REQUIRED OK untagged responses:  UNSEEN,  PERMANENTFLAGS,
							UIDNEXT, UIDVALIDITY

				Result:     OK - examine completed, now in selected state
							NO - examine failure, now in authenticated state: no
									such mailbox, can't access mailbox
							BAD - command unknown or arguments invalid

				The EXAMINE command is identical to SELECT and returns the same
				output; however, the selected mailbox is identified as read-only.
				No changes to the permanent state of the mailbox, including
				per-user state, are permitted; in particular, EXAMINE MUST NOT
				cause messages to lose the \Recent flag.

				The text of the tagged OK response to the EXAMINE command MUST
				begin with the "[READ-ONLY]" response code.

				Example:    C: A932 EXAMINE blurdybloop
							S: * 17 EXISTS
							S: * 2 RECENT
							S: * OK [UNSEEN 8] Message 8 is first unseen
							S: * OK [UIDVALIDITY 3857529045] UIDs valid
							S: * OK [UIDNEXT 4392] Predicted next UID
							S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
							S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
							S: A932 OK [READ-ONLY] EXAMINE completed
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD EXAMINE invalid arguments. Syntax: {{<command-tag> EXAMINE \"mailboxName\"}}", cmdTag));
                return;
            }

            // Store start time
            long startTime = DateTime.Now.Ticks;

            IMAP_SelectedFolder selectedFolder = new IMAP_SelectedFolder(Core.Decode_IMAP_UTF7_String(args[0]));
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, selectedFolder);
            if (eArgs.ErrorText == null)
            {
                m_pSelectedFolder = selectedFolder;
                m_pSelectedFolder.ReadOnly = true;
                SelectedMailbox = Core.Decode_IMAP_UTF7_String(args[0]);

                string response = "";
                response += "* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n";
                response += string.Format("* {0} EXISTS\r\n", m_pSelectedFolder.Messages.Count);
                response += string.Format("* {0} RECENT\r\n", m_pSelectedFolder.RecentCount);
                response += string.Format("* OK [UNSEEN {0}] Message {1} is first unseen\r\n", m_pSelectedFolder.FirstUnseen, m_pSelectedFolder.FirstUnseen);
                response += string.Format("* OK [UIDVALIDITY {0}] UIDs valid\r\n", m_pSelectedFolder.FolderUID);
                response += string.Format("* OK [UIDNEXT {0}] Predicted next UID\r\n", m_pSelectedFolder.MessageUidNext);
                response +=
                    "* OK [PERMANENTFLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)] Available permanent falgs\r\n";
                response += string.Format("{0} OK [READ-ONLY] EXAMINE  Completed in {1} seconds\r\n", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2"));

                TcpStream.Write(response);
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, eArgs.ErrorText));
            }
        }

        private void Create(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.3
				
				Arguments:  mailbox name

				Responses:  no specific responses for this command

				Result:     OK - create completed
							NO - create failure: can't create mailbox with that name
							BAD - command unknown or arguments invalid
			   
				The CREATE command creates a mailbox with the given name.  An OK
				response is returned only if a new mailbox with that name has been
				created.  It is an error to attempt to create INBOX or a mailbox
				with a name that refers to an extant mailbox.  Any error in
				creation will return a tagged NO response.

				If the mailbox name is suffixed with the server's hierarchy
				separator character (as returned from the server by a LIST
				command), this is a declaration that the client intends to create
				mailbox names under this name in the hierarchy.  Server
				implementations that do not require this declaration MUST ignore
				it.

				If the server's hierarchy separator character appears elsewhere in
				the name, the server SHOULD create any superior hierarchical names
				that are needed for the CREATE command to complete successfully.
				In other words, an attempt to create "foo/bar/zap" on a server in
				which "/" is the hierarchy separator character SHOULD create foo/
				and foo/bar/ if they do not already exist.

				If a new mailbox is created with the same name as a mailbox which
				was deleted, its unique identifiers MUST be greater than any
				unique identifiers used in the previous incarnation of the mailbox
				UNLESS the new incarnation has a different unique identifier
				validity value.  See the description of the UID command for more
				detail.
				
				Example:    C: A003 CREATE owatagusiam/
							S: A003 OK CREATE completed
							C: A004 CREATE owatagusiam/blurdybloop
							S: A004 OK CREATE completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD CREATE invalid arguments. Syntax: {{<command-tag> CREATE \"mailboxName\"}}", cmdTag));
                return;
            }

            // Store start time
            long startTime = DateTime.Now.Ticks;

            string errorText = ImapServer.OnCreateMailbox(this, Core.Decode_IMAP_UTF7_String(args[0]));
            if (errorText == null)
            {
                WriteLine(string.Format("{0} OK CREATE Completed in {1} seconds", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2")));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
            }
        }

        private void Delete(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.4 DELETE Command
			
				Arguments:  mailbox name

				Responses:  no specific responses for this command

				Result:     OK - create completed
							NO - create failure: can't create mailbox with that name
							BAD - command unknown or arguments invalid
			   
				The DELETE command permanently removes the mailbox with the given
				name.  A tagged OK response is returned only if the mailbox has
				been deleted.  It is an error to attempt to delete INBOX or a
				mailbox name that does not exist.

				The DELETE command MUST NOT remove inferior hierarchical names.
				For example, if a mailbox "foo" has an inferior "foo.bar"
				(assuming "." is the hierarchy delimiter character), removing
				"foo" MUST NOT remove "foo.bar".  It is an error to attempt to
				delete a name that has inferior hierarchical names and also has
				the \Noselect mailbox name attribute (see the description of the
				LIST response for more details).

				It is permitted to delete a name that has inferior hierarchical
				names and does not have the \Noselect mailbox name attribute.  In
				this case, all messages in that mailbox are removed, and the name
				will acquire the \Noselect mailbox name attribute.

				The value of the highest-used unique identifier of the deleted
				mailbox MUST be preserved so that a new mailbox created with the
				same name will not reuse the identifiers of the former
				incarnation, UNLESS the new incarnation has a different unique
				identifier validity value.  See the description of the UID command
				for more detail.
				
				Examples:   C: A682 LIST "" *
							S: * LIST () "/" blurdybloop
							S: * LIST (\Noselect) "/" foo
							S: * LIST () "/" foo/bar
							S: A682 OK LIST completed
							C: A683 DELETE blurdybloop
							S: A683 OK DELETE completed
							C: A684 DELETE foo
							S: A684 NO Name "foo" has inferior hierarchical names
							C: A685 DELETE foo/bar
							S: A685 OK DELETE Completed
							C: A686 LIST "" *
							S: * LIST (\Noselect) "/" foo
							S: A686 OK LIST completed
							C: A687 DELETE foo
							S: A687 OK DELETE Completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD DELETE invalid arguments. Syntax: {{<command-tag> DELETE \"mailboxName\"}}", cmdTag));
                return;
            }

            string errorText = ImapServer.OnDeleteMailbox(this, Core.Decode_IMAP_UTF7_String(args[0]));
            if (errorText == null)
            {
                WriteLine(string.Format("{0} OK DELETE Completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
            }
        }

        private void Rename(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.5 RENAME Command
			  
				Arguments:  existing mailbox name
							new mailbox name

				Responses:  no specific responses for this command

				Result:     OK - rename completed
							NO - rename failure: can't rename mailbox with that name,
								 can't rename to mailbox with that name
							BAD - command unknown or arguments invalid
			   
				The RENAME command changes the name of a mailbox.  A tagged OK
				response is returned only if the mailbox has been renamed.  It is		  
				an error to attempt to rename from a mailbox name that does not
				exist or to a mailbox name that already exists.  Any error in
				renaming will return a tagged NO response.

				If the name has inferior hierarchical names, then the inferior
				hierarchical names MUST also be renamed.  For example, a rename of
				"foo" to "zap" will rename "foo/bar" (assuming "/" is the
				hierarchy delimiter character) to "zap/bar".

				The value of the highest-used unique identifier of the old mailbox
				name MUST be preserved so that a new mailbox created with the same
				name will not reuse the identifiers of the former incarnation,
				UNLESS the new incarnation has a different unique identifier
				validity value.  See the description of the UID command for more
				detail.

				Renaming INBOX is permitted, and has special behavior.  It moves
				all messages in INBOX to a new mailbox with the given name,
				leaving INBOX empty.  If the server implementation supports
				inferior hierarchical names of INBOX, these are unaffected by a
				rename of INBOX.
				
				Examples:   C: A682 LIST "" *
							S: * LIST () "/" blurdybloop
							S: * LIST (\Noselect) "/" foo
							S: * LIST () "/" foo/bar
							S: A682 OK LIST completed
							C: A683 RENAME blurdybloop sarasoop
							S: A683 OK RENAME completed
							C: A684 RENAME foo zowie
							S: A684 OK RENAME Completed
							C: A685 LIST "" *
							S: * LIST () "/" sarasoop
							S: * LIST (\Noselect) "/" zowie
							S: * LIST () "/" zowie/bar
							S: A685 OK LIST completed
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD RENAME invalid arguments. Syntax: {{<command-tag> RENAME \"mailboxName\" \"newMailboxName\"}}", cmdTag));
                return;
            }

            string mailbox = Core.Decode_IMAP_UTF7_String(args[0]);
            string newMailbox = Core.Decode_IMAP_UTF7_String(args[1]);

            string errorText = ImapServer.OnRenameMailbox(this, mailbox, newMailbox);
            if (errorText == null)
            {
                WriteLine(string.Format("{0} OK RENAME Completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
            }
        }

        private void Suscribe(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.6 SUBSCRIBE Commmand
				
				Arguments:  mailbox

				Responses:  no specific responses for this command

				Result:     OK - subscribe completed
							NO - subscribe failure: can't subscribe to that name
							BAD - command unknown or arguments invalid
			   
				The SUBSCRIBE command adds the specified mailbox name to the
				server's set of "active" or "subscribed" mailboxes as returned by
				the LSUB command.  This command returns a tagged OK response only
				if the subscription is successful.

				A server MAY validate the mailbox argument to SUBSCRIBE to verify
				that it exists.  However, it MUST NOT unilaterally remove an
				existing mailbox name from the subscription list even if a mailbox
				by that name no longer exists.

				Note: this requirement is because some server sites may routinely
				remove a mailbox with a well-known name (e.g.  "system-alerts")
				after its contents expire, with the intention of recreating it
				when new contents are appropriate.

				Example:    C: A002 SUBSCRIBE #news.comp.mail.mime
							S: A002 OK SUBSCRIBE completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD SUBSCRIBE invalid arguments. Syntax: {{<command-tag> SUBSCRIBE \"mailboxName\"}}", cmdTag));
                return;
            }
            string errorText = ImapServer.OnSubscribeMailbox(this, Core.Decode_IMAP_UTF7_String(args[0]));
            if (errorText == null)
            {
                AdditionalSelect(Core.Decode_IMAP_UTF7_String(args[0]));
                WriteLine(string.Format("{0} OK SUBSCRIBE completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
            }
        }

        

        private void AdditionalSelect(string folder)
        {
            m_StatusedMailbox = folder;
            m_pAdditionalFolder = new IMAP_SelectedFolder(folder);
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, m_pAdditionalFolder);
        }

        private void UnSuscribe(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.7 UNSUBSCRIBE Command
				
				Arguments:  mailbox

				Responses:  no specific responses for this command

				Result:     OK - subscribe completed
							NO - subscribe failure: can't subscribe to that name
							BAD - command unknown or arguments invalid
			   
				The UNSUBSCRIBE command removes the specified mailbox name from
				the server's set of "active" or "subscribed" mailboxes as returned
				by the LSUB command.  This command returns a tagged OK response
				only if the unsubscription is successful.

				Example:    C: A002 UNSUBSCRIBE #news.comp.mail.mime
							S: A002 OK UNSUBSCRIBE completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD UNSUBSCRIBE invalid arguments. Syntax: {{<command-tag> UNSUBSCRIBE \"mailboxName\"}}", cmdTag));
                return;
            }

            string errorText = ImapServer.OnUnSubscribeMailbox(this, Core.Decode_IMAP_UTF7_String(args[0]));

            if (errorText == null)
            {
                AdditionalSelect(Core.Decode_IMAP_UTF7_String(args[0]));
                WriteLine(string.Format("{0} OK UNSUBSCRIBE completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
            }
        }

        private void List(string cmdTag, string argsText)
        {
            /* Rc 3501 6.3.8 LIST Command
			 
				Arguments:  reference name
							mailbox name with possible wildcards

				Responses:  untagged responses: LIST

				Result:     OK - list completed
							NO - list failure: can't list that reference or name
							BAD - command unknown or arguments invalid
							
				The LIST command returns a subset of names from the complete set
				of all names available to the client.  Zero or more untagged LIST
				replies are returned, containing the name attributes, hierarchy
				delimiter, and name; see the description of the LIST reply for
				more detail.
				
				An empty ("" string) reference name argument indicates that the
				mailbox name is interpreted as by SELECT. The returned mailbox
				names MUST match the supplied mailbox name pattern.  A non-empty
				reference name argument is the name of a mailbox or a level of
				mailbox hierarchy, and indicates a context in which the mailbox
				name is interpreted in an implementation-defined manner.
				
				An empty ("" string) mailbox name argument is a special request to
				return the hierarchy delimiter and the root name of the name given
				in the reference.  The value returned as the root MAY be null if
				the reference is non-rooted or is null.  In all cases, the
				hierarchy delimiter is returned.  This permits a client to get the
				hierarchy delimiter even when no mailboxes by that name currently
				exist.
				
				The character "*" is a wildcard, and matches zero or more
				characters at this position.  The character "%" is similar to "*",
				but it does not match a hierarchy delimiter.  If the "%" wildcard
				is the last character of a mailbox name argument, matching levels
				of hierarchy are also returned.
			    
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD Invalid LIST arguments. Syntax: {{<command-tag> LIST \"<reference-name>\" \"<mailbox-name>\"}}", cmdTag));
                return;
            }

            // Store start time
            long startTime = DateTime.Now.Ticks;

            string refName = Core.Decode_IMAP_UTF7_String(args[0]);
            string mailbox = Core.Decode_IMAP_UTF7_String(args[1]);

            string reply = "";

            // Folder separator wanted
            if (mailbox.Length == 0)
            {
                reply += "* LIST (\\Noselect) \"/\" \"\"\r\n";
            }
            // List mailboxes
            else
            {
                IMAP_Folders mailboxes = ImapServer.OnGetMailboxes(this, refName, mailbox);
                foreach (IMAP_Folder mBox in mailboxes.Folders)
                {
                    if (mBox.Selectable)
                    {
                        reply += string.Format("* LIST () \"/\" \"{0}\" \r\n", Core.Encode_IMAP_UTF7_String(mBox.Folder));
                    }
                    else
                    {
                        reply += string.Format("* LIST (\\Noselect) \"/\" \"{0}\" \r\n", Core.Encode_IMAP_UTF7_String(mBox.Folder));
                    }
                }
            }

            reply += string.Format("{0} OK LIST Completed in {1} seconds\r\n", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2"));
            TcpStream.Write(reply);
        }

        private void LSub(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.9 LSUB Command
			 
				Arguments:  reference name
							mailbox name with possible wildcards

				Responses:  untagged responses: LSUB

				Result:     OK - lsub completed
							NO - lsub failure: can't list that reference or name
							BAD - command unknown or arguments invalid
				   
				The LSUB command returns a subset of names from the set of names
				that the user has declared as being "active" or "subscribed".
				Zero or more untagged LSUB replies are returned.  The arguments to
				LSUB are in the same form as those for LIST.

				The returned untagged LSUB response MAY contain different mailbox
				flags from a LIST untagged response.  If this should happen, the
				flags in the untagged LIST are considered more authoritative.

				A special situation occurs when using LSUB with the % wildcard.
				Consider what happens if "foo/bar" (with a hierarchy delimiter of
				"/") is subscribed but "foo" is not.  A "%" wildcard to LSUB must
				return foo, not foo/bar, in the LSUB response, and it MUST be
				flagged with the \Noselect attribute.

				The server MUST NOT unilaterally remove an existing mailbox name
				from the subscription list even if a mailbox by that name no
				longer exists.

				Example:    C: A002 LSUB "#news." "comp.mail.*"
							S: * LSUB () "." #news.comp.mail.mime
							S: * LSUB () "." #news.comp.mail.misc
							S: A002 OK LSUB completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD LSUB invalid arguments", cmdTag));
                return;
            }

            string refName = Core.Decode_IMAP_UTF7_String(args[0]);
            string mailbox = Core.Decode_IMAP_UTF7_String(args[1]);

            string reply = "";

            IMAP_Folders mailboxes = ImapServer.OnGetSubscribedMailboxes(this, refName, mailbox);
            foreach (IMAP_Folder mBox in mailboxes.Folders)
            {
                reply += string.Format("* LSUB () \"/\" \"{0}\" \r\n", Core.Encode_IMAP_UTF7_String(mBox.Folder));
            }

            reply += string.Format("{0} OK LSUB Completed\r\n", cmdTag);
            TcpStream.Write(reply);
        }

        private void Status(string cmdTag, string argsText)
        {
            /* RFC 3501 6.3.10 STATUS Command
			
				Arguments:  mailbox name
							status data item names

				Responses:  untagged responses: STATUS

				Result:     OK - status completed
							NO - status failure: no status for that name
							BAD - command unknown or arguments invalid
			   
				The STATUS command requests the status of the indicated mailbox.
				It does not change the currently selected mailbox, nor does it
				affect the state of any messages in the queried mailbox (in
				particular, STATUS MUST NOT cause messages to lose the \Recent
				flag).

				The STATUS command provides an alternative to opening a second
				IMAP4rev1 connection and doing an EXAMINE command on a mailbox to
				query that mailbox's status without deselecting the current
				mailbox in the first IMAP4rev1 connection.

				Unlike the LIST command, the STATUS command is not guaranteed to
				be fast in its response.  In some implementations, the server is
				obliged to open the mailbox read-only internally to obtain certain
				status information.  Also unlike the LIST command, the STATUS
				command does not accept wildcards.

				The currently defined status data items that can be requested are:

				MESSAGES
					The number of messages in the mailbox.

				RECENT
					The number of messages with the \Recent flag set.

				UIDNEXT
					The next unique identifier value of the mailbox.  Refer to
					section 2.3.1.1 for more information.

				UIDVALIDITY
					The unique identifier validity value of the mailbox.  Refer to
					section 2.3.1.1 for more information.

				UNSEEN
					The number of messages which do not have the \Seen flag set.


				Example:    C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
							S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
							S: A042 OK STATUS completed
				  
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = ParseParams(argsText);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD Invalid STATUS arguments. Syntax: {{<command-tag> STATUS \"<mailbox-name>\" \"(status-data-items)\"}}", cmdTag));
                return;
            }

            string folder = Core.Decode_IMAP_UTF7_String(args[0]);
            string wantedItems = args[1].ToUpper();

            // See wanted items are valid.
            if (
                wantedItems.Replace("MESSAGES", "").Replace("RECENT", "").Replace("UIDNEXT", "").Replace(
                    "UIDVALIDITY", "").Replace("UNSEEN", "").Trim().Length > 0)
            {
                WriteLine(string.Format("{0} BAD STATUS invalid arguments", cmdTag));
                return;
            }

            AdditionalSelect(folder);
            IMAP_SelectedFolder selectedFolder = new IMAP_SelectedFolder(folder);
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, selectedFolder);
            if (eArgs.ErrorText == null)
            {
                string itemsReply = "";
                if (wantedItems.IndexOf("MESSAGES") > -1)
                {
                    itemsReply += string.Format(" MESSAGES {0}", selectedFolder.Messages.Count);
                }
                if (wantedItems.IndexOf("RECENT") > -1)
                {
                    itemsReply += string.Format(" RECENT {0}", selectedFolder.RecentCount);
                }
                if (wantedItems.IndexOf("UNSEEN") > -1)
                {
                    itemsReply += string.Format(" UNSEEN {0}", selectedFolder.UnSeenCount);
                }
                if (wantedItems.IndexOf("UIDVALIDITY") > -1)
                {
                    itemsReply += string.Format(" UIDVALIDITY {0}", selectedFolder.FolderUID);
                }
                if (wantedItems.IndexOf("UIDNEXT") > -1)
                {
                    itemsReply += string.Format(" UIDNEXT {0}", selectedFolder.MessageUidNext);
                }
                itemsReply = itemsReply.Trim();

                WriteLine(string.Format("* STATUS {0} ({1})", args[0], itemsReply));
                WriteLine(string.Format("{0} OK STATUS completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, eArgs.ErrorText));
            }
        }

        /// <summary>
        /// Returns true if command ended syncronously.
        /// </summary>
        private bool BeginAppendCmd(string cmdTag, string argsText)
        {
            /* Rfc 3501 6.3.11 APPEND Command
			
				Arguments:  mailbox name
							OPTIONAL flag parenthesized list
							OPTIONAL date/time string
							message literal

				Responses:  no specific responses for this command

				Result:     OK - append completed
							NO - append error: can't append to that mailbox, error
									in flags or date/time or message text
							BAD - command unknown or arguments invalid

				The APPEND command appends the literal argument as a new message
				to the end of the specified destination mailbox.  This argument
				SHOULD be in the format of an [RFC-2822] message.  8-bit
				characters are permitted in the message.  A server implementation
				that is unable to preserve 8-bit data properly MUST be able to
				reversibly convert 8-bit APPEND data to 7-bit using a [MIME-IMB]
				content transfer encoding.
					
				If a flag parenthesized list is specified, the flags SHOULD be set
				in the resulting message; otherwise, the flag list of the
				resulting message is set to empty by default.  In either case, the
				Recent flag is also set.

				If a date-time is specified, the internal date SHOULD be set in
				the resulting message; otherwise, the internal date of the
				resulting message is set to the current date and time by default.

				If the append is unsuccessful for any reason, the mailbox MUST be
				restored to its state before the APPEND attempt; no partial
				appending is permitted.

				If the destination mailbox does not exist, a server MUST return an
				error, and MUST NOT automatically create the mailbox.  Unless it
				is certain that the destination mailbox can not be created, the
				server MUST send the response code "[TRYCREATE]" as the prefix of
				the text of the tagged NO response.  This gives a hint to the
				client that it can attempt a CREATE command and retry the APPEND
				if the CREATE is successful.
					
				Example:    C: A003 APPEND saved-messages (\Seen) {310}
							S: + Ready for literal data
							C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
							C: From: <NAME> <<EMAIL>>
							C: Subject: afternoon meeting
							C: To: <EMAIL>
							C: Message-Id: <<EMAIL>>
							C: MIME-Version: 1.0
							C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
							C:
							C: Hello Joe, do you think we can meet at 3:30 tomorrow?
							C:
							S: A003 OK APPEND completed
					
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return true;
            }

            string[] args = ParseParams(argsText);
            if (args.Length < 2 || args.Length > 4)
            {
                WriteLine(string.Format("{0} BAD APPEND Invalid arguments", cmdTag));
                return true;
            }

            string mailbox = Core.Decode_IMAP_UTF7_String(args[0]);
            IMAP_MessageFlags mFlags = 0;
            DateTime date = DateTime.Now;
            long msgLen = Convert.ToInt64(args[args.Length - 1].Replace("{", "").Replace("}", ""));

            if (args.Length == 4)
            {
                //--- Parse flags, see if valid ----------------
                string flags = args[1].ToUpper();
                if (
                    flags.Replace("\\ANSWERED", "").Replace("\\FLAGGED", "").Replace("\\DELETED", "").Replace(
                        "\\SEEN", "").Replace("\\DRAFT", "").Trim().Length > 0)
                {
                    WriteLine(string.Format("{0} BAD arguments invalid", cmdTag));
                    return false;
                }

                mFlags = IMAP_Utils.ParseMessageFlags(flags);
                date = MimeUtils.ParseDate(args[2]);
            }
            else if (args.Length == 3)
            {
                // See if date or flags specified, try date first
                try
                {
                    date = MimeUtils.ParseDate(args[1]);
                }
                catch
                {
                    //--- Parse flags, see if valid ----------------
                    string flags = args[1].ToUpper();
                    if (
                        flags.Replace("\\ANSWERED", "").Replace("\\FLAGGED", "").Replace("\\DELETED", "").
                            Replace("\\SEEN", "").Replace("\\DRAFT", "").Trim().Length > 0)
                    {
                        WriteLine(string.Format("{0} BAD arguments invalid", cmdTag));
                        return false;
                    }

                    mFlags = IMAP_Utils.ParseMessageFlags(flags);
                }
            }

            // Request data
            WriteLine("+ Ready for literal data");

            MemoryStream strm = new MemoryStream();
            Hashtable param = new Hashtable();
            param.Add("cmdTag", cmdTag);
            param.Add("mailbox", mailbox);
            param.Add("mFlags", mFlags);
            param.Add("date", date);
            param.Add("strm", strm);

            // Begin recieving data                      Why needed msgLen+2 ??? 
            TcpStream.BeginReadFixedCount(strm, (int)msgLen + 2, EndAppendCmd, param);

            return false;
        }

        /// <summary>
        /// Is called when DATA command is finnished.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void EndAppendCmd(IAsyncResult ar)
        {
            try
            {
                TcpStream.EndReadFixedCount(ar);
                if (ar.IsCompleted)
                {

                    Hashtable param = (Hashtable)ar.AsyncState;
                    string cmdTag = (string)param["cmdTag"];
                    string mailbox = (string)param["mailbox"];
                    IMAP_MessageFlags mFlags = (IMAP_MessageFlags)param["mFlags"];
                    DateTime date = (DateTime)param["date"];
                    MemoryStream strm = (MemoryStream)param["strm"];

                    IMAP_Message msg = new IMAP_Message(null, "", 0, date, 0, mFlags);
                    string errotText = ImapServer.OnStoreMessage(this, mailbox, msg, strm.ToArray());
                    if (errotText == null)
                    {
                        WriteLine(string.Format("{0} OK APPEND completed, recieved {1} bytes", cmdTag, strm.Length));
                    }
                    else
                    {
                        WriteLine(string.Format("{0} NO {1}", cmdTag, errotText));
                    }
                }

                // Command completed ok, get next command
                BeginRecieveCmd();
            }
            catch (Exception x)
            {
                OnError(x);
            }
        }

        private void Namespace(string cmdTag, string argsText)
        {
            /* Rfc 2342 5. NAMESPACE Command.              
             
                Arguments: none

                Response:  an untagged NAMESPACE response that contains the prefix
                             and hierarchy delimiter to the server's Personal
                             Namespace(s), Other Users' Namespace(s), and Shared
                             Namespace(s) that the server wishes to expose. The
                             response will contain a NIL for any namespace class
                             that is not available. Namespace_Response_Extensions
                             MAY be included in the response.
                             Namespace_Response_Extensions which are not on the IETF
                             standards track, MUST be prefixed with an "X-".

                Result:    OK - Command completed
                           NO - Error: Can't complete command
                           BAD - argument invalid
             
				Example: < A server that contains a Personal Namespace and a single Shared
						Namespace. >

						C: A001 NAMESPACE
						S: * NAMESPACE (("" "/")) NIL (("Public Folders/" "/"))
						S: A001 OK NAMESPACE command completed	  
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            SharedRootFolders_EventArgs eArgs = ImapServer.OnGetSharedRootFolders(this);
            string publicRootFolders = "NIL";
            if (eArgs.PublicRootFolders != null && eArgs.PublicRootFolders.Length > 0)
            {
                publicRootFolders = "(";
                foreach (string publicRootFolder in eArgs.PublicRootFolders)
                {
                    publicRootFolders += string.Format("(\"{0}/\" \"/\")", publicRootFolder);
                }
                publicRootFolders += ")";
            }
            string sharedRootFolders = "NIL";
            if (eArgs.SharedRootFolders != null && eArgs.SharedRootFolders.Length > 0)
            {
                sharedRootFolders = "(";
                foreach (string sharedRootFolder in eArgs.SharedRootFolders)
                {
                    sharedRootFolders += string.Format("(\"{0}/\" \"/\")", sharedRootFolder);
                }
                sharedRootFolders += ")";
            }

            string response = string.Format("* NAMESPACE ((\"\" \"/\")) {0} {1}\r\n", sharedRootFolders, publicRootFolders);
            response += string.Format("{0} OK NAMESPACE completed", cmdTag);

            WriteLine(response);
        }

        private void GETACL(string cmdTag, string argsText)
        {
            /* RFC 2086 4.3. GETACL
				Arguments:  mailbox name

				Data:       untagged responses: ACL

				Result:     OK - getacl completed
							NO - getacl failure: can't get acl
							BAD - command unknown or arguments invalid

					The GETACL command returns the access control list for mailbox in
					an untagged ACL reply.

				Example:    C: A002 GETACL INBOX
							S: * ACL INBOX Fred rwipslda
							S: A002 OK Getacl complete
							
							.... Multiple users
							S: * ACL INBOX Fred rwipslda test rwipslda
							
							.... No acl flags for Fred
							S: * ACL INBOX Fred "" test rwipslda
									
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD GETACL invalid arguments. Syntax: GETACL<SP>FolderName<CRLF>", cmdTag));
                return;
            }

            IMAP_GETACL_eArgs eArgs = ImapServer.OnGetFolderACL(this,
                                                               Core.Decode_IMAP_UTF7_String(
                                                                   IMAP_Utils.NormalizeFolder(args[0])));
            if (eArgs.ErrorText.Length > 0)
            {
                WriteLine(string.Format("{0} NO GETACL {1}", cmdTag, eArgs.ErrorText));
            }
            else
            {
                string response = "";
                if (eArgs.ACL.Count > 0)
                {
                    response += string.Format("* ACL \"{0}\"", args[0]);
                    foreach (DictionaryEntry ent in eArgs.ACL)
                    {
                        string aclFalgs = IMAP_Utils.ACL_to_String((IMAP_ACL_Flags)ent.Value);
                        if (aclFalgs.Length == 0)
                        {
                            aclFalgs = "\"\"";
                        }
                        response += string.Format(" \"{0}\" {1}", ent.Key, aclFalgs);
                    }
                    response += "\r\n";
                }
                response += string.Format("{0} OK Getacl complete\r\n", cmdTag);

                TcpStream.Write(response);
            }
        }

        private void SETACL(string cmdTag, string argsText)
        {
            /* RFC 2086 4.1. SETACL
				Arguments:  mailbox name
							authentication identifier
							access right modification

				Data:       no specific data for this command

				Result:     OK - setacl completed
							NO - setacl failure: can't set acl
							BAD - command unknown or arguments invalid

					The SETACL command changes the access control list on the
					specified mailbox so that the specified identifier is granted
					permissions as specified in the third argument.

					The third argument is a string containing an optional plus ("+")
					or minus ("-") prefix, followed by zero or more rights characters.
					If the string starts with a plus, the following rights are added
					to any existing rights for the identifier.  If the string starts
					with a minus, the following rights are removed from any existing
					rights for the identifier.  If the string does not start with a
					plus or minus, the rights replace any existing rights for the
					identifier.
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = ParseParams(argsText);
            if (args.Length != 3)
            {
                WriteLine(string.Format("{0} BAD GETACL invalid arguments. Syntax: SETACL<SP>FolderName<SP>UserName<SP>ACL_Flags<CRLF>", cmdTag));
                return;
            }

            string aclFlags = args[2];
            IMAP_Flags_SetType setType = IMAP_Flags_SetType.Replace;
            if (aclFlags.StartsWith("+"))
            {
                setType = IMAP_Flags_SetType.Add;
            }
            else if (aclFlags.StartsWith("-"))
            {
                setType = IMAP_Flags_SetType.Remove;
            }

            IMAP_SETACL_eArgs eArgs = ImapServer.OnSetFolderACL(this,
                                                               IMAP_Utils.NormalizeFolder(args[0]),
                                                               args[1],
                                                               setType,
                                                               IMAP_Utils.ACL_From_String(aclFlags));
            if (eArgs.ErrorText.Length > 0)
            {
                WriteLine(string.Format("{0} NO SETACL {1}", cmdTag, eArgs.ErrorText));
            }
            else
            {
                WriteLine(string.Format("{0} OK SETACL completed", cmdTag));
            }
        }

        private void DELETEACL(string cmdTag, string argsText)
        {
            /* RFC 2086 4.2. DELETEACL
				Arguments:  mailbox name
							authentication identifier

				Data:       no specific data for this command

				Result:     OK - deleteacl completed
							NO - deleteacl failure: can't delete acl
							BAD - command unknown or arguments invalid

					The DELETEACL command removes any <identifier,rights> pair for the
					specified identifier from the access control list for the specified
					mailbox.
					
				Example:    C: A002 DELETEACL INBOX test
							S: A002 OK DELETEACL completed
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD GETACL invalid arguments. Syntax: DELETEACL<SP>FolderName<SP>UserName<CRLF>", cmdTag));
                return;
            }

            IMAP_DELETEACL_eArgs eArgs = ImapServer.OnDeleteFolderACL(this,
                                                                     IMAP_Utils.NormalizeFolder(args[0]),
                                                                     args[1]);
            if (eArgs.ErrorText.Length > 0)
            {
                WriteLine(string.Format("{0} NO DELETEACL {1}", cmdTag, eArgs.ErrorText));
            }
            else
            {
                WriteLine(string.Format("{0} OK DELETEACL completed", cmdTag));
            }
        }

        private void LISTRIGHTS(string cmdTag, string argsText)
        {
            /* RFC 2086 4.4. LISTRIGHTS
				Arguments:  mailbox name
				authentication identifier

				Data:       untagged responses: LISTRIGHTS

				Result:     OK - listrights completed
							NO - listrights failure: can't get rights list
							BAD - command unknown or arguments invalid

					The LISTRIGHTS command takes a mailbox name and an identifier and
					returns information about what rights may be granted to the identifier
					in the ACL for the mailbox.
					
				Example:    C: a001 LISTRIGHTS ~/Mail/saved smith
							S: * LISTRIGHTS ~/Mail/saved "smith" la r swicd
							S: a001 OK Listrights completed


							C: a005 LISTRIGHTS archive.imap anyone
							S: * LISTRIGHTS archive.imap "anyone" "" l r s w i p c d a
							0 1 2 3 4 5 6 7 8 9
			   
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD GETACL invalid arguments. Syntax: LISTRIGHTS<SP>FolderName<SP>UserName<CRLF>", cmdTag));
                return;
            }

            string response = string.Format("* LISTRIGHTS \"{0}\" \"{1}\" l r s w i p c d a\r\n", args[0], args[1]);
            response += string.Format("{0} OK MYRIGHTS Completed\r\n", cmdTag);

            TcpStream.Write(response);
        }

        private void MYRIGHTS(string cmdTag, string argsText)
        {
            /* RFC 2086 4.5. MYRIGHTS
				Arguments:  mailbox name

				Data:       untagged responses: MYRIGHTS

				Result:     OK - myrights completed
							NO - myrights failure: can't get rights
							BAD - command unknown or arguments invalid

					The MYRIGHTS command returns the set of rights that the user has
					to mailbox in an untagged MYRIGHTS reply.

				Example:    C: A003 MYRIGHTS INBOX
							S: * MYRIGHTS INBOX rwipslda
							S: A003 OK Myrights complete
							
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD GETACL invalid arguments. Syntax: MYRIGHTS<SP>FolderName<CRLF>", cmdTag));
                return;
            }

            IMAP_GetUserACL_eArgs eArgs = ImapServer.OnGetUserACL(this,
                                                                 IMAP_Utils.NormalizeFolder(args[0]),
                                                                 UserName);
            if (eArgs.ErrorText.Length > 0)
            {
                WriteLine(string.Format("{0} NO MYRIGHTS {1}", cmdTag, eArgs.ErrorText));
            }
            else
            {
                string aclFlags = IMAP_Utils.ACL_to_String(eArgs.ACL);
                if (aclFlags.Length == 0)
                {
                    aclFlags = "\"\"";
                }
                string response = string.Format("* MYRIGHTS \"{0}\" {1}\r\n", args[0], aclFlags);
                response += string.Format("{0} OK MYRIGHTS Completed\r\n", cmdTag);

                TcpStream.Write(response);
            }
        }

        private void GETQUOTA(string cmdTag, string argsText)
        {
            /* RFC 2087 4.2. GETQUOTA
				Arguments:  quota root

                Data:       untagged responses: QUOTA

                Result:     OK - getquota completed
                            NO - getquota  error:  no  such  quota  root,  permission denied
                            BAD - command unknown or arguments invalid

                The GETQUOTA command takes the name of a quota root and returns the
                quota root's resource usage and limits in an untagged QUOTA response.

                Example:    C: A003 GETQUOTA ""
                            S: * QUOTA "" (STORAGE 10 512)
                            S: A003 OK Getquota completed
							
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD GETQUOTA invalid arguments. Syntax: GETQUOTA \"quota_root\"<CRLF>", cmdTag));
                return;
            }

            IMAP_eArgs_GetQuota eArgs = ImapServer.OnGetUserQuota(this);
            string reply = string.Format("* QUOTA \"\" (STORAGE {0} {1})\r\n", eArgs.MailboxSize, eArgs.MaxMailboxSize);
            reply += string.Format("{0} OK GETQUOTA completed\r\n", cmdTag);
            TcpStream.Write(reply);
        }

        private void GETQUOTAROOT(string cmdTag, string argsText)
        {
            /* RFC 2087 4.3. GETQUOTAROOT
				Arguments:  mailbox name

                Data:       untagged responses: QUOTAROOT, QUOTA

                Result:     OK - getquota completed
                            NO - getquota error: no such mailbox, permission denied
                            BAD - command unknown or arguments invalid

                The GETQUOTAROOT command takes the name of a mailbox and returns the
                list of quota roots for the mailbox in an untagged QUOTAROOT
                response.  For each listed quota root, it also returns the quota
                root's resource usage and limits in an untagged QUOTA response.

                Example:    C: A003 GETQUOTAROOT INBOX
                            S: * QUOTAROOT INBOX ""
                            S: * QUOTA "" (STORAGE 10 512)
                            S: A003 OK Getquota completed
							
			*/

            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }

            string[] args = TextUtils.SplitQuotedString(argsText, ' ', true);
            if (args.Length != 1)
            {
                WriteLine(string.Format("{0} BAD GETQUOTAROOT invalid arguments. Syntax: GETQUOTAROOT \"folder\"<CRLF>", cmdTag));
                return;
            }

            IMAP_eArgs_GetQuota eArgs = ImapServer.OnGetUserQuota(this);
            string reply = string.Format("* QUOTAROOT \"{0}\" \"\"\r\n", args[0]);
            reply += string.Format("* QUOTA \"\" (STORAGE {0} {1})\r\n", eArgs.MailboxSize, eArgs.MaxMailboxSize);
            reply += string.Format("{0} OK GETQUOTAROOT completed\r\n", cmdTag);
            TcpStream.Write(reply);
        }

        //--- End of IsAuthenticated State 

        //--- Selected State ------

        private void Check(string cmdTag)
        {
            /* RFC 3501 6.4.1 CHECK Command
			
				Arguments:  none

				Responses:  no specific responses for this command

				Result:     OK - check completed
							BAD - command unknown or arguments invalid
			   
				The CHECK command requests a checkpoint of the currently selected
				mailbox.  A checkpoint refers to any implementation-dependent
				housekeeping associated with the mailbox (e.g. resolving the
				server's in-memory state of the mailbox with the state on its
				disk) that is not normally executed as part of each command.  A
				checkpoint MAY take a non-instantaneous amount of real time to
				complete.  If a server implementation has no such housekeeping
				considerations, CHECK is equivalent to NOOP.

				There is no guarantee that an EXISTS untagged response will happen
				as a result of CHECK.  NOOP, not CHECK, SHOULD be used for new
				mail polling.
				
				Example:    C: FXXZ CHECK
							S: FXXZ OK CHECK Completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            WriteLine(string.Format("{0} OK CHECK completed", cmdTag));
        }

        private void Close(string cmdTag)
        {
            /* RFC 3501 6.4.2 CLOSE Command
			
				Arguments:  none

				Responses:  no specific responses for this command

				Result:     OK - close completed, now in authenticated state
							BAD - command unknown or arguments invalid
			   
				The CLOSE command permanently removes from the currently selected
				mailbox all messages that have the \Deleted flag set, and returns
				to authenticated state from selected state.  No untagged EXPUNGE
				responses are sent.

				No messages are removed, and no error is given, if the mailbox is
				selected by an EXAMINE command or is otherwise selected read-only.

				Even if a mailbox is selected, a SELECT, EXAMINE, or LOGOUT
				command MAY be issued without previously issuing a CLOSE command.
				The SELECT, EXAMINE, and LOGOUT commands implicitly close the
				currently selected mailbox without doing an expunge.  However,
				when many messages are deleted, a CLOSE-LOGOUT or CLOSE-SELECT
				sequence is considerably faster than an EXPUNGE-LOGOUT or
				EXPUNGE-SELECT because no untagged EXPUNGE responses (which the
				client would probably ignore) are sent.

				Example:    C: A341 CLOSE
							S: A341 OK CLOSE completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            if (!m_pSelectedFolder.ReadOnly)
            {
                IMAP_Message[] messages = m_pSelectedFolder.Messages.GetWithFlags(IMAP_MessageFlags.Deleted);
                foreach (IMAP_Message msg in messages)
                {
                    ImapServer.OnDeleteMessage(this, msg);
                }
            }

            SelectedMailbox = "";
            m_pSelectedFolder = null;

            WriteLine(string.Format("{0} OK CLOSE completed", cmdTag));
            //EndSession();
        }

        private void Expunge(string cmdTag)
        {
            /* RFC 3501 6.4.3 EXPUNGE Command
			
				Arguments:  none

				Responses:  untagged responses: EXPUNGE

				Result:     OK - expunge completed
							NO - expunge failure: can't expunge (e.g., permission
									denied)
							BAD - command unknown or arguments invalid

					The EXPUNGE command permanently removes all messages that have the
					\Deleted flag set from the currently selected mailbox.  Before
					returning an OK to the client, an untagged EXPUNGE response is
					sent for each message that is removed.
					
				The EXPUNGE response reports that the specified message sequence
			    number has been permanently removed from the mailbox.  The message
				sequence number for each successive message in the mailbox is
				IMMEDIATELY DECREMENTED BY 1, and this decrement is reflected in
				message sequence numbers in subsequent responses (including other
				untagged EXPUNGE responses).


				Example:    C: A202 EXPUNGE
							S: * 3 EXPUNGE
							S: * 3 EXPUNGE
							S: * 5 EXPUNGE
							S: * 8 EXPUNGE
							S: A202 OK EXPUNGE completed

						Note: In this example, messages 3, 4, 7, and 11 had the
						\Deleted flag set.  See the description of the EXPUNGE
						response for further explanation.
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            IMAP_Message[] messages = m_pSelectedFolder.Messages.GetWithFlags(IMAP_MessageFlags.Deleted);
            for (int i = 0; i < messages.Length; i++)
            {
                IMAP_Message msg = messages[i];

                string errorText = ImapServer.OnDeleteMessage(this, msg);
                if (errorText == null)
                {
                    WriteLine(string.Format("* {0} EXPUNGE", msg.SequenceNo));
                    m_pSelectedFolder.Messages.Remove(msg);
                }
                else
                {
                    WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
                    return;
                }
            }

            WriteLine(string.Format("{0} OK EXPUNGE completed", cmdTag));
        }

        private void Search(string cmdTag, string argsText, bool uidSearch)
        {
            /* RFC 3501 6.4.4 SEARCH Command
			
				Arguments:  OPTIONAL [CHARSET] specification
							searching criteria (one or more)

				Responses:  REQUIRED untagged response: SEARCH

				Result:     OK - search completed
							NO - search error: can't search that [CHARSET] or
									criteria
							BAD - command unknown or arguments invalid
							
				The SEARCH command searches the mailbox for messages that match
				the given searching criteria.  Searching criteria consist of one
				or more search keys.  The untagged SEARCH response from the server
				contains a listing of message sequence numbers corresponding to
				those messages that match the searching criteria.
				
				When multiple keys are specified, the result is the intersection
				(AND function) of all the messages that match those keys.  For
				example, the criteria DELETED FROM "SMITH" SINCE 1-Feb-1994 refers
				to all deleted messages from Smith that were placed in the mailbox
				since February 1, 1994.  A search key can also be a parenthesized
				list of one or more search keys (e.g., for use with the OR and NOT
				keys).

				Server implementations MAY exclude [MIME-IMB] body parts with
				terminal content media types other than TEXT and MESSAGE from
				consideration in SEARCH matching.

				The OPTIONAL [CHARSET] specification consists of the word
				"CHARSET" followed by a registered [CHARSET].  It indicates the
				[CHARSET] of the strings that appear in the search criteria.
				[MIME-IMB] content transfer encodings, and [MIME-HDRS] strings in
				[RFC-2822]/[MIME-IMB] headers, MUST be decoded before comparing
				text in a [CHARSET] other than US-ASCII.  US-ASCII MUST be
				supported; other [CHARSET]s MAY be supported.

				If the server does not support the specified [CHARSET], it MUST
				return a tagged NO response (not a BAD).  This response SHOULD
				contain the BADCHARSET response code, which MAY list the
				[CHARSET]s supported by the server.

				In all search keys that use strings, a message matches the key if
				the string is a substring of the field.  The matching is
				case-insensitive.

				The defined search keys are as follows.  Refer to the Formal
				Syntax section for the precise syntactic definitions of the
				arguments.

				<sequence set>
					Messages with message sequence numbers corresponding to the
					specified message sequence number set.

				ALL
					All messages in the mailbox; the default initial key for
					ANDing.

				ANSWERED
					Messages with the \Answered flag set.
					
				BCC <string>
					Messages that contain the specified string in the envelope
					structure's BCC field.

				BEFORE <date>
					Messages whose internal date (disregarding time and timezone)
					is earlier than the specified date.

				BODY <string>
					Messages that contain the specified string in the body of the
					message.

				CC <string>
					Messages that contain the specified string in the envelope
					structure's CC field.

				DELETED
					Messages with the \Deleted flag set.

				DRAFT
					Messages with the \Draft flag set.

				FLAGGED
					Messages with the \Flagged flag set.

				FROM <string>
					Messages that contain the specified string in the envelope
					structure's FROM field.

				HEADER <field-name> <string>
					Messages that have a header with the specified field-name (as
					defined in [RFC-2822]) and that contains the specified string
					in the text of the header (what comes after the colon).  If the
					string to search is zero-length, this matches all messages that
					have a header line with the specified field-name regardless of
					the contents.

				KEYWORD <flag>
					Messages with the specified keyword flag set.

				LARGER <n>
					Messages with an [RFC-2822] size larger than the specified
					number of octets.

				NEW
					Messages that have the \Recent flag set but not the \Seen flag.
					This is functionally equivalent to "(RECENT UNSEEN)".
					
				NOT <search-key>
					Messages that do not match the specified search key.

				OLD
					Messages that do not have the \Recent flag set.  This is
					functionally equivalent to "NOT RECENT" (as opposed to "NOT
					NEW").

				ON <date>
					Messages whose internal date (disregarding time and timezone)
					is within the specified date.

				OR <search-key1> <search-key2>
					Messages that match either search key.

				RECENT
					Messages that have the \Recent flag set.

				SEEN
					Messages that have the \Seen flag set.

				SENTBEFORE <date>
					Messages whose [RFC-2822] Date: header (disregarding time and
					timezone) is earlier than the specified date.

				SENTON <date>
					Messages whose [RFC-2822] Date: header (disregarding time and
					timezone) is within the specified date.

				SENTSINCE <date>
					Messages whose [RFC-2822] Date: header (disregarding time and
					timezone) is within or later than the specified date.

				SINCE <date>
					Messages whose internal date (disregarding time and timezone)
					is within or later than the specified date.

				SMALLER <n>
					Messages with an [RFC-2822] size smaller than the specified
					number of octets.
					
				SUBJECT <string>
					Messages that contain the specified string in the envelope
					structure's SUBJECT field.

				TEXT <string>
					Messages that contain the specified string in the header or
					body of the message.

				TO <string>
					Messages that contain the specified string in the envelope
					structure's TO field.

				UID <sequence set>
					Messages with unique identifiers corresponding to the specified
					unique identifier set.  Sequence set ranges are permitted.

				UNANSWERED
					Messages that do not have the \Answered flag set.

				UNDELETED
					Messages that do not have the \Deleted flag set.

				UNDRAFT
					Messages that do not have the \Draft flag set.

				UNFLAGGED
					Messages that do not have the \Flagged flag set.

				UNKEYWORD <flag>
					Messages that do not have the specified keyword flag set.

				UNSEEN
					Messages that do not have the \Seen flag set.
					
					Example:   
						C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"
						S: * SEARCH 2 84 882
						S: A282 OK SEARCH completed
						C: A283 SEARCH TEXT "string not in mailbox"
						S: * SEARCH
						S: A283 OK SEARCH completed
						C: A284 SEARCH CHARSET UTF-8 TEXT {6}
						S: + Continue                          ### THIS IS UNDOCUMENTED !!!
						C: XXXXXX[arg conitnue]<CRLF>
						S: * SEARCH 43
						S: A284 OK SEARCH completed

				Note: Since this document is restricted to 7-bit ASCII
				text, it is not possible to show actual UTF-8 data.  The
				"XXXXXX" is a placeholder for what would be 6 octets of
				8-bit data in an actual transaction.
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            // Store start time
            long startTime = DateTime.Now.Ticks;

            //--- Get Optional charset, if specified -----------------------------------------------------------------//
            string charset = "ASCII";
            // CHARSET charset
            if (argsText.ToUpper().StartsWith("CHARSET"))
            {
                // Remove CHARSET from argsText
                argsText = argsText.Substring(7).Trim();

                string charsetValueString = IMAP_Utils.ParseQuotedParam(ref argsText);

                try
                {
                    EncodingTools.GetEncodingByCodepageName_Throws(charsetValueString);

                    charset = charsetValueString;
                }
                catch
                {
                    WriteLine(string.Format("{0} NO [BADCHARSET UTF-8] {1} is not supported", cmdTag, charsetValueString));
                    return;
                }
            }
            //---------------------------------------------------------------------------------------------------------//

            /* If multiline command, read all lines
				C: A284 SEARCH CHARSET UTF-8 TEXT {6}
				S: + Continue                             ### THIS IS UNDOCUMENTED !!!
				C: XXXXXX[arg conitnue]<CRLF>
			*/
            argsText = argsText.Trim();
            while (argsText.EndsWith("}") && argsText.IndexOf("{") > -1)
            {
                long dataLength = 0;
                try
                {
                    // Get data length from {xxx}
                    dataLength =
                        Convert.ToInt64(argsText.Substring(argsText.LastIndexOf("{") + 1,
                                                           argsText.Length - argsText.LastIndexOf("{") - 2));
                }
                // There is no valid numeric value between {}, just skip and allow SearchGroup parser to handle this value
                catch
                {
                    break;
                }

                MemoryStream dataStream = new MemoryStream();

                WriteLine("+ Continue");
                ReadSpecifiedLength((int)dataLength, dataStream);
                string argsContinueLine = ReadLine();

                // Append readed data + [args conitnue] line
                argsText += EncodingTools.GetEncodingByCodepageName_Throws(charset).GetString(dataStream.ToArray()) + argsContinueLine;

                // There is no more argumets, stop getting. 
                // We must check this because if length = 0 and no args returned, last line ends with {0},
                // leaves this into endless loop.
                if (argsContinueLine == "")
                {
                    break;
                }
            }

            //--- Parse search criteria ------------------------//
            SearchGroup searchCriteria = new SearchGroup();
            try
            {
                searchCriteria.Parse(new StringReader(argsText));
            }
            catch (Exception x)
            {
                WriteLine(cmdTag + " NO " + x.Message);
                return;
            }
            //--------------------------------------------------//
            /*
			string searchResponse = "* SEARCH";

			// No header and body text needed, can do search on internal messages info data
			if(!searchCriteria.IsHeaderNeeded() && !searchCriteria.IsBodyTextNeeded()){
				// Loop internal messages info, see what messages match
				for(int i=0;i<m_Messages.Count;i++){
					IMAP_Message messageInfo = m_Messages[i];

					// See if message matches
					if(searchCriteria.Match(i,messageInfo.MessageUID,(int)messageInfo.Size,messageInfo.Date,messageInfo.Flags,null,"")){
						// For UID search we must return message UID's
						if(uidSearch){
							searchResponse += " " + messageInfo.MessageUID.ToString();
						}
						// For normal search we must return message index numbers.
						else{
							searchResponse += " " + messageInfo.MessageNo.ToString();							
						}
					}
				}
			}
			// Can't search on iternal messages info, need to do header or body text search, call Search event
			else{
				// Call 'Search' event, get search criteria matching messages
				IMAP_eArgs_Search eArgs = ImapServer.OnSearch(this,Core.Decode_IMAP_UTF7_String(this.SelectedMailbox),new IMAP_SearchMatcher(searchCriteria));
				
				// Constuct matching messages search response
				for(int i=0;i<eArgs.MatchingMessages.Count;i++){
					IMAP_Message messageInfo = eArgs.MatchingMessages[i];

					// For UID search we must return message UID's
					if(uidSearch){
						searchResponse += " " + messageInfo.MessageUID.ToString();
					}
					// For normal search we must return message index numbers.
					else{
						// Map search returnded message to internal message number
						int no = m_Messages.IndexFromUID(messageInfo.MessageUID);
						if(no > -1){
							searchResponse += " " + no.ToString();
						}
					}
				}
			}

			searchResponse += "\r\n";
			searchResponse += cmdTag + " OK SEARCH completed in " + ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2") + " seconds\r\n";
*/
            ProcessMailboxChanges();

            // Just loop messages headers or full messages (depends on search type)
            //	string searchResponse = "* SEARCH";
            TcpStream.Write("* SEARCH");
            string searchResponse = "";

            IMAP_MessageItems_enum messageItems = IMAP_MessageItems_enum.None;
            if (searchCriteria.IsBodyTextNeeded())
            {
                messageItems |= IMAP_MessageItems_enum.Message;
            }
            else if (searchCriteria.IsHeaderNeeded())
            {
                messageItems |= IMAP_MessageItems_enum.Header;
            }
            for (int i = 0; i < m_pSelectedFolder.Messages.Count; i++)
            {
                IMAP_Message msg = m_pSelectedFolder.Messages[i];

                //-- Get message only if matching needs it ------------------------//
                Mime parser = null;
                if ((messageItems & IMAP_MessageItems_enum.Message) != 0 ||
                    (messageItems & IMAP_MessageItems_enum.Header) != 0)
                {
                    // Raise event GetMessageItems, get requested message items.
                    IMAP_eArgs_MessageItems eArgs = ImapServer.OnGetMessageItems(this, msg, messageItems);

                    // Message data is null if no such message available, just skip that message
                    if (!eArgs.MessageExists)
                    {
                        continue;
                    }
                    try
                    {
                        // Ensure that all requested items were provided.
                        eArgs.Validate();
                    }
                    catch (Exception x)
                    {
                        ImapServer.OnSysError(x.Message, x);
                        WriteLine(cmdTag + " NO Internal IMAP server component error: " + x.Message);
                        return;
                    }

                    try
                    {
                        if (eArgs.MessageStream != null)
                        {
                            parser = Mime.Parse(eArgs.MessageStream);
                        }
                        else
                        {
                            parser = Mime.Parse(eArgs.Header);
                        }
                    }
                    // Message parsing failed, bad message. Just make new warning message.
                    catch (Exception x)
                    {
                        parser = 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,
                                                   "");
                    }
                }
                //-----------------------------------------------------------------//

                string bodyText = "";
                if (searchCriteria.IsBodyTextNeeded())
                {
                    bodyText = parser.BodyText;
                }

                // See if message matches to search criteria
                if (searchCriteria.Match(i,
                                         msg.UID,
                                         (int)msg.Size,
                                         msg.InternalDate,
                                         msg.Flags,
                                         parser,
                                         bodyText))
                {
                    if (uidSearch)
                    {
                        TcpStream.Write(" " + msg.UID);

                        //		searchResponse += " " + msg.MessageUID.ToString();
                    }
                    else
                    {
                        TcpStream.Write(" " + (i + 1));

                        //		searchResponse += " " + i.ToString();
                    }
                }
            }

            searchResponse += "\r\n";
            searchResponse += string.Format("{0} OK SEARCH completed in {1} seconds\r\n", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2"));

            // Send search server response
            TcpStream.Write(searchResponse);
        }

        private void ReadSpecifiedLength(int dataLength, MemoryStream dataStream)
        {
            TcpStream.ReadFixedCount(dataStream, dataLength);
        }

        private string ReadLine()
        {
            SmartStream.ReadLineAsyncOP args = new SmartStream.ReadLineAsyncOP(new byte[Workaround.Definitions.MaxStreamLineLength],
                                                                               SizeExceededAction.
                                                                                   JunkAndThrowException);
            if (TcpStream.ReadLine(args, false))
            {
                return args.LineUtf8;
            }
            return string.Empty;
        }


        private void Fetch(string cmdTag, string argsText, bool uidFetch)
        {
            /* Rfc 3501 6.4.5 FETCH Command
			
                Arguments:  message set
                            message data item names

                Responses:  untagged responses: FETCH

                Result:     OK - fetch completed
                            NO - fetch error: can't fetch that data
                            BAD - command unknown or arguments invalid

                The FETCH command retrieves data associated with a message in the
                mailbox.  The data items to be fetched can be either a single atom
                or a parenthesized list.
				
            Most data items, identified in the formal syntax under the
            msg-att-static rule, are static and MUST NOT change for any
            particular message.  Other data items, identified in the formal
            syntax under the msg-att-dynamic rule, MAY change, either as a
            result of a STORE command or due to external events.

                For example, if a client receives an ENVELOPE for a
                message when it already knows the envelope, it can
                safely ignore the newly transmitted envelope.

            There are three macros which specify commonly-used sets of data
            items, and can be used instead of data items.  A macro must be
            used by itself, and not in conjunction with other macros or data
            items.
			
            ALL
                Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)

            FAST
                Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)

            FULL
                Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE
                BODY)

            The currently defined data items that can be fetched are:

            BODY
                Non-extensible form of BODYSTRUCTURE.

            BODY[<section>]<<partial>>
                The text of a particular body section.  The section
                specification is a set of zero or more part specifiers
                delimited by periods.  A part specifier is either a part number
                or one of the following: HEADER, HEADER.FIELDS,
                HEADER.FIELDS.NOT, MIME, and TEXT.  An empty section
                specification refers to the entire message, including the
                header.

                Every message has at least one part number.  Non-[MIME-IMB]
                messages, and non-multipart [MIME-IMB] messages with no
                encapsulated message, only have a part 1.

                Multipart messages are assigned consecutive part numbers, as
                they occur in the message.  If a particular part is of type
                message or multipart, its parts MUST be indicated by a period
                followed by the part number within that nested multipart part.

                A part of type MESSAGE/RFC822 also has nested part numbers,
                referring to parts of the MESSAGE part's body.

                The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part
                specifiers can be the sole part specifier or can be prefixed by
                one or more numeric part specifiers, provided that the numeric
                part specifier refers to a part of type MESSAGE/RFC822.  The
                MIME part specifier MUST be prefixed by one or more numeric
                part specifiers.

                The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part
                specifiers refer to the [RFC-2822] header of the message or of
                an encapsulated [MIME-IMT] MESSAGE/RFC822 message.
                HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of
                field-name (as defined in [RFC-2822]) names, and return a
                subset of the header.  The subset returned by HEADER.FIELDS
                contains only those header fields with a field-name that
                matches one of the names in the list; similarly, the subset
                returned by HEADER.FIELDS.NOT contains only the header fields
                with a non-matching field-name.  The field-matching is
                case-insensitive but otherwise exact.  Subsetting does not
                exclude the [RFC-2822] delimiting blank line between the header
                and the body; the blank line is included in all header fetches,
                except in the case of a message which has no body and no blank
                line.

                The MIME part specifier refers to the [MIME-IMB] header for
                this part.

                The TEXT part specifier refers to the text body of the message,
                omitting the [RFC-2822] header.

                    Here is an example of a complex message with some of its
                    part specifiers:

                    HEADER     ([RFC-2822] header of the message)
                    TEXT       ([RFC-2822] text body of the message) MULTIPART/MIXED
                    1          TEXT/PLAIN
                    2          APPLICATION/OCTET-STREAM
                    3          MESSAGE/RFC822
                    3.HEADER   ([RFC-2822] header of the message)
                    3.TEXT     ([RFC-2822] text body of the message) MULTIPART/MIXED
                    3.1        TEXT/PLAIN
                    3.2        APPLICATION/OCTET-STREAM
                    4          MULTIPART/MIXED
                    4.1        IMAGE/GIF
                    4.1.MIME   ([MIME-IMB] header for the IMAGE/GIF)
                    4.2        MESSAGE/RFC822
                    4.2.HEADER ([RFC-2822] header of the message)
                    4.2.TEXT   ([RFC-2822] text body of the message) MULTIPART/MIXED
                    4.2.1      TEXT/PLAIN
                    4.2.2      MULTIPART/ALTERNATIVE
                    4.2.2.1    TEXT/PLAIN
                    4.2.2.2    TEXT/RICHTEXT


                It is possible to fetch a substring of the designated text.
                This is done by appending an open angle bracket ("<"), the
                octet position of the first desired octet, a period, the
                maximum number of octets desired, and a close angle bracket
                (">") to the part specifier.  If the starting octet is beyond
                the end of the text, an empty string is returned.
				
                Any partial fetch that attempts to read beyond the end of the
                text is truncated as appropriate.  A partial fetch that starts
                at octet 0 is returned as a partial fetch, even if this
                truncation happened.

                    Note: This means that BODY[]<0.2048> of a 1500-octet message
                    will return BODY[]<0> with a literal of size 1500, not
                    BODY[].

                    Note: A substring fetch of a HEADER.FIELDS or
                    HEADER.FIELDS.NOT part specifier is calculated after
                    subsetting the header.

                The \Seen flag is implicitly set; if this causes the flags to
                change, they SHOULD be included as part of the FETCH responses.

            BODY.PEEK[<section>]<<partial>>
                An alternate form of BODY[<section>] that does not implicitly
                set the \Seen flag.

            BODYSTRUCTURE
                The [MIME-IMB] body structure of the message.  This is computed
                by the server by parsing the [MIME-IMB] header fields in the
                [RFC-2822] header and [MIME-IMB] headers.

            ENVELOPE
                The envelope structure of the message.  This is computed by the
                server by parsing the [RFC-2822] header into the component
                parts, defaulting various fields as necessary.

            FLAGS
                The flags that are set for this message.

            INTERNALDATE
                The internal date of the message.

            RFC822
                Functionally equivalent to BODY[], differing in the syntax of
                the resulting untagged FETCH data (RFC822 is returned).

            RFC822.HEADER
                Functionally equivalent to BODY.PEEK[HEADER], differing in the
                syntax of the resulting untagged FETCH data (RFC822.HEADER is
                returned).

            RFC822.SIZE
                The [RFC-2822] size of the message.
				
            RFC822.TEXT
                Functionally equivalent to BODY[TEXT], differing in the syntax
                of the resulting untagged FETCH data (RFC822.TEXT is returned).

            UID
                The unique identifier for the message.


            Example:    C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
                        S: * 2 FETCH ....
                        S: * 3 FETCH ....
                        S: * 4 FETCH ....
                        S: A654 OK FETCH completed
	  
            */
            if (!this.IsAuthenticated)
            {
                TcpStream.WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                this.TcpStream.WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            TcpStream.MemoryBuffer = true;

            // Store start time
            long startTime = DateTime.Now.Ticks;

            IMAP_MessageItems_enum messageItems = IMAP_MessageItems_enum.None;

            #region Parse parameters

            string[] args = ParseParams(argsText);
            if (args.Length != 2)
            {
                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid arguments", cmdTag));
                return;
            }

            IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
            // Just try if it can be parsed as sequence-set
            try
            {
                if (uidFetch)
                {
                    if (m_pSelectedFolder.Messages.Count > 0)
                    {
                        sequenceSet.Parse(args[0], m_pSelectedFolder.Messages[m_pSelectedFolder.Messages.Count - 1].UID);
                    }
                }
                else
                {
                    sequenceSet.Parse(args[0], m_pSelectedFolder.Messages.Count);
                }
            }
            // This isn't valid sequnce-set value
            catch
            {
                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid <sequnce-set> value '{1}' Syntax: {{<command-tag> FETCH <sequnce-set> (<fetch-keys>)}}!", cmdTag, args[0]));
                return;
            }

            // Replace macros
            string fetchItems = args[1].ToUpper();
            fetchItems = fetchItems.Replace("ALL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE");
            fetchItems = fetchItems.Replace("FAST", "FLAGS INTERNALDATE RFC822.SIZE");
            fetchItems = fetchItems.Replace("FULL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY");

            // If UID FETCH and no UID, we must implicity add it, it's required 
            if (uidFetch && fetchItems.ToUpper().IndexOf("UID") == -1)
            {
                fetchItems += " UID";
            }

            // Start parm parsing from left to end in while loop while params parsed or bad param found
            ArrayList fetchFlags = new ArrayList();
            StringReader argsReader = new StringReader(fetchItems.Trim());
            while (argsReader.Available > 0)
            {
                argsReader.ReadToFirstChar();

                #region BODYSTRUCTURE

                // BODYSTRUCTURE
                if (argsReader.StartsWith("BODYSTRUCTURE"))
                {
                    argsReader.ReadSpecifiedLength("BODYSTRUCTURE".Length);

                    fetchFlags.Add(new object[] { "BODYSTRUCTURE" });
                    messageItems |= IMAP_MessageItems_enum.BodyStructure;
                }

                #endregion

                #region BODY, BODY[<section>]<<partial>>, BODY.PEEK[<section>]<<partial>>

                // BODY, BODY[<section>]<<partial>>, BODY.PEEK[<section>]<<partial>>
                else if (argsReader.StartsWith("BODY"))
                {
                    // Remove BODY
                    argsReader.ReadSpecifiedLength("BODY".Length);

                    bool peek = false;
                    // BODY.PEEK
                    if (argsReader.StartsWith(".PEEK"))
                    {
                        // Remove .PEEK
                        argsReader.ReadSpecifiedLength(".PEEK".Length);

                        peek = true;
                    }

                    // [<section>]<<partial>>
                    if (argsReader.StartsWith("["))
                    {
                        // Read value between []
                        string section = "";
                        try
                        {
                            section = argsReader.ReadParenthesized();
                        }
                        catch
                        {
                            this.TcpStream.WriteLine(cmdTag + " BAD Invalid BODY[], closing ] parenthesize is missing !");
                            return;
                        }

                        string originalSectionValue = section;
                        string mimePartsSpecifier = "";
                        string sectionType = "";
                        string sectionArgs = "";
                        /* Validate <section>
                             Section can be:
                                ""                                                    - entire message								
                                [MimePartsSepcifier.]HEADER                           - message header
                                [MimePartsSepcifier.]HEADER.FIELDS (headerFields)     - message header fields
                                [MimePartsSepcifier.]HEADER.FIELDS.NOT (headerFields) - message header fields except requested
                                [MimePartsSepcifier.]TEXT                             - message text
                                [MimePartsSepcifier.]MIME                             - same as header, different response
                        */
                        if (section.Length > 0)
                        {
                            string[] section_args = section.Split(new char[] { ' ' }, 2);
                            section = section_args[0];
                            if (section_args.Length == 2)
                            {
                                sectionArgs = section_args[1];
                            }

                            if (section.EndsWith("HEADER"))
                            {
                                // Remove HEADER from end
                                section = section.Substring(0, section.Length - "HEADER".Length);

                                sectionType = "HEADER";
                                messageItems |= IMAP_MessageItems_enum.Header;
                            }
                            else if (section.EndsWith("HEADER.FIELDS"))
                            {
                                // Remove HEADER.FIELDS from end
                                section = section.Substring(0, section.Length - "HEADER.FIELDS".Length);

                                sectionType = "HEADER.FIELDS";
                                messageItems |= IMAP_MessageItems_enum.Header;
                            }
                            else if (section.EndsWith("HEADER.FIELDS.NOT"))
                            {
                                // Remove HEADER.FIELDS.NOT from end
                                section = section.Substring(0, section.Length - "HEADER.FIELDS.NOT".Length);

                                sectionType = "HEADER.FIELDS.NOT";
                                messageItems |= IMAP_MessageItems_enum.Header;
                            }
                            else if (section.EndsWith("TEXT"))
                            {
                                // Remove TEXT from end
                                section = section.Substring(0, section.Length - "TEXT".Length);

                                sectionType = "TEXT";
                                messageItems |= IMAP_MessageItems_enum.Message;
                            }
                            else if (section.EndsWith("MIME"))
                            {
                                // Remove MIME from end
                                section = section.Substring(0, section.Length - "MIME".Length);

                                sectionType = "MIME";
                                messageItems = IMAP_MessageItems_enum.Header;
                            }

                            // Remove last ., if there is any
                            if (section.EndsWith("."))
                            {
                                section = section.Substring(0, section.Length - 1);
                            }

                            // MimePartsSepcifier is specified, validate it. It can contain numbers only.
                            if (section.Length > 0)
                            {
                                // Now we certainly need full message, because nested mime parts wanted
                                messageItems |= IMAP_MessageItems_enum.Message;

                                string[] sectionParts = section.Split('.');
                                foreach (string sectionPart in sectionParts)
                                {
                                    if (!Core.IsNumber(sectionPart))
                                    {
                                        this.TcpStream.WriteLine(string.Format("{0} BAD Invalid BODY[<section>] argument. Invalid <section>: {1}", cmdTag, section));
                                        return;
                                    }
                                }

                                mimePartsSpecifier = section;
                            }
                        }
                        else
                        {
                            messageItems |= IMAP_MessageItems_enum.Message;
                        }

                        long startPosition = -1;
                        long length = -1;
                        // See if partial fetch
                        if (argsReader.StartsWith("<"))
                        {
                            /* <partial> syntax:
									startPosition[.endPosition]							  
							*/

                            // Read partial value between <>
                            string partial = "";
                            try
                            {
                                partial = argsReader.ReadParenthesized();
                            }
                            catch
                            {
                                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid BODY[]<start[.length]>, closing > parenthesize is missing !", cmdTag));
                                return;
                            }

                            string[] start_length = partial.Split('.');

                            // Validate <partial>
                            if (start_length.Length == 0 || start_length.Length > 2 || !Core.IsNumber(start_length[0]) || (start_length.Length == 2 && !Core.IsNumber(start_length[1])))
                            {
                                this.TcpStream.WriteLine(string.Format("{0} BAD Invalid BODY[]<partial> argument. Invalid <partial>: {1}", cmdTag, partial));
                                return;
                            }

                            startPosition = Convert.ToInt64(start_length[0]);
                            if (start_length.Length == 2)
                            {
                                length = Convert.ToInt64(start_length[1]);
                            }
                        }

                        // object[] structure for BODY[]
                        //	fetchFlagName
                        //	isPeek
                        //	mimePartsSpecifier
                        //  originalSectionValue
                        //	sectionType
                        //	sectionArgs
                        //	startPosition
                        //	length
                        fetchFlags.Add(new object[] { "BODY[]", peek, mimePartsSpecifier, originalSectionValue, sectionType, sectionArgs, startPosition, length });
                    }
                    // BODY
                    else
                    {
                        fetchFlags.Add(new object[] { "BODY" });
                        messageItems |= IMAP_MessageItems_enum.BodyStructure;
                    }
                }

                #endregion

                #region ENVELOPE

                // ENVELOPE
                else if (argsReader.StartsWith("ENVELOPE"))
                {
                    argsReader.ReadSpecifiedLength("ENVELOPE".Length);

                    fetchFlags.Add(new object[] { "ENVELOPE" });
                    messageItems |= IMAP_MessageItems_enum.Envelope;
                }

                #endregion

                #region FLAGS

                // FLAGS
                //	The flags that are set for this message.
                else if (argsReader.StartsWith("FLAGS"))
                {
                    argsReader.ReadSpecifiedLength("FLAGS".Length);

                    fetchFlags.Add(new object[] { "FLAGS" });
                }

                #endregion

                #region INTERNALDATE

                // INTERNALDATE
                else if (argsReader.StartsWith("INTERNALDATE"))
                {
                    argsReader.ReadSpecifiedLength("INTERNALDATE".Length);

                    fetchFlags.Add(new object[] { "INTERNALDATE" });
                }

                #endregion

                #region RFC822.HEADER

                // RFC822.HEADER
                else if (argsReader.StartsWith("RFC822.HEADER"))
                {
                    argsReader.ReadSpecifiedLength("RFC822.HEADER".Length);

                    fetchFlags.Add(new object[] { "RFC822.HEADER" });
                    messageItems |= IMAP_MessageItems_enum.Header;
                }

                #endregion

                #region RFC822.SIZE

                // RFC822.SIZE
                //	The [RFC-2822] size of the message.
                else if (argsReader.StartsWith("RFC822.SIZE"))
                {
                    argsReader.ReadSpecifiedLength("RFC822.SIZE".Length);

                    fetchFlags.Add(new object[] { "RFC822.SIZE" });
                }

                #endregion

                #region RFC822.TEXT

                // RFC822.TEXT
                else if (argsReader.StartsWith("RFC822.TEXT"))
                {
                    argsReader.ReadSpecifiedLength("RFC822.TEXT".Length);

                    fetchFlags.Add(new object[] { "RFC822.TEXT" });
                    messageItems |= IMAP_MessageItems_enum.Message;
                }

                #endregion

                #region RFC822

                // RFC822 NOTE: RFC822 must be below RFC822.xxx or is parsed wrong !
                else if (argsReader.StartsWith("RFC822"))
                {
                    argsReader.ReadSpecifiedLength("RFC822".Length);

                    fetchFlags.Add(new object[] { "RFC822" });
                    messageItems |= IMAP_MessageItems_enum.Message;
                }

                #endregion

                #region UID

                // UID
                //	The unique identifier for the message.
                else if (argsReader.StartsWith("UID"))
                {
                    argsReader.ReadSpecifiedLength("UID".Length);

                    fetchFlags.Add(new object[] { "UID" });
                }

                #endregion

                // This must be unknown fetch flag
                else
                {
                    this.TcpStream.WriteLine(string.Format("{0} BAD Invalid fetch-items argument. Unkown part starts from: {1}", cmdTag, argsReader.SourceString));
                    return;
                }
            }

            #endregion

            // ToDo: ??? But non of the servers do it ?
            // The server should respond with a tagged BAD response to a command that uses a message
            // sequence number greater than the number of messages in the selected mailbox.  This
            // includes "*" if the selected mailbox is empty.
            //	if(m_Messages.Count == 0 || ){
            //		SendData(cmdTag + " BAD Sequence number greater than the number of messages in the selected mailbox !\r\n");
            //		return;
            //	}

            // Create buffered writer, so we make less network calls.

            for (int i = 0; i < m_pSelectedFolder.Messages.Count; i++)
            {
                IMAP_Message msg = m_pSelectedFolder.Messages[i];

                // For UID FETCH we must compare UIDs and for normal FETCH message numbers. 
                bool sequenceSetContains = false;
                if (uidFetch)
                {
                    sequenceSetContains = sequenceSet.Contains(msg.UID);
                }
                else
                {
                    sequenceSetContains = sequenceSet.Contains(i + 1);
                }

                if (sequenceSetContains)
                {
                    IMAP_eArgs_MessageItems eArgs = null;
                    // Get message items only if they are needed.
                    if (messageItems != IMAP_MessageItems_enum.None)
                    {
                        // Raise event GetMessageItems to get all neccesary message itmes
                        eArgs = ImapServer.OnGetMessageItems(this, msg, messageItems);

                        // Message doesn't exist any more, notify email client.
                        if (!eArgs.MessageExists)
                        {
                            TcpStream.Write("* " + msg.SequenceNo + " EXPUNGE");
                            ImapServer.OnDeleteMessage(this, msg);
                            m_pSelectedFolder.Messages.Remove(msg);
                            i--;
                            continue;
                        }
                        try
                        {
                            // Ensure that all requested items were provided.
                            eArgs.Validate();
                        }
                        catch (Exception x)
                        {
                            ImapServer.OnSysError(x.Message, x);
                            this.TcpStream.WriteLine(string.Format("{0} NO Internal IMAP server component error: {1}", cmdTag, x.Message));
                            return;
                        }
                    }

                    // Write fetch start data "* msgNo FETCH ("
                    TcpStream.Write("* " + (i + 1) + " FETCH (");

                    IMAP_MessageFlags msgFlagsOr = msg.Flags;
                    // Construct reply here, based on requested fetch items
                    int nCount = 0;
                    foreach (object[] fetchFlag in fetchFlags)
                    {
                        string fetchFlagName = (string)fetchFlag[0];

                        #region BODY

                        // BODY
                        if (fetchFlagName == "BODY")
                        {
                            // Sets \seen flag
                            msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);

                            // BODY ()
                            TcpStream.Write("BODY " + eArgs.BodyStructure);
                        }

                        #endregion

                        #region BODY[], BODY.PEEK[]

                        // BODY[<section>]<<partial>>, BODY.PEEK[<section>]<<partial>>
                        else if (fetchFlagName == "BODY[]")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // object[] structure for BODY[]
                            //	fetchFlagName
                            //	isPeek
                            //	mimePartsSpecifier
                            //  originalSectionValue
                            //	sectionType
                            //	sectionArgs
                            //	startPosition
                            //	length
                            bool isPeek = (bool)fetchFlag[1];
                            string mimePartsSpecifier = (string)fetchFlag[2];
                            string originalSectionValue = (string)fetchFlag[3];
                            string sectionType = (string)fetchFlag[4];
                            string sectionArgs = (string)fetchFlag[5];
                            long startPosition = (long)fetchFlag[6];
                            long length = (long)fetchFlag[7];

                            // Difference between BODY[] and BODY.PEEK[] is that .PEEK won't set seen flag
                            if (!isPeek)
                            {
                                // Sets \seen flag
                                msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);
                            }

                            /* Section value:
                                ""                - entire message								
                                HEADER            - message header
                                HEADER.FIELDS     - message header fields
                                HEADER.FIELDS.NOT - message header fields except requested
                                TEXT              - message text
                                MIME              - same as header, different response
                            */
                            Stream dataStream = null;
                            if (sectionType == "" && mimePartsSpecifier == "")
                            {
                                dataStream = eArgs.MessageStream;
                            }
                            else
                            {
                                Mime parser = null;
                                try
                                {
                                    if (eArgs.MessageStream == null)
                                    {
                                        parser = Mime.Parse(eArgs.Header);
                                    }
                                    else
                                    {
                                        parser = Mime.Parse(eArgs.MessageStream);
                                    }
                                }
                                // Invalid message, parsing failed
                                catch
                                {
                                    parser = Mime.CreateSimple(new AddressList(), new AddressList(), "BAD Message", "This is BAD message, mail server failed to parse it !", "");
                                }
                                MimeEntity currentEntity = parser.MainEntity;
                                // Specific mime entity requested, get it
                                if (mimePartsSpecifier != "")
                                {
                                    currentEntity = FetchHelper.GetMimeEntity(parser, mimePartsSpecifier);
                                }

                                if (currentEntity != null)
                                {
                                    if (sectionType == "HEADER")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.GetMimeEntityHeader(currentEntity));
                                    }
                                    else if (sectionType == "HEADER.FIELDS")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.ParseHeaderFields(sectionArgs, currentEntity));
                                    }
                                    else if (sectionType == "HEADER.FIELDS.NOT")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.ParseHeaderFieldsNot(sectionArgs, currentEntity));
                                    }
                                    else if (sectionType == "TEXT")
                                    {
                                        try
                                        {
                                            if (currentEntity.DataEncoded != null)
                                            {
                                                dataStream = new MemoryStream(currentEntity.DataEncoded);
                                            }
                                        }
                                        catch
                                        { // This probably multipart entity, data isn't available
                                        }
                                    }
                                    else if (sectionType == "MIME")
                                    {
                                        dataStream = new MemoryStream(FetchHelper.GetMimeEntityHeader(currentEntity));
                                    }
                                    else if (sectionType == "")
                                    {
                                        try
                                        {
                                            dataStream = new MemoryStream(currentEntity.DataEncoded);
                                        }
                                        catch
                                        { // This probably multipart entity, data isn't available
                                        }
                                    }
                                }
                            }

                            // Partial fetch. Reports <origin position> in fetch reply.
                            if (startPosition > -1)
                            {
                                if (dataStream == null)
                                {
                                    this.TcpStream.Write("BODY[" + originalSectionValue + "]<" + startPosition.ToString() + "> \"\"\r\n");
                                }
                                else
                                {
                                    long lengthToSend = length;
                                    if (lengthToSend == -1)
                                    {
                                        lengthToSend = (dataStream.Length - dataStream.Position) - startPosition;
                                    }
                                    if ((lengthToSend + startPosition) > (dataStream.Length - dataStream.Position))
                                    {
                                        lengthToSend = (dataStream.Length - dataStream.Position) - startPosition;
                                    }

                                    if (startPosition >= (dataStream.Length - dataStream.Position))
                                    {
                                        this.TcpStream.Write("BODY[" + originalSectionValue + "]<" + startPosition.ToString() + "> \"\"\r\n");
                                    }
                                    else
                                    {
                                        this.TcpStream.Write("BODY[" + originalSectionValue + "]<" + startPosition.ToString() + "> {" + lengthToSend + "}\r\n");
                                        dataStream.Position += startPosition;
                                        this.TcpStream.WriteStream(dataStream, lengthToSend);
                                    }
                                }
                            }
                            // Normal fetch
                            else
                            {
                                if (dataStream == null)
                                {
                                    this.TcpStream.Write("BODY[" + originalSectionValue + "] \"\"\r\n");
                                }
                                else
                                {
                                    this.TcpStream.Write("BODY[" + originalSectionValue + "] {" + (dataStream.Length - dataStream.Position) + "}\r\n");
                                    this.TcpStream.WriteStream(dataStream);
                                }
                            }
                        }

                        #endregion

                        #region BODYSTRUCTURE

                        // BODYSTRUCTURE
                        else if (fetchFlagName == "BODYSTRUCTURE")
                        {
                            TcpStream.Write("BODYSTRUCTURE " + eArgs.BodyStructure);
                        }

                        #endregion

                        #region ENVELOPE

                        // ENVELOPE
                        else if (fetchFlagName == "ENVELOPE")
                        {
                            TcpStream.Write("ENVELOPE " + eArgs.Envelope);
                        }

                        #endregion

                        #region FLAGS

                        // FLAGS
                        else if (fetchFlagName == "FLAGS")
                        {
                            TcpStream.Write("FLAGS (" + msg.FlagsString + ")");
                        }

                        #endregion

                        #region INTERNALDATE

                        // INTERNALDATE
                        else if (fetchFlagName == "INTERNALDATE")
                        {
                            // INTERNALDATE "date"
                            TcpStream.Write("INTERNALDATE \"" + IMAP_Utils.DateTimeToString(msg.InternalDate) + "\"");
                        }

                        #endregion

                        #region RFC822

                        // RFC822
                        else if (fetchFlagName == "RFC822")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // Sets \seen flag
                            msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);

                            // RFC822 {size}
                            // msg data
                            this.TcpStream.Write("RFC822 {" + eArgs.MessageSize.ToString() + "}\r\n");
                            this.TcpStream.WriteStream(eArgs.MessageStream);
                        }

                        #endregion

                        #region RFC822.HEADER

                        // RFC822.HEADER
                        else if (fetchFlagName == "RFC822.HEADER")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // RFC822.HEADER {size}
                            // msg header data
                            this.TcpStream.Write("RFC822.HEADER {" + eArgs.Header.Length + "}\r\n");
                            this.TcpStream.Write(eArgs.Header);
                        }

                        #endregion

                        #region RFC822.SIZE

                        // RFC822.SIZE
                        else if (fetchFlagName == "RFC822.SIZE")
                        {
                            // RFC822.SIZE size
                            TcpStream.Write("RFC822.SIZE " + msg.Size);
                        }

                        #endregion

                        #region RFC822.TEXT

                        // RFC822.TEXT
                        else if (fetchFlagName == "RFC822.TEXT")
                        {
                            // Force to write all buffered data.
                            TcpStream.Flush();

                            // Sets \seen flag
                            msg.SetFlags(msg.Flags | IMAP_MessageFlags.Seen);

                            //--- Find body text entity ------------------------------------//
                            Mime parser = Mime.Parse(eArgs.MessageStream);
                            MimeEntity bodyTextEntity = null;
                            if (parser.MainEntity.ContentType == MediaType_enum.NotSpecified)
                            {
                                if (parser.MainEntity.DataEncoded != null)
                                {
                                    bodyTextEntity = parser.MainEntity;
                                }
                            }
                            else
                            {
                                MimeEntity[] entities = parser.MimeEntities;
                                foreach (MimeEntity entity in entities)
                                {
                                    if (entity.ContentType == MediaType_enum.Text_plain)
                                    {
                                        bodyTextEntity = entity;
                                        break;
                                    }
                                }
                            }
                            //----------------------------------------------------------------//

                            // RFC822.TEXT {size}
                            // msg text	
                            byte[] data = null;
                            if (bodyTextEntity != null)
                            {
                                data = bodyTextEntity.DataEncoded;
                            }
                            else
                            {
                                data = System.Text.Encoding.ASCII.GetBytes("");
                            }

                            this.TcpStream.Write("RFC822.TEXT {" + data.Length + "}\r\n");
                            this.TcpStream.Write(data);
                        }

                        #endregion

                        #region UID

                        // UID
                        else if (fetchFlagName == "UID")
                        {
                            TcpStream.Write("UID " + msg.UID);
                        }

                        #endregion

                        nCount++;

                        // Write fetch item separator data " "
                        // We don't write it for last item
                        if (nCount < fetchFlags.Count)
                        {
                            TcpStream.Write(" ");
                        }
                    }

                    // Write fetch end data ")"
                    TcpStream.Write(")\r\n");

                    // Free event args, close message stream, ... .
                    if (eArgs != null)
                    {
                        eArgs.Dispose();
                    }

                    // Set message flags here if required or changed
                    if (((int)IMAP_MessageFlags.Recent & (int)msg.Flags) != 0 || msgFlagsOr != msg.Flags)
                    {
                        msg.SetFlags(msg.Flags & ~IMAP_MessageFlags.Recent);

                        ImapServer.OnStoreMessageFlags(this, msg);
                    }
                }
            }

            // Force to write all buffered data.
            TcpStream.Flush();

            this.TcpStream.WriteLine(string.Format("{0} OK FETCH completed in {1} seconds", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2")));
        }

        

        private void Store(string cmdTag, string argsText, bool uidStore)
        {
            /* Rfc 3501 6.4.6 STORE Command
				
				Arguments:  message set
							message data item name
							value for message data item

				Responses:  untagged responses: FETCH

				Result:     OK - store completed
							NO - store error: can't store that data
							BAD - command unknown or arguments invalid
							
				The STORE command alters data associated with a message in the
				mailbox.  Normally, STORE will return the updated value of the
				data with an untagged FETCH response.  A suffix of ".SILENT" in
				the data item name prevents the untagged FETCH, and the server
				SHOULD assume that the client has determined the updated value
				itself or does not care about the updated value.
				
				Note: regardless of whether or not the ".SILENT" suffix was
					used, the server SHOULD send an untagged FETCH response if a
					change to a message's flags from an external source is
					observed.  The intent is that the status of the flags is
					determinate without a race condition.

				The currently defined data items that can be stored are:

				FLAGS <flag list>
					Replace the flags for the message (other than \Recent) with the
					argument.  The new value of the flags is returned as if a FETCH
					of those flags was done.

				FLAGS.SILENT <flag list>
					Equivalent to FLAGS, but without returning a new value.

				+FLAGS <flag list>
					Add the argument to the flags for the message.  The new value
					of the flags is returned as if a FETCH of those flags was done.

				+FLAGS.SILENT <flag list>
					Equivalent to +FLAGS, but without returning a new value.

				-FLAGS <flag list>
					Remove the argument from the flags for the message.  The new
					value of the flags is returned as if a FETCH of those flags was
					done.

				-FLAGS.SILENT <flag list>
					Equivalent to -FLAGS, but without returning a new value.
		 

				Example:    C: A003 STORE 2:4 +FLAGS (\Deleted)
							S: * 2 FETCH FLAGS (\Deleted \Seen)
							S: * 3 FETCH FLAGS (\Deleted)
							S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
							S: A003 OK STORE completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }
            if (m_pSelectedFolder.ReadOnly)
            {
                WriteLine(string.Format("{0} NO Mailbox is read-only", cmdTag));
                return;
            }

            // Store start time
            long startTime = DateTime.Now.Ticks;

            string[] args = ParseParams(argsText);
            if (args.Length != 3)
            {
                WriteLine(string.Format("{0} BAD STORE invalid arguments. Syntax: {{<command-tag> STORE <sequnce-set> <data-item> (<message-flags>)}}", cmdTag));
                return;
            }

            IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
            // Just try if it can be parsed as sequence-set
            try
            {
                if (uidStore)
                {
                    if (m_pSelectedFolder.Messages.Count > 0)
                    {
                        sequenceSet.Parse(args[0],
                                          m_pSelectedFolder.Messages[m_pSelectedFolder.Messages.Count - 1].UID);
                    }
                }
                else
                {
                    sequenceSet.Parse(args[0], m_pSelectedFolder.Messages.Count);
                }
            }
            // This isn't vaild sequnce-set value
            catch
            {
                WriteLine(string.Format("{0}BAD Invalid <sequnce-set> value '{1}' Syntax: {{<command-tag> STORE <sequnce-set> <data-item> (<message-flags>)}}!", cmdTag, args[0]));
                return;
            }

            //--- Parse Flags behaviour ---------------//
            string flagsAction = "";
            bool silent = false;
            string flagsType = args[1].ToUpper();
            switch (flagsType)
            {
                case "FLAGS":
                    flagsAction = "REPLACE";
                    break;

                case "FLAGS.SILENT":
                    flagsAction = "REPLACE";
                    silent = true;
                    break;

                case "+FLAGS":
                    flagsAction = "ADD";
                    break;

                case "+FLAGS.SILENT":
                    flagsAction = "ADD";
                    silent = true;
                    break;

                case "-FLAGS":
                    flagsAction = "REMOVE";
                    break;

                case "-FLAGS.SILENT":
                    flagsAction = "REMOVE";
                    silent = true;
                    break;

                default:
                    WriteLine(cmdTag + " BAD arguments invalid");
                    return;
            }
            //-------------------------------------------//

            //--- Parse flags, see if valid ----------------
            string flags = args[2].ToUpper();
            if (
                flags.Replace("\\ANSWERED", "").Replace("\\FLAGGED", "").Replace("\\DELETED", "").Replace(
                    "\\SEEN", "").Replace("\\DRAFT", "").Trim().Length > 0)
            {
                WriteLine(string.Format("{0} BAD arguments invalid", cmdTag));
                return;
            }

            IMAP_MessageFlags mFlags = IMAP_Utils.ParseMessageFlags(flags);

            // Call OnStoreMessageFlags for each message in sequence set
            // Calulate new flags(using old message flags + new flags) for message 
            // and request to store all flags to message, don't specify if add, remove or replace falgs.

            for (int i = 0; i < m_pSelectedFolder.Messages.Count; i++)
            {
                IMAP_Message msg = m_pSelectedFolder.Messages[i];

                // For UID STORE we must compare UIDs and for normal STORE message numbers. 
                bool sequenceSetContains = false;
                if (uidStore)
                {
                    sequenceSetContains = sequenceSet.Contains(msg.UID);
                }
                else
                {
                    sequenceSetContains = sequenceSet.Contains(i + 1);
                }

                if (sequenceSetContains)
                {
                    // Calculate new flags and set to msg
                    switch (flagsAction)
                    {
                        case "REPLACE":
                            msg.SetFlags(mFlags);
                            break;

                        case "ADD":
                            msg.SetFlags(msg.Flags | mFlags);
                            break;

                        case "REMOVE":
                            msg.SetFlags(msg.Flags & ~mFlags);
                            break;
                    }

                    // ToDo: see if flags changed, if not don't call OnStoreMessageFlags

                    string errorText = ImapServer.OnStoreMessageFlags(this, msg);
                    if (errorText == null)
                    {
                        if (!silent)
                        {
                            // Silent doesn't reply untagged lines
                            if (!uidStore)
                            {
                                WriteLine(string.Format("* {0} FETCH FLAGS ({1})", (i + 1), msg.FlagsString));
                            }
                            // Called from UID command, need to add UID response
                            else
                            {
                                WriteLine(string.Format("* {0} FETCH (FLAGS ({1}) UID {2}))", (i + 1), msg.FlagsString, msg.UID));
                            }
                        }
                    }
                    else
                    {
                        WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
                        return;
                    }
                }
            }

            WriteLine(string.Format("{0} OK STORE completed in {1} seconds", cmdTag, ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2")));
        }

        private void Copy(string cmdTag, string argsText, bool uidCopy)
        {
            /* RFC 3501 6.4.7 COPY Command
			
				Arguments:  message set
							mailbox name

				Responses:  no specific responses for this command

				Result:     OK - copy completed
							NO - copy error: can't copy those messages or to that
									name
							BAD - command unknown or arguments invalid
			   
				The COPY command copies the specified message(s) to the end of the
				specified destination mailbox.  The flags and internal date of the
				message(s) SHOULD be preserved in the copy.

				If the destination mailbox does not exist, a server SHOULD return
				an error.  It SHOULD NOT automatically create the mailbox.  Unless
				it is certain that the destination mailbox can not be created, the
				server MUST send the response code "[TRYCREATE]" as the prefix of
				the text of the tagged NO response.  This gives a hint to the
				client that it can attempt a CREATE command and retry the COPY if
				
				If the COPY command is unsuccessful for any reason, server
				implementations MUST restore the destination mailbox to its state
				before the COPY attempt.

				Example:    C: A003 COPY 2:4 MEETING
							S: A003 OK COPY completed
			   
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            string[] args = ParseParams(argsText);
            if (args.Length != 2)
            {
                WriteLine(string.Format("{0} BAD Invalid arguments", cmdTag));
                return;
            }

            IMAP_SequenceSet sequenceSet = new IMAP_SequenceSet();
            // Just try if it can be parsed as sequence-set
            try
            {
                if (uidCopy)
                {
                    if (m_pSelectedFolder.Messages.Count > 0)
                    {
                        sequenceSet.Parse(args[0],
                                          m_pSelectedFolder.Messages[m_pSelectedFolder.Messages.Count - 1].UID);
                    }
                }
                else
                {
                    sequenceSet.Parse(args[0], m_pSelectedFolder.Messages.Count);
                }
            }
            // This isn't vaild sequnce-set value
            catch
            {
                WriteLine(string.Format("{0}BAD Invalid <sequnce-set> value '{1}' Syntax: {{<command-tag> COPY <sequnce-set> \"<mailbox-name>\"}}!", cmdTag, args[0]));
                return;
            }

            string errorText = "";
            for (int i = 0; i < m_pSelectedFolder.Messages.Count; i++)
            {
                IMAP_Message msg = m_pSelectedFolder.Messages[i];

                // For UID COPY we must compare UIDs and for normal COPY message numbers. 
                bool sequenceSetContains = false;
                if (uidCopy)
                {
                    sequenceSetContains = sequenceSet.Contains(msg.UID);
                }
                else
                {
                    sequenceSetContains = sequenceSet.Contains(i + 1);
                }

                if (sequenceSetContains)
                {
                    errorText = ImapServer.OnCopyMessage(this, msg, Core.Decode_IMAP_UTF7_String(args[1]));
                    if (errorText != null)
                    {
                        break; // Errors return error text, don't try to copy other messages
                    }
                }
            }

            if (errorText == null)
            {
                WriteLine(string.Format("{0} OK COPY completed", cmdTag));
            }
            else
            {
                WriteLine(string.Format("{0} NO {1}", cmdTag, errorText));
            }
        }

        private void Uid(string cmdTag, string argsText)
        {
            /* Rfc 3501 6.4.8 UID Command
				
				Arguments:  command name
							command arguments

				Responses:  untagged responses: FETCH, SEARCH

				Result:     OK - UID command completed
							NO - UID command error
							BAD - command unknown or arguments invalid
							
				The UID command has two forms.  In the first form, it takes as its
				arguments a COPY, FETCH, or STORE command with arguments
				appropriate for the associated command.  However, the numbers in
				the message set argument are unique identifiers instead of message
				sequence numbers.

				In the second form, the UID command takes a SEARCH command with
				SEARCH command arguments.  The interpretation of the arguments is
				the same as with SEARCH; however, the numbers returned in a SEARCH
				response for a UID SEARCH command are unique identifiers instead
				of message sequence numbers.  For example, the command UID SEARCH
				1:100 UID 443:557 returns the unique identifiers corresponding to
				the intersection of the message sequence number set 1:100 and the
				UID set 443:557.

				Message set ranges are permitted; however, there is no guarantee
				that unique identifiers be contiguous.  A non-existent unique
				identifier within a message set range is ignored without any error
				message generated.

				The number after the "*" in an untagged FETCH response is always a
				message sequence number, not a unique identifier, even for a UID
				command response.  However, server implementations MUST implicitly
				include the UID message data item as part of any FETCH response
				caused by a UID command, regardless of whether a UID was specified
				as a message data item to the FETCH.
				
				Example:    C: A999 UID FETCH 4827313:4828442 FLAGS
							S: * 23 FETCH (FLAGS (\Seen) UID 4827313)
							S: * 24 FETCH (FLAGS (\Seen) UID 4827943)
							S: * 25 FETCH (FLAGS (\Seen) UID 4828442)
							S: A999 UID FETCH completed
			*/
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return;
            }
            if (SelectedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} NO Select mailbox first !", cmdTag));
                return;
            }

            string[] args = ParseParams(argsText);
            if (args.Length < 2)
            {
                // We must have at least command and message-set or cmd args
                WriteLine(string.Format("{0} BAD Invalid arguments", cmdTag));
                return;
            }

            // Get commands args text, we just remove COMMAND
            string cmdArgs = Core.GetArgsText(argsText, args[0]);

            // See if valid command specified with UID command
            switch (args[0].ToUpper())
            {
                case "COPY":
                    Copy(cmdTag, cmdArgs, true);
                    break;

                case "FETCH":
                    Fetch(cmdTag, cmdArgs, true);
                    break;

                case "STORE":
                    Store(cmdTag, cmdArgs, true);
                    break;

                case "SEARCH":
                    Search(cmdTag, cmdArgs, true);
                    break;

                default:
                    WriteLine(cmdTag + " BAD Invalid arguments");
                    return;
            }
        }

        /// <summary>
        /// Processes IDLE command.
        /// </summary>
        /// <param name="cmdTag">Command tag.</param>
        /// <param name="argsText">Command arguments text.</param>
        /// <returns>Returns true if IDLE comand accepted, otherwise false.</returns>
        private bool Idle(string cmdTag, string argsText)
        {
            if (!IsAuthenticated)
            {
                WriteLine(string.Format("{0} NO Authenticate first !", cmdTag));
                return false;
            }
            if (SelectedMailbox.Length == 0 && m_StatusedMailbox.Length == 0)
            {
                WriteLine(string.Format("{0} BAD Select mailbox first !", cmdTag));
                return false;
            }
            if (m_pIDLE!=null)
            {
                m_pIDLE.Dispose();
            }
            m_pIDLE = new Command_IDLE(this, cmdTag, SelectedMailbox.Length == 0 ? m_StatusedMailbox : SelectedMailbox);

            return true;
        }

        //--- End of Selected State

        //--- Any State ------

        private void Capability(string cmdTag)
        {
            /* RFC 3501 6.1.1
			
				Arguments:  none

				Responses:  REQUIRED untagged response: CAPABILITY

				Result:     OK - capability completed
							BAD - command unknown or arguments invalid
			   
				The CAPABILITY command requests a listing of capabilities that the
				server supports.  The server MUST send a single untagged
				CAPABILITY response with "IMAP4rev1" as one of the listed
				capabilities before the (tagged) OK response.

				A capability name which begins with "AUTH=" indicates that the
				server supports that particular authentication mechanism.
				
				Example:    C: abcd CAPABILITY
							S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI
							LOGINDISABLED
							S: abcd OK CAPABILITY completed
							C: efgh STARTTLS
							S: efgh OK STARTLS completed
							<TLS negotiation, further commands are under [TLS] layer>
							C: ijkl CAPABILITY
							S: * CAPABILITY IMAP4rev1 AUTH=GSSAPI AUTH=PLAIN
							S: ijkl OK CAPABILITY completed
			*/

            string reply = "* CAPABILITY IMAP4rev1";
            if ((ImapServer.SupportedAuthentications & SaslAuthTypes.Digest_md5) != 0)
            {
                reply += " AUTH=DIGEST-MD5";
            }
            if ((ImapServer.SupportedAuthentications & SaslAuthTypes.Cram_md5) != 0)
            {
                reply += " AUTH=CRAM-MD5";
            }
            if (!IsSecureConnection && Certificate != null)
            {
                reply += " STARTTLS";
            }
            reply += " NAMESPACE ACL QUOTA IDLE X-FILTER\r\n";
            reply += cmdTag + " OK CAPABILITY completed\r\n";

            TcpStream.Write(reply);
        }

        private void Noop(string cmdTag)
        {
            /* RFC 3501 6.1.2 NOOP Command
			
				Arguments:  none

				Responses:  no specific responses for this command (but see below)

				Result:     OK - noop completed
							BAD - command unknown or arguments invalid
			   
				The NOOP command always succeeds.  It does nothing.
				Since any command can return a status update as untagged data, the
				NOOP command can be used as a periodic poll for new messages or
				message status updates during a period of inactivity.  The NOOP
				command can also be used to reset any inactivity autologout timer
				on the server.
				
				Example: C: a002 NOOP
						 S: a002 OK NOOP completed
			*/

            // Store start time
            long startTime = DateTime.Now.Ticks;

            // If there is selected mailbox, see if messages status has changed
            if (SelectedMailbox.Length > 0)
            {
                ProcessMailboxChanges();

                WriteLine(cmdTag + " OK NOOP Completed in " +
                                 ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2") +
                                 " seconds\r\n");
            }
            else
            {
                WriteLine(cmdTag + " OK NOOP Completed in " +
                                 ((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2") +
                                 " seconds\r\n");
            }
        }

        private void LogOut(string cmdTag)
        {
            /* RFC 3501 6.1.3
			
				Arguments:  none

				Responses:  REQUIRED untagged response: BYE

				Result:     OK - logout completed
							BAD - command unknown or arguments invalid
			   
				The LOGOUT command informs the server that the client is done with
				the connection.  The server MUST send a BYE untagged response
				before the (tagged) OK response, and then close the network
				connection.
				
				Example: C: A023 LOGOUT
						S: * BYE IMAP4rev1 Server logging out
						S: A023 OK LOGOUT completed
						(Server and client then close the connection)
			*/

            string reply = "* BYE IMAP4rev1 Server logging out\r\n";
            reply += cmdTag + " OK LOGOUT completed\r\n";

            TcpStream.Write(reply);
            TcpStream.Flush();
        }

        //--- End of Any State

        /// <summary>
        /// Processes changes and sends status responses if there are changes in selected mailbox.
        /// </summary>
        private void ProcessMailboxChanges()
        {
            ProcessMailboxChanges(SelectedMailbox);
        }

        /// <summary>
        /// Processes changes and sends status responses if there are changes in selected mailbox.
        /// </summary>
        private void ProcessMailboxChanges(string mailBox)
        {
            //TODO: Many whelps! Handle it!
            // Get status
            IMAP_SelectedFolder folderInfo = new IMAP_SelectedFolder(mailBox);
            IMAP_eArgs_GetMessagesInfo eArgs = ImapServer.OnGetMessagesInfo(this, folderInfo);

            // Join new info with exisiting
            if (m_pSelectedFolder != null)
            {
                string statusResponse = m_pSelectedFolder.Update(folderInfo);
                if (!string.IsNullOrEmpty(statusResponse))
                {
                    WriteLine(statusResponse);

                    m_pSelectedFolder = folderInfo;
                }
            }
            if (m_pAdditionalFolder != null)
            {
                string statusResponse = m_pAdditionalFolder.Update(folderInfo);
                if (!string.IsNullOrEmpty(statusResponse))
                {
                    WriteLine(statusResponse);

                    m_pAdditionalFolder = folderInfo;
                }
            }
        }

        private string[] ParseParams(string argsText)
        {
            List<string> p = new List<string>();

            try
            {
                while (argsText.Length > 0)
                {
                    // Parameter is between ""
                    if (argsText.StartsWith("\""))
                    {
                        p.Add(argsText.Substring(1, argsText.IndexOf("\"", 1) - 1));
                        // Remove parsed param
                        argsText = argsText.Substring(argsText.IndexOf("\"", 1) + 1).Trim();
                    }
                    else
                    {
                        // Parameter is between ()
                        if (argsText.StartsWith("("))
                        {
                            p.Add(argsText.Substring(1, argsText.LastIndexOf(")") - 1));
                            // Remove parsed param
                            argsText = argsText.Substring(argsText.LastIndexOf(")") + 1).Trim();
                        }
                        else
                        {
                            // Read parameter till " ", probably there is more params
                            // Note: If there is ({ before SP, cosider that it's last parameter.
                            //       For example body[header.fields (from to)]
                            if (argsText.IndexOf(" ") > -1 &&
                                argsText.IndexOfAny(new[] { '(', '[' }, 0, argsText.IndexOf(" ")) == -1)
                            {
                                p.Add(argsText.Substring(0, argsText.IndexOf(" ")));
                                // Remove parsed param
                                argsText = argsText.Substring(argsText.IndexOf(" ") + 1).Trim();
                            }
                            // This is last param
                            else
                            {
                                p.Add(argsText);
                                argsText = "";
                            }
                        }
                    }
                }
            }
            catch { }

            return p.ToArray();
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/PortalEncryption/js/portalencryption.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.PortalEncryption = new function () {
    this.init = function () {
        showProgress(0);
        getProgress();
    };

    function showProgress(progress) {
        var $progressValue = $(".asc-progress-value"),
            $progressText = $(".asc-progress_percent");

        $progressValue.animate({ "width": progress + "%" });
        $progressText.text(progress + "% ");
    };

    function getProgress() {
        Teamlab.getEncryptionProgress({},
        {
            success: function (params, progress) {
                if (progress === -1) {
                    showProgress(100);
                    completeReload();
                    return;
                }

                var percentage = Math.round(Number(progress));
                showProgress(percentage);
                if (percentage === 100) {
                    completeReload();
                }

                setTimeout(function () {
                    getProgress();
                }, 10000);
            },
            error: function (params, errors) {
                showError(errors[0]);
            }
        });
    };

    function showError(er) {
        $("#progress-line").hide();
        $("#progress-error").text(er).show();
    };

    function completeReload() {
        jQuery("body").css("cursor", "wait");
        setTimeout(function () {
            window.location.href = "/";
        }, 5000);
    }
}

$(function () {
    ServiceHelper.init("/api/2.0/");
    PortalEncryption.init();
});

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Handlers/WikiFileHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Net;
using System.Text.RegularExpressions;
using System.Web;

using ASC.Core;
using ASC.Data.Storage;
using ASC.Web.Core;

namespace ASC.Web.UserControls.Wiki.Handlers
{
    public class WikiFileHandler : IHttpHandler
    {
        public static string ImageExtentions = ".png.jpg.bmp.gif";


        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            if (!SecurityContext.IsAuthenticated)
            {
                if (!SecurityContext.AuthenticateMe(CookiesManager.GetCookies(CookiesType.AuthKey)))
                {
                    context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                    context.Response.End();
                    return;
                }
            }

            context.Response.Clear();
            if (string.IsNullOrEmpty(context.Request["file"]))
            {
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                context.Response.End();
                return;
            }

            var file = GetFile(context.Request["file"]);
            if (file == null)
            {
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                context.Response.End();
                return;
            }
            if (string.IsNullOrEmpty(file.FileLocation))
            {
                context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                context.Response.End();
                return;
            }

            var storage = StorageFactory.GetStorage(CoreContext.TenantManager.GetCurrentTenant().TenantId.ToString(), WikiSection.Section.DataStorage.ModuleName);
            context.Response.Redirect(storage.GetUri(WikiSection.Section.DataStorage.DefaultDomain, file.FileLocation).ToString());
        }

        private Data.File GetFile(string fileName)
        {
            var file = new WikiEngine().GetFile(fileName);
            if (file != null) return file;
            var regex = new Regex(Regex.Escape("_"));
            var newFileName = regex.Replace(fileName, " ", 1);
            return fileName != newFileName ? GetFile(newFileName) : null;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/js/tariffdesktop.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function ($) {
    $(function () {
        var domain = new RegExp("^http(s)?:\/\/[^\/]+").exec(location)[0];

        var data = {
            displayName: Teamlab.profile.displayName,
            domain: domain,
            email: Teamlab.profile.email,
            provider: "onlyoffice",
        };

        window.AscDesktopEditor.execCommand("portal:login", JSON.stringify(data));
    });
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Search/NewsWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.ElasticSearch;
using ASC.Web.Community.News.Code;

namespace ASC.Web.Community.Search
{
    public sealed class NewsWrapper : Wrapper
    {
        [ColumnTenantId("tenant")]
        public override int TenantId { get; set; }

        [ColumnLastModified("LastModified")]
        public override DateTime LastModifiedOn { get; set; }

        [Column("caption", 1)]
        public string Caption { get; set; }

        [Column("text", 2, charFilter: CharFilter.html | CharFilter.io)]
        public string Text { get; set; }

        protected override string Table { get { return "events_feed"; } }

        [Join(JoinTypeEnum.Sub, "tenant:tenant", "id:poll")]
        public List<PollVariantWrapper> PollVariantWrapper { get; set; }

        public static implicit operator NewsWrapper(Feed feed)
        {
            var result = new NewsWrapper
            {
                Id = (int)feed.Id,
                TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId,
                Caption = feed.Caption,
                Text = feed.Text
            };

            var poll = feed as FeedPoll;
            if (poll != null)
            {
                result.PollVariantWrapper = poll.Variants.Select(r => new PollVariantWrapper { Name = r.Name }).ToList();
            }

            return result;
        }

        /*
         * }
            }
         * */
    }

    public sealed class PollVariantWrapper : Wrapper
    {
        [Column("name", 1)]
        public string Name { get; set; }

        [ColumnId("")]
        public override int Id { get; set; }

        [ColumnTenantId("")]
        public override int TenantId { get; set; }

        [ColumnLastModified("")]
        public override DateTime LastModifiedOn { get; set; }

        protected override string Table { get { return "events_pollvariant"; } }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_WarningValue.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements SIP "warning-value" value. Defined in RFC 3261.
    /// </summary>
    /// <remarks>
    /// <code>
    /// RFC 3261 Syntax:
    ///     warning-value = warn-code SP warn-agent SP warn-text
    ///     warn-code     = 3DIGIT
    ///     warn-agent    = hostport / pseudonym
    ///                      ;  the name or pseudonym of the server adding
    ///                      ;  the Warning header, for use in debugging
    ///     warn-text     = quoted-string
    ///     pseudonym     = token
    /// </code>
    /// </remarks>
    public class SIP_t_WarningValue : SIP_t_Value
    {
        #region Members

        private string m_Agent = "";
        private int m_Code;
        private string m_Text = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets warning code.
        /// </summary>
        public int Code
        {
            get { return m_Code; }

            set
            {
                if (value < 100 || value > 999)
                {
                    throw new ArgumentException("Property Code value must be 3 digit !");
                }

                m_Code = value;
            }
        }

        /// <summary>
        /// Gets or sets name or pseudonym of the server.
        /// </summary>
        public string Agent
        {
            get { return m_Agent; }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("Property Agent value may not be null or empty !");
                }

                m_Agent = value;
            }
        }

        /// <summary>
        /// Gets or sets warning text.
        /// </summary>
        public string Text
        {
            get { return m_Text; }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("Property Text value may not be null or empty !");
                }

                m_Text = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "warning-value" from specified value.
        /// </summary>
        /// <param name="value">SIP "warning-value" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("reader");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "warning-value" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            /*                
                warning-value  =  warn-code SP warn-agent SP warn-text
                warn-code      =  3DIGIT
                warn-agent     =  hostport / pseudonym
                                  ;  the name or pseudonym of the server adding
                                  ;  the Warning header, for use in debugging
                warn-text      =  quoted-string
                pseudonym      =  token
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            string word = reader.ReadWord();
            if (word == null)
            {
                throw new SIP_ParseException("Invalid 'warning-value' value, warn-code is missing !");
            }
            try
            {
                Code = Convert.ToInt32(word);
            }
            catch
            {
                throw new SIP_ParseException("Invalid 'warning-value' warn-code value, warn-code is missing !");
            }

            word = reader.ReadWord();
            if (word == null)
            {
                throw new SIP_ParseException("Invalid 'warning-value' value, warn-agent is missing !");
            }
            Agent = word;

            word = reader.ReadToEnd();
            if (word == null)
            {
                throw new SIP_ParseException("Invalid 'warning-value' value, warn-text is missing !");
            }
            Agent = TextUtils.UnQuoteString(word);
        }

        /// <summary>
        /// Converts this to valid "warning-value" value.
        /// </summary>
        /// <returns>Returns "warning-value" value.</returns>
        public override string ToStringValue()
        {
            return m_Code + " " + m_Agent + " " + TextUtils.QuoteString(m_Text);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/ChainDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Core.Dao.Expressions.Conversation;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Enums;

namespace ASC.Mail.Core.Dao
{
    public class ChainDao : BaseDao, IChainDao
    {
        protected static ITable table = new MailTableFactory().Create<ChainTable>();

        protected string CurrentUserId { get; private set; }

        public ChainDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public List<Chain> GetChains(IConversationsExp exp)
        {
            var query = Query()
                .Where(exp.GetExpression());

            return Db.ExecuteList(query)
                .ConvertAll(ToChain);
        }

        public Dictionary<int, int> GetChainCount(IConversationsExp exp)
        {
            var query = new SqlQuery(ChainTable.TABLE_NAME)
                .Select(ChainTable.Columns.Folder)
                .SelectCount()
                .Where(exp.GetExpression())
                .GroupBy(ChainTable.Columns.Folder);

            return Db.ExecuteList(query)
                .ConvertAll(r => new
                {
                    folder = Convert.ToInt32(r[0]),
                    count = Convert.ToInt32(r[1])
                })
                .ToDictionary(o => o.folder, o => o.count);
        }

        private const string QUERY_COUNT_FORMAT = "SELECT chains.{3}, COUNT(*) FROM " +
                                                  "(select t.{3}, c.{4} from {0} t " +
                                                  "inner join {1} m on t.{5} = m.{6} " +
                                                  "inner join {2} c on m.{7} = c.{4} AND " +
                                                                      "m.id_mailbox = c.id_mailbox AND " +
                                                                      "m.tenant = c.tenant AND " +
                                                                      "m.id_user = c.id_user AND " +
                                                                      "m.folder = c.folder " +
                                                  "where t.{8} = @tenant and t.{9} = @user {10}" +
                                                  "group by t.{3}, c.{4}) as chains " +
                                                  "GROUP BY chains.{3};";

        public Dictionary<uint, int> GetChainUserFolderCount(bool? unread = null)
        {
            var query = string.Format(QUERY_COUNT_FORMAT,
                UserFoldertXMailTable.TABLE_NAME,
                MailTable.TABLE_NAME,
                ChainTable.TABLE_NAME,
                UserFoldertXMailTable.Columns.FolderId,
                ChainTable.Columns.Id,
                UserFoldertXMailTable.Columns.MailId,
                MailTable.Columns.Id,
                MailTable.Columns.ChainId,
                UserFoldertXMailTable.Columns.Tenant,
                UserFoldertXMailTable.Columns.User,
                unread.HasValue ? string.Format("and m.{0} = {1} ", MailTable.Columns.Unread, unread.Value ? 1 : 0) : "");

            var result = Db.ExecuteList(query, new { tenant = Tenant, user = CurrentUserId })
                .ConvertAll(r => new
                {
                    folder = Convert.ToUInt32(r[0]),
                    count = Convert.ToInt32(r[1])
                })
                .ToDictionary(o => o.folder, o => o.count);

            return result;
        }

        public Dictionary<uint, int> GetChainUserFolderCount(List<int> userFolderIds, bool? unread = null)
        {
            var query = string.Format(QUERY_COUNT_FORMAT,
                UserFoldertXMailTable.TABLE_NAME,
                MailTable.TABLE_NAME,
                ChainTable.TABLE_NAME,
                UserFoldertXMailTable.Columns.FolderId,
                ChainTable.Columns.Id,
                UserFoldertXMailTable.Columns.MailId,
                MailTable.Columns.Id,
                MailTable.Columns.ChainId,
                UserFoldertXMailTable.Columns.Tenant,
                UserFoldertXMailTable.Columns.User,
                string.Format("and t.{0} in ({1}) {2}", UserFoldertXMailTable.Columns.FolderId, string.Join(",", userFolderIds),
                    unread.HasValue
                        ? string.Format("and m.{0} = {1} ", MailTable.Columns.Unread, unread.Value ? 1 : 0)
                        : "")
                );

            var result = Db.ExecuteList(query, new { tenant = Tenant, user = CurrentUserId })
                .ConvertAll(r => new
                {
                    folder = Convert.ToUInt32(r[0]),
                    count = Convert.ToInt32(r[1])
                })
                .ToDictionary(o => o.folder, o => o.count);

            return result;
        }

        public int SaveChain(Chain chain)
        {
            var query = new SqlInsert(ChainTable.TABLE_NAME, true)
                .InColumnValue(ChainTable.Columns.Id, chain.Id)
                .InColumnValue(ChainTable.Columns.MailboxId, chain.MailboxId)
                .InColumnValue(ChainTable.Columns.Tenant, chain.Tenant)
                .InColumnValue(ChainTable.Columns.User, chain.User)
                .InColumnValue(ChainTable.Columns.Folder, chain.Folder)
                .InColumnValue(ChainTable.Columns.Length, chain.Length)
                .InColumnValue(ChainTable.Columns.Unread, chain.Unread)
                .InColumnValue(ChainTable.Columns.HasAttachments, chain.HasAttachments)
                .InColumnValue(ChainTable.Columns.Importance, chain.Importance)
                .InColumnValue(ChainTable.Columns.Tags, chain.Tags);

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        public int Delete(IConversationsExp exp)
        {
            var query = new SqlDelete(ChainTable.TABLE_NAME)
                .Where(exp.GetExpression());

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        public int SetFieldValue<T>(IConversationsExp exp, string field, T value)
        {
            var query =
                new SqlUpdate(ChainTable.TABLE_NAME)
                    .Set(field, value)
                    .Where(exp.GetExpression());

            return Db.ExecuteNonQuery(query);
        }

        protected Chain ToChain(object[] r)
        {
            var chain = new Chain
            {
                Id = Convert.ToString(r[0]),
                MailboxId = Convert.ToInt32(r[1]),
                Tenant = Convert.ToInt32(r[2]),
                User = Convert.ToString(r[3]),
                Folder = (FolderType)Convert.ToInt32(r[4]),
                Length = Convert.ToInt32(r[5]),
                Unread = Convert.ToBoolean(r[6]),
                HasAttachments = Convert.ToBoolean(r[7]),
                Importance = Convert.ToBoolean(r[8]),
                Tags = Convert.ToString(r[9])
            };

            return chain;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/filters/filter.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined") {
    ASC = {};
}
if (typeof ASC.Mail === "undefined") {
    ASC.Mail = (function () {
        return {};
    })();
}
if (typeof ASC.Mail.Filter === "undefined") {
    ASC.Mail.Filter = function(id, name, position, enabled, conditions, actions, options) {
        this.id = id || 0;
        this.name = name || "";
        this.position = position || 0;
        this.enabled = enabled || true;

        this.conditions = conditions || [];
        this.actions = actions || [];

        this.options = options || new ASC.Mail.Filter.Options();

        this.ToData = function() {
            var json = JSON.stringify(this);
            var data = JSON.parse(json);
            return data;
        };
    };

    ASC.Mail.Filter.Constants = (function() {
        var condition = {
                KeyType:
                {
                    None: -1,
                    From: 0,
                    ToOrCc: 1,
                    To: 2,
                    Cc: 3,
                    Subject: 4
                },
                OperationType:
                {
                    None: -1,
                    Matches: 0,
                    NotMatches: 1,
                    Contains: 2,
                    NotContains: 3
                },
                MatchMultiType:
                {
                    None: 0,
                    MatchAll: 1,
                    MatchAtLeastOne: 2
                }
            },
            actionType = {
                None: -1,
                DeleteForever: 0,
                MoveTo: 1,
                MarkTag: 2,
                MarkAsImportant: 3,
                MarkAsRead: 4
            },
            applyTo = {
                AttachmentsType:
                {
                    WithAndWithoutAttachments: 0,
                    WithAttachments: 1,
                    WithoutAttachments: 2
                },
                MessagesType:
                {
                    AllExceptSpam: 0,
                    AllIncludeSpam: 1,
                    SpamOnly: 2
                }
            };

        return {
            Condition: condition,
            ActionType: actionType,
            ApplyTo: applyTo
        };
    })();

    ASC.Mail.Filter.Options = function(folders) {
        this.matchMultiConditions = ASC.Mail.Filter.Constants.Condition.MatchMultiType.None;
        this.applyTo = {
            folders: folders || [],
            mailboxes: [],
            withAttachments: ASC.Mail.Filter.Constants.ApplyTo.AttachmentsType.WithAndWithoutAttachments
        };
        this.ignoreOther = false;
    };

    ASC.Mail.Filter.Action = function (action, data) {
        this.action = action === null || action === undefined ? ASC.Mail.Filter.Constants.ActionType.None : action;
        this.data = data || null;
    };

    ASC.Mail.Filter.Condition = function (key, operation, value) {
        this.id = "condition" + TMMail.getRandomId();
        this.key = key;
        this.operation = operation;
        this.value = value || null;
    };
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Controls/DocumentsPopup/DocumentsPopup.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Files.Core;
using ASC.Web.Files;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Common.LoaderPage;

namespace ASC.Web.Mail.Controls
{
    public partial class DocumentsPopup : UserControl
    {
        public static string Location
        {
            get { return "~/addons/mail/Controls/DocumentsPopup/DocumentsPopup.ascx"; }
        }

        protected string FrameUrl;

        private void InitScripts()
        {
            Page.RegisterStyle("~/addons/mail/Controls/DocumentsPopup/css/documentspopup.less")
                .RegisterBodyScripts("~/addons/mail/Controls/DocumentsPopup/js/documentspopup.js");
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            FrameUrl = FileChoice.GetUrl(filterType: FilterType.FilesOnly, multiple: true, successButton: UserControlsCommonResource.AttachFiles);

            loaderHolder.Controls.Add(LoadControl(LoaderPage.Location));

            _documentUploader.Options.IsPopup = true;
            InitScripts();
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Core/Notify/StudioPeriodicNotify.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Common.Billing;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Notify;
using ASC.Notify.Model;
using ASC.Notify.Patterns;
using ASC.Web.Core.Helpers;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Core.Notify
{
    public class StudioPeriodicNotify
    {
        public static void SendSaasLetters(INotifyClient client, string senderName, DateTime scheduleDate)
        {
            var log = LogManager.GetLogger("ASC.Notify");
            var nowDate = scheduleDate.Date;

            log.Info("Start SendSaasTariffLetters");

            var activeTenants = CoreContext.TenantManager.GetTenants().ToList();

            if (activeTenants.Count <= 0)
            {
                log.Info("End SendSaasTariffLetters");
                return;
            }

            foreach (var tenant in activeTenants)
            {
                try
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant.TenantId);

                    var tariff = CoreContext.PaymentManager.GetTariff(tenant.TenantId);
                    var quota = CoreContext.TenantManager.GetTenantQuota(tenant.TenantId);

                    var createdDate = tenant.CreatedDateTime.Date;

                    var dueDateIsNotMax = tariff.DueDate != DateTime.MaxValue;
                    var dueDate = tariff.DueDate.Date;

                    var delayDueDateIsNotMax = tariff.DelayDueDate != DateTime.MaxValue;
                    var delayDueDate = tariff.DelayDueDate.Date;

                    INotifyAction action = null;
                    var paymentMessage = true;

                    var toadmins = false;
                    var tousers = false;
                    var toowner = false;

                    var coupon = string.Empty;

                    Func<string> greenButtonText = () => string.Empty;
                    Func<string> blueButtonText = () => WebstudioNotifyPatternResource.ButtonRequestCallButton;
                    var greenButtonUrl = string.Empty;

                    Func<string> tableItemText1 = () => string.Empty;
                    Func<string> tableItemText2 = () => string.Empty;
                    Func<string> tableItemText3 = () => string.Empty;
                    Func<string> tableItemText4 = () => string.Empty;
                    Func<string> tableItemText5 = () => string.Empty;
                    Func<string> tableItemText6 = () => string.Empty;
                    Func<string> tableItemText7 = () => string.Empty;

                    var tableItemUrl1 = string.Empty;
                    var tableItemUrl2 = string.Empty;
                    var tableItemUrl3 = string.Empty;
                    var tableItemUrl4 = string.Empty;
                    var tableItemUrl5 = string.Empty;
                    var tableItemUrl6 = string.Empty;
                    var tableItemUrl7 = string.Empty;

                    var tableItemImg1 = string.Empty;
                    var tableItemImg2 = string.Empty;
                    var tableItemImg3 = string.Empty;
                    var tableItemImg4 = string.Empty;
                    var tableItemImg5 = string.Empty;
                    var tableItemImg6 = string.Empty;
                    var tableItemImg7 = string.Empty;

                    Func<string> tableItemComment1 = () => string.Empty;
                    Func<string> tableItemComment2 = () => string.Empty;
                    Func<string> tableItemComment3 = () => string.Empty;
                    Func<string> tableItemComment4 = () => string.Empty;
                    Func<string> tableItemComment5 = () => string.Empty;
                    Func<string> tableItemComment6 = () => string.Empty;
                    Func<string> tableItemComment7 = () => string.Empty;

                    Func<string> tableItemLearnMoreText1 = () => string.Empty;
                    Func<string> tableItemLearnMoreText2 = () => string.Empty;
                    Func<string> tableItemLearnMoreText3 = () => string.Empty;
                    Func<string> tableItemLearnMoreText4 = () => string.Empty;
                    Func<string> tableItemLearnMoreText5 = () => string.Empty;
                    Func<string> tableItemLearnMoreText6 = () => string.Empty;
                    Func<string> tableItemLearnMoreText7 = () => string.Empty;

                    var tableItemLearnMoreUrl1 = string.Empty;
                    var tableItemLearnMoreUrl2 = string.Empty;
                    var tableItemLearnMoreUrl3 = string.Empty;
                    var tableItemLearnMoreUrl4 = string.Empty;
                    var tableItemLearnMoreUrl5 = string.Empty;
                    var tableItemLearnMoreUrl6 = string.Empty;
                    var tableItemLearnMoreUrl7 = string.Empty;

                    if (quota.Free)
                    {
                        #region Free tariff every 2 months during 1 year

                        if (createdDate.AddMonths(2) == nowDate || createdDate.AddMonths(4) == nowDate || createdDate.AddMonths(6) == nowDate || createdDate.AddMonths(8) == nowDate || createdDate.AddMonths(10) == nowDate || createdDate.AddMonths(12) == nowDate)
                        {
                            action = Actions.SaasAdminPaymentWarningEvery2MonthsV115;
                            toadmins = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonUseDiscount;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx");
                        }

                        #endregion
                    }
                    else if (quota.Trial)
                    {
                        #region After registration letters

                        #region 1 days after registration to admins SAAS TRIAL

                        if (createdDate.AddDays(1) == nowDate)
                        {
                            action = Actions.SaasAdminModulesV115;
                            paymentMessage = false;
                            toadmins = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonAccessYouWebOffice;
                            greenButtonUrl = String.Format("{0}/", CommonLinkUtility.GetFullAbsolutePath("~").TrimEnd('/'));
                        }

                        #endregion

                        #region  4 days after registration to admins SAAS TRIAL

                        else if (createdDate.AddDays(4) == nowDate)
                        {
                            action = Actions.SaasAdminComfortTipsV115;
                            paymentMessage = false;
                            toadmins = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonUseDiscount;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx");
                        }

                        #endregion

                        #region 7 days after registration to admins and users SAAS TRIAL

                        else if (createdDate.AddDays(7) == nowDate)
                        {
                            action = Actions.SaasAdminUserDocsTipsV115;
                            paymentMessage = false;
                            toadmins = true;
                            tousers = true;

                            tableItemImg1 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-formatting-100.png");
                            tableItemText1 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_formatting_hdr;
                            tableItemComment1 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_formatting;

                            if (!CoreContext.Configuration.CustomMode)
                            {
                                tableItemLearnMoreUrl1 = StudioNotifyHelper.Helplink + "/onlyoffice-editors/index.aspx";
                                tableItemLearnMoreText1 = () => WebstudioNotifyPatternResource.LinkLearnMore;
                            }

                            tableItemImg2 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-share-100.png");
                            tableItemText2 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_share_hdr;
                            tableItemComment2 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_share;

                            tableItemImg3 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-coediting-100.png");
                            tableItemText3 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_coediting_hdr;
                            tableItemComment3 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_coediting;

                            tableItemImg4 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-review-100.png");
                            tableItemText4 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_review_hdr;
                            tableItemComment4 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_review;

                            tableItemImg5 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-modules-100.png");
                            tableItemText5 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_contentcontrols_hdr;
                            tableItemComment5 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_contentcontrols;

                            tableItemImg6 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-customize-100.png");
                            tableItemText6 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_spreadsheets_hdr;
                            tableItemComment6 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_spreadsheets;

                            tableItemImg7 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-attach-100.png");
                            tableItemText7 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_differences_hdr;
                            tableItemComment7 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_differences;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonAccessYouWebOffice;
                            greenButtonUrl = String.Format("{0}/Products/Files/", CommonLinkUtility.GetFullAbsolutePath("~").TrimEnd('/'));
                        }

                        #endregion

                        #region 14 days after registration to admins and users SAAS TRIAL

                        else if (createdDate.AddDays(14) == nowDate)
                        {
                            action = Actions.SaasAdminUserAppsTipsV115;
                            paymentMessage = false;
                            toadmins = true;
                            tousers = true;
                        }

                        #endregion

                        #endregion

                        #region Trial warning letters

                        #region 5 days before SAAS TRIAL ends to admins

                        else if (dueDateIsNotMax && dueDate.AddDays(-5) == nowDate)
                        {
                            toadmins = true;
                            action = Actions.SaasAdminTrialWarningBefore5V115;
                            coupon = "PortalCreation10%";

                            if (string.IsNullOrEmpty(coupon))
                            {
                                try
                                {
                                    log.InfoFormat("start CreateCoupon to {0}", tenant.TenantAlias);

                                    coupon = SetupInfo.IsSecretEmail(CoreContext.UserManager.GetUsers(tenant.OwnerId).Email)
                                                ? tenant.TenantAlias
                                                : CouponManager.CreateCoupon();

                                    log.InfoFormat("end CreateCoupon to {0} coupon = {1}", tenant.TenantAlias, coupon);
                                }
                                catch (AggregateException ae)
                                {
                                    foreach (var ex in ae.InnerExceptions)
                                        log.Error(ex);
                                }
                                catch (Exception ex)
                                {
                                    log.Error(ex);
                                }
                            }

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonUseDiscount;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx");
                        }

                        #endregion

                        #region SAAS TRIAL expires today to admins

                        else if (dueDate == nowDate)
                        {
                            action = Actions.SaasAdminTrialWarningV115;
                            toadmins = true;
                        }

                        #endregion

                        #region 1 day after SAAS TRIAL expired to admins

                        if (dueDateIsNotMax && dueDate.AddDays(1) == nowDate)
                        {
                            action = Actions.SaasAdminTrialWarningAfter1V115;
                            toadmins = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonRenewNow;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx");
                        }

                        #endregion

                        #region 6 months after SAAS TRIAL expired

                        else if (dueDateIsNotMax && dueDate.AddMonths(6) == nowDate)
                        {
                            action = Actions.SaasAdminTrialWarningAfterHalfYearV115;
                            toowner = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonLeaveFeedback;

                            var owner = CoreContext.UserManager.GetUsers(tenant.OwnerId);
                            greenButtonUrl = SetupInfo.TeamlabSiteRedirect + "/remove-portal-feedback-form.aspx#" +
                                          System.Web.HttpUtility.UrlEncode(Convert.ToBase64String(
                                              System.Text.Encoding.UTF8.GetBytes("{\"firstname\":\"" + owner.FirstName +
                                                                                 "\",\"lastname\":\"" + owner.LastName +
                                                                                 "\",\"alias\":\"" + tenant.TenantAlias +
                                                                                 "\",\"email\":\"" + owner.Email + "\"}")));
                        }
                        else if (dueDateIsNotMax && dueDate.AddMonths(6).AddDays(7) <= nowDate)
                        {
                            CoreContext.TenantManager.RemoveTenant(tenant.TenantId, true);

                            if (!String.IsNullOrEmpty(ApiSystemHelper.ApiCacheUrl))
                            {
                                ApiSystemHelper.RemoveTenantFromCache(tenant.TenantAlias);
                            }
                        }

                        #endregion

                        #endregion
                    }
                    else if (tariff.State >= TariffState.Paid)
                    {
                        #region Payment warning letters

                        #region 6 months after SAAS PAID expired

                        if (tariff.State == TariffState.NotPaid && dueDateIsNotMax && dueDate.AddMonths(6) == nowDate)
                        {
                            action = Actions.SaasAdminTrialWarningAfterHalfYearV115;
                            toowner = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonLeaveFeedback;

                            var owner = CoreContext.UserManager.GetUsers(tenant.OwnerId);
                            greenButtonUrl = SetupInfo.TeamlabSiteRedirect + "/remove-portal-feedback-form.aspx#" +
                                          System.Web.HttpUtility.UrlEncode(Convert.ToBase64String(
                                              System.Text.Encoding.UTF8.GetBytes("{\"firstname\":\"" + owner.FirstName +
                                                                                 "\",\"lastname\":\"" + owner.LastName +
                                                                                 "\",\"alias\":\"" + tenant.TenantAlias +
                                                                                 "\",\"email\":\"" + owner.Email + "\"}")));
                        }
                        else if (tariff.State == TariffState.NotPaid && dueDateIsNotMax && dueDate.AddMonths(6).AddDays(7) <= nowDate)
                        {
                            CoreContext.TenantManager.RemoveTenant(tenant.TenantId, true);

                            if (!String.IsNullOrEmpty(ApiSystemHelper.ApiCacheUrl))
                            {
                                ApiSystemHelper.RemoveTenantFromCache(tenant.TenantAlias);
                            }
                        }

                        #endregion

                        #endregion
                    }


                    if (action == null) continue;

                    var users = toowner
                                    ? new List<UserInfo> { CoreContext.UserManager.GetUsers(tenant.OwnerId) }
                                    : StudioNotifyHelper.GetRecipients(toadmins, tousers, false);


                    foreach (var u in users.Where(u => paymentMessage || StudioNotifyHelper.IsSubscribedToNotify(u, Actions.PeriodicNotify)))
                    {
                        var culture = string.IsNullOrEmpty(u.CultureName) ? tenant.GetCulture() : u.GetCulture();
                        Thread.CurrentThread.CurrentCulture = culture;
                        Thread.CurrentThread.CurrentUICulture = culture;
                        var rquota = TenantExtra.GetRightQuota() ?? TenantQuota.Default;

                        client.SendNoticeToAsync(
                            action,
                            null,
                            new[] { StudioNotifyHelper.ToRecipient(u.ID) },
                            new[] { senderName },
                            null,
                            new TagValue(Tags.UserName, u.FirstName.HtmlEncode()),
                            new TagValue(Tags.PricingPage, CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx")),
                            new TagValue(Tags.ActiveUsers, CoreContext.UserManager.GetUsers().Count()),
                            new TagValue(Tags.Price, rquota.Price),
                            new TagValue(Tags.PricePeriod, rquota.Year3 ? UserControlsCommonResource.TariffPerYear3 : rquota.Year ? UserControlsCommonResource.TariffPerYear : UserControlsCommonResource.TariffPerMonth),
                            new TagValue(Tags.DueDate, dueDate.ToLongDateString()),
                            new TagValue(Tags.DelayDueDate, (delayDueDateIsNotMax ? delayDueDate : dueDate).ToLongDateString()),
                            TagValues.BlueButton(blueButtonText, "http://www.onlyoffice.com/call-back-form.aspx"),
                            TagValues.GreenButton(greenButtonText, greenButtonUrl),
                            TagValues.TableTop(),
                            TagValues.TableItem(1, tableItemText1, tableItemUrl1, tableItemImg1, tableItemComment1, tableItemLearnMoreText1, tableItemLearnMoreUrl1),
                            TagValues.TableItem(2, tableItemText2, tableItemUrl2, tableItemImg2, tableItemComment2, tableItemLearnMoreText2, tableItemLearnMoreUrl2),
                            TagValues.TableItem(3, tableItemText3, tableItemUrl3, tableItemImg3, tableItemComment3, tableItemLearnMoreText3, tableItemLearnMoreUrl3),
                            TagValues.TableItem(4, tableItemText4, tableItemUrl4, tableItemImg4, tableItemComment4, tableItemLearnMoreText4, tableItemLearnMoreUrl4),
                            TagValues.TableItem(5, tableItemText5, tableItemUrl5, tableItemImg5, tableItemComment5, tableItemLearnMoreText5, tableItemLearnMoreUrl5),
                            TagValues.TableItem(6, tableItemText6, tableItemUrl6, tableItemImg6, tableItemComment6, tableItemLearnMoreText6, tableItemLearnMoreUrl6),
                            TagValues.TableItem(7, tableItemText7, tableItemUrl7, tableItemImg7, tableItemComment7, tableItemLearnMoreText7, tableItemLearnMoreUrl7),
                            TagValues.TableBottom(),
                            new TagValue(CommonTags.Footer, u.IsAdmin() ? "common" : "social"),
                            new TagValue(Tags.Coupon, coupon));
                    }
                }
                catch (Exception err)
                {
                    log.Error(err);
                }
            }

            log.Info("End SendSaasTariffLetters");
        }

        public static void SendEnterpriseLetters(INotifyClient client, string senderName, DateTime scheduleDate)
        {
            var log = LogManager.GetLogger("ASC.Notify");
            var nowDate = scheduleDate.Date;
            const string dbid = "webstudio";

            log.Info("Start SendTariffEnterpriseLetters");

            var defaultRebranding = MailWhiteLabelSettings.Instance.IsDefault;

            var activeTenants = CoreContext.TenantManager.GetTenants();

            if (activeTenants.Count <= 0)
            {
                log.Info("End SendTariffEnterpriseLetters");
                return;
            }

            foreach (var tenant in activeTenants)
            {
                try
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant.TenantId);

                    var tariff = CoreContext.PaymentManager.GetTariff(tenant.TenantId);
                    var quota = CoreContext.TenantManager.GetTenantQuota(tenant.TenantId);

                    var createdDate = tenant.CreatedDateTime.Date;

                    var actualEndDate = (tariff.DueDate != DateTime.MaxValue ? tariff.DueDate : tariff.LicenseDate);
                    var dueDateIsNotMax = actualEndDate != DateTime.MaxValue;
                    var dueDate = actualEndDate.Date;

                    var delayDueDateIsNotMax = tariff.DelayDueDate != DateTime.MaxValue;
                    var delayDueDate = tariff.DelayDueDate.Date;

                    INotifyAction action = null;
                    var paymentMessage = true;

                    var toadmins = false;
                    var tousers = false;

                    Func<string> greenButtonText = () => string.Empty;
                    Func<string> blueButtonText = () => WebstudioNotifyPatternResource.ButtonRequestCallButton;
                    var greenButtonUrl = string.Empty;

                    Func<string> tableItemText1 = () => string.Empty;
                    Func<string> tableItemText2 = () => string.Empty;
                    Func<string> tableItemText3 = () => string.Empty;
                    Func<string> tableItemText4 = () => string.Empty;
                    Func<string> tableItemText5 = () => string.Empty;
                    Func<string> tableItemText6 = () => string.Empty;
                    Func<string> tableItemText7 = () => string.Empty;

                    var tableItemUrl1 = string.Empty;
                    var tableItemUrl2 = string.Empty;
                    var tableItemUrl3 = string.Empty;
                    var tableItemUrl4 = string.Empty;
                    var tableItemUrl5 = string.Empty;
                    var tableItemUrl6 = string.Empty;
                    var tableItemUrl7 = string.Empty;

                    var tableItemImg1 = string.Empty;
                    var tableItemImg2 = string.Empty;
                    var tableItemImg3 = string.Empty;
                    var tableItemImg4 = string.Empty;
                    var tableItemImg5 = string.Empty;
                    var tableItemImg6 = string.Empty;
                    var tableItemImg7 = string.Empty;

                    Func<string> tableItemComment1 = () => string.Empty;
                    Func<string> tableItemComment2 = () => string.Empty;
                    Func<string> tableItemComment3 = () => string.Empty;
                    Func<string> tableItemComment4 = () => string.Empty;
                    Func<string> tableItemComment5 = () => string.Empty;
                    Func<string> tableItemComment6 = () => string.Empty;
                    Func<string> tableItemComment7 = () => string.Empty;

                    Func<string> tableItemLearnMoreText1 = () => string.Empty;
                    Func<string> tableItemLearnMoreText2 = () => string.Empty;
                    Func<string> tableItemLearnMoreText3 = () => string.Empty;
                    Func<string> tableItemLearnMoreText4 = () => string.Empty;
                    Func<string> tableItemLearnMoreText5 = () => string.Empty;
                    Func<string> tableItemLearnMoreText6 = () => string.Empty;
                    Func<string> tableItemLearnMoreText7 = () => string.Empty;

                    var tableItemLearnMoreUrl1 = string.Empty;
                    var tableItemLearnMoreUrl2 = string.Empty;
                    var tableItemLearnMoreUrl3 = string.Empty;
                    var tableItemLearnMoreUrl4 = string.Empty;
                    var tableItemLearnMoreUrl5 = string.Empty;
                    var tableItemLearnMoreUrl6 = string.Empty;
                    var tableItemLearnMoreUrl7 = string.Empty;


                    if (quota.Trial && defaultRebranding)
                    {
                        #region After registration letters

                        #region 1 day after registration to admins ENTERPRISE TRIAL + defaultRebranding

                        if (createdDate.AddDays(1) == nowDate)
                        {
                            action = Actions.EnterpriseAdminCustomizePortalV10;
                            paymentMessage = false;
                            toadmins = true;

                            tableItemImg1 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-brand-100.png");
                            tableItemText1 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_brand_hdr;
                            tableItemComment1 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_brand;

                            tableItemImg2 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-regional-100.png");
                            tableItemText2 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_regional_hdr;
                            tableItemComment2 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_regional;

                            tableItemImg3 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-customize-100.png");
                            tableItemText3 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_customize_hdr;
                            tableItemComment3 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_customize;

                            tableItemImg4 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-modules-100.png");
                            tableItemText4 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_modules_hdr;
                            tableItemComment4 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_modules;

                            tableItemImg5 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-3rdparty-100.png");
                            tableItemText5 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_3rdparty_hdr;
                            tableItemComment5 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_3rdparty;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonConfigureRightNow;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath(CommonLinkUtility.GetAdministration(ManagementType.General));
                        }

                        #endregion

                        #region 4 days after registration to admins ENTERPRISE TRIAL + only 1 user + defaultRebranding

                        else if (createdDate.AddDays(4) == nowDate && CoreContext.UserManager.GetUsers().Count() == 1)
                        {
                            action = Actions.EnterpriseAdminInviteTeammatesV10;
                            paymentMessage = false;
                            toadmins = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonInviteRightNow;
                            greenButtonUrl = String.Format("{0}/Products/People/", CommonLinkUtility.GetFullAbsolutePath("~").TrimEnd('/'));
                        }

                        #endregion

                        #region 5 days after registration to admins ENTERPRISE TRAIL + without activity in 1 or more days + defaultRebranding

                        else if (createdDate.AddDays(5) == nowDate)
                        {
                            List<DateTime> datesWithActivity;

                            var query = new SqlQuery("feed_aggregate")
                                .Select(new SqlExp("cast(created_date as date) as short_date"))
                                .Where("tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                                .Where(Exp.Le("created_date", nowDate.AddDays(-1)))
                                .GroupBy("short_date");

                            using (var db = new DbManager(dbid))
                            {
                                datesWithActivity = db
                                    .ExecuteList(query)
                                    .ConvertAll(r => Convert.ToDateTime(r[0]));
                            }

                            if (datesWithActivity.Count < 5)
                            {
                                action = Actions.EnterpriseAdminWithoutActivityV10;
                                paymentMessage = false;
                                toadmins = true;
                            }
                        }

                        #endregion

                        #region 7 days after registration to admins and users ENTERPRISE TRIAL + defaultRebranding

                        else if (createdDate.AddDays(7) == nowDate)
                        {
                            action = Actions.EnterpriseAdminUserDocsTipsV10;
                            paymentMessage = false;
                            toadmins = true;
                            tousers = true;

                            tableItemImg1 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-formatting-100.png");
                            tableItemText1 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_formatting_hdr;
                            tableItemComment1 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_formatting;

                            if (!CoreContext.Configuration.CustomMode)
                            {
                                tableItemLearnMoreUrl1 = StudioNotifyHelper.Helplink + "/onlyoffice-editors/index.aspx";
                                tableItemLearnMoreText1 = () => WebstudioNotifyPatternResource.LinkLearnMore;
                            }

                            tableItemImg2 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-share-100.png");
                            tableItemText2 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_share_hdr;
                            tableItemComment2 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_share;

                            tableItemImg3 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-coediting-100.png");
                            tableItemText3 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_coediting_hdr;
                            tableItemComment3 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_coediting;

                            tableItemImg4 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-review-100.png");
                            tableItemText4 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_review_hdr;
                            tableItemComment4 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_review;

                            tableItemImg5 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-3rdparty-100.png");
                            tableItemText5 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_3rdparty_hdr;
                            tableItemComment5 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_3rdparty;

                            tableItemImg6 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-attach-100.png");
                            tableItemText6 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_attach_hdr;
                            tableItemComment6 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_attach;

                            tableItemImg7 = StudioNotifyHelper.GetNotificationImageUrl("tips-documents-apps-100.png");
                            tableItemText7 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_apps_hdr;
                            tableItemComment7 = () => WebstudioNotifyPatternResource.pattern_saas_admin_user_docs_tips_v115_item_apps;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonAccessYouWebOffice;
                            greenButtonUrl = String.Format("{0}/Products/Files/", CommonLinkUtility.GetFullAbsolutePath("~").TrimEnd('/'));
                        }

                        #endregion

                        #region 21 days after registration to admins and users ENTERPRISE TRIAL + defaultRebranding

                        else if (createdDate.AddDays(21) == nowDate)
                        {
                            action = Actions.EnterpriseAdminUserAppsTipsV10;
                            paymentMessage = false;
                            toadmins = true;
                            tousers = true;
                        }

                        #endregion

                        #endregion

                        #region Trial warning letters

                        #region 7 days before ENTERPRISE TRIAL ends to admins + defaultRebranding

                        else if (dueDateIsNotMax && dueDate.AddDays(-7) == nowDate)
                        {
                            action = Actions.EnterpriseAdminTrialWarningBefore7V10;
                            toadmins = true;

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonSelectPricingPlans;
                            greenButtonUrl = "http://www.onlyoffice.com/enterprise-edition.aspx";
                        }

                        #endregion

                        #region ENTERPRISE TRIAL expires today to admins + defaultRebranding

                        else if (dueDate == nowDate)
                        {
                            action = Actions.EnterpriseAdminTrialWarningV10;
                            toadmins = true;
                        }

                        #endregion

                        #endregion
                    }
                    else if (quota.Trial && !defaultRebranding)
                    {
                        #region After registration letters

                        #region 1 day after registration to admins ENTERPRISE TRIAL + !defaultRebranding

                        if (createdDate.AddDays(1) == nowDate)
                        {
                            action = Actions.EnterpriseWhitelabelAdminCustomizePortalV10;
                            paymentMessage = false;
                            toadmins = true;

                            tableItemImg1 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-brand-100.png");
                            tableItemText1 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_brand_hdr;
                            tableItemComment1 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_brand;

                            tableItemImg2 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-regional-100.png");
                            tableItemText2 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_regional_hdr;
                            tableItemComment2 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_regional;

                            tableItemImg3 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-customize-100.png");
                            tableItemText3 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_customize_hdr;
                            tableItemComment3 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_customize;

                            tableItemImg4 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-modules-100.png");
                            tableItemText4 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_modules_hdr;
                            tableItemComment4 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_modules;

                            if (!CoreContext.Configuration.CustomMode)
                            {
                                tableItemImg5 = StudioNotifyHelper.GetNotificationImageUrl("tips-customize-3rdparty-100.png");
                                tableItemText5 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_3rdparty_hdr;
                                tableItemComment5 = () => WebstudioNotifyPatternResource.pattern_enterprise_admin_customize_portal_v10_item_3rdparty;
                            }

                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonConfigureRightNow;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath(CommonLinkUtility.GetAdministration(ManagementType.General));
                        }

                        #endregion

                        #endregion
                    }
                    else if (tariff.State == TariffState.Paid)
                    {
                        #region Payment warning letters

                        #region 7 days before ENTERPRISE PAID expired to admins

                        if (dueDateIsNotMax && dueDate.AddDays(-7) == nowDate)
                        {
                            action = defaultRebranding
                                         ? Actions.EnterpriseAdminPaymentWarningBefore7V10
                                         : Actions.EnterpriseWhitelabelAdminPaymentWarningBefore7V10;
                            toadmins = true;
                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonSelectPricingPlans;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx");
                        }

                        #endregion

                        #region ENTERPRISE PAID expires today to admins

                        else if (dueDate == nowDate)
                        {
                            action = defaultRebranding
                                         ? Actions.EnterpriseAdminPaymentWarningV10
                                         : Actions.EnterpriseWhitelabelAdminPaymentWarningV10;
                            toadmins = true;
                            greenButtonText = () => WebstudioNotifyPatternResource.ButtonSelectPricingPlans;
                            greenButtonUrl = CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx");
                        }

                        #endregion

                        #endregion
                    }


                    if (action == null) continue;

                    var users = StudioNotifyHelper.GetRecipients(toadmins, tousers, false);

                    foreach (var u in users.Where(u => paymentMessage || StudioNotifyHelper.IsSubscribedToNotify(u, Actions.PeriodicNotify)))
                    {
                        var culture = string.IsNullOrEmpty(u.CultureName) ? tenant.GetCulture() : u.GetCulture();
                        Thread.CurrentThread.CurrentCulture = culture;
                        Thread.CurrentThread.CurrentUICulture = culture;

                        var rquota = TenantExtra.GetRightQuota() ?? TenantQuota.Default;

                        client.SendNoticeToAsync(
                            action,
                            null,
                            new[] { StudioNotifyHelper.ToRecipient(u.ID) },
                            new[] { senderName },
                            null,
                            new TagValue(Tags.UserName, u.FirstName.HtmlEncode()),
                            new TagValue(Tags.PricingPage, CommonLinkUtility.GetFullAbsolutePath("~/Tariffs.aspx")),
                            new TagValue(Tags.ActiveUsers, CoreContext.UserManager.GetUsers().Count()),
                            new TagValue(Tags.Price, rquota.Price),
                            new TagValue(Tags.PricePeriod, rquota.Year3 ? UserControlsCommonResource.TariffPerYear3 : rquota.Year ? UserControlsCommonResource.TariffPerYear : UserControlsCommonResource.TariffPerMonth),
                            new TagValue(Tags.DueDate, dueDate.ToLongDateString()),
                            new TagValue(Tags.DelayDueDate, (delayDueDateIsNotMax ? delayDueDate : dueDate).ToLongDateString()),
                            TagValues.BlueButton(blueButtonText, "http://www.onlyoffice.com/call-back-form.aspx"),
                            TagValues.GreenButton(greenButtonText, greenButtonUrl),
                            TagValues.TableTop(),
                            TagValues.TableItem(1, tableItemText1, tableItemUrl1, tableItemImg1, tableItemComment1, tableItemLearnMoreText1, tableItemLearnMoreUrl1),
                            TagValues.TableItem(2, tableItemText2, tableItemUrl2, tableItemImg2, tableItemComment2, tableItemLearnMoreText2, tableItemLearnMoreUrl2),
                            TagValues.TableItem(3, tableItemText3, tableItemUrl3, tableItemImg3, tableItemComment3, tableItemLearnMoreText3, tableItemLearnMoreUrl3),
                            TagValues.TableItem(4, tableItemText4, tableItemUrl4, tableItemImg4, tableItemComment4, tableItemLearnMoreText4, tableItemLearnMoreUrl4),
                            TagValues.TableItem(5, tableItemText5, tableItemUrl5, tableItemImg5, tableItemComment5, tableItemLearnMoreText5, tableItemLearnMoreUrl5),
                            TagValues.TableItem(6, tableItemText6, tableItemUrl6, tableItemImg6, tableItemComment6, tableItemLearnMoreText6, tableItemLearnMoreUrl6),
                            TagValues.TableItem(7, tableItemText7, tableItemUrl7, tableItemImg7, tableItemComment7, tableItemLearnMoreText7, tableItemLearnMoreUrl7),
                            TagValues.TableBottom());
                    }
                }
                catch (Exception err)
                {
                    log.Error(err);
                }
            }

            log.Info("End SendTariffEnterpriseLetters");
        }

        public static void SendOpensourceLetters(INotifyClient client, string senderName, DateTime scheduleDate)
        {
            var log = LogManager.GetLogger("ASC.Notify");
            var nowDate = scheduleDate.Date;

            log.Info("Start SendOpensourceTariffLetters");

            var activeTenants = CoreContext.TenantManager.GetTenants();

            if (activeTenants.Count <= 0)
            {
                log.Info("End SendOpensourceTariffLetters");
                return;
            }

            foreach (var tenant in activeTenants)
            {
                try
                {
                    CoreContext.TenantManager.SetCurrentTenant(tenant.TenantId);

                    var createdDate = tenant.CreatedDateTime.Date;

                    #region After registration letters

                    #region 5 days after registration to admins and users

                    if (createdDate.AddDays(5) == nowDate)
                    {
                        var users = StudioNotifyHelper.GetRecipients(true, true, false);

                        foreach (var u in users.Where(u => StudioNotifyHelper.IsSubscribedToNotify(u, Actions.PeriodicNotify)))
                        {
                            var culture = string.IsNullOrEmpty(u.CultureName) ? tenant.GetCulture() : u.GetCulture();
                            Thread.CurrentThread.CurrentCulture = culture;
                            Thread.CurrentThread.CurrentUICulture = culture;

                            client.SendNoticeToAsync(
                                u.IsAdmin() ? Actions.OpensourceAdminDocsTipsV11 : Actions.OpensourceUserDocsTipsV11,
                                null,
                                new[] { StudioNotifyHelper.ToRecipient(u.ID) },
                                new[] { senderName },
                                null,
                                new TagValue(Tags.UserName, u.DisplayUserName()),
                                new TagValue(CommonTags.Footer, "opensource"));
                        }
                    }

                    #endregion

                    #endregion
                }
                catch (Exception err)
                {
                    log.Error(err);
                }
            }

            log.Info("End SendOpensourceTariffLetters");
        }

        public static void SendPersonalLetters(INotifyClient client, string senderName, DateTime scheduleDate)
        {
            var log = LogManager.GetLogger("ASC.Notify");

            log.Info("Start SendLettersPersonal...");

            foreach (var tenant in CoreContext.TenantManager.GetTenants())
            {
                try
                {
                    Func<string> greenButtonText = () => string.Empty;
                    var greenButtonUrl = string.Empty;

                    int sendCount = 0;

                    CoreContext.TenantManager.SetCurrentTenant(tenant.TenantId);

                    log.InfoFormat("Current tenant: {0}", tenant.TenantId);

                    var users = CoreContext.UserManager.GetUsers(EmployeeStatus.Active);

                    foreach (var user in users.Where(u => StudioNotifyHelper.IsSubscribedToNotify(u, Actions.PeriodicNotify)))
                    {
                        INotifyAction action;

                        SecurityContext.AuthenticateMe(CoreContext.Authentication.GetAccountByID(user.ID));

                        var culture = tenant.GetCulture();
                        if (!string.IsNullOrEmpty(user.CultureName))
                        {
                            try
                            {
                                culture = user.GetCulture();
                            }
                            catch (CultureNotFoundException exception)
                            {

                                log.Error(exception);
                            }
                        }

                        Thread.CurrentThread.CurrentCulture = culture;
                        Thread.CurrentThread.CurrentUICulture = culture;

                        var dayAfterRegister = (int)scheduleDate.Date.Subtract(user.CreateDate.Date).TotalDays;

                        if (CoreContext.Configuration.CustomMode)
                        {
                            switch (dayAfterRegister)
                            {
                                case 7:
                                    action = Actions.PersonalCustomModeAfterRegistration7;
                                    break;
                                default:
                                    continue;
                            }
                        }
                        else
                        {

                            switch (dayAfterRegister)
                            {
                                case 7:
                                    action = Actions.PersonalAfterRegistration7;
                                    break;
                                case 14:
                                    action = Actions.PersonalAfterRegistration14;
                                    break;
                                case 21:
                                    action = Actions.PersonalAfterRegistration21;
                                    break;
                                case 28:
                                    action = Actions.PersonalAfterRegistration28;
                                    greenButtonText = () => WebstudioNotifyPatternResource.ButtonStartFreeTrial;
                                    greenButtonUrl = "https://www.onlyoffice.com/download-commercial.aspx";
                                    break;
                                default:
                                    continue;
                            }
                        }

                        if (action == null) continue;

                        log.InfoFormat(@"Send letter personal '{1}' to {0} culture {2}. tenant id: {3} user culture {4} create on {5} now date {6}",
                              user.Email, action.ID, culture, tenant.TenantId, user.GetCulture(), user.CreateDate, scheduleDate.Date);

                        sendCount++;

                        client.SendNoticeToAsync(
                          action,
                          null,
                          StudioNotifyHelper.RecipientFromEmail(user.Email, true),
                          new[] { senderName },
                          null,
                          TagValues.PersonalHeaderStart(),
                          TagValues.PersonalHeaderEnd(),
                          TagValues.GreenButton(greenButtonText, greenButtonUrl),
                          new TagValue(CommonTags.Footer, CoreContext.Configuration.CustomMode ? "personalCustomMode" : "personal"));
                    }

                    log.InfoFormat("Total send count: {0}", sendCount);
                }
                catch (Exception err)
                {
                    log.Error(err);
                }
            }

            log.Info("End SendLettersPersonal.");
        }

        public static bool ChangeSubscription(Guid userId)
        {
            var recipient = StudioNotifyHelper.ToRecipient(userId);

            var isSubscribe = StudioNotifyHelper.IsSubscribedToNotify(recipient, Actions.PeriodicNotify);

            StudioNotifyHelper.SubscribeToNotify(recipient, Actions.PeriodicNotify, !isSubscribe);

            return !isSubscribe;
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/Routing/ApiRouteRegistratorBase.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;

using ASC.Api.Interfaces;
using ASC.Common.Logging;

using Autofac;

namespace ASC.Api.Impl.Routing
{
    internal abstract class ApiRouteRegistratorBase : IApiRouteRegistrator
    {
        public IComponentContext Container { get; set; }

        public IApiConfiguration Config { get; set; }

        public ILog Log { get; set; }

        public void RegisterRoutes(RouteCollection routes)
        {
            var entryPoints = Container.Resolve<IEnumerable<IApiMethodCall>>();
            var extensions = new List<string>();
            foreach (var apiSerializer in Container.Resolve<IEnumerable<IApiResponder>>())
            {
                extensions.AddRange(apiSerializer.GetSupportedExtensions().Select(x => x.StartsWith(".") ? x : "." + x));
            }
            RegisterEntryPoints(routes, entryPoints, extensions);
        }

        protected abstract void RegisterEntryPoints(RouteCollection routes, IEnumerable<IApiMethodCall> entryPoints, List<string> extensions);
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/CommunityModuleSpecifics.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;

using ASC.Data.Backup.Tasks.Data;
using ASC.Data.Backup.Utils;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal class CommunityModuleSpecifics : ModuleSpecificsBase
    {
        private readonly TableInfo[] _tables = new[]
            {
                new TableInfo("bookmarking_bookmark", "Tenant", "ID")
                    {
                        UserIDColumns = new[] {"UserCreatorID"},
                        DateColumns = new Dictionary<string, bool> {{"Date", false}}
                    },
                new TableInfo("bookmarking_bookmarktag", "tenant"),
                new TableInfo("bookmarking_comment", "tenant", "ID", IdType.Guid)
                    {
                        UserIDColumns = new[] {"UserID"},
                        DateColumns = new Dictionary<string, bool> {{"Datetime", false}}
                    },
                new TableInfo("bookmarking_tag", "tenant", "TagID"),
                new TableInfo("bookmarking_userbookmark", "tenant", "UserBookmarkID")
                    {
                        UserIDColumns = new[] {"UserID"},
                        DateColumns = new Dictionary<string, bool> {{"DateAdded", false}, {"LastModified", false}}
                    },
                new TableInfo("bookmarking_userbookmarktag", "tenant"),
                new TableInfo("blogs_comments", "Tenant", "id", IdType.Guid)
                    {
                        UserIDColumns = new[] {"created_by"},
                        DateColumns = new Dictionary<string, bool> {{"created_when", false}}
                    },
                new TableInfo("blogs_posts", "Tenant", "post_id", IdType.Autoincrement)
                    {
                        UserIDColumns = new[] {"created_by"},
                        DateColumns = new Dictionary<string, bool> {{"created_when", false}, {"LastModified", false}}
                    },
                new TableInfo("blogs_reviewposts", "Tenant")
                    {
                        UserIDColumns = new[] {"reviewed_by"},
                        DateColumns = new Dictionary<string, bool> {{"timestamp", false}}
                    },
                new TableInfo("blogs_tags", "Tenant"),
                new TableInfo("events_comment", "Tenant", "id")
                    {
                        UserIDColumns = new[] {"Creator"},
                        DateColumns = new Dictionary<string, bool> {{"Date", false}}
                    },
                new TableInfo("events_feed", "Tenant", "id")
                    {
                        UserIDColumns = new[] {"Creator"},
                        DateColumns = new Dictionary<string, bool> {{"Date", false}, {"LastModified", false}}
                    },
                new TableInfo("events_poll", "Tenant")
                    {
                        DateColumns = new Dictionary<string, bool> {{"StartDate", true}, {"EndDate", true}}
                    },
                new TableInfo("events_pollanswer", "Tenant") {UserIDColumns = new[] {"User"}}, //todo: check //varchar(64)?
                new TableInfo("events_pollvariant", "Tenant", "Id"),
                new TableInfo("events_reader", "Tenant") {UserIDColumns = new[] {"Reader"}}, //todo: check
                new TableInfo("forum_answer", "TenantID", "id")
                    {
                        UserIDColumns = new[] {"user_id"},
                        DateColumns = new Dictionary<string, bool> {{"create_date", false}}
                    },
                new TableInfo("forum_answer_variant"),
                new TableInfo("forum_attachment", "TenantID", "id")
                    {
                        DateColumns = new Dictionary<string, bool> {{"create_date", false}}
                    },
                new TableInfo("forum_category", "TenantID", "id")
                    {
                        UserIDColumns = new[] {"poster_id"},
                        DateColumns = new Dictionary<string, bool> {{"create_date", false}}
                    },
                new TableInfo("forum_lastvisit", "tenantid")
                    {
                        UserIDColumns = new[] {"user_id"},
                        DateColumns = new Dictionary<string, bool> {{"last_visit", false}}
                    },
                new TableInfo("forum_post", "TenantID", "id")
                    {
                        UserIDColumns = new[] {"poster_id", "editor_id"},
                        DateColumns = new Dictionary<string, bool> {{"create_date", false}, {"edit_date", false}, {"LastModified", false}}
                    },
                new TableInfo("forum_question", "TenantID", "id") {DateColumns = new Dictionary<string, bool> {{"create_date", false}}},
                new TableInfo("forum_tag", "TenantID", "id"),
                new TableInfo("forum_thread", "TenantID", "id")
                    {
                        UserIDColumns = new[] {"recent_poster_id"},
                        DateColumns = new Dictionary<string, bool> {{"recent_post_date", false}}
                    },
                new TableInfo("forum_topic", "TenantID", "id")
                    {
                        UserIDColumns = new[] {"poster_id"},
                        DateColumns = new Dictionary<string, bool> {{"create_date", false}, {"LastModified", false}}
                    },
                new TableInfo("forum_topicwatch", "TenantID") {UserIDColumns = new[] {"UserID"}},
                new TableInfo("forum_topic_tag"),
                new TableInfo("forum_variant", idColumn: "id"),
                new TableInfo("wiki_categories", "Tenant"),
                new TableInfo("wiki_comments", "Tenant", "Id", IdType.Guid)
                    {
                        UserIDColumns = new[] {"UserId"},
                        DateColumns = new Dictionary<string, bool> {{"Date", false}}
                    },
                new TableInfo("wiki_files", "Tenant")
                    {
                        UserIDColumns = new[] {"UserID"},
                        DateColumns = new Dictionary<string, bool> {{"Date", false}}
                    },
                new TableInfo("wiki_pages", "tenant", "id", IdType.Autoincrement)
                    {
                        UserIDColumns = new[] {"modified_by"},
                        DateColumns = new Dictionary<string, bool> {{"modified_on", false}}
                    },
                new TableInfo("wiki_pages_history", "Tenant")
                    {
                        UserIDColumns = new[] {"create_by"},
                        DateColumns = new Dictionary<string, bool> {{"create_on", false}}
                    },
            };

        private readonly RelationInfo[] _tableRelations = new[]
            {
                new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_bookmarktag", "BookmarkID"),
                new RelationInfo("bookmarking_tag", "TagID", "bookmarking_bookmarktag", "TagID"),
                new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_comment", "BookmarkID"),
                new RelationInfo("bookmarking_comment", "ID", "bookmarking_comment", "Parent"),
                new RelationInfo("bookmarking_bookmark", "ID", "bookmarking_userbookmark", "BookmarkID"),
                new RelationInfo("bookmarking_tag", "TagID", "bookmarking_userbookmarktag", "TagID"),
                new RelationInfo("bookmarking_userbookmark", "UserBookmarkID", "bookmarking_userbookmarktag", "UserBookmarkID"),
                new RelationInfo("blogs_comments", "id", "blogs_comments", "parent_id"),
                new RelationInfo("blogs_posts", "id", "blogs_comments", "post_id"),
                new RelationInfo("blogs_comments", "id", "blogs_posts", "LastCommentId", null, null, RelationImportance.Low),
                new RelationInfo("blogs_posts", "id", "blogs_reviewposts", "post_id"),
                new RelationInfo("blogs_posts", "id", "blogs_tags", "post_id"),
                new RelationInfo("events_feed", "Id", "events_comment", "Feed"),
                new RelationInfo("events_comment", "Id", "events_comment", "Parent"),
                new RelationInfo("events_feed", "Id", "events_poll", "Id"),
                new RelationInfo("events_pollvariant", "Id", "events_pollanswer", "Variant"),
                new RelationInfo("events_feed", "Id", "events_pollvariant", "Poll"),
                new RelationInfo("events_feed", "Id", "events_reader", "Feed"),
                new RelationInfo("forum_question", "id", "forum_answer", "question_id"),
                new RelationInfo("forum_answer", "id", "forum_answer_variant", "answer_id"),
                new RelationInfo("forum_variant", "id", "forum_answer_variant", "variant_id"),
                new RelationInfo("forum_post", "id", "forum_attachment", "post_id"),
                new RelationInfo("forum_category", "id", "forum_attachment", "path"),
                new RelationInfo("forum_thread", "id", "forum_attachment", "path"),
                new RelationInfo("forum_thread", "id", "forum_lastvisit", "thread_id"),
                new RelationInfo("forum_topic", "id", "forum_post", "topic_id"),
                new RelationInfo("forum_post", "id", "forum_post", "parent_post_id"),
                new RelationInfo("forum_topic", "id", "forum_question", "topic_id"),
                new RelationInfo("forum_category", "id", "forum_thread", "category_id"),
                new RelationInfo("forum_post", "id", "forum_thread", "recent_post_id", null, null, RelationImportance.Low),
                new RelationInfo("forum_topic", "id", "forum_thread", "recent_topic_id", null, null, RelationImportance.Low),
                new RelationInfo("forum_thread", "id", "forum_topic", "thread_id"),
                new RelationInfo("forum_question", "id", "forum_topic", "question_id", null, null, RelationImportance.Low),
                new RelationInfo("forum_post", "id", "forum_topic", "recent_post_id", null, null, RelationImportance.Low),
                new RelationInfo("forum_topic", "id", "forum_topicwatch", "TopicID"),
                new RelationInfo("forum_topic", "id", "forum_topic_tag", "topic_id"),
                new RelationInfo("forum_tag", "id", "forum_topic_tag", "tag_id"),
                new RelationInfo("forum_question", "id", "forum_variant", "question_id"),
                new RelationInfo("wiki_comments", "Id", "wiki_comments", "ParentId")
            };

        public override ModuleName ModuleName
        {
            get { return ModuleName.Community; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return _tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return _tableRelations; }
        }

        public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
        {
            filePath = PreparePath(dump, columnMapper, "/", filePath);
            return filePath != null;
        }

        protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
        {
            relations = relations.ToList();

            if (relations.All(x => x.ChildTable == "forum_attachment" && x.ChildColumn == "path"))
            {
                value = PreparePath(dump, columnMapper, "\\", Convert.ToString(value));
                return value != null;
            }

            return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relations, ref value);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
        {
            var column = columnName.ToLowerInvariant();
            if (table.Name == "forum_post" && column == "text" ||
                table.Name == "events_feed" && column == "text" ||
                table.Name == "events_comment" && column == "comment" ||
                table.Name == "blogs_posts" && column == "content" ||
                table.Name == "blogs_comments" && column == "content" ||
                table.Name == "bookmarking_comment" && column == "content" ||
                table.Name == "wiki_comments" && column == "body")
            {
                value = FCKEditorPathUtility.CorrectStoragePath(value as string, columnMapper.GetTenantMapping());
                return true;
            }
            return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
        }

        protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
        {
            if (table.Name == "forum_answer_variant")
                return "inner join forum_answer as t1 on t1.id = t.answer_id where t1.TenantID = " + tenantId;

            if (table.Name == "forum_variant")
                return "inner join forum_question as t1 on t1.id = t.question_id where t1.TenantID = " + tenantId;

            if (table.Name == "forum_topic_tag")
                return "inner join forum_topic as t1 on t1.id = t.topic_id where t1.TenantID = " + tenantId;

            return base.GetSelectCommandConditionText(tenantId, table);
        }


        private static string PreparePath(bool dump, ColumnMapper columnMapper, string partsSeparator, string path)
        {
            string[] parts = path.Split(new[] { partsSeparator }, StringSplitOptions.None);

            if (parts.Length != 4)
                return null;

            var categoryId = columnMapper.GetMapping("forum_category", "id", parts[0]);
            if (categoryId == null)
            {
                if (!dump) return null;
                categoryId = parts[0];
            }

            var threadId = columnMapper.GetMapping("forum_thread", "id", parts[1]);
            if (threadId == null)
            {
                if (!dump) return null;
                threadId = parts[1];
            }

            parts[0] = categoryId.ToString();
            parts[1] = threadId.ToString();

            return string.Join(partsSeparator, parts);
        }
    }
}


<|start_filename|>module/ASC.Feed.Aggregator/Modules/Projects/DiscussionsModule.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Domain.Entities.Feed;
using ASC.Projects.Engine;
using ASC.Web.Projects.Core;
using ASC.Web.Studio.Utility;
using ASC.Web.Studio.Utility.HtmlUtility;

using Autofac;

namespace ASC.Feed.Aggregator.Modules.Projects
{
    internal class DiscussionsModule : FeedModule
    {
        private const string item = "discussion";


        protected override string Table
        {
            get { return "projects_messages"; }
        }

        protected override string LastUpdatedColumn
        {
            get { return "create_on"; }
        }

        protected override string TenantColumn
        {
            get { return "tenant_id"; }
        }

        protected override string DbId
        {
            get { return Constants.ProjectsDbId; }
        }


        public override string Name
        {
            get { return Constants.DiscussionsModule; }
        }

        public override string Product
        {
            get { return ModulesHelper.ProjectsProductName; }
        }

        public override Guid ProductID
        {
            get { return ModulesHelper.ProjectsProductID; }
        }

        public override IEnumerable<int> GetTenantsWithFeeds(DateTime fromTime)
        {
            var q1 = new SqlQuery("projects_messages")
                .Select("tenant_id")
                .Where(Exp.Gt("create_on", fromTime))
                .GroupBy(1)
                .Having(Exp.Gt("count(*)", 0));

            var q2 = new SqlQuery("projects_comments")
                .Select("tenant_id")
                .Where("substring_index(target_uniq_id, '_', 1) = 'Message'")
                .Where(Exp.Gt("create_on", fromTime))
                .GroupBy(1)
                .Having(Exp.Gt("count(*)", 0));

            using (var db = new DbManager(DbId))
            {
                return db.ExecuteList(q1)
                         .ConvertAll(r => Convert.ToInt32(r[0]))
                         .Union(db.ExecuteList(q2).ConvertAll(r => Convert.ToInt32(r[0])));
            }
        }

        public override bool VisibleFor(Feed feed, object data, Guid userId)
        {
            using (var scope = DIHelper.Resolve())
            {
                return base.VisibleFor(feed, data, userId) && scope.Resolve<ProjectSecurity>().CanGoToFeed((Message)data, userId);
            }
        }

        public override IEnumerable<Tuple<Feed, object>> GetFeeds(FeedFilter filter)
        {
            var q1 = new SqlQuery("projects_messages d")
                    .Select(DiscussionColumns().Select(d => "d." + d).ToArray())
                    .Select(ProjectColumns().Select(p => "p." + p).ToArray())
                    .Select(CommentColumns().Select(c => "c." + c).ToArray())
                    .InnerJoin("projects_projects p", Exp.EqColumns("p.id", "d.project_id") & Exp.Eq("p.tenant_id", filter.Tenant))
                    .LeftOuterJoin("projects_comments c",
                        Exp.EqColumns("c.target_uniq_id", "concat('Message_', d.id)") &
                        Exp.Eq("c.tenant_id", filter.Tenant) & Exp.Eq("c.inactive", 0))
                    .Where("d.tenant_id", filter.Tenant)
                    .Where(Exp.Between("d.create_on", filter.Time.From, filter.Time.To));

            var q2 = new SqlQuery("projects_messages d")
                    .Select(DiscussionColumns().Select(d => "d." + d).ToArray())
                    .Select(ProjectColumns().Select(p => "p." + p).ToArray())
                    .Select(CommentColumns().Select(c => "c." + c).ToArray())
                    .InnerJoin("projects_projects p", Exp.EqColumns("p.id", "d.project_id") & Exp.Eq("p.tenant_id", filter.Tenant))
                    .LeftOuterJoin("projects_comments c",
                        Exp.EqColumns("c.target_uniq_id", "concat('Message_', d.id)") &
                        Exp.Eq("c.tenant_id", filter.Tenant) & Exp.Eq("c.inactive", 0))
                    .Where("d.tenant_id", filter.Tenant)
                    .Where(Exp.Between("c.create_on", filter.Time.From, filter.Time.To));

            using (var db = new DbManager(DbId))
            {
                var comments = db.ExecuteList(q1.Union(q2)).ConvertAll(ToComment);
                var groupedDiscussions = comments.GroupBy(c => c.Discussion.ID);

                return groupedDiscussions
                    .Select(d => new Tuple<Message, IEnumerable<ProjectComment>>(d.First().Discussion, d))
                    .Select(ToFeed);
            }
        }


        private static IEnumerable<string> DiscussionColumns()
        {
            return new[]
                {
                    "id",
                    "title",
                    "content",
                    "create_by",
                    "create_on",
                    "last_modified_by",
                    "last_modified_on" // 6
                };
        }

        private static IEnumerable<string> ProjectColumns()
        {
            return new[]
                {
                    "id", //7
                    "title",
                    "description",
                    "status",
                    "status_changed",
                    "responsible_id",
                    "private",
                    "create_by",
                    "create_on",
                    "last_modified_by",
                    "last_modified_on" // 17
                };
        }

        private static IEnumerable<string> CommentColumns()
        {
            return new[]
                {
                    "id", // 18
                    "content",
                    "create_by",
                    "create_on",
                    "parent_id",
                    "target_uniq_id" // 23
                };
        }

        private static ProjectComment ToComment(object[] r)
        {
            var p = new ProjectComment
            {
                Discussion = new Message
                {
                    ID = Convert.ToInt32(r[0]),
                    Title = Convert.ToString(r[1]),
                    Description = Convert.ToString(r[2]),
                    CreateBy = new Guid(Convert.ToString(r[3])),
                    CreateOn = Convert.ToDateTime(r[4]),
                    LastModifiedBy = ToGuid(r[5]),
                    LastModifiedOn = Convert.ToDateTime(r[6]),
                    Project = new Project
                    {
                        ID = Convert.ToInt32(r[7]),
                        Title = Convert.ToString(r[8]),
                        Description = Convert.ToString(r[9]),
                        Status = (ProjectStatus)Convert.ToInt32(10),
                        StatusChangedOn = Convert.ToDateTime(r[11]),
                        Responsible = new Guid(Convert.ToString(r[12])),
                        Private = Convert.ToBoolean(r[13]),
                        CreateBy = new Guid(Convert.ToString(r[14])),
                        CreateOn = Convert.ToDateTime(r[15]),
                        LastModifiedBy = ToGuid(r[16]),
                        LastModifiedOn = Convert.ToDateTime(r[17]),
                    }
                }
            };
            if (r[18] != null)
            {
                p.Comment = new Comment
                {
                    OldGuidId = new Guid(Convert.ToString(r[18])),
                    Content = Convert.ToString(r[19]),
                    CreateBy = new Guid(Convert.ToString(r[20])),
                    CreateOn = Convert.ToDateTime(r[21]),
                    Parent = new Guid(Convert.ToString(r[22])),
                    TargetUniqID = Convert.ToString(r[23])
                };
            }
            return p;
        }

        private Tuple<Feed, object> ToFeed(Tuple<Message, IEnumerable<ProjectComment>> d)
        {
            var discussion = d.Item1;

            var itemUrl = "/Products/Projects/Messages.aspx?prjID=" + discussion.Project.ID + "&id=" + discussion.ID;
            var projectUrl = "/Products/Projects/Tasks.aspx?prjID=" + discussion.Project.ID;
            var commentApiUrl = "/api/2.0/project/message/" + discussion.ID + "/comment.json";

            var comments = d.Item2.Where(c => c.Comment != null).OrderBy(c => c.Comment.CreateOn).ToList();
            var feedDate = comments.Any() ? comments.First().Comment.CreateOn : discussion.CreateOn;
            var feedAuthor = comments.Any() ? comments.Last().Comment.CreateBy : discussion.CreateBy;

            var feed = new Feed(discussion.CreateBy, discussion.CreateOn, true)
            {
                Item = item,
                ItemId = discussion.ID.ToString(CultureInfo.InvariantCulture),
                ItemUrl = CommonLinkUtility.ToAbsolute(itemUrl),
                ModifiedBy = feedAuthor,
                ModifiedDate = feedDate,
                Product = Product,
                Module = Name,
                Action = comments.Any() ? FeedAction.Commented : FeedAction.Created,
                Title = discussion.Title,
                Description = HtmlUtility.GetFull(discussion.Description),
                ExtraLocation = discussion.Project.Title,
                ExtraLocationUrl = CommonLinkUtility.ToAbsolute(projectUrl),
                HasPreview = discussion.Description.Contains("class=\"asccut\""),
                CanComment = true,
                CommentApiUrl = CommonLinkUtility.ToAbsolute(commentApiUrl),
                Comments = comments.Select(ToFeedComment),
                GroupId = string.Format("{0}_{1}", item, discussion.ID)
            };
            feed.Keywords = string.Format("{0} {1} {2}",
                                          discussion.Title,
                                          Helper.GetText(discussion.Description),
                                          string.Join(" ", feed.Comments.Select(x => x.Description)));

            return new Tuple<Feed, object>(feed, discussion);
        }

        private static FeedComment ToFeedComment(ProjectComment comment)
        {
            return new FeedComment(comment.Comment.CreateBy)
            {
                Id = comment.Comment.OldGuidId.ToString(),
                Description = HtmlUtility.GetFull(comment.Comment.Content),
                Date = comment.Comment.CreateOn
            };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/ServersCore/ValidateIP_EventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net
{
    #region usings

    using System.Net;

    #endregion

    /// <summary>
    /// Provides data for the ValidateIPAddress event for servers.
    /// </summary>
    public class ValidateIP_EventArgs
    {
        #region Members

        private readonly IPEndPoint m_pLocalEndPoint;
        private readonly IPEndPoint m_pRemoteEndPoint;
        private string m_ErrorText = "";
        private bool m_Validated = true;

        #endregion

        #region Properties

        /// <summary>
        /// IP address of computer, which is sending mail to here.
        /// </summary>
        public string ConnectedIP
        {
            get { return m_pRemoteEndPoint.Address.ToString(); }
        }

        /// <summary>
        /// Gets local endpoint.
        /// </summary>
        public IPEndPoint LocalEndPoint
        {
            get { return m_pLocalEndPoint; }
        }

        /// <summary>
        /// Gets remote endpoint.
        /// </summary>
        public IPEndPoint RemoteEndPoint
        {
            get { return m_pRemoteEndPoint; }
        }

        /// <summary>
        /// Gets or sets if IP is allowed access.
        /// </summary>
        public bool Validated
        {
            get { return m_Validated; }

            set { m_Validated = value; }
        }

        /// <summary>
        /// Gets or sets user data what is stored to session.Tag property.
        /// </summary>
        public object SessionTag { get; set; }

        /// <summary>
        /// Gets or sets error text what is sent to connected socket. NOTE: This is only used if Validated = false.
        /// </summary>
        public string ErrorText
        {
            get { return m_ErrorText; }

            set { m_ErrorText = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="localEndPoint">Server IP.</param>
        /// <param name="remoteEndPoint">Connected client IP.</param>
        public ValidateIP_EventArgs(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint)
        {
            m_pLocalEndPoint = localEndPoint;
            m_pRemoteEndPoint = remoteEndPoint;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/_Obsolete/Write_EventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IO
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class provides data for BeginWriteCallback delegate.
    /// </summary>
    public class Write_EventArgs
    {
        #region Members

        private readonly Exception m_pException;

        #endregion

        #region Properties

        /// <summary>
        /// Gets exception happened during write or null if operation was successfull.
        /// </summary>
        public Exception Exception
        {
            get { return m_pException; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="exception">Exception happened during write or null if operation was successfull.</param>
        internal Write_EventArgs(Exception exception)
        {
            m_pException = exception;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Socket.IO/app/hubs/files.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = (io) => {
    const log = require("../log.js");
    const files = io.of("/files");

    files.on("connection", (socket) => {
        const request = socket.client.request;
        if (!request.user || !request.user.id) {
            return;
        }

        const tenantId = request.portal.tenantId;

        socket
            .on("subscribeChangeEditors", (fileIds) => {
                if (typeof fileIds != "object") {
                    fileIds = [fileIds];
                }

                fileIds.forEach(function(fileId) {
                    let room = `${tenantId}-${fileId}`;

                    socket.join(room);
                });
            });
    });

    function changeEditors({ tenantId, fileId, finish } = {}) {
        if (typeof tenantId === "undefined" || typeof fileId === "undefined") {
            log.error(`files: changeEditors without arguments`);
            return;
        }

        let room = `${tenantId}-${fileId}`;

        files.to(room).emit("changeEditors", fileId);

        if (finish) {
            files.in(room).clients((error, clients) => {
                if (error) throw error;
                clients.forEach(function(client) {
                    let clientSocket = files.connected[client];
                    if(clientSocket){
                        clientSocket.leave(room);
                    }
                });
            });
         }
    }

    return { changeEditors };
};

<|start_filename|>module/ASC.Api/ASC.Api.Settings/StorageWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Core.Common.Configuration;
using ASC.Core.Common.Settings;
using ASC.Data.Storage.Configuration;
using ASC.Web.Studio.UserControls.Management;

namespace ASC.Api.Settings
{
    public class StorageWrapper
    {
        public string Id { get; set; }

        public string Title { get; set; }

        public List<AuthKey> Properties { get; set; }

        public bool Current { get; set; }

        public bool IsSet { get; set; }

        public StorageWrapper(DataStoreConsumer consumer, StorageSettings current)
        {
            StorageWrapperInit(consumer, current);
        }

        public StorageWrapper(DataStoreConsumer consumer, CdnStorageSettings current)
        {
            StorageWrapperInit(consumer, current);
        }

        private void StorageWrapperInit<T>(DataStoreConsumer consumer, BaseStorageSettings<T> current) where T : class, ISettings, new()
        {
            Id = consumer.Name;
            Title = consumer.GetResourceString(consumer.Name) ?? consumer.Name;
            Current = consumer.Name == current.Module;
            IsSet = consumer.IsSet;

            var props = Current
                ? current.Props
                : current.Switch(consumer).AdditionalKeys.ToDictionary(r => r, a => consumer[a]);

            Properties = props.Select(
                r => new AuthKey
                {
                    Name = r.Key,
                    Value = r.Value,
                    Title = consumer.GetResourceString(consumer.Name + r.Key) ?? r.Key,
                    Description = consumer.GetResourceString(consumer.Name + r.Key + "Description"),
                }).ToList();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/AccessRights/js/accessrights.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined")
    ASC = {};

if (typeof ASC.Settings === "undefined")
    ASC.Settings = {};

ASC.Settings.AccessRights = new function() {

    var pNameList = [];

    var getSelectedUsers = function (pName) {
        return window["SelectedUsers_" + pName];
    };

    var getSelectedGroups = function (pName) {
        return window["SelectedGroups_" + pName];
    };

    var setSelectedUsers = function (pName, value) {
        window["SelectedUsers_" + pName] = value;
        return getSelectedUsers(pName);
    };

    var setSelectedGroups = function (pName, value) {
        window["SelectedGroups_" + pName] = value;
        return getSelectedGroups(pName);
    };

    return {
        init: function (products) {
            pNameList = products;

            jq("#changeOwnerBtn").click(ASC.Settings.AccessRights.changeOwner);
            jq("#adminTable tbody tr").remove();
            jq("#adminTmpl").tmpl(window.adminList, { isRetina: jq.cookies.get("is_retina") }).prependTo("#adminTable tbody");

            if (window.adminList.length) {
                jq("#adminTable").removeClass("display-none");
            }

            var items = jq("[id^=switcherAccessRights]"), 
                pName;

            for (var i = 0; i < items.length; i++) {
                pName = jq(items[i]).attr("data-id");
                jq.switcherAction("#switcherAccessRights_" + pName, "#accessRightsContainer_" + pName);
            }

            jq("#ownerSelector").on("click", initOwnerSelector);
            jq("#adminAdvancedSelector").on("click", initAdminSelector);

            function initOwnerSelector() {
                var os = jq(this);
                os.off("click", initOwnerSelector);
                os.useradvancedSelector({
                    itemsChoose: [],
                    itemsDisabledIds: [window.ownerId],
                    canadd: false,       // enable to create the new item
                    showGroups: true, // show the group list
                    onechosen: true,
                    withGuests: false
                });
                os.on("showList", function (event, item) {
                    os.html(item.title).attr("data-id", item.id);
                    jq("#changeOwnerBtn").removeClass("disable");
                });
                os.click();
            }

            function initAdminSelector() {
                var as = jq(this);
                var adminIds = [window.ownerId];
                window.adminList.forEach(function (admin) {
                    if (admin.id) adminIds.push(admin.id);
                });
                as.off("click", initAdminSelector);
                as.useradvancedSelector({
                    itemsDisabledIds: adminIds,
                    canadd: true,       // enable to create the new item
                    isAdmin: false, // show Admin only
                    showGroups: true,
                    withGuests: false
                });
                as.on("showList", function (event, admins) {
                    admins.forEach(function (admin) {
                        ASC.Settings.AccessRights.addAdmin(admin.id);
                    });
                });
                as.click();
            }
        },

        changeOwner: function() {
            var ownerId = jq("#ownerSelector").attr("data-id");
            var self = jq(this);
            if (ownerId == null || self.hasClass("disable")) return false;

            window.AjaxPro.onLoading = function(b) {
                if (b)
                    LoadingBanner.displayLoading();
                else
                    LoadingBanner.hideLoading();
            };

            window.AccessRightsController.ChangeOwner(ownerId, function(result) {
                var res = result.value;
                if (res.Status == 1) {
                    toastr.success(res.Message);
                    self.addClass("disable");
                }
                else {
                    toastr.error(res.Message);
                }
            });
            return false;
        },

        addAdmin: function(uId) {
            window.AccessRightsController.AddAdmin(uId, function(res) {
                if (res.error != null) {
                    toastr.error(res.error.Message);
                    return;
                }
                if (!res.value.enable) {

                    jq("#adminAdvancedSelector").addClass("disabled");
                    jq("#ErrorNotAllowed").removeClass("display-none");
                }
                window.adminList.push(res.value);
                jq("#adminTmpl").tmpl(res.value, { isRetina: jq.cookies.get("is_retina") }).appendTo("#adminTable tbody");
                jq("#adminTable").removeClass("display-none");

                jq("#adminAdvancedSelector").useradvancedSelector("disable", [uId]);
                ASC.Settings.AccessRights.hideUserFromAll(uId, true);
            });
        },

        changeAccessType: function(obj, pName) {

            var subjects = ASC.Settings.AccessRights.getSubjects(pName);

            var type = jq(obj).attr("id").split("_")[0];
            var id = jq(obj).attr("id").split("_")[1];
            var params = {};
            var data = {
                id: id,
                enabled: true
            };

            if (type == "all") {
                Teamlab.setWebItemSecurity(params, data, {
                    success: function() {
                        jq("#selectorContent_" + pName).hide();
                    }
                });
            } else {
                if (subjects.length == 0)
                    data.enabled = false;
                if (subjects.length > 0)
                    data.subjects = subjects;
                Teamlab.setWebItemSecurity(params, data, {
                    success: function() {
                        jq("#selectorContent_" + pName).show();
                    }
                });
            }
        },

        selectedItem_mouseOver: function() {
            var $obj = jq(this);
            $obj.find("img:first").hide();
            $obj.find("img:last").show();
        },

        selectedItem_mouseOut: function() {
            var $obj = jq(this);
            $obj.find("img:first").show();
            $obj.find("img:last").hide();
        },
        
        initProduct: function (productItem) {
            var pItem = jq.parseJSON(jq.base64.decode(productItem)),
                pId = pItem.ID,
                pName = pItem.ItemName,
                pIsPuplic = pItem.SelectedUsers.length == 0 && pItem.SelectedGroups.length == 0,
                su = setSelectedUsers(pName, {}),
                sg = setSelectedGroups(pName, {});

            var len = pItem.SelectedUsers.length;
            while (len--) {
                su[pItem.SelectedUsers[len].ID] = pItem.SelectedUsers[len].Name;
            }

            len = pItem.SelectedGroups.length;
            while (len--) {
                sg[pItem.SelectedGroups[len].ID] = pItem.SelectedGroups[len].Name;
            }

            jq.tmpl("template-productItem", pItem).appendTo("#studioPageContent .mainPageContent:first");

            var $container = jq("#accessRightsContainer_" + pName),
                $allRadio = $container.find("#all_" + pId),
                $fromListRadio = $container.find("#fromList_" + pId),
                $content = $container.find("#selectorContent_" + pName),
                $emptyLabel = $content.find("#emptyUserListLabel_" + pName),
                $selectedUsers = $content.find("#selectedUsers_" + pName),
                $selectedGroups = $content.find("#selectedGroups_" + pName),
                $userSelector = $content.find("#userSelector_" + pName),
                $groupSelector = $content.find("#groupSelector_" + pName);

            if (pIsPuplic) {
                $allRadio.prop("checked", true);
                $emptyLabel.show();
                $content.hide();
            } else {
                $fromListRadio.prop("checked", true);
                $emptyLabel.hide();
                $content.show();
            }

            $content.on("mouseover", ".accessRights-selectedItem", ASC.Settings.AccessRights.selectedItem_mouseOver);
            $content.on("mouseout", ".accessRights-selectedItem", ASC.Settings.AccessRights.selectedItem_mouseOut);
            $selectedUsers.on("click", "img[id^=deleteSelectedUserImg_]", ASC.Settings.AccessRights.deleteUserFromList);
            $selectedGroups.on("click", "img[id^=deleteSelectedGroupImg_]", ASC.Settings.AccessRights.deleteGroupFromList);
            $userSelector.on("click", initUserSelector);
            $groupSelector.on("click", initGroupSelector);

            function initUserSelector() {
                var us = jq(this);
                us.off("click", initUserSelector);
                us.useradvancedSelector({
                    showGroups: true,
                    withGuests: (pName !== "crm" && pName !== "people")
                }).on("showList", ASC.Settings.AccessRights.pushUserIntoList);
                us.useradvancedSelector("disable", Object.keys(su));
                us.click();
            }

            function initGroupSelector() {
                var gs = jq(this);
                gs.off("click", initGroupSelector);
                gs.groupadvancedSelector().on("showList", ASC.Settings.AccessRights.pushGroupIntoList);
                gs.groupadvancedSelector("disable", Object.keys(sg));
                gs.click();
            }
        },

        pushUserIntoList: function (event, users) {
            var pName = jq(this).attr("id").split('_')[1],
                pId = jq("#accessRightsContainer_" + pName).attr("data-id");

            var us = jq("#userSelector_" + pName);
            var su = getSelectedUsers(pName);

            users.forEach(function (el) {
                su[el.id] = el.title;

                var item = jq("<div></div>")
                    .attr("id", "selectedUser_" + pName + "_" + el.id)
                    .addClass("accessRights-selectedItem");

                var peopleImg = jq("<img>")
                    .attr("src", window.imageHelper.PeopleImgSrc);

                var deleteImg = jq("<img>")
                    .attr("src", window.imageHelper.TrashImgSrc)
                    .css("display", "none")
                    .attr("id", "deleteSelectedUserImg_" + pName + "_" + el.id)
                    .attr("title", window.imageHelper.TrashImgTitle);

                item.append(peopleImg).append(deleteImg).append(Encoder.htmlEncode(el.title));

                jq("#selectedUsers_" + pName).append(item);
            });

            jq("#emptyUserListLabel_" + pName).hide();
            jq("#selectedUsers_" + pName).parent().find("div.adv-userselector-DepsAndUsersContainer").hide();

            var data = {
                id: pId,
                enabled: true
            };

            var subjects = ASC.Settings.AccessRights.getSubjects(pName);

            if (subjects.length > 0)
                data.subjects = subjects;

            Teamlab.setWebItemSecurity({}, data, {
                success: function () {
                    us.useradvancedSelector("disable", Object.keys(su));
                }
            });
        },

        pushGroupIntoList: function (event, groups) {
            var pName = jq(this).attr("id").split('_')[1],
                pId = jq("#accessRightsContainer_" + pName).attr("data-id");

            var gs = jq("#groupSelector_" + pName);
            var sg = getSelectedGroups(pName);

            groups.forEach(function (group) {
                sg[group.id] = group.title;

                var item = jq("<div></div>")
                    .attr("id", "selectedGroup_" + pName + "_" + group.id)
                    .addClass("accessRights-selectedItem");

                var groupImg = jq("<img>")
                    .attr("src", window.imageHelper.GroupImgSrc);

                var deleteImg = jq("<img>")
                    .attr("src", window.imageHelper.TrashImgSrc)
                    .css("display", "none")
                    .attr("id", "deleteSelectedGroupImg_" + pName + "_" + group.id)
                    .attr("title", window.imageHelper.TrashImgTitle);

                item.append(groupImg).append(deleteImg).append(Encoder.htmlEncode(group.title));

                jq("#selectedGroups_" + pName).append(item);
            });

            jq("#emptyUserListLabel_" + pName).hide();
            jq("#selectedUsers_" + pName).parent().find("div[id^=groupSelectorContainer_]").hide();

            var data = {
                id: pId,
                enabled: true
            };

            var subjects = ASC.Settings.AccessRights.getSubjects(pName);

            if (subjects.length > 0)
                data.subjects = subjects;

            Teamlab.setWebItemSecurity({}, data, {
                success: function () {
                    gs.groupadvancedSelector("disable", Object.keys(sg));
                }
            });
        },

        deleteUserFromList: function () {
            var $obj = jq(this);
            var idComponent = $obj.attr("id").split("_");
            var pName = idComponent[1];
            var uId = idComponent[2];
            var pId = jq("#accessRightsContainer_" + pName).attr("data-id");
            
            $obj.parent().remove();

            var sg = getSelectedGroups(pName);
            var su = getSelectedUsers(pName);

            var us = jq("#userSelector_" + pName);

            delete su[uId];

            if (!Object.keys(su).length && !Object.keys(sg).length)
                jq("#emptyUserListLabel_" + pName).show();

            var data = {
                id: pId,
                enabled: true
            };

            var subjects = ASC.Settings.AccessRights.getSubjects(pName);

            if (subjects.length > 0) {
                data.subjects = subjects;
            } else {
                data.enabled = false;
            }

            Teamlab.setWebItemSecurity({}, data, {
                success: function () {
                    if (us.data("useradvancedSelector"))
                        us.useradvancedSelector("undisable", [uId]);
                }
            });

        },

        deleteGroupFromList: function () {
            var $obj = jq(this);
            var idComponent = $obj.attr("id").split("_");
            var pName = idComponent[1];
            var gId = idComponent[2];
            var pId = jq("#accessRightsContainer_" + pName).attr("data-id");

            $obj.parent().remove();

            var sg = getSelectedGroups(pName);
            var su = getSelectedUsers(pName);

            var gs = jq("#groupSelector_" + pName);

            delete sg[gId];

            if (!Object.keys(su).length && !Object.keys(sg).length)
                jq("#emptyUserListLabel_" + pName).show();

            var data = {
                id: pId,
                enabled: true
            };

            var subjects = ASC.Settings.AccessRights.getSubjects(pName);

            if (subjects.length > 0) {
                data.subjects = subjects;
            } else {
                data.enabled = false;
            }

            Teamlab.setWebItemSecurity({}, data, {
                success: function () {
                    if (gs.data("groupadvancedSelector"))
                        gs.groupadvancedSelector("undisable", [gId]);
                }
            });
        },
        
        getSubjects: function(pName) {
            var su = getSelectedUsers(pName);
            var sg = getSelectedGroups(pName);
            return Object.keys(su).concat(Object.keys(sg));
        },
        
        setAdmin: function (obj, pId) {
            var idComponent = jq(obj).attr("id").split("_"),
                pName = idComponent[1],
                uId = idComponent[2],
                isChecked = jq(obj).is(":checked"),
                data = {
                   productid: pId,
                   userid: uId,
                   administrator: isChecked
                };

            if (pName == "full") {
                ASC.Settings.AccessRights.setFullAdmin(obj, data);
            } else {
                ASC.Settings.AccessRights.setProductAdmin(pName, data);
            }
        },
        
        setProductAdmin: function (pName, data) {
            Teamlab.setProductAdministrator({}, data, {
                success: function () {
                    var us = jq("#userSelector_" + pName);
                    if (us.data("useradvancedSelector"))
                        us.useradvancedSelector("disable", [data.userid]);
                }
            });
        },

        setFullAdmin: function (obj, data) {
            Teamlab.setProductAdministrator({}, data, {
                success: function() {
                    if (data.administrator) {
                        jq("#adminItem_" + data.userid + " input[type=checkbox]").prop("checked", true).attr("disabled", true);
                        jq(obj).removeAttr("disabled");
                    } else {
                        jq("#adminItem_" + data.userid + " input[type=checkbox]").prop("checked", false).attr("disabled", false);
                    }
                    ASC.Settings.AccessRights.hideUserFromAll(data.userid, data.administrator);
                }
            });
        },
        
        hideUserFromAll: function (uId) {
            for (var i = 0; i < pNameList.length; i++){
                var us = jq("#userSelector_" + pNameList[i]);
                if (us.data("useradvancedSelector"))
                    us.useradvancedSelector("disable", [uId]);
            }
        }
    };
    
};


<|start_filename|>web/studio/ASC.Web.Studio/Core/Import/TextFileUserImporter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace ASC.Web.Studio.Core.Import
{

    public class MultiFormatTextFileUserImporter : TextFileUserImporter
    {
        public MultiFormatTextFileUserImporter(Stream stream)
            : base(stream)
        {
        }

        public MultiFormatTextFileUserImporter(string csvText)
            : base(csvText)
        {
        }

        protected override ContactInfo GetExportedUser(string line, IDictionary<int, PropertyInfo> mappedProperties, int fieldsCount)
        {
            try
            {
                var address = new MailAddress(line);
                var info = new ContactInfo { Email = address.Address };

                if (!string.IsNullOrEmpty(address.DisplayName))
                {
                    if (address.DisplayName.Contains(' '))
                    {
                        //Try split
                        info.FirstName = address.DisplayName.Split(' ')[0];
                        info.LastName = address.DisplayName.Split(' ')[1];
                    }
                    else
                    {
                        info.FirstName = address.DisplayName;
                    }
                }
                return info;

            }
            catch (Exception)
            {
                //thats bad. Failed to parse an address
            }
            return base.GetExportedUser(line, mappedProperties, fieldsCount);
        }
    }

    public class TextFileUserImporter : IUserImporter
    {
        private readonly Stream stream;
        private readonly string text;
        private readonly Encoding encoding;

        protected Dictionary<string, string> NameMapping { get; set; }
        protected IList<string> ExcludeList { get; private set; }

        public char[] Separators { get; set; }

        public bool HasHeader { get; set; }

        public string TextDelmiter { get; set; }

        public string DefaultHeader { get; set; }


        public TextFileUserImporter(Stream stream)
        {
            this.stream = stream;
            try
            {
                encoding = Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.ANSICodePage);
            }
            catch
            {
                encoding = Encoding.UTF8;
            }
            HasHeader = false;
            Separators = new[] { ';', ',' };
            TextDelmiter = "\"";
            ExcludeList = new List<string> { "ID", "Status" };
        }

        public TextFileUserImporter(string csvText)
        {
            this.encoding = Encoding.UTF8;
            text = csvText;
            HasHeader = false;
            Separators = new[] { ';', ',' };
            TextDelmiter = "\"";
            ExcludeList = new List<string> { "ID", "Status" };
        }

        public IEnumerable<ContactInfo> GetDiscoveredUsers()
        {
            var users = new List<ContactInfo>();

            var fileLines = new List<string>();
            if (stream != null)
            {
                using (var reader = new StreamReader(stream, encoding, true))
                {
                    fileLines.AddRange(reader.ReadToEnd().Split(new[] { Environment.NewLine, "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
                }
            }
            else
            {
                fileLines.AddRange(text.Split(new[] { Environment.NewLine, "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries));
            }

            if (!string.IsNullOrEmpty(DefaultHeader))
            {
                fileLines.Insert(0, DefaultHeader);
            }

            if (0 < fileLines.Count)
            {
                var mappedProperties = new Dictionary<int, PropertyInfo>();
                var infos = typeof(ContactInfo).GetProperties(BindingFlags.Public | BindingFlags.Instance);
                var fieldsCount = GetFieldsMapping(fileLines[0], infos, mappedProperties);

                for (int i = 1; i < fileLines.Count; i++)
                {
                    users.Add(GetExportedUser(fileLines[i], mappedProperties, fieldsCount));
                }
            }
            return users;
        }

        protected virtual ContactInfo GetExportedUser(string line, IDictionary<int, PropertyInfo> mappedProperties, int fieldsCount)
        {
            var exportedUser = new ContactInfo();
            var dataFields = GetDataFields(line);
            for (int j = 0; j < Math.Min(fieldsCount, dataFields.Length); j++)
            {
                var propinfo = mappedProperties[j];
                if (propinfo != null)
                {
                    var value = ConvertFromString(dataFields[j], propinfo.PropertyType);
                    if (value != null)
                    {
                        value = Regex.Replace(value.ToString(), "(^')|(^\")|(\"$)|('$)", String.Empty);

                        propinfo.SetValue(exportedUser, value, null);
                    }
                }
            }

            try
            {
                if (string.IsNullOrEmpty(exportedUser.FirstName) && string.IsNullOrEmpty(exportedUser.LastName) && !string.IsNullOrEmpty(exportedUser.Email))
                {
                    var username = exportedUser.Email.Contains('@') ? exportedUser.Email.Substring(0, exportedUser.Email.IndexOf('@')) : exportedUser.Email;
                    if (username.Contains('.'))
                    {
                        exportedUser.FirstName = username.Split('.')[0];
                        exportedUser.LastName = username.Split('.')[1];
                    }
                }
            }
            catch { }

            return exportedUser;
        }

        private string[] GetDataFields(string line)
        {
            var pattern = String.Format("[{0}](?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))", string.Join("|", Array.ConvertAll(Separators, c => c.ToString())));
            var result = Regex.Split(line, pattern);

            return Array.ConvertAll<string, string>(result,
                original =>
                {
                    return original.StartsWith(TextDelmiter) && original.EndsWith(TextDelmiter) ?
                        original.Substring(1, original.Length - 2) :
                        original;
                }
             );
        }

        private int GetFieldsMapping(string firstLine, IEnumerable<PropertyInfo> infos, IDictionary<int, PropertyInfo> mappedProperties)
        {
            var fields = firstLine.Split(Separators, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < fields.Length; i++)
            {
                var field = fields[i];
                //Find apropriate field in UserInfo
                foreach (var info in infos)
                {
                    var propertyField = field.Trim();
                    propertyField = propertyField.Trim('"');
                    if (NameMapping != null && NameMapping.ContainsKey(propertyField))
                    {
                        propertyField = NameMapping[propertyField];
                    }
                    if (!string.IsNullOrEmpty(propertyField) && !ExcludeList.Contains(propertyField) && propertyField.Equals(info.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        //Add to map
                        mappedProperties.Add(i, info);
                    }
                }
                if (!mappedProperties.ContainsKey(i))
                {
                    //No property was found
                    mappedProperties.Add(i, null);
                }
            }

            if (!mappedProperties.Values.Any(p => p != null))
            {
                mappedProperties[2] = infos.First(p => p.Name == "Email");
                mappedProperties[0] = infos.First(p => p.Name == "FirstName");
                mappedProperties[1] = infos.First(p => p.Name == "LastName");
            }

            return fields.Length;
        }

        private static object ConvertFromString(string value, Type type)
        {
            var converter = TypeDescriptor.GetConverter(type);
            return converter != null && converter.CanConvertFrom(typeof(string)) ? converter.ConvertFromString(value) : null;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Exceptions/DraftException.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Mail.Exceptions
{
    public enum DraftFieldTypes
    {
        None,
        From,
        To,
        Cc,
        Bcc
    }

    public class DraftException : Exception
    {
        public enum ErrorTypes
        {
            EmptyField = 1,
            IncorrectField = 2,
            TotalSizeExceeded = 3
        }

        public ErrorTypes ErrorType { get; set; }
        public DraftFieldTypes FieldType { get; set; }

        public DraftException(ErrorTypes type, string message, DraftFieldTypes fieldType = DraftFieldTypes.None)
            : base(message)
        {
            ErrorType = type;
            FieldType = fieldType;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.CRM/CRMApi.Tasks.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.CRM.Wrappers;
using ASC.Api.Exceptions;
using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.MessagingSystem;
using ASC.Specific;
using ASC.Web.CRM.Resources;
using ASC.Web.CRM.Services.NotifyService;

namespace ASC.Api.CRM
{
    public partial class CRMApi
    {
        /// <summary>
        ///  Returns the detailed information about the task with the ID specified in the request
        /// </summary>
        /// <param name="taskid">Task ID</param>
        /// <returns>Task</returns>
        /// <short>Get task by ID</short> 
        /// <category>Tasks</category>
        ///<exception cref="ArgumentException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"task/{taskid:[0-9]+}")]
        public TaskWrapper GetTaskByID(int taskid)
        {
            if (taskid <= 0) throw new ArgumentException();

            var task = DaoFactory.TaskDao.GetByID(taskid);
            if (task == null) throw new ItemNotFoundException();

            if (!CRMSecurity.CanAccessTo(task))
            {
                throw CRMSecurity.CreateSecurityException();
            }

            return ToTaskWrapper(task);
        }

        /// <summary>
        ///   Returns the list of tasks matching the creteria specified in the request
        /// </summary>
        /// <param optional="true" name="responsibleid">Task responsible</param>
        /// <param optional="true" name="categoryid">Task category ID</param>
        /// <param optional="true" name="isClosed">Show open or closed tasks only</param>
        /// <param optional="true" name="fromDate">Earliest task due date</param>
        /// <param optional="true" name="toDate">Latest task due date</param>
        /// <param name="entityType" remark="Allowed values: opportunity, contact or case">Related entity type</param>
        /// <param name="entityid">Related entity ID</param>
        /// <exception cref="ArgumentException"></exception>
        /// <short>Get task list</short> 
        /// <category>Tasks</category>
        /// <returns>
        ///   Task list
        /// </returns>
        [Read(@"task/filter")]
        public IEnumerable<TaskWrapper> GetAllTasks(
            Guid responsibleid,
            int categoryid,
            bool? isClosed,
            ApiDateTime fromDate,
            ApiDateTime toDate,
            string entityType,
            int entityid)
        {
            TaskSortedByType taskSortedByType;

            if (!string.IsNullOrEmpty(entityType) &&
                !(
                     string.Compare(entityType, "contact", StringComparison.OrdinalIgnoreCase) == 0 ||
                     string.Compare(entityType, "opportunity", StringComparison.OrdinalIgnoreCase) == 0 ||
                     string.Compare(entityType, "case", StringComparison.OrdinalIgnoreCase) == 0)
                )
                throw new ArgumentException();

            var searchText = _context.FilterValue;

            IEnumerable<TaskWrapper> result;

            OrderBy taskOrderBy;

            if (Web.CRM.Classes.EnumExtension.TryParse(_context.SortBy, true, out taskSortedByType))
            {
                taskOrderBy = new OrderBy(taskSortedByType, !_context.SortDescending);
            }
            else if (string.IsNullOrEmpty(_context.SortBy))
            {
                taskOrderBy = new OrderBy(TaskSortedByType.DeadLine, true);
            }
            else
            {
                taskOrderBy = null;
            }

            var fromIndex = (int)_context.StartIndex;
            var count = (int)_context.Count;

            if (taskOrderBy != null)
            {
                result = ToTaskListWrapper(
                    DaoFactory
                        .TaskDao
                        .GetTasks(
                            searchText,
                            responsibleid,
                            categoryid,
                            isClosed,
                            fromDate,
                            toDate,
                            ToEntityType(entityType),
                            entityid,
                            fromIndex,
                            count,
                            taskOrderBy)).ToList();

                _context.SetDataPaginated();
                _context.SetDataFiltered();
                _context.SetDataSorted();
            }
            else
                result = ToTaskListWrapper(
                    DaoFactory
                        .TaskDao
                        .GetTasks(
                            searchText,
                            responsibleid,
                            categoryid,
                            isClosed,
                            fromDate,
                            toDate,
                            ToEntityType(entityType),
                            entityid,
                            0,
                            0, null)).ToList();


            int totalCount;

            if (result.Count() < count)
            {
                totalCount = fromIndex + result.Count();
            }
            else
            {
                totalCount = DaoFactory
                    .TaskDao
                    .GetTasksCount(
                        searchText,
                        responsibleid,
                        categoryid,
                        isClosed,
                        fromDate,
                        toDate,
                        ToEntityType(entityType),
                        entityid);
            }

            _context.SetTotalCount(totalCount);

            return result;
        }

        /// <summary>
        ///   Open anew the task with the ID specified in the request
        /// </summary>
        /// <short>Resume task</short> 
        /// <category>Tasks</category>
        /// <param name="taskid">Task ID</param>
        /// <exception cref="ArgumentException"></exception>
        /// <returns>
        ///   Task
        /// </returns>
        [Update(@"task/{taskid:[0-9]+}/reopen")]
        public TaskWrapper ReOpenTask(int taskid)
        {
            if (taskid <= 0) throw new ArgumentException();

            DaoFactory.TaskDao.OpenTask(taskid);

            var task = DaoFactory.TaskDao.GetByID(taskid);
            MessageService.Send(Request, MessageAction.CrmTaskOpened, MessageTarget.Create(task.ID), task.Title);

            return ToTaskWrapper(task);
        }

        /// <summary>
        ///   Close the task with the ID specified in the request
        /// </summary>
        /// <short>Close task</short> 
        /// <category>Tasks</category>
        /// <param name="taskid">Task ID</param>
        /// <exception cref="ArgumentException"></exception>
        /// <returns>
        ///   Task
        /// </returns>
        [Update(@"task/{taskid:[0-9]+}/close")]
        public TaskWrapper CloseTask(int taskid)
        {
            if (taskid <= 0) throw new ArgumentException();

            DaoFactory.TaskDao.CloseTask(taskid);

            var task = DaoFactory.TaskDao.GetByID(taskid);
            MessageService.Send(Request, MessageAction.CrmTaskClosed, MessageTarget.Create(task.ID), task.Title);

            return ToTaskWrapper(task);
        }

        /// <summary>
        ///   Delete the task with the ID specified in the request
        /// </summary>
        /// <short>Delete task</short> 
        /// <category>Tasks</category>
        /// <param name="taskid">Task ID</param>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ItemNotFoundException"></exception>
        /// <returns>
        ///  Deleted task
        /// </returns>
        [Delete(@"task/{taskid:[0-9]+}")]
        public TaskWrapper DeleteTask(int taskid)
        {
            if (taskid <= 0) throw new ArgumentException();

            var task = DaoFactory.TaskDao.GetByID(taskid);
            if (task == null) throw new ItemNotFoundException();

            DaoFactory.TaskDao.DeleteTask(taskid);
            MessageService.Send(Request, MessageAction.CrmTaskDeleted, MessageTarget.Create(task.ID), task.Title);

            return ToTaskWrapper(task);
        }

        /// <summary>
        ///  Creates the task with the parameters (title, description, due date, etc.) specified in the request
        /// </summary>
        /// <param name="title">Task title</param>
        /// <param optional="true"  name="description">Task description</param>
        /// <param name="deadline">Task due date</param>
        /// <param name="responsibleId">Task responsible ID</param>
        /// <param name="categoryId">Task category ID</param>
        /// <param optional="true"  name="contactId">Contact ID</param>
        /// <param optional="true"  name="entityType" remark="Allowed values: opportunity or case">Related entity type</param>
        /// <param optional="true"  name="entityId">Related entity ID</param>
        /// <param optional="true"  name="isNotify">Notify the responsible about the task</param>
        /// <param optional="true"  name="alertValue">Time period in minutes for reminder to the responsible about the task</param>
        /// <exception cref="ArgumentException"></exception>
        /// <short>Create task</short> 
        /// <category>Tasks</category>
        /// <returns>Task</returns>
        [Create(@"task")]
        public TaskWrapper CreateTask(
            string title,
            string description,
            ApiDateTime deadline,
            Guid responsibleId,
            int categoryId,
            int contactId,
            string entityType,
            int entityId,
            bool isNotify,
            int alertValue
            )
        {
            if (!string.IsNullOrEmpty(entityType) &&
                !(
                     string.Compare(entityType, "opportunity", StringComparison.OrdinalIgnoreCase) == 0 ||
                     string.Compare(entityType, "case", StringComparison.OrdinalIgnoreCase) == 0
                 )
                || categoryId <= 0)
                throw new ArgumentException();

            var listItem = DaoFactory.ListItemDao.GetByID(categoryId);
            if (listItem == null) throw new ItemNotFoundException(CRMErrorsResource.TaskCategoryNotFound);

            var task = new Task
            {
                Title = title,
                Description = description,
                ResponsibleID = responsibleId,
                CategoryID = categoryId,
                DeadLine = deadline,
                ContactID = contactId,
                EntityType = ToEntityType(entityType),
                EntityID = entityId,
                IsClosed = false,
                AlertValue = alertValue
            };

            task = DaoFactory.TaskDao.SaveOrUpdateTask(task);

            if (isNotify)
            {
                Contact taskContact = null;
                Cases taskCase = null;
                Deal taskDeal = null;

                if (task.ContactID > 0)
                {
                    taskContact = DaoFactory.ContactDao.GetByID(task.ContactID);
                }

                if (task.EntityID > 0)
                {
                    switch (task.EntityType)
                    {
                        case EntityType.Case:
                            taskCase = DaoFactory.CasesDao.GetByID(task.EntityID);
                            break;
                        case EntityType.Opportunity:
                            taskDeal = DaoFactory.DealDao.GetByID(task.EntityID);
                            break;
                    }
                }

                NotifyClient.Instance.SendAboutResponsibleByTask(task, listItem.Title, taskContact, taskCase, taskDeal, null);
            }

            MessageService.Send(Request, MessageAction.CrmTaskCreated, MessageTarget.Create(task.ID), task.Title);

            return ToTaskWrapper(task);
        }

        /// <summary>
        ///  Creates the group of the same task with the parameters (title, description, due date, etc.) specified in the request for several contacts
        /// </summary>
        /// <param name="title">Task title</param>
        /// <param optional="true"  name="description">Task description</param>
        /// <param name="deadline">Task due date</param>
        /// <param name="responsibleId">Task responsible ID</param>
        /// <param name="categoryId">Task category ID</param>
        /// <param name="contactId">contact ID list</param>
        /// <param optional="true"  name="entityType" remark="Allowed values: opportunity or case">Related entity type</param>
        /// <param optional="true"  name="entityId">Related entity ID</param>
        /// <param optional="true"  name="isNotify">Notify the responsible about the task</param>
        /// <param optional="true"  name="alertValue">Time period in minutes for reminder to the responsible about the task</param>
        /// <exception cref="ArgumentException"></exception>
        /// <short>Create task list</short> 
        /// <category>Tasks</category>
        /// <returns>Tasks</returns>
        /// <visible>false</visible>
        [Create(@"contact/task/group")]
        public IEnumerable<TaskWrapper> CreateTaskGroup(
            string title,
            string description,
            ApiDateTime deadline,
            Guid responsibleId,
            int categoryId,
            int[] contactId,
            string entityType,
            int entityId,
            bool isNotify,
            int alertValue)
        {
            var tasks = new List<Task>();

            if (
                !string.IsNullOrEmpty(entityType) &&
                !(string.Compare(entityType, "opportunity", StringComparison.OrdinalIgnoreCase) == 0 ||
                  string.Compare(entityType, "case", StringComparison.OrdinalIgnoreCase) == 0)
                )
                throw new ArgumentException();

            foreach (var cid in contactId)
            {
                tasks.Add(new Task
                {
                    Title = title,
                    Description = description,
                    ResponsibleID = responsibleId,
                    CategoryID = categoryId,
                    DeadLine = deadline,
                    ContactID = cid,
                    EntityType = ToEntityType(entityType),
                    EntityID = entityId,
                    IsClosed = false,
                    AlertValue = alertValue
                });
            }

            tasks = DaoFactory.TaskDao.SaveOrUpdateTaskList(tasks).ToList();

            string taskCategory = null;
            if (isNotify)
            {
                if (categoryId > 0)
                {
                    var listItem = DaoFactory.ListItemDao.GetByID(categoryId);
                    if (listItem == null) throw new ItemNotFoundException();

                    taskCategory = listItem.Title;
                }
            }

            for (var i = 0; i < tasks.Count; i++)
            {
                if (!isNotify) continue;

                Contact taskContact = null;
                Cases taskCase = null;
                Deal taskDeal = null;

                if (tasks[i].ContactID > 0)
                {
                    taskContact = DaoFactory.ContactDao.GetByID(tasks[i].ContactID);
                }

                if (tasks[i].EntityID > 0)
                {
                    switch (tasks[i].EntityType)
                    {
                        case EntityType.Case:
                            taskCase = DaoFactory.CasesDao.GetByID(tasks[i].EntityID);
                            break;
                        case EntityType.Opportunity:
                            taskDeal = DaoFactory.DealDao.GetByID(tasks[i].EntityID);
                            break;
                    }
                }

                NotifyClient.Instance.SendAboutResponsibleByTask(tasks[i], taskCategory, taskContact, taskCase, taskDeal, null);
            }

            if (tasks.Any())
            {
                var contacts = DaoFactory.ContactDao.GetContacts(contactId);
                var task = tasks.First();
                MessageService.Send(Request, MessageAction.ContactsCreatedCrmTasks, MessageTarget.Create(tasks.Select(x => x.ID)), contacts.Select(x => x.GetTitle()), task.Title);
            }

            return ToTaskListWrapper(tasks);
        }


        /// <summary>
        ///   Updates the selected task with the parameters (title, description, due date, etc.) specified in the request
        /// </summary>
        /// <param name="taskid">Task ID</param>
        /// <param name="title">Task title</param>
        /// <param name="description">Task description</param>
        /// <param name="deadline">Task due date</param>
        /// <param name="responsibleid">Task responsible ID</param>
        /// <param name="categoryid">Task category ID</param>
        /// <param name="contactid">Contact ID</param>
        /// <param name="entityType" remark="Allowed values: opportunity or case">Related entity type</param>
        /// <param name="entityid">Related entity ID</param>
        /// <param name="isNotify">Notify or not</param>
        /// <param optional="true"  name="alertValue">Time period in minutes for reminder to the responsible about the task</param>
        /// <short> Update task</short> 
        /// <category>Tasks</category>
        /// <returns>Task</returns>
        [Update(@"task/{taskid:[0-9]+}")]
        public TaskWrapper UpdateTask(
            int taskid,
            string title,
            string description,
            ApiDateTime deadline,
            Guid responsibleid,
            int categoryid,
            int contactid,
            string entityType,
            int entityid,
            bool isNotify,
            int alertValue)
        {
            if (!string.IsNullOrEmpty(entityType) &&
                !(string.Compare(entityType, "opportunity", StringComparison.OrdinalIgnoreCase) == 0 ||
                  string.Compare(entityType, "case", StringComparison.OrdinalIgnoreCase) == 0
                 ) || categoryid <= 0)
                throw new ArgumentException();

            var listItem = DaoFactory.ListItemDao.GetByID(categoryid);
            if (listItem == null) throw new ItemNotFoundException(CRMErrorsResource.TaskCategoryNotFound);

            var task = new Task
            {
                ID = taskid,
                Title = title,
                Description = description,
                DeadLine = deadline,
                AlertValue = alertValue,
                ResponsibleID = responsibleid,
                CategoryID = categoryid,
                ContactID = contactid,
                EntityID = entityid,
                EntityType = ToEntityType(entityType)
            };


            task = DaoFactory.TaskDao.SaveOrUpdateTask(task);

            if (isNotify)
            {
                Contact taskContact = null;
                Cases taskCase = null;
                Deal taskDeal = null;

                if (task.ContactID > 0)
                {
                    taskContact = DaoFactory.ContactDao.GetByID(task.ContactID);
                }

                if (task.EntityID > 0)
                {
                    switch (task.EntityType)
                    {
                        case EntityType.Case:
                            taskCase = DaoFactory.CasesDao.GetByID(task.EntityID);
                            break;
                        case EntityType.Opportunity:
                            taskDeal = DaoFactory.DealDao.GetByID(task.EntityID);
                            break;
                    }
                }

                NotifyClient.Instance.SendAboutResponsibleByTask(task, listItem.Title, taskContact, taskCase, taskDeal, null);
            }

            MessageService.Send(Request, MessageAction.CrmTaskUpdated, MessageTarget.Create(task.ID), task.Title);

            return ToTaskWrapper(task);
        }

        /// <visible>false</visible>
        [Update(@"task/{taskid:[0-9]+}/creationdate")]
        public void SetTaskCreationDate(int taskId, ApiDateTime creationDate)
        {
            var dao = DaoFactory.TaskDao;
            var task = dao.GetByID(taskId);

            if (task == null || !CRMSecurity.CanAccessTo(task))
                throw new ItemNotFoundException();

            dao.SetTaskCreationDate(taskId, creationDate);
        }

        /// <visible>false</visible>
        [Update(@"task/{taskid:[0-9]+}/lastmodifeddate")]
        public void SetTaskLastModifedDate(int taskId, ApiDateTime lastModifedDate)
        {
            var dao = DaoFactory.TaskDao;
            var task = dao.GetByID(taskId);

            if (task == null || !CRMSecurity.CanAccessTo(task))
                throw new ItemNotFoundException();

            dao.SetTaskLastModifedDate(taskId, lastModifedDate);
        }

        private IEnumerable<TaskWrapper> ToTaskListWrapper(IEnumerable<Task> itemList)
        {
            var result = new List<TaskWrapper>();

            var contactIDs = new List<int>();
            var taskIDs = new List<int>();
            var categoryIDs = new List<int>();
            var entityWrappersIDs = new Dictionary<EntityType, List<int>>();

            foreach (var item in itemList)
            {
                taskIDs.Add(item.ID);

                if (!categoryIDs.Contains(item.CategoryID))
                {
                    categoryIDs.Add(item.CategoryID);
                }

                if (item.ContactID > 0 && !contactIDs.Contains(item.ContactID))
                {
                    contactIDs.Add(item.ContactID);
                }

                if (item.EntityID > 0)
                {
                    if (item.EntityType != EntityType.Opportunity && item.EntityType != EntityType.Case) continue;

                    if (!entityWrappersIDs.ContainsKey(item.EntityType))
                    {
                        entityWrappersIDs.Add(item.EntityType, new List<int>
                            {
                                item.EntityID
                            });
                    }
                    else if (!entityWrappersIDs[item.EntityType].Contains(item.EntityID))
                    {
                        entityWrappersIDs[item.EntityType].Add(item.EntityID);
                    }
                }
            }

            var entityWrappers = new Dictionary<string, EntityWrapper>();

            foreach (var entityType in entityWrappersIDs.Keys)
            {
                switch (entityType)
                {
                    case EntityType.Opportunity:
                        DaoFactory.DealDao.GetDeals(entityWrappersIDs[entityType].Distinct().ToArray())
                                  .ForEach(item =>
                                      {
                                          if (item == null) return;

                                          entityWrappers.Add(
                                              string.Format("{0}_{1}", (int)entityType, item.ID),
                                              new EntityWrapper
                                              {
                                                  EntityId = item.ID,
                                                  EntityTitle = item.Title,
                                                  EntityType = "opportunity"
                                              });
                                      });
                        break;
                    case EntityType.Case:
                        DaoFactory.CasesDao.GetByID(entityWrappersIDs[entityType].ToArray())
                                  .ForEach(item =>
                                      {
                                          if (item == null) return;

                                          entityWrappers.Add(
                                              string.Format("{0}_{1}", (int)entityType, item.ID),
                                              new EntityWrapper
                                              {
                                                  EntityId = item.ID,
                                                  EntityTitle = item.Title,
                                                  EntityType = "case"
                                              });
                                      });
                        break;
                }
            }

            var categories = DaoFactory.ListItemDao.GetItems(categoryIDs.ToArray()).ToDictionary(x => x.ID, x => new TaskCategoryBaseWrapper(x));
            var contacts = DaoFactory.ContactDao.GetContacts(contactIDs.ToArray()).ToDictionary(item => item.ID, ToContactBaseWithEmailWrapper);
            var restrictedContacts = DaoFactory.ContactDao.GetRestrictedContacts(contactIDs.ToArray()).ToDictionary(item => item.ID, ToContactBaseWithEmailWrapper);



            foreach (var item in itemList)
            {
                var taskWrapper = new TaskWrapper(item) { CanEdit = CRMSecurity.CanEdit(item) };

                if (contacts.ContainsKey(item.ContactID))
                {
                    taskWrapper.Contact = contacts[item.ContactID];
                }
                if (restrictedContacts.ContainsKey(item.ContactID))
                {
                    taskWrapper.Contact = restrictedContacts[item.ContactID];
                    /*Hide some fields. Should be refactored! */
                    taskWrapper.Contact.Currency = null;
                    taskWrapper.Contact.Email = null;
                    taskWrapper.Contact.AccessList = null;
                }

                if (item.EntityID > 0)
                {
                    var entityStrKey = string.Format("{0}_{1}", (int)item.EntityType, item.EntityID);

                    if (entityWrappers.ContainsKey(entityStrKey))
                    {
                        taskWrapper.Entity = entityWrappers[entityStrKey];
                    }
                }

                if (categories.ContainsKey(item.CategoryID))
                {
                    taskWrapper.Category = categories[item.CategoryID];
                }

                result.Add(taskWrapper);
            }

            return result;
        }


        private TaskWrapper ToTaskWrapper(Task task)
        {
            var result = new TaskWrapper(task);

            if (task.CategoryID > 0)
            {
                result.Category = GetTaskCategoryByID(task.CategoryID);
            }

            if (task.ContactID > 0)
            {
                result.Contact = ToContactBaseWithEmailWrapper(DaoFactory.ContactDao.GetByID(task.ContactID));
            }

            if (task.EntityID > 0)
            {
                result.Entity = ToEntityWrapper(task.EntityType, task.EntityID);
            }

            result.CanEdit = CRMSecurity.CanEdit(task);

            return result;
        }
    }
}

<|start_filename|>common/ASC.ActiveDirectory/Base/Expressions/Op.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.ActiveDirectory.Base.Expressions
{
    /// <summary>
    /// Operations
    /// </summary>
    /// <remarks>
    /// [1 - negation][1 - binary][number]
    /// </remarks>
    public enum Op
    {
        //------------  UNARY -------------
        /// <summary>Attribute exists</summary>
        Exists = 0x000001,
        /// <summary>Attribute does not exist</summary>
        NotExists = 0x010002,

        //------------  BINARY -------------
        /// <summary>Equal</summary>
        Equal = 0x000103,
        /// <summary>Not equal</summary>
        NotEqual = 0x010104,
        /// <summary>Strong less</summary>
        Less = 0x000105,
        /// <summary>Less or equal</summary>
        LessOrEqual = 0x000106,
        /// <summary>Strong greater</summary>
        Greater = 0x000107,
        /// <summary>Greater or equal</summary>
        GreaterOrEqual = 0x000108
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Mail/MailApi.Filters.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Threading;

using ASC.Api.Attributes;
using ASC.Mail.Core.Engine.Operations.Base;
using ASC.Mail.Data.Contracts;
using ASC.Web.Mail.Resources;

namespace ASC.Api.Mail
{
    public partial class MailApi
    {
        /// <summary>
        ///    Returns list of the tags used in Mail
        /// </summary>
        /// <returns>Filters list. Filters represented as JSON.</returns>
        /// <short>Get filters list</short> 
        /// <category>Filters</category>
        [Read(@"filters")]
        public IEnumerable<MailSieveFilterData> GetFilters()
        {
            var filters = MailEngineFactory.FilterEngine.GetList();
            return filters;
        }

        /// <summary>
        ///    Creates a new filter
        /// </summary>
        /// <param name="filter"></param>
        /// <returns>Filter</returns>
        /// <short>Create filter</short> 
        /// <category>Filters</category>
        /// <exception cref="ArgumentException">Exception happens when in parameters is invalid. Text description contains parameter name and text description.</exception>
        [Create(@"filters")]
        public MailSieveFilterData CreateFilter(MailSieveFilterData filter)
        {
            var id = MailEngineFactory.FilterEngine.Create(filter);
            filter.Id = id;
            return filter;
        }

        /// <summary>
        ///    Updates the selected filter
        /// </summary>
        /// <param name="filter"></param>
        /// <returns>Updated filter</returns>
        /// <short>Update filter</short> 
        /// <category>Filters</category>
        /// <exception cref="ArgumentException">Exception happens when in parameters is invalid. Text description contains parameter name and text description.</exception>
        [Update(@"filters")]
        public MailSieveFilterData UpdateFilter(MailSieveFilterData filter)
        {
            MailEngineFactory.FilterEngine.Update(filter);

            return filter;
        }

        /// <summary>
        ///    Deletes the selected filter
        /// </summary>
        /// <param name="id">Filter id</param>
        /// <returns>Deleted Filter id</returns>
        /// <short>Delete filter</short> 
        /// <category>Filters</category>
        /// <exception cref="ArgumentException">Exception happens when in parameters is invalid. Text description contains parameter name and text description.</exception>
        [Delete(@"filters/{id}")]
        public int DeleteFilter(int id)
        {
            MailEngineFactory.FilterEngine.Delete(id);
            return id;
        }

        /// <summary>
        ///    Check filter result
        /// </summary>
        /// <param name="filter"></param>
        /// <param optional="true" name="page">Page number</param>
        /// <param optional="true" name="pageSize">Number of messages on page</param>
        /// <returns>List messages</returns>
        /// <short>Check filter</short> 
        /// <category>Filters</category>
        /// <exception cref="ArgumentException">Exception happens when in parameters is invalid. Text description contains parameter name and text description.</exception>
        [Read(@"filters/check")]
        public List<MailMessageData> CheckFilter(MailSieveFilterData filter, int? page, int? pageSize)
        {
            if (!page.HasValue)
                page = 0;

            if (!pageSize.HasValue)
                pageSize = 10;

            long total;
            var messages = MailEngineFactory.MessageEngine.GetFilteredMessages(filter, page.Value, pageSize.Value, out total);

            _context.SetTotalCount(total);

            return messages;
        }

        /// <summary>
        ///    Apply filter to existing messages
        /// </summary>
        /// <param name="id">Filter id</param>
        /// <returns>MailOperationResult object</returns>
        /// <short>Check filter</short> 
        /// <category>Filters</category>
        /// <exception cref="ArgumentException">Exception happens when in parameters is invalid. Text description contains parameter name and text description.</exception>
        [Read(@"filters/{id}/apply")]
        public MailOperationStatus ApplyFilter(int id)
        {
            Thread.CurrentThread.CurrentCulture = CurrentCulture;
            Thread.CurrentThread.CurrentUICulture = CurrentCulture;

            try
            {
                return MailEngineFactory.OperationEngine.ApplyFilter(id, TranslateMailOperationStatus);
            }
            catch (Exception)
            {
                throw new Exception(MailApiErrorsResource.ErrorInternalServer);
            }
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Notify/Senders/TelegramSender.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

using ASC.Common.Logging;
using ASC.Core.Common.Notify;
using ASC.Notify.Messages;

namespace ASC.Core.Notify.Senders
{
    public class TelegramSender : INotifySender
    {
        private static readonly ILog log = LogManager.GetLogger("ASC");

        public void Init(IDictionary<string, string> properties)
        {
        }

        public NoticeSendResult Send(NotifyMessage m)
        {
            if (!string.IsNullOrEmpty(m.Content))
            {
                m.Content = m.Content.Replace("\r\n", "\n").Trim('\n', '\r', ' ');
                m.Content = Regex.Replace(m.Content, "\n{3,}", "\n\n");
            }
            try
            {
                TelegramHelper.Instance.SendMessage(m);
            }
            catch (Exception e)
            {
                log.ErrorFormat("Unexpected error, {0}, {1}, {2}",
                       e.Message, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
            }
            return NoticeSendResult.OK;
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Imap/ImapFolderUids.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

namespace ASC.Mail.Data.Imap
{
    public class ImapFolderUids
    {
        public int BeginDateUid { get; set; }
        public uint? UidValidity { get; set; }
        public List<int> UnhandledUidIntervals { get; set; }

        public ImapFolderUids(IEnumerable<int> uidIntervals, int beginDateUid, uint? uidValidity = null)
        {
            if (uidIntervals == null)
                uidIntervals = new List<int>();

            UnhandledUidIntervals = new List<int>(uidIntervals);
            BeginDateUid = beginDateUid;
            UidValidity = uidValidity;
        }

        public static bool operator ==(ImapFolderUids a, ImapFolderUids b)
        {
            // If both are null, or both are same instance, return true.
            if (ReferenceEquals(a, b))
            {
                return true;
            }

            // If one is null, but not both, return false.
            if (((object)a == null) || ((object)b == null))
            {
                return false;
            }

            // Return true if the fields match:
            return a.Equals(b);
        }

        public static bool operator !=(ImapFolderUids a, ImapFolderUids b)
        {
            return !(a == b);
        }

        public override bool Equals(object obj)
        {
            var p = obj as ImapFolderUids;
            return (object)p != null && Equals(p);
        }

        public bool Equals(ImapFolderUids p)
        {
            // If parameter is null return false:
            if ((object)p == null)
            {
                return false;
            }

            // Return true if the fields match:
            return BeginDateUid == p.BeginDateUid && UnhandledUidIntervals.SequenceEqual(p.UnhandledUidIntervals) && UidValidity == p.UidValidity;
        }

        public override int GetHashCode()
        {
            return BeginDateUid ^ UnhandledUidIntervals.GetHashCode() ^ UidValidity.GetHashCode();
        }
    }
}


<|start_filename|>module/ASC.Files.Thirdparty/Box/BoxDaoBase.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Files.Core;
using ASC.Files.Core.Security;
using ASC.Security.Cryptography;
using ASC.Web.Files.Classes;

using Box.V2.Models;

namespace ASC.Files.Thirdparty.Box
{
    internal abstract class BoxDaoBase
    {
        protected readonly BoxDaoSelector BoxDaoSelector;

        public int TenantID { get; private set; }
        public BoxProviderInfo BoxProviderInfo { get; private set; }
        public string PathPrefix { get; private set; }


        protected BoxDaoBase(BoxDaoSelector.BoxInfo boxInfo, BoxDaoSelector boxDaoSelector)
        {
            BoxProviderInfo = boxInfo.BoxProviderInfo;
            PathPrefix = boxInfo.PathPrefix;
            BoxDaoSelector = boxDaoSelector;
            TenantID = CoreContext.TenantManager.GetCurrentTenant().TenantId;
        }

        public void Dispose()
        {
            BoxProviderInfo.Dispose();
        }

        protected DbManager GetDb()
        {
            return new DbManager(FileConstant.DatabaseId);
        }

        protected object MappingID(object id, bool saveIfNotExist = false)
        {
            if (id == null) return null;
            int n;

            var isNumeric = int.TryParse(id.ToString(), out n);

            if (isNumeric) return n;

            object result;
            using (var db = GetDb())
            {
                if (id.ToString().StartsWith("box"))
                {
                    result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower();
                }
                else
                {
                    result = db.ExecuteScalar<String>(Query("files_thirdparty_id_mapping")
                                                          .Select("id")
                                                          .Where(Exp.Eq("hash_id", id)));
                }
                if (saveIfNotExist)
                {
                    db.ExecuteNonQuery(Insert("files_thirdparty_id_mapping")
                                           .InColumnValue("id", id)
                                           .InColumnValue("hash_id", result));
                }
            }
            return result;
        }

        protected SqlQuery Query(string table)
        {
            return new SqlQuery(table).Where(GetTenantColumnName(table), TenantID);
        }

        protected SqlDelete Delete(string table)
        {
            return new SqlDelete(table).Where(GetTenantColumnName(table), TenantID);
        }

        protected SqlInsert Insert(string table)
        {
            return new SqlInsert(table, true).InColumns(GetTenantColumnName(table)).Values(TenantID);
        }

        private static string GetTenantColumnName(string table)
        {
            const string tenant = "tenant_id";
            if (!table.Contains(" ")) return tenant;
            return table.Substring(table.IndexOf(" ", StringComparison.InvariantCulture)).Trim() + "." + tenant;
        }


        protected static string MakeBoxId(object entryId)
        {
            var id = Convert.ToString(entryId, CultureInfo.InvariantCulture);
            return string.IsNullOrEmpty(id)
                       ? "0"
                       : id.TrimStart('/');
        }

        protected static string GetParentFolderId(BoxItem boxItem)
        {
            return boxItem == null || boxItem.Parent == null
                       ? null
                       : boxItem.Parent.Id;
        }

        protected string MakeId(BoxItem boxItem)
        {
            var path = string.Empty;
            if (boxItem != null)
            {
                path = boxItem.Id;
            }

            return MakeId(path);
        }

        protected string MakeId(string path = null)
        {
            return string.Format("{0}{1}", PathPrefix,
                                 string.IsNullOrEmpty(path) || path == "0"
                                     ? "" : ("-|" + path.TrimStart('/')));
        }

        protected String MakeFolderTitle(BoxFolder boxFolder)
        {
            if (boxFolder == null || IsRoot(boxFolder))
            {
                return BoxProviderInfo.CustomerTitle;
            }

            return Global.ReplaceInvalidCharsAndTruncate(boxFolder.Name);
        }

        protected String MakeFileTitle(BoxFile boxFile)
        {
            if (boxFile == null || string.IsNullOrEmpty(boxFile.Name))
            {
                return BoxProviderInfo.ProviderKey;
            }

            return Global.ReplaceInvalidCharsAndTruncate(boxFile.Name);
        }

        protected Folder ToFolder(BoxFolder boxFolder)
        {
            if (boxFolder == null) return null;
            if (boxFolder is ErrorFolder)
            {
                //Return error entry
                return ToErrorFolder(boxFolder as ErrorFolder);
            }

            var isRoot = IsRoot(boxFolder);

            var folder = new Folder
            {
                ID = MakeId(boxFolder.Id),
                ParentFolderID = isRoot ? null : MakeId(GetParentFolderId(boxFolder)),
                CreateBy = BoxProviderInfo.Owner,
                CreateOn = isRoot ? BoxProviderInfo.CreateOn : (boxFolder.CreatedAt.HasValue ? boxFolder.CreatedAt.Value : default(DateTime)),
                FolderType = FolderType.DEFAULT,
                ModifiedBy = BoxProviderInfo.Owner,
                ModifiedOn = isRoot ? BoxProviderInfo.CreateOn : (boxFolder.ModifiedAt.HasValue ? boxFolder.ModifiedAt.Value : default(DateTime)),
                ProviderId = BoxProviderInfo.ID,
                ProviderKey = BoxProviderInfo.ProviderKey,
                RootFolderCreator = BoxProviderInfo.Owner,
                RootFolderId = MakeId(),
                RootFolderType = BoxProviderInfo.RootFolderType,

                Shareable = false,
                Title = MakeFolderTitle(boxFolder),
                TotalFiles = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFile) : 0,
                TotalSubFolders = boxFolder.ItemCollection != null ? boxFolder.ItemCollection.Entries.Count(item => item is BoxFolder) : 0,
            };

            if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc)
                folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn);

            if (folder.ModifiedOn != DateTime.MinValue && folder.ModifiedOn.Kind == DateTimeKind.Utc)
                folder.ModifiedOn = TenantUtil.DateTimeFromUtc(folder.ModifiedOn);

            return folder;
        }

        protected static bool IsRoot(BoxFolder boxFolder)
        {
            return boxFolder.Id == "0";
        }

        private File ToErrorFile(ErrorFile boxFile)
        {
            if (boxFile == null) return null;
            return new File
            {
                ID = MakeId(boxFile.ErrorId),
                CreateBy = BoxProviderInfo.Owner,
                CreateOn = TenantUtil.DateTimeNow(),
                ModifiedBy = BoxProviderInfo.Owner,
                ModifiedOn = TenantUtil.DateTimeNow(),
                ProviderId = BoxProviderInfo.ID,
                ProviderKey = BoxProviderInfo.ProviderKey,
                RootFolderCreator = BoxProviderInfo.Owner,
                RootFolderId = MakeId(),
                RootFolderType = BoxProviderInfo.RootFolderType,
                Title = MakeFileTitle(boxFile),
                Error = boxFile.Error
            };
        }

        private Folder ToErrorFolder(ErrorFolder boxFolder)
        {
            if (boxFolder == null) return null;
            return new Folder
            {
                ID = MakeId(boxFolder.ErrorId),
                ParentFolderID = null,
                CreateBy = BoxProviderInfo.Owner,
                CreateOn = TenantUtil.DateTimeNow(),
                FolderType = FolderType.DEFAULT,
                ModifiedBy = BoxProviderInfo.Owner,
                ModifiedOn = TenantUtil.DateTimeNow(),
                ProviderId = BoxProviderInfo.ID,
                ProviderKey = BoxProviderInfo.ProviderKey,
                RootFolderCreator = BoxProviderInfo.Owner,
                RootFolderId = MakeId(),
                RootFolderType = BoxProviderInfo.RootFolderType,
                Shareable = false,
                Title = MakeFolderTitle(boxFolder),
                TotalFiles = 0,
                TotalSubFolders = 0,
                Error = boxFolder.Error
            };
        }

        public File ToFile(BoxFile boxFile)
        {
            if (boxFile == null) return null;

            if (boxFile is ErrorFile)
            {
                //Return error entry
                return ToErrorFile(boxFile as ErrorFile);
            }

            return new File
            {
                ID = MakeId(boxFile.Id),
                Access = FileShare.None,
                ContentLength = boxFile.Size.HasValue ? (long)boxFile.Size : 0,
                CreateBy = BoxProviderInfo.Owner,
                CreateOn = boxFile.CreatedAt.HasValue ? TenantUtil.DateTimeFromUtc(boxFile.CreatedAt.Value) : default(DateTime),
                FileStatus = FileStatus.None,
                FolderID = MakeId(GetParentFolderId(boxFile)),
                ModifiedBy = BoxProviderInfo.Owner,
                ModifiedOn = boxFile.ModifiedAt.HasValue ? TenantUtil.DateTimeFromUtc(boxFile.ModifiedAt.Value) : default(DateTime),
                NativeAccessor = boxFile,
                ProviderId = BoxProviderInfo.ID,
                ProviderKey = BoxProviderInfo.ProviderKey,
                Title = MakeFileTitle(boxFile),
                RootFolderId = MakeId(),
                RootFolderType = BoxProviderInfo.RootFolderType,
                RootFolderCreator = BoxProviderInfo.Owner,
                Shared = false,
                Version = 1
            };
        }

        public Folder GetRootFolder(object folderId)
        {
            return ToFolder(GetBoxFolder("0"));
        }

        protected BoxFolder GetBoxFolder(object folderId)
        {
            var boxFolderId = MakeBoxId(folderId);
            try
            {
                var folder = BoxProviderInfo.GetBoxFolder(boxFolderId);
                return folder;
            }
            catch (Exception ex)
            {
                return new ErrorFolder(ex, boxFolderId);
            }
        }

        protected BoxFile GetBoxFile(object fileId)
        {
            var boxFileId = MakeBoxId(fileId);
            try
            {
                var file = BoxProviderInfo.GetBoxFile(boxFileId);
                return file;
            }
            catch (Exception ex)
            {
                return new ErrorFile(ex, boxFileId);
            }
        }

        protected IEnumerable<string> GetChildren(object folderId)
        {
            return GetBoxItems(folderId).Select(entry => MakeId(entry.Id));
        }

        protected List<BoxItem> GetBoxItems(object parentId, bool? folder = null)
        {
            var boxFolderId = MakeBoxId(parentId);
            var items = BoxProviderInfo.GetBoxItems(boxFolderId);

            if (folder.HasValue)
            {
                if (folder.Value)
                {
                    return items.Where(i => i is BoxFolder).ToList();
                }

                return items.Where(i => i is BoxFile).ToList();
            }

            return items;
        }

        protected sealed class ErrorFolder : BoxFolder
        {
            public string Error { get; set; }

            public string ErrorId { get; private set; }


            public ErrorFolder(Exception e, object id)
            {
                ErrorId = id.ToString();
                if (e != null)
                {
                    Error = e.Message;
                }
            }
        }

        protected sealed class ErrorFile : BoxFile
        {
            public string Error { get; set; }

            public string ErrorId { get; private set; }


            public ErrorFile(Exception e, object id)
            {
                ErrorId = id.ToString();
                if (e != null)
                {
                    Error = e.Message;
                }
            }
        }

        protected String GetAvailableTitle(String requestTitle, string parentFolderId, Func<string, string, bool> isExist)
        {
            if (!isExist(requestTitle, parentFolderId)) return requestTitle;

            var re = new Regex(@"( \(((?<index>[0-9])+)\)(\.[^\.]*)?)$");
            var match = re.Match(requestTitle);

            if (!match.Success)
            {
                var insertIndex = requestTitle.Length;
                if (requestTitle.LastIndexOf(".", StringComparison.InvariantCulture) != -1)
                {
                    insertIndex = requestTitle.LastIndexOf(".", StringComparison.InvariantCulture);
                }
                requestTitle = requestTitle.Insert(insertIndex, " (1)");
            }

            while (isExist(requestTitle, parentFolderId))
            {
                requestTitle = re.Replace(requestTitle, MatchEvaluator);
            }
            return requestTitle;
        }

        private static String MatchEvaluator(Match match)
        {
            var index = Convert.ToInt32(match.Groups[2].Value);
            var staticText = match.Value.Substring(String.Format(" ({0})", index).Length);
            return String.Format(" ({0}){1}", index + 1, staticText);
        }
    }
}

<|start_filename|>common/ASC.Data.Storage/DataList.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Data.Storage.Configuration;

namespace ASC.Data.Storage
{
    public class DataList : Dictionary<string, string>
    {
        public DataList(ModuleConfigurationElement config)
        {
            Add(string.Empty, config.Data);
            foreach (DomainConfigurationElement domain in config.Domains)
            {
                Add(domain.Name, domain.Data);
            }
        }

        public string GetData(string name)
        {
            if (ContainsKey(name))
            {
                return this[name] ?? string.Empty;
            }
            return string.Empty;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Expressions/UserFolder/UserFoldersTreeExpBuilder.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

namespace ASC.Mail.Core.Dao.Expressions.UserFolder
{
    public class UserFoldersTreeExpBuilder
    {
        private readonly SimpleUserFoldersTreeExp _exp;

        public UserFoldersTreeExpBuilder()
        {
            _exp = new SimpleUserFoldersTreeExp();
        }

        public UserFoldersTreeExpBuilder SetIds(List<uint> ids)
        {
            _exp.Ids = ids;
            return this;
        }

        public UserFoldersTreeExpBuilder SetParent(uint parentId)
        {
            _exp.ParentId = parentId;
            return this;
        }

        public UserFoldersTreeExpBuilder SetLevel(uint level)
        {
            _exp.Level = level;
            return this;
        }

        public UserFoldersTreeExpBuilder SetOrderBy(string orderBy)
        {
            _exp.OrderBy = orderBy;
            return this;
        }

        public UserFoldersTreeExpBuilder SetOrderAsc(bool orderAsc)
        {
            _exp.OrderAsc = orderAsc;
            return this;
        }

        public UserFoldersTreeExpBuilder SetStartIndex(int startIndex)
        {
            _exp.StartIndex = startIndex;
            return this;
        }

        public UserFoldersTreeExpBuilder SetLimit(int limit)
        {
            _exp.Limit = limit;
            return this;
        }

        public SimpleUserFoldersTreeExp Build()
        {
            return _exp;
        }

        public static implicit operator SimpleUserFoldersTreeExp(UserFoldersTreeExpBuilder builder)
        {
            return builder._exp;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Utils/ReportHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Net;

using ASC.Core.Tenants;
using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.Files.Core;
using ASC.Web.CRM.Core;
using ASC.Web.CRM.Resources;
using ASC.Web.Files.Services.DocumentService;

using Autofac;

using Newtonsoft.Json;

namespace ASC.Web.CRM.Classes
{
    public class ReportHelper
    {
        private static string GetFileName(ReportType reportType)
        {
            string reportName;

            switch (reportType)
            {
                case ReportType.SalesByManagers:
                    reportName = CRMReportResource.SalesByManagersReport;
                    break;
                case ReportType.SalesForecast:
                    reportName = CRMReportResource.SalesForecastReport;
                    break;
                case ReportType.SalesFunnel:
                    reportName = CRMReportResource.SalesFunnelReport;
                    break;
                case ReportType.WorkloadByContacts:
                    reportName = CRMReportResource.WorkloadByContactsReport;
                    break;
                case ReportType.WorkloadByTasks:
                    reportName = CRMReportResource.WorkloadByTasksReport;
                    break;
                case ReportType.WorkloadByDeals:
                    reportName = CRMReportResource.WorkloadByDealsReport;
                    break;
                case ReportType.WorkloadByInvoices:
                    reportName = CRMReportResource.WorkloadByInvoicesReport;
                    break;
                case ReportType.WorkloadByVoip:
                    reportName = CRMReportResource.WorkloadByVoipReport;
                    break;
                case ReportType.SummaryForThePeriod:
                    reportName = CRMReportResource.SummaryForThePeriodReport;
                    break;
                case ReportType.SummaryAtThisMoment:
                    reportName = CRMReportResource.SummaryAtThisMomentReport;
                    break;
                default:
                    reportName = string.Empty;
                    break;
            }

            return string.Format("{0} ({1} {2}).xlsx",
                                 reportName,
                                 TenantUtil.DateTimeNow().ToShortDateString(),
                                 TenantUtil.DateTimeNow().ToShortTimeString());
        }

        public static bool CheckReportData(ReportType reportType, ReportTimePeriod timePeriod, Guid[] managers)
        {
            using (var scope = DIHelper.Resolve())
            {
                var reportDao = scope.Resolve<DaoFactory>().ReportDao;

                switch (reportType)
                {
                    case ReportType.SalesByManagers:
                        return reportDao.CheckSalesByManagersReportData(timePeriod, managers);
                    case ReportType.SalesForecast:
                        return reportDao.CheckSalesForecastReportData(timePeriod, managers);
                    case ReportType.SalesFunnel:
                        return reportDao.CheckSalesFunnelReportData(timePeriod, managers);
                    case ReportType.WorkloadByContacts:
                        return reportDao.CheckWorkloadByContactsReportData(timePeriod, managers);
                    case ReportType.WorkloadByTasks:
                        return reportDao.CheckWorkloadByTasksReportData(timePeriod, managers);
                    case ReportType.WorkloadByDeals:
                        return reportDao.CheckWorkloadByDealsReportData(timePeriod, managers);
                    case ReportType.WorkloadByInvoices:
                        return reportDao.CheckWorkloadByInvoicesReportData(timePeriod, managers);
                    case ReportType.WorkloadByVoip:
                        return reportDao.CheckWorkloadByViopReportData(timePeriod, managers);
                    case ReportType.SummaryForThePeriod:
                        return reportDao.CheckSummaryForThePeriodReportData(timePeriod, managers);
                    case ReportType.SummaryAtThisMoment:
                        return reportDao.CheckSummaryAtThisMomentReportData(timePeriod, managers);
                    default:
                        return false;
                }
            }
        }

        public static List<string> GetMissingRates(ReportType reportType)
        {
            using (var scope = DIHelper.Resolve())
            {
                var reportDao = scope.Resolve<DaoFactory>().ReportDao;
                if (reportType == ReportType.WorkloadByTasks || reportType == ReportType.WorkloadByInvoices ||
                    reportType == ReportType.WorkloadByContacts || reportType == ReportType.WorkloadByVoip) return null;

                return reportDao.GetMissingRates(Global.TenantSettings.DefaultCurrency.Abbreviation);
            }
        }

        private static object GetReportData(ReportType reportType, ReportTimePeriod timePeriod, Guid[] managers)
        {
            using (var scope = DIHelper.Resolve())
            {
                var reportDao = scope.Resolve<DaoFactory>().ReportDao;

                var defaultCurrency = Global.TenantSettings.DefaultCurrency.Abbreviation;

                switch (reportType)
                {
                    case ReportType.SalesByManagers:
                        return reportDao.GetSalesByManagersReportData(timePeriod, managers, defaultCurrency);
                    case ReportType.SalesForecast:
                        return reportDao.GetSalesForecastReportData(timePeriod, managers, defaultCurrency);
                    case ReportType.SalesFunnel:
                        return reportDao.GetSalesFunnelReportData(timePeriod, managers, defaultCurrency);
                    case ReportType.WorkloadByContacts:
                        return reportDao.GetWorkloadByContactsReportData(timePeriod, managers);
                    case ReportType.WorkloadByTasks:
                        return reportDao.GetWorkloadByTasksReportData(timePeriod, managers);
                    case ReportType.WorkloadByDeals:
                        return reportDao.GetWorkloadByDealsReportData(timePeriod, managers, defaultCurrency);
                    case ReportType.WorkloadByInvoices:
                        return reportDao.GetWorkloadByInvoicesReportData(timePeriod, managers);
                    case ReportType.WorkloadByVoip:
                        return reportDao.GetWorkloadByViopReportData(timePeriod, managers);
                    case ReportType.SummaryForThePeriod:
                        return reportDao.GetSummaryForThePeriodReportData(timePeriod, managers, defaultCurrency);
                    case ReportType.SummaryAtThisMoment:
                        return reportDao.GetSummaryAtThisMomentReportData(timePeriod, managers, defaultCurrency);
                    default:
                        return null;
                }
            }
        }

        private static string GetReportScript(object data, ReportType type, string fileName)
        {
            var script =
                FileHelper.ReadTextFromEmbeddedResource(string.Format("ASC.Web.CRM.ReportTemplates.{0}.docbuilder", type));

            if (string.IsNullOrEmpty(script))
                throw new Exception(CRMReportResource.BuildErrorEmptyDocbuilderTemplate);

            return script.Replace("${outputFilePath}", fileName)
                         .Replace("${reportData}", JsonConvert.SerializeObject(data));
        }

        private static void SaveReportFile(ReportState state, string url)
        {
            using (var scope = DIHelper.Resolve())
            {
                var daoFactory = scope.Resolve<DaoFactory>();
                var data = new WebClient().DownloadData(url);

                using (var stream = new MemoryStream(data))
                {
                    var document = new ASC.Files.Core.File
                    {
                        Title = state.FileName,
                        FolderID = daoFactory.FileDao.GetRoot(),
                        ContentLength = stream.Length,
                        ThumbnailStatus = Thumbnail.NotRequired,
                    };

                    var file = daoFactory.FileDao.SaveFile(document, stream);

                    daoFactory.ReportDao.SaveFile((int)file.ID, state.ReportType);
                    state.FileId = (int)file.ID;
                }
            }
        }

        public static ReportState RunGenareteReport(ReportType reportType, ReportTimePeriod timePeriod, Guid[] managers)
        {
            var reportData = GetReportData(reportType, timePeriod, managers);
            if (reportData == null)
                throw new Exception(CRMReportResource.ErrorNullReportData);

            var tmpFileName = DocbuilderReportsUtility.TmpFileName;

            var script = GetReportScript(reportData, reportType, tmpFileName);
            if (string.IsNullOrEmpty(script))
                throw new Exception(CRMReportResource.ErrorNullReportScript);

            var state = new ReportState(GetFileName(reportType), tmpFileName, script, (int)reportType, ReportOrigin.CRM, SaveReportFile, null);

            DocbuilderReportsUtility.Enqueue(state);

            return state;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/skins/default/groupselector.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.groupSelectorContainer
{
    display:none;
    position:absolute;
    z-index:99;
    width:300px;
    height:230px;
    padding: 10px;
}
.groupSelectorContainer.groupSelectorContainerMobile
{
    height: auto;
    width: auto;
}
.groupSelectorContainer .filterBox
{
    padding:2px;
}

.groupSelectorContainer .filterBox input
{
    float:left;
    width:170px;
    margin-right:10px;
}

.groupSelectorContainer .grpselector_groupList {
    display: block;
    height: 200px;
    overflow-x: hidden;
    overflow-y: auto;
    margin:10px 0px;
}
.groupSelectorContainer .grpselector_groupList .group {
    padding:4px;
    cursor:pointer;
}
.groupSelectorContainer .grpselector_groupList .group:hover
{
    background-color:#f2f2f2;
}
.groupSelectorBox {
    position: relative;
}
.groupSelectorBox .mobileSelectList {
    width: 230px;
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IO/LineReader.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IO
{
    #region usings

    using System;
    using System.IO;
    using System.Text;

    #endregion

    /// <summary>
    /// This class implements "line" reader, LF and CRLF lines are supported.
    /// </summary>
    public class LineReader : IDisposable
    {
        #region Members

        private readonly int m_BufferSize = Workaround.Definitions.MaxStreamLineLength;
        private readonly bool m_Owner;
        private readonly byte[] m_pLineBuffer;
        private readonly byte[] m_pReadBuffer;
        private readonly Stream m_pSource;
        private bool m_IsDisposed;
        private int m_OffsetInBuffer;
        private Encoding m_pCharset;
        private int m_StoredInBuffer;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get { return m_IsDisposed; }
        }

        /// <summary>
        /// Gets source stream.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public Stream Stream
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pSource;
            }
        }

        /// <summary>
        /// Gets if line reader is <b>Stream</b> owner.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public bool IsStreamOwner
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_Owner;
            }
        }

        /// <summary>
        /// Gets or sets charset to us for deocoding bytes.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when null reference is passed.</exception>
        public Encoding Charset
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pCharset;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }

                m_pCharset = value;
            }
        }

        /// <summary>
        /// Gets number of bytes in read buffer.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public int AvailableInBuffer
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_StoredInBuffer - m_OffsetInBuffer;
            }
        }

        /// <summary>
        /// Gets if line reader can synchronize source stream to actual readed data position.
        /// </summary>
        public bool CanSyncStream
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pSource.CanSeek;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stream">Stream from where to read lines.</param>
        /// <param name="owner">Specifies if <b>LineReader</b> is owner of <b>stream</b>. 
        /// <param name="bufferSize">Read buffer size, value 1 means no buffering.</param>
        /// If this value is true, closing reader will close <b>stream</b>.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null.</exception>
        public LineReader(Stream stream, bool owner, int bufferSize)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (bufferSize < 1)
            {
                throw new ArgumentException("Argument 'bufferSize' value must be >= 1.");
            }

            m_pSource = stream;
            m_Owner = owner;
            m_BufferSize = bufferSize;

            m_pReadBuffer = new byte[bufferSize];
            m_pLineBuffer = new byte[Workaround.Definitions.MaxStreamLineLength];
            m_pCharset = Encoding.UTF8;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            m_IsDisposed = true;

            if (m_Owner)
            {
                m_pSource.Dispose();
            }
        }

        /// <summary>
        /// Reads line from source stream. Returns null if end of stream(EOS) reached.
        /// </summary>
        /// <returns>Returns readed line or null if end of stream reached.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public string ReadLine()
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            int storedCount = ReadLine(m_pLineBuffer,
                                       0,
                                       m_pLineBuffer.Length,
                                       SizeExceededAction.ThrowException);
            if (storedCount == -1)
            {
                return null;
            }
            else
            {
                return m_pCharset.GetString(m_pLineBuffer, 0, storedCount);
            }
        }

        /// <summary>
        /// Reads binary line and stores it to the specified buffer.
        /// </summary>
        /// <param name="buffer">Buffer where to store line data.</param>
        /// <param name="offset">Start offset in the buffer.</param>
        /// <param name="count">Maximum number of bytes store to the buffer.</param>
        /// <param name="exceededAction">Specifies how reader acts when line buffer too small.</param>
        /// <returns>Returns number of bytes stored to <b>buffer</b> or -1 if end of stream reached.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="LineSizeExceededException">Is raised when line is bigger than <b>buffer</b> can store.</exception>
        public int ReadLine(byte[] buffer, int offset, int count, SizeExceededAction exceededAction)
        {
            int rawBytesReaded = 0;

            return ReadLine(buffer, offset, count, exceededAction, out rawBytesReaded);
        }

        /// <summary>
        /// Reads binary line and stores it to the specified buffer.
        /// </summary>
        /// <param name="buffer">Buffer where to store line data.</param>
        /// <param name="offset">Start offset in the buffer.</param>
        /// <param name="count">Maximum number of bytes store to the buffer.</param>
        /// <param name="exceededAction">Specifies how reader acts when line buffer too small.</param>
        /// <param name="rawBytesReaded">Gets raw number of bytes readed from source.</param>
        /// <returns>Returns number of bytes stored to <b>buffer</b> or -1 if end of stream reached.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="LineSizeExceededException">Is raised when line is bigger than <b>buffer</b> can store.</exception>
        public virtual int ReadLine(byte[] buffer,
                                    int offset,
                                    int count,
                                    SizeExceededAction exceededAction,
                                    out int rawBytesReaded)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0)
            {
                throw new ArgumentException("Argument 'offset' value must be >= 0.");
            }
            if (count < 0)
            {
                throw new ArgumentException("Argument 'count' value must be >= 0.");
            }
            if (buffer.Length < (count + offset))
            {
                throw new ArgumentException(
                    "Argument 'count' value is bigger than specified 'buffer' can store.");
            }

            int maxStoreCount = buffer.Length - offset;
            int storedCount = 0;
            rawBytesReaded = 0;
            bool sizeExceeded = false;
            while (true)
            {
                // No data in buffer, buffer next block.
                if (m_StoredInBuffer == m_OffsetInBuffer)
                {
                    m_OffsetInBuffer = 0;
                    m_StoredInBuffer = m_pSource.Read(m_pReadBuffer, 0, m_BufferSize);
                    // We reached end of stream, no more data.
                    if (m_StoredInBuffer == 0)
                    {
                        break;
                    }
                }

                byte currentByte = m_pReadBuffer[m_OffsetInBuffer++];
                rawBytesReaded++;
                // We have LF, we got a line.
                if (currentByte == '\n')
                {
                    break;
                }
                    // We just skip CR, because CR must be with LF, otherwise it's invalid CR.
                else if (currentByte == '\r') {}
                    // Normal byte.
                else
                {
                    // Line buffer full.
                    if (storedCount == maxStoreCount)
                    {
                        sizeExceeded = true;

                        if (exceededAction == SizeExceededAction.ThrowException)
                        {
                            throw new LineSizeExceededException();
                        }
                    }
                    else
                    {
                        buffer[offset + storedCount] = currentByte;
                        storedCount++;
                    }
                }
            }

            // Line buffer is not big enough to store whole line data.
            if (sizeExceeded)
            {
                throw new LineSizeExceededException();
            }
                // We haven't readed nothing, we are end of stream.
            else if (rawBytesReaded == 0)
            {
                return -1;
            }
            else
            {
                return storedCount;
            }
        }

        /// <summary>
        /// Sets stream position to the place we have consumed from stream and clears buffer data.
        /// For example if we have 10 byets in buffer, stream position is actually +10 bigger than 
        /// we readed, the result is that stream.Position -= 10 and buffer is cleared.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when source stream won't support seeking.</exception>
        public virtual void SyncStream()
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (!m_pSource.CanSeek)
            {
                throw new InvalidOperationException("Source stream does not support seeking, can't sync.");
            }

            if (AvailableInBuffer > 0)
            {
                m_pSource.Position -= AvailableInBuffer;
                m_OffsetInBuffer = 0;
                m_StoredInBuffer = 0;
            }
        }

        #endregion
    }
}

<|start_filename|>common/Tests/ASC.Core.Common.Tests/EmailValidationKeyPairProvider_Test.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#if DEBUG
using System;

namespace ASC.Common.Tests.Security.Cryptography
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using ASC.Security.Cryptography;
    using System.Security.Cryptography;
    using ASC.Core;

    [TestClass]
    public class EmailValidationKeyPairProvider_Test
    {
        public EmailValidationKeyPairProvider_Test()
        {
            CoreContext.TenantManager.SetCurrentTenant(1);
        }

        public void PasswordDerivedBytes_Test()
        {

            byte[] randBytes = new byte[5];
            new Random(10032010).NextBytes(randBytes);


            var tdes = new TripleDESCryptoServiceProvider();
            var pwddb = new PasswordDeriveBytes("1", new byte[] {1});
            tdes.Key = pwddb.CryptDeriveKey("TripleDES", "SHA1", 192, tdes.IV);
            //string s = Convert.ToBase64String(tdes.Key);

        }

        [TestMethod]
        public void GetEmailKey_MillisecondDistanceDifference()
        {
            var k1 = EmailValidationKeyProvider.GetEmailKey("<EMAIL>");
            System.Threading.Thread.Sleep(15);
            var k2 = EmailValidationKeyProvider.GetEmailKey("<EMAIL>");

            Assert.AreNotEqual(k1, k2);
        }

        [TestMethod]
        public void ValidateKeyImmediate()
        {
            var k1 = EmailValidationKeyProvider.GetEmailKey("<EMAIL>");
            Assert.AreEqual(EmailValidationKeyProvider.ValidateEmailKey("<EMAIL>", k1), EmailValidationKeyProvider.ValidationResult.Ok);
            Assert.AreEqual(EmailValidationKeyProvider.ValidateEmailKey("<EMAIL>", k1), EmailValidationKeyProvider.ValidationResult.Invalid);
        }

        [TestMethod]
        public void ValidateKey_Delayed()
        {
            var k1 = EmailValidationKeyProvider.GetEmailKey("<EMAIL>");
            System.Threading.Thread.Sleep(100);
            Assert.AreEqual(EmailValidationKeyProvider.ValidateEmailKey("<EMAIL>", k1, TimeSpan.FromMilliseconds(150)), EmailValidationKeyProvider.ValidationResult.Ok);
            System.Threading.Thread.Sleep(100);
            Assert.AreEqual(EmailValidationKeyProvider.ValidateEmailKey("<EMAIL>", k1, TimeSpan.FromMilliseconds(150)), EmailValidationKeyProvider.ValidationResult.Expired);
        }
    }
}

#endif

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Reports.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web;

using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Domain.Reports;

using PathProvider = ASC.Web.Projects.Classes.PathProvider;
using Report = ASC.Web.Projects.Classes.Report;

namespace ASC.Web.Projects
{
    public partial class Reports : BasePage
    {
        public List<Report> ListReports { get; private set; }
        public List<ReportTemplate> ListTemplates { get; set; }
        public int ReportsCount { get; set; }

        protected override bool CheckSecurity { get { return !Participant.IsVisitor; } }

        protected override void PageLoad()
        {
            Page.RegisterBodyScripts(PathProvider.GetFileStaticRelativePath, "reports.js");

            ReportsCount = EngineFactory.ReportEngine.Get().Count();

            var tmplId = Request["tmplId"];
            if (!string.IsNullOrEmpty(tmplId))
            {
                _content.Controls.Add(LoadControl(PathProvider.GetFileStaticRelativePath("Reports/ReportTemplateView.ascx")));
            }
            else
            {
                if (!string.IsNullOrEmpty(Request["reportType"]))
                {
                    _content.Controls.Add(LoadControl(PathProvider.GetFileStaticRelativePath("Reports/ReportView.ascx")));
                }
                else if (ReportsCount > 0)
                {
                    _content.Controls.Add(LoadControl(PathProvider.GetFileStaticRelativePath("Reports/ReportFile.ascx")));
                }
                else
                {
                    Response.Redirect("Reports.aspx?reportType=0");
                }
            }

            ListTemplates = EngineFactory.ReportEngine.GetTemplates(Participant.ID);
            SetReportList();
        }


        #region private Methods

        private void SetReportList()
        {
            var typeCount = Enum.GetValues(typeof(ReportType)).Length - 1;
            ListReports = new List<Report>();
            for (var i = 0; i < typeCount; i++)
            {
                var report = Report.CreateNewReport((ReportType)i, new TaskFilter());
                ListReports.Add(report);
            }
        }


        #endregion
    }

    public static class TemplateParamInitialiser
    {
        public static string InitHoursCombobox()
        {
            var sb = new StringBuilder();

            for (var i = 0; i < 24; i++)
            {
                var value = string.Format(i < 10 ? "0{0}:00" : "{0}:00", i);

                sb.AppendFormat(
                    i == 12
                        ? "<option value='{0}' selected='selected'>{1}</option>"
                        : "<option value='{0}' >{1}</option>", i, value);
            }

            return sb.ToString();
        }
        public static string InitDaysOfWeek()
        {
            var sb = new StringBuilder();
            var format = Thread.CurrentThread.CurrentCulture.DateTimeFormat;
            //in cron expression week day 1-7 (not 0-6)
            var firstday = (int)format.FirstDayOfWeek;
            for (var i = firstday; i < firstday + 7; i++)
            {
                sb.AppendFormat("<option value='{0}'>{1}</option>", i % 7 + 1, format.GetDayName((DayOfWeek)(i % 7)));
            }
            return sb.ToString();
        }
        public static string InitDaysOfMonth()
        {
            var sb = new StringBuilder();
            for (var i = 1; i < 32; i++)
            {
                sb.AppendFormat("<option value='{0}'>{0}</option>", i);
            }
            return sb.ToString();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/SmsControls/js/changemobile.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


;
window.ASC.Controls.UserMobilePhoneManager = (function () {
    var openDialog = function () {
        jq("#changeMobileContent").show();
        jq("#changeMobileProgress, #changeMobileResult").hide();

        StudioBlockUIManager.blockUI("#studio_mobilePhoneChangeDialog", 400);

        PopupKeyUpActionProvider.EnterAction = "jq(\"#changeMobileSend\").click();";
    };

    var sendNotify = function () {
        jq("#changeMobileContent").hide();
        jq("#changeMobileProgress").show();

        var userInfoId = jq("#hiddenUserInfoId").val();
        AjaxPro.ChangeMobileNumber.SendNotificationToChange(userInfoId, function (result) {
            if (result.error) {
                toastr.error(result.error.Message);
                PopupKeyUpActionProvider.CloseDialog();
            } else {
                if (userInfoId) {
                    jq("#changeMobileProgress").hide();
                    jq("#changeMobileResult").show();
                }

                if (result.value.length) {
                    window.location.href = result.value;
                } else {
                    window.location.reload(true);
                }
            }
        });
    };

    return {
        openDialog: openDialog,
        sendNotify: sendNotify
    };
})();

(function () {
    jq(function () {
        jq("#changeMobileSend").on("click", function () {
            ASC.Controls.UserMobilePhoneManager.sendNotify();
        });
    });
})();

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/ServerAddressDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class ServerAddressDao : BaseDao, IServerAddressDao
    {
        protected static ITable table = new MailTableFactory().Create<ServerAddressTable>();

        public ServerAddressDao(IDbManager dbManager, int tenant)
            : base(table, dbManager, tenant)
        {
        }

        public ServerAddress Get(int id)
        {
            var query = Query()
                .Where(ServerAddressTable.Columns.Tenant, Tenant)
                .Where(ServerAddressTable.Columns.Id, id);

            var address = Db.ExecuteList(query)
                .ConvertAll(ToServerAddress)
                .SingleOrDefault();

            return address;
        }

        public List<ServerAddress> GetList(List<int> ids = null)
        {
            var query = Query()
                .Where(ServerAddressTable.Columns.Tenant, Tenant);

            if (ids != null && ids.Any())
            {
                query.Where(Exp.In(ServerAddressTable.Columns.Id, ids));
            }

            var list = Db.ExecuteList(query)
                .ConvertAll(ToServerAddress);

            return list;
        }

        public List<ServerAddress> GetList(int mailboxId)
        {
            var query = Query()
                .Where(ServerAddressTable.Columns.Tenant, Tenant)
                .Where(ServerAddressTable.Columns.MailboxId, mailboxId);

            var list = Db.ExecuteList(query)
                .ConvertAll(ToServerAddress);

            return list;
        }

        public List<ServerAddress> GetGroupAddresses(int groupId)
        {
            const string m_x_a_alias = "mxa";
            const string address_alias = "msa";

            var query = Query(address_alias)
                .InnerJoin(ServerMailGroupXAddressesTable.TABLE_NAME.Alias(m_x_a_alias),
                    Exp.EqColumns(ServerMailGroupXAddressesTable.Columns.AddressId.Prefix(m_x_a_alias),
                        ServerAddressTable.Columns.Id.Prefix(address_alias)))
                .Where(ServerMailGroupXAddressesTable.Columns.MailGroupId.Prefix(m_x_a_alias), groupId)
                .Where(ServerAddressTable.Columns.Tenant.Prefix(address_alias), Tenant);

            return Db.ExecuteList(query)
                .ConvertAll(ToServerAddress);
        }

        public List<ServerAddress> GetDomainAddresses(int domainId)
        {
            var query = Query()
                .Where(ServerAddressTable.Columns.Tenant, Tenant)
                .Where(ServerAddressTable.Columns.DomainId, domainId);

            var list = Db.ExecuteList(query)
                .ConvertAll(ToServerAddress);

            return list;
        }

        public void AddAddressesToMailGroup(int groupId, List<int> addressIds)
        {
            var query = new SqlInsert(ServerMailGroupXAddressesTable.TABLE_NAME)
                .InColumns(ServerMailGroupXAddressesTable.Columns.AddressId,
                    ServerMailGroupXAddressesTable.Columns.MailGroupId);

            addressIds.ForEach(addressId => query.Values(addressId, groupId));

            Db.ExecuteNonQuery(query);
        }

        public void DeleteAddressFromMailGroup(int groupId, int addressId)
        {
            var query = new SqlDelete(ServerMailGroupXAddressesTable.TABLE_NAME)
                .Where(ServerMailGroupXAddressesTable.Columns.AddressId, addressId)
                .Where(ServerMailGroupXAddressesTable.Columns.MailGroupId, groupId);

            Db.ExecuteNonQuery(query);
        }

        public void DeleteAddressesFromMailGroup(int groupId)
        {
            var query = new SqlDelete(ServerMailGroupXAddressesTable.TABLE_NAME)
                .Where(ServerMailGroupXAddressesTable.Columns.MailGroupId, groupId);

            Db.ExecuteNonQuery(query);
        }

        public void DeleteAddressesFromAnyMailGroup(List<int> addressIds)
        {
            var query = new SqlDelete(ServerMailGroupXAddressesTable.TABLE_NAME)
                .Where(Exp.In(ServerMailGroupXAddressesTable.Columns.AddressId, addressIds));

            Db.ExecuteNonQuery(query);
        }

        public int Save(ServerAddress address)
        {
            var query = new SqlInsert(ServerAddressTable.TABLE_NAME, true)
                .InColumnValue(ServerAddressTable.Columns.Id, address.Id)
                .InColumnValue(ServerAddressTable.Columns.AddressName, address.AddressName)
                .InColumnValue(ServerAddressTable.Columns.Tenant, address.Tenant)
                .InColumnValue(ServerAddressTable.Columns.DomainId, address.DomainId)
                .InColumnValue(ServerAddressTable.Columns.MailboxId, address.MailboxId)
                .InColumnValue(ServerAddressTable.Columns.IsMailGroup, address.IsMailGroup)
                .InColumnValue(ServerAddressTable.Columns.IsAlias, address.IsAlias)
                .Identity(0, 0, true);

            if (address.Id <= 0)
            {
                query
                    .InColumnValue(ServerAddressTable.Columns.DateCreated, DateTime.UtcNow);
            }

            var id = Db.ExecuteScalar<int>(query);

            return id;
        }

        public int Delete(int id)
        {
            var query = new SqlDelete(ServerAddressTable.TABLE_NAME)
                .Where(ServerAddressTable.Columns.Tenant, Tenant)
                .Where(ServerAddressTable.Columns.Id, id);

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        public int Delete(List<int> ids)
        {
            var query = new SqlDelete(ServerAddressTable.TABLE_NAME)
                .Where(ServerAddressTable.Columns.Tenant, Tenant)
                .Where(Exp.In(ServerAddressTable.Columns.Id, ids));

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        private const string DOMAIN_ALIAS = "msd";
        private const string ADDRESS_ALIAS = "msa";

        public bool IsAddressAlreadyRegistered(string addressName, string domainName)
        {
            if (string.IsNullOrEmpty(addressName))
                throw new ArgumentNullException("addressName");

            if (string.IsNullOrEmpty(domainName))
                throw new ArgumentNullException("domainName");

            var addressQuery = new SqlQuery(ServerAddressTable.TABLE_NAME.Alias(ADDRESS_ALIAS))
                .InnerJoin(ServerDomainTable.TABLE_NAME.Alias(DOMAIN_ALIAS),
                    Exp.EqColumns(
                        ServerAddressTable.Columns.DomainId.Prefix(ADDRESS_ALIAS),
                        ServerDomainTable.Columns.Id.Prefix(DOMAIN_ALIAS))
                )
                .Select(ServerAddressTable.Columns.Id.Prefix(ADDRESS_ALIAS))
                .Where(ServerAddressTable.Columns.AddressName.Prefix(ADDRESS_ALIAS), addressName)
                .Where(Exp.In(ServerAddressTable.Columns.Tenant.Prefix(ADDRESS_ALIAS),
                    new List<int> { Tenant, Defines.SHARED_TENANT_ID }))
                .Where(ServerDomainTable.Columns.DomainName.Prefix(DOMAIN_ALIAS), domainName);

            return Db.ExecuteList(addressQuery).Any();
        }

        protected ServerAddress ToServerAddress(object[] r)
        {
            var s = new ServerAddress
            {
                Id = Convert.ToInt32(r[0]),
                AddressName = Convert.ToString(r[1]),
                Tenant = Convert.ToInt32(r[2]),
                DomainId = Convert.ToInt32(r[3]),
                MailboxId = Convert.ToInt32(r[4]),
                IsMailGroup = Convert.ToBoolean(r[5]),
                IsAlias = Convert.ToBoolean(r[6]),
                DateCreated = Convert.ToDateTime(r[7])
            };

            return s;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Classes/ProjectSecurityInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Web.Projects.Classes
{
    [DataContract(Name = "project_security", Namespace = "")]
    public class ProjectSecurityInfo
    {
        [DataMember]
        public bool CanCreateMilestone { get; set; }

        [DataMember]
        public bool CanCreateMessage { get; set; }

        [DataMember]
        public bool CanCreateTask { get; set; }

        [DataMember]
        public bool CanCreateTimeSpend { get; set; }

        [DataMember]
        public bool CanEditTeam { get; set; }

        [DataMember]
        public bool CanReadFiles { get; set; }

        [DataMember]
        public bool CanReadMilestones { get; set; }

        [DataMember]
        public bool CanReadMessages { get; set; }

        [DataMember]
        public bool CanReadTasks { get; set; }

        [DataMember]
        public bool CanLinkContact { get; set; }

        [DataMember]
        public bool CanReadContacts { get; set; }

        [DataMember]
        public bool CanEdit { get; set; }

        [DataMember]
        public bool CanDelete { get; set; }

        [DataMember]
        public bool IsInTeam { get; set; }

        public static ProjectSecurityInfo GetSample()
        {
            return new ProjectSecurityInfo();
        }
    }

    [DataContract(Name = "common_security", Namespace = "")]
    public class CommonSecurityInfo
    {
        [DataMember]
        public bool CanCreateProject { get; set; }

        [DataMember]
        public bool CanCreateTask { get; set; }

        [DataMember]
        public bool CanCreateMilestone { get; set; }

        [DataMember]
        public bool CanCreateMessage { get; set; }

        [DataMember]
        public bool CanCreateTimeSpend { get; set; }

        public CommonSecurityInfo()
        {
            var filter = new TaskFilter
            {
                SortBy = "title",
                SortOrder = true,
                ProjectStatuses = new List<ProjectStatus> { ProjectStatus.Open }
            };

            using (var scope = DIHelper.Resolve())
            {
                var projectSecurity = scope.Resolve<ProjectSecurity>();
                var engineFactory = scope.Resolve<EngineFactory>();
                var projects = engineFactory.ProjectEngine.GetByFilter(filter).ToList();

                CanCreateProject = projectSecurity.CanCreate<Project>(null);
                CanCreateTask = projects.Any(projectSecurity.CanCreate<Task>);
                CanCreateMilestone = projects.Any(projectSecurity.CanCreate<Milestone>);
                CanCreateMessage = projects.Any(projectSecurity.CanCreate<Message>);
                CanCreateTimeSpend = projects.Any(projectSecurity.CanCreate<TimeSpend>);
            }
        }
    }

    public class TaskSecurityInfo
    {
        public bool CanEdit { get; set; }

        public bool CanCreateSubtask { get; set; }

        public bool CanCreateTimeSpend { get; set; }

        public bool CanDelete { get; set; }

        public bool CanReadFiles { get; set; }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/News/Code/FeedPoll.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Collections.Generic;

using ASC.Core.Tenants;
using ASC.Web.Community.Product;

#endregion

namespace ASC.Web.Community.News.Code
{
    [Serializable]
    public class FeedPoll : Feed
    {
        public FeedPollType PollType { get; set; }

        public DateTime StartDate { get; set; }

        public DateTime EndDate { get; set; }

        public List<FeedPollVariant> Variants { get; private set; }

        internal List<FeedPollAnswer> Answers;


        public FeedPoll()
        {
            FeedType = FeedType.Poll;
            PollType = FeedPollType.SimpleAnswer;
            StartDate = TenantUtil.DateTimeNow();
            EndDate = StartDate.AddYears(100);
            Variants = new List<FeedPollVariant>();
            Answers = new List<FeedPollAnswer>();
        }

        public int GetVariantVoteCount(long variantId)
        {
            return Answers.FindAll(a => a.VariantId == variantId).Count;
        }

        public bool IsUserVote(string userId)
        {
            if (CommunitySecurity.IsOutsider()) return true;

            return Answers.Exists(a => a.UserId == userId);
        }
    }
}


<|start_filename|>module/ASC.ElasticSearch/Service/Launcher.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using System.Threading.Tasks;

using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Module;
using ASC.ElasticSearch.Service;

using Autofac;

namespace ASC.ElasticSearch
{
    public class Launcher : IServiceController
    {
        private static readonly ICacheNotify Notify = AscCache.Notify;
        private static Timer timer;
        private static TimeSpan Period { get { return TimeSpan.FromMinutes(Settings.Default.Period); } }
        private static ILog logger;
        private static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

        internal static ServiceHost Searcher { get; private set; }
        internal static bool IsStarted { get; private set; }
        internal static string Indexing { get; private set; }
        internal static DateTime? LastIndexed { get; private set; }

        public void Start()
        {
            Searcher = new ServiceHost(typeof(Service.Service));
            Searcher.Open();

            logger = LogManager.GetLogger("ASC.Indexer");

            try
            {
                Notify.Subscribe<AscCacheItem>(async (item, action) =>
                {
                    while (IsStarted)
                    {
                        await Task.Delay(10000);
                    }
                    IndexAll(true);
                });
            }
            catch (Exception e)
            {
                logger.Error("Subscribe on start", e);
            }

            var task = new Task(() =>
            {
                while (!FactoryIndexer.CheckState(false))
                {
                    if (cancellationTokenSource.IsCancellationRequested)
                    {
                        return;
                    }
                    Thread.Sleep(10000);
                }

                CheckIfChange();
            }, cancellationTokenSource.Token, TaskCreationOptions.LongRunning);

            task.ConfigureAwait(false);
            task.Start();
        }

        private static void CheckIfChange()
        {
            IsStarted = true;

            var generic = typeof(BaseIndexer<>);
            var products = FactoryIndexer.Builder.Resolve<IEnumerable<Wrapper>>()
                .Select(r => (IIndexer)Activator.CreateInstance(generic.MakeGenericType(r.GetType()), r))
                .ToList();

            products.ForEach(product =>
            {
                try
                {
                    if (!IsStarted) return;

                    logger.DebugFormat("Product check {0}", product.IndexName);
                    Indexing = product.IndexName;
                    product.Check();
                }
                catch (Exception e)
                {
                    logger.Error(e);
                    logger.ErrorFormat("Product check {0}", product.IndexName);
                }
            });

            IsStarted = false;
            Indexing = null;

            timer = new Timer(_ => IndexAll(), null, TimeSpan.Zero, TimeSpan.Zero);
        }

        private static void IndexAll(bool reindex = false)
        {
            try
            {
                timer.Change(Timeout.Infinite, Timeout.Infinite);
                IsStarted = true;

                var generic = typeof(BaseIndexer<>);
                var products = FactoryIndexer.Builder.Resolve<IEnumerable<Wrapper>>()
                    .Select(r => (IIndexer)Activator.CreateInstance(generic.MakeGenericType(r.GetType()), r))
                    .ToList();

                if (reindex)
                {
                    Parallel.ForEach(products, product =>
                    {
                        try
                        {
                            if (!IsStarted) return;

                            logger.DebugFormat("Product reindex {0}", product.IndexName);
                            product.ReIndex();
                        }
                        catch (Exception e)
                        {
                            logger.Error(e);
                            logger.ErrorFormat("Product reindex {0}", product.IndexName);
                        }
                    });
                }

                Parallel.ForEach(products, product =>
                {
                    try
                    {
                        if (!IsStarted) return;

                        logger.DebugFormat("Product {0}", product.IndexName);
                        Indexing = product.IndexName;
                        product.IndexAll();
                    }
                    catch (Exception e)
                    {
                        logger.Error(e);
                        logger.ErrorFormat("Product {0}", product.IndexName);
                    }
                });

                timer.Change(Period, Period);
                LastIndexed = DateTime.UtcNow;
                IsStarted = false;
                Indexing = null;
            }
            catch (Exception e)
            {
                logger.Fatal("IndexAll", e);
                throw;
            }

        }

        public void Stop()
        {
            logger.Debug("Stop");

            if (Searcher != null)
            {
                Searcher.Close();
                Searcher = null;
            }

            IsStarted = false;

            if (timer != null)
            {
                timer.Dispose();
            }

            cancellationTokenSource.Cancel();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Photos.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web.UI;

using ASC.Api;
using ASC.Web.Studio;
using ASC.Web.Studio.Core;

#endregion

namespace ASC.Web.Community
{
    public partial class Photos : MainPage
    {
        protected ApiServer apiServer = new ApiServer();

        protected void Page_Load(object sender, EventArgs e)
        {
            PublishRecentUploadPhotos("recentPhotos");
            PublishAllAlbumInfo("");
            PublishAlbumsPhotos("", Enumerable.Empty<int>());

            // Page.JsonPublisher(contactsForFirstRequest, "contactsForFirstRequest");

        }

        protected String PublishRecentUploadPhotos(String publishByName)
        {
            var apiResponse = apiServer.GetApiResponse(
                String.Format("{0}crm/contact/filter.json?{1}", SetupInfo.WebApiBaseUrl, ""), "GET");

            JsonPublisher(apiResponse, publishByName);

            return apiResponse;
        }

        protected String PublishAllAlbumInfo(String publishByName)
        {
            var apiResponse = apiServer.GetApiResponse(String.Format("{0}files/@photos", SetupInfo.WebApiBaseUrl), "GET");

            JsonPublisher(apiResponse, publishByName);

            return apiResponse;
        }

        protected String PublishAlbumsPhotos(String publishByName, IEnumerable<int> albumIDs)
        {

            throw new NotImplementedException();
        }

        protected void JsonPublisher<T>(T data, String jsonClassName) where T : class
        {

            String json;

            using (var stream = new MemoryStream())
            {

                var serializer = new DataContractJsonSerializer(typeof(T));

                serializer.WriteObject(stream, data);

                json = Encoding.UTF8.GetString(stream.ToArray());
            }

            Page.ClientScript.RegisterClientScriptBlock(GetType(),
                                                       Guid.NewGuid().ToString(),
                                                        String.Format(" var {1} = {0};", json, jsonClassName),
                                                        true);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Controls/ChunkUploadDialog/ChunkUploadDialog.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using System.Web.UI;

using ASC.Web.Files.Classes;
using ASC.Web.Studio.Core.Quota;

namespace ASC.Web.Files.Controls
{
    public partial class ChunkUploadDialog : UserControl
    {
        public static string Location
        {
            get { return PathProvider.GetFileControlPath("ChunkUploadDialog/ChunkUploadDialog.ascx"); }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            InitScripts();
        }

        private void InitScripts()
        {
            var tenantQuota = GetQuotaString();

            var inlineScript = new StringBuilder();

            inlineScript.AppendFormat("ASC.Files.ChunkUploads.init({0});", tenantQuota);

            Page.RegisterInlineScript(inlineScript.ToString());
        }

        private static string GetQuotaString()
        {
            var quota = QuotaWrapper.GetCurrent();

            using (var ms = new MemoryStream())
            {
                var serializer = new DataContractJsonSerializer(typeof(QuotaWrapper));
                serializer.WriteObject(ms, quota);
                ms.Seek(0, SeekOrigin.Begin);

                return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/UserControls/Common/PageLocation.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Web.UserControls.Forum.Common
{
    public enum ForumPage
    {
        Default,
        TopicList,
        PostList,
        NewPost,
        EditTopic,
        Search,
        UserProfile,
        ManagementCenter
    }

    public class PageLocation : ICloneable
    {
        public ForumPage Page { get; set; }
        public string Url { get; set; }

        public PageLocation(ForumPage page, string url)
        {
            this.Page = page;
            this.Url = url;
        }

        #region ICloneable Members

        public object Clone()
        {
            return new PageLocation(this.Page, this.Url);
        }

        #endregion
    }
}


<|start_filename|>common/ASC.Core.Common/Notify/Push/Enums.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

namespace ASC.Core.Common.Notify.Push
{
    [DataContract]
    public enum PushAction
    {
        [EnumMember]
        Unknown,

        [EnumMember]
        Created,

        [EnumMember]
        Assigned,

        [EnumMember]
        InvitedTo,

        [EnumMember]
        Closed,

        [EnumMember]
        Resumed,

        [EnumMember]
        Deleted
    }

    [DataContract]
    public enum PushItemType
    {
        [EnumMember]
        Unknown,

        [EnumMember]
        Task,

        [EnumMember]
        Subtask,

        [EnumMember]
        Milestone,

        [EnumMember]
        Project,

        [EnumMember]
        Message
    }

    [DataContract]
    public enum PushModule
    {
        [EnumMember]
        Unknown,

        [EnumMember]
        Projects
    }

    [DataContract]
    public enum MobileAppType
    {
        [EnumMember]
        IosProjects = 0,

        [EnumMember]
        AndroidProjects = 1,

        [EnumMember]
        IosDocuments = 2,

        [EnumMember]
        AndroidDocuments = 3,

        [EnumMember]
        DesktopEditor = 4
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Data/IBlogDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Blogs.Core.Domain;

namespace ASC.Blogs.Core.Data
{
    public interface IPostDao
    {
        List<Post> Select(Guid? id, long? blogId, Guid? userId, string tag, bool withContent, bool asc, int? from, int? count, bool fillTags, bool withCommentsCount);

        List<Post> Select(Guid? id, long? blogId, Guid? userId, bool withContent, bool asc, int? from, int? count, bool fillTags, bool withCommentsCount);

        List<Post> Select(Guid? id, long? blogId, Guid? userId, bool withContent, bool fillTags, bool withCommentsCount);

        List<Post> GetPosts(List<Guid> ids, bool withContent, bool withTags);
        List<Post> GetPosts(List<int> ids, bool withContent, bool withTags);

        List<int> SearchPostsByWord(string word);

        void SavePost(Post post);
        void DeletePost(Guid postId);

        int GetCount(Guid? id, long? blogId, Guid? userId, string tag);

        List<Comment> GetComments(Guid postId);
        Comment GetCommentById(Guid commentId);
        List<int> GetCommentsCount(List<Guid> postsIds);

        void SaveComment(Comment comment);

        List<TagStat> GetTagStat(int? top);
        List<string> GetTags(string like, int limit);

        void SavePostReview(Guid userId, Guid postId, DateTime datetime);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Test/DataGenerator.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Projects.Core.Domain;
using ASC.Web.Core;

using AutoFixture;
using AutoFixture.Dsl;

namespace ASC.Web.Projects.Test
{
    public class DataGenerator
    {
        private List<Guid> Users { get; set; }
        private Fixture Fixture { get; set; }

        public DataGenerator()
        {
            WebItemManager.Instance.LoadItems();
            CoreContext.TenantManager.SetCurrentTenant(0);
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            SecurityContext.AuthenticateMe(tenant.OwnerId);
            Users = CoreContext.UserManager.GetUsers().Select(r => r.ID).ToList();
            Fixture = new Fixture();
        }

        private IPostprocessComposer<Project> GetProjectBuilder(Guid responsibleID)
        {
            return Fixture.Build<Project>()
                .Without(p => p.ID)
                .With(p => p.Private, false)
                .With(p => p.CreateBy, responsibleID)
                .With(p => p.CreateOn, DateTime.UtcNow)
                .With(p => p.Responsible, responsibleID)
                .With(p => p.Status, ProjectStatus.Open);
        }

        private IPostprocessComposer<Milestone> GetMilestoneBuilder(Project project)
        {
            return Fixture.Build<Milestone>()
                .Without(t => t.ID)
                .With(t => t.Project, project)
                .With(t => t.CreateBy, project.Responsible)
                .With(t => t.CreateOn, DateTime.UtcNow)
                .With(t => t.Status, MilestoneStatus.Open);
        }

        private IPostprocessComposer<Message> GetMessageBuilder(Project project)
        {
            return Fixture.Build<Message>()
                .Without(t => t.ID)
                .With(t => t.Project, project)
                .With(t => t.CreateOn, DateTime.UtcNow)
                .With(t => t.Status, MessageStatus.Open);
        }

        private IPostprocessComposer<Task> GetTaskBuilder(Project project)
        {
            return Fixture.Build<Task>()
                .Without(t => t.ID)
                .With(t => t.Project, project)
                .With(t => t.Status, TaskStatus.Open)
                .With(t => t.CreateOn, DateTime.UtcNow)
                .With(t => t.Links, new List<TaskLink>())
                .With(t => t.SubTasks, new List<Subtask>())
                .With(p => p.Responsibles, new List<Guid>());
        }

        private IPostprocessComposer<Subtask> GetSubTaskBuilder(Task task)
        {
            return Fixture.Build<Subtask>()
                .Without(t => t.ID)
                .With(t => t.Task, task.ID)
                .With(t => t.ParentTask, task)
                .With(t => t.Status, TaskStatus.Open)
                .With(t => t.CreateOn, DateTime.UtcNow);
        }

        private IPostprocessComposer<TimeSpend> GetTimeTrackingBuilder(Task task)
        {
            return Fixture.Build<TimeSpend>()
                .Without(t => t.ID)
                .With(t => t.Task, task)
                .With(t => t.Person, SecurityContext.CurrentAccount.ID)
                .With(t => t.CreateOn, DateTime.UtcNow)
                .With(t => t.PaymentStatus, PaymentStatus.NotChargeable);
        }

        public Project GenerateProject(Guid responsibleID)
        {
            return GetProjectBuilder(responsibleID).Create();
        }

        public Task GenerateTask(Project project)
        {
            return GetTaskBuilder(project).Create();
        }

        public Subtask GenerateSubtask(Task task)
        {
            return GetSubTaskBuilder(task).Create();
        }

        public Milestone GenerateMilestone(Project project)
        {
            return GetMilestoneBuilder(project).Create();
        }

        public Message GenerateMessage(Project project)
        {
            return GetMessageBuilder(project).Create();
        }

        public TimeSpend GenerateTimeTracking(Task task)
        {
            return GetTimeTrackingBuilder(task).Create();
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailSieveFilterActionData.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Mail.Enums.Filter;

namespace ASC.Mail.Data.Contracts
{
    [Serializable]
    [DataContract(Namespace = "", Name = "FilterAction")]
    public class MailSieveFilterActionData : IEquatable<MailSieveFilterActionData>
    {
        [DataMember(IsRequired = true, Name = "action")]
        public ActionType Action { get; set; }

        [DataMember(IsRequired = false, Name = "data")]
        public string Data { get; set; }

        public bool Equals(MailSieveFilterActionData other)
        {
            if (other == null) return false;

            return Action == other.Action && Data.Equals(other.Data);
        }

        public override int GetHashCode()
        {
            return Action.GetHashCode() ^ (Data ?? "").GetHashCode();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Entities/Filter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ASC.CRM.Core.Dao;
using ASC.Web.CRM.Classes;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using EnumExtension = ASC.Web.CRM.Classes.EnumExtension;

#endregion

namespace ASC.CRM.Core.Entities
{
    public abstract class FilterObject
    {
        public string SortBy { get; set; }
        public string SortOrder { get; set; }
        public string FilterValue { get; set; }

        public bool IsAsc
        {
            get
            {
                return !String.IsNullOrEmpty(SortOrder) && SortOrder != "descending";
            }
        }

        public abstract ICollection GetItemsByFilter(DaoFactory daofactory);
    }

    public class CasesFilterObject : FilterObject
    {
        public bool? IsClosed { get; set; }
        public List<string> Tags { get; set; }

        public CasesFilterObject()
        {
            SortBy = "title";
            SortOrder = "ascending";
        }

        public CasesFilterObject(string base64String)
        {
            if (string.IsNullOrEmpty(base64String)) return;

            var json = Encoding.UTF8.GetString(Convert.FromBase64String(base64String));

            var jsonArray = json.Split(';');

            foreach (var filterItem in jsonArray)
            {
                var filterObj = JObject.Parse(filterItem);

                var paramString = filterObj.Value<string>("params");

                if (string.IsNullOrEmpty(paramString)) continue;

                var filterParam = JObject.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(paramString)));

                switch (filterObj.Value<string>("id"))
                {
                    case "sorter":
                        SortBy = filterParam.Value<string>("id");
                        SortOrder = filterParam.Value<string>("sortOrder");
                        break;

                    case "text":
                        FilterValue = filterParam.Value<string>("value");
                        break;

                    case "closed":
                    case "opened":
                        IsClosed = filterParam.Value<bool>("value");
                        break;

                    case "tags":
                        Tags = filterParam.Value<JArray>("value").ToList().ConvertAll(n => n.ToString());
                        break;
                }
            }
        }

        public override ICollection GetItemsByFilter(DaoFactory daofactory)
        {
            SortedByType sortBy;
            if (!EnumExtension.TryParse(SortBy, true, out sortBy))
            {
                sortBy = SortedByType.Title;
            }

            return daofactory.CasesDao.GetCases(
                FilterValue,
                0,
                IsClosed,
                Tags,
                0, 0,
                new OrderBy(sortBy, IsAsc));
        }
    }

    public class TaskFilterObject : FilterObject
    {
        public int CategoryId { get; set; }
        public int ContactId { get; set; }
        public Guid ResponsibleId { get; set; }
        public bool? IsClosed { get; set; }
        public DateTime FromDate { get; set; }
        public DateTime ToDate { get; set; }

        public TaskFilterObject()
        {
            IsClosed = null;
            FromDate = DateTime.MinValue;
            ToDate = DateTime.MinValue;
            SortBy = "deadline";
            SortOrder = "ascending";
        }

        public TaskFilterObject(string base64String)
        {
            if (string.IsNullOrEmpty(base64String)) return;

            var json = Encoding.UTF8.GetString(Convert.FromBase64String(base64String));

            var jsonArray = json.Split(';');

            foreach (var filterItem in jsonArray)
            {
                var filterObj = JObject.Parse(filterItem);

                var paramString = filterObj.Value<string>("params");

                if (string.IsNullOrEmpty(paramString)) continue;

                var filterParam = Global.JObjectParseWithDateAsString(Encoding.UTF8.GetString(Convert.FromBase64String(paramString)));

                switch (filterObj.Value<string>("id"))
                {
                    case "sorter":
                        SortBy = filterParam.Value<string>("id");
                        SortOrder = filterParam.Value<string>("sortOrder");
                        break;

                    case "text":
                        FilterValue = filterParam.Value<string>("value");
                        break;

                    case "my":
                    case "responsibleID":
                        ResponsibleId = new Guid(filterParam.Value<string>("value"));
                        break;

                    case "overdue":
                    case "today":
                    case "theNext":
                        var valueString = filterParam.Value<string>("value");
                        var fromToArray = JsonConvert.DeserializeObject<List<string>>(valueString);
                        if (fromToArray.Count != 2) continue;
                        FromDate = !String.IsNullOrEmpty(fromToArray[0])
                                              ? Global.ApiDateTimeParse(fromToArray[0]) : DateTime.MinValue;
                        ToDate = !String.IsNullOrEmpty(fromToArray[1])
                                            ? Global.ApiDateTimeParse(fromToArray[1]) : DateTime.MinValue;
                        break;

                    case "fromToDate":
                        FromDate = filterParam.Value<DateTime>("from");
                        ToDate = (filterParam.Value<DateTime>("to")).AddDays(1).AddSeconds(-1);
                        break;

                    case "categoryID":
                        CategoryId = filterParam.Value<int>("value");
                        break;

                    case "openTask":
                    case "closedTask":
                        IsClosed = filterParam.Value<bool>("value");
                        break;

                    case "contactID":
                        ContactId = filterParam.Value<int>("id");
                        break;
                }
            }
        }

        public override ICollection GetItemsByFilter(DaoFactory daofactory)
        {
            TaskSortedByType sortBy;
            if (!EnumExtension.TryParse(SortBy, true, out sortBy))
            {
                sortBy = TaskSortedByType.DeadLine;
            }

            return daofactory.TaskDao.GetTasks(
                FilterValue,
                ResponsibleId,
                CategoryId,
                IsClosed,
                FromDate,
                ToDate,
                ContactId > 0 ? EntityType.Contact : EntityType.Any,
                ContactId,
                0, 0,
                new OrderBy(sortBy, IsAsc));
        }
    }

    public class DealFilterObject : FilterObject
    {
        public Guid ResponsibleId { get; set; }
        public String StageType { get; set; }
        public int OpportunityStageId { get; set; }
        public DateTime FromDate { get; set; }
        public DateTime ToDate { get; set; }
        public int ContactId { get; set; }
        public bool? ContactAlsoIsParticipant { get; set; }
        public List<string> Tags { get; set; }

        public DealFilterObject()
        {
            ContactAlsoIsParticipant = null;
            FromDate = DateTime.MinValue;
            ToDate = DateTime.MinValue;
            SortBy = "stage";
            SortOrder = "ascending";
        }

        public DealFilterObject(string base64String)
        {
            if (string.IsNullOrEmpty(base64String)) return;

            var json = Encoding.UTF8.GetString(Convert.FromBase64String(base64String));

            var jsonArray = json.Split(';');

            foreach (var filterItem in jsonArray)
            {
                var filterObj = JObject.Parse(filterItem);

                var paramString = filterObj.Value<string>("params");

                if (string.IsNullOrEmpty(paramString)) continue;

                var filterParam = Global.JObjectParseWithDateAsString(Encoding.UTF8.GetString(Convert.FromBase64String(paramString)));

                switch (filterObj.Value<string>("id"))
                {
                    case "sorter":
                        SortBy = filterParam.Value<string>("id");
                        SortOrder = filterParam.Value<string>("sortOrder");
                        break;

                    case "text":
                        FilterValue = filterParam.Value<string>("value");
                        break;

                    case "my":
                    case "responsibleID":
                        ResponsibleId = new Guid(filterParam.Value<string>("value"));
                        break;

                    case "stageTypeOpen":
                    case "stageTypeClosedAndWon":
                    case "stageTypeClosedAndLost":
                        StageType = filterParam.Value<string>("value");
                        break;

                    case "opportunityStagesID":
                        OpportunityStageId = filterParam.Value<int>("value");
                        break;

                    case "lastMonth":
                    case "yesterday":
                    case "today":
                    case "thisMonth":
                        var valueString = filterParam.Value<string>("value");
                        var fromToArray = JsonConvert.DeserializeObject<List<string>>(valueString);
                        if (fromToArray.Count != 2) continue;
                        FromDate = Global.ApiDateTimeParse(fromToArray[0]);
                        ToDate = Global.ApiDateTimeParse(fromToArray[1]);
                        break;

                    case "fromToDate":
                        FromDate = Global.ApiDateTimeParse(filterParam.Value<string>("from"));
                        ToDate = Global.ApiDateTimeParse(filterParam.Value<string>("to"));
                        break;

                    case "participantID":
                        ContactId = filterParam.Value<int>("id");
                        ContactAlsoIsParticipant = true;
                        break;

                    case "contactID":
                        ContactId = filterParam.Value<int>("id");
                        ContactAlsoIsParticipant = false;
                        break;

                    case "tags":
                        Tags = filterParam.Value<JArray>("value").ToList().ConvertAll(n => n.ToString());
                        break;
                }
            }

        }

        public override ICollection GetItemsByFilter(DaoFactory daofactory)
        {
            DealSortedByType sortBy;
            EnumExtension.TryParse(SortBy, true, out sortBy);

            DealMilestoneStatus? stageType = null;
            DealMilestoneStatus stage;
            if (EnumExtension.TryParse(StageType, true, out stage))
            {
                stageType = stage;
            }

            return daofactory.DealDao.GetDeals(
                FilterValue,
                ResponsibleId,
                OpportunityStageId,
                Tags,
                ContactId,
                stageType,
                ContactAlsoIsParticipant,
                FromDate,
                ToDate,
                0, 0,
                new OrderBy(sortBy, IsAsc));
        }
    }

    public class ContactFilterObject : FilterObject
    {
        public List<string> Tags { get; set; }
        public string ContactListView { get; set; }
        public int ContactStage { get; set; }
        public int ContactType { get; set; }
        public Guid? ResponsibleId { get; set; }
        public bool? IsShared { get; set; }
        public DateTime FromDate { get; set; }
        public DateTime ToDate { get; set; }

        public ContactFilterObject()
        {
            FromDate = DateTime.MinValue;
            ToDate = DateTime.MinValue;
            ResponsibleId = null;
            ContactStage = -1;
            ContactType = -1;
            SortBy = "created";
            SortOrder = "descending";
        }

        public ContactFilterObject(string base64String)
        {
            ContactStage = -1;
            ContactType = -1;

            if (string.IsNullOrEmpty(base64String)) return;

            var json = Encoding.UTF8.GetString(Convert.FromBase64String(base64String));

            var jsonArray = json.Split(';');

            foreach (var filterItem in jsonArray)
            {
                var filterObj = JObject.Parse(filterItem);

                var paramString = filterObj.Value<string>("params");

                if (string.IsNullOrEmpty(paramString)) continue;

                var filterParam = Global.JObjectParseWithDateAsString(Encoding.UTF8.GetString(Convert.FromBase64String(paramString)));

                switch (filterObj.Value<string>("id"))
                {
                    case "sorter":
                        SortBy = filterParam.Value<string>("id");
                        SortOrder = filterParam.Value<string>("sortOrder");
                        break;

                    case "text":
                        FilterValue = filterParam.Value<string>("value");
                        break;

                    case "my":
                    case "responsibleID":
                    case "noresponsible":
                        ResponsibleId = new Guid(filterParam.Value<string>("value"));
                        break;

                    case "tags":
                        Tags = filterParam.Value<JArray>("value").ToList().ConvertAll(n => n.ToString());
                        break;

                    case "withopportunity":
                    case "person":
                    case "company":
                        ContactListView = filterParam.Value<string>("value");
                        break;

                    case "contactType":
                        ContactType = filterParam.Value<int>("value");
                        break;

                    case "contactStage":
                        ContactStage = filterParam.Value<int>("value");
                        break;

                    case "lastMonth":
                    case "yesterday":
                    case "today":
                    case "thisMonth":
                        var valueString = filterParam.Value<string>("value");
                        var fromToArray = JsonConvert.DeserializeObject<List<string>>(valueString);
                        if (fromToArray.Count != 2) continue;
                        FromDate = Global.ApiDateTimeParse(fromToArray[0]);
                        ToDate = Global.ApiDateTimeParse(fromToArray[1]);
                        break;

                    case "fromToDate":
                        FromDate = Global.ApiDateTimeParse(filterParam.Value<string>("from"));
                        ToDate = Global.ApiDateTimeParse(filterParam.Value<string>("to"));
                        break;

                    case "restricted":
                    case "shared":
                        IsShared = filterParam.Value<bool>("value");
                        break;
                }
            }
        }

        public override ICollection GetItemsByFilter(DaoFactory daofactory)
        {
            ContactSortedByType sortBy;
            if (!EnumExtension.TryParse(SortBy, true, out sortBy))
            {
                sortBy = ContactSortedByType.Created;
            }

            ContactListViewType contactListViewType;
            EnumExtension.TryParse(ContactListView, true, out contactListViewType);

            return daofactory.ContactDao.GetContacts(
                FilterValue,
                Tags,
                ContactStage,
                ContactType,
                contactListViewType,
                FromDate,
                ToDate,
                0,
                0,
                new OrderBy(sortBy, IsAsc),
                ResponsibleId,
                IsShared);
        }
    };

    public class InvoiceItemFilterObject : FilterObject
    {
        public bool? InventoryStock { get; set; }

        public InvoiceItemFilterObject()
        {
            InventoryStock = null;
            SortBy = "name";
            SortOrder = "ascending";
        }

        public InvoiceItemFilterObject(string base64String)
        {
            if (string.IsNullOrEmpty(base64String)) return;

            var json = Encoding.UTF8.GetString(Convert.FromBase64String(base64String));

            var jsonArray = json.Split(';');

            foreach (var filterItem in jsonArray)
            {
                var filterObj = JObject.Parse(filterItem);

                var paramString = filterObj.Value<string>("params");

                if (string.IsNullOrEmpty(paramString)) continue;

                var filterParam = JObject.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(paramString)));

                switch (filterObj.Value<string>("id"))
                {
                    case "sorter":
                        SortBy = filterParam.Value<string>("id");
                        SortOrder = filterParam.Value<string>("sortOrder");
                        break;

                    case "text":
                        FilterValue = filterParam.Value<string>("value");
                        break;

                    case "withInventoryStock":
                    case "withoutInventoryStock":
                        InventoryStock = filterParam.Value<bool>("value");
                        break;
                }
            }

        }

        public override ICollection GetItemsByFilter(DaoFactory daofactory)
        {
            InvoiceItemSortedByType sortBy;
            EnumExtension.TryParse(SortBy, true, out sortBy);

            return daofactory.InvoiceItemDao.GetInvoiceItems(
                FilterValue,
                0,
                InventoryStock,
                0, 0,
                new OrderBy(sortBy, IsAsc));
        }
    }
}

<|start_filename|>module/ASC.CdnCheck/Controllers/CdnController.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Linq;
using System.Web;
using System.Web.Http;

namespace ASC.CdnCheck.Controllers
{
    public class CdnController : ApiController
    {
        [HttpGet]
        public void Error(int status, string url)
        {
            var logger = log4net.LogManager.GetLogger("ASC");
            logger.Debug("");
            logger.DebugFormat("status:{0}", status);

            foreach (var header in Request.Headers)
            {
                logger.DebugFormat("{0}: {1}", header.Key, header.Value.Aggregate((a,b)=> string.Format("{0},{1}",a,b)));
            }

            logger.DebugFormat("host address {0}", HttpContext.Current.Request.UserHostAddress);
            logger.DebugFormat("host name {0}", HttpContext.Current.Request.UserHostName);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Resources/CRMCasesResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.CRM.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class CRMCasesResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal CRMCasesResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.CRM.Resources.CRMCasesResource", typeof(CRMCasesResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save and Create New Case.
        /// </summary>
        public static string AddThisAndCreateCaseButton {
            get {
                return ResourceManager.GetString("AddThisAndCreateCaseButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All Cases.
        /// </summary>
        public static string AllCases {
            get {
                return ResourceManager.GetString("AllCases", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case.
        /// </summary>
        public static string Case {
            get {
                return ResourceManager.GetString("Case", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The permissions will be set to the cases where you are the author.
        /// </summary>
        public static string CasesAccessRightsLimit {
            get {
                return ResourceManager.GetString("CasesAccessRightsLimit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Status.
        /// </summary>
        public static string CasesByStatus {
            get {
                return ResourceManager.GetString("CasesByStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case Participant.
        /// </summary>
        public static string CasesParticipant {
            get {
                return ResourceManager.GetString("CasesParticipant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case Participants.
        /// </summary>
        public static string CasesParticipants {
            get {
                return ResourceManager.GetString("CasesParticipants", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case Tag.
        /// </summary>
        public static string CasesTag {
            get {
                return ResourceManager.GetString("CasesTag", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case Tag List.
        /// </summary>
        public static string CasesTagList {
            get {
                return ResourceManager.GetString("CasesTagList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Status.
        /// </summary>
        public static string CaseStatus {
            get {
                return ResourceManager.GetString("CaseStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case title.
        /// </summary>
        public static string CaseTitle {
            get {
                return ResourceManager.GetString("CaseTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close case.
        /// </summary>
        public static string CloseCase {
            get {
                return ResourceManager.GetString("CloseCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creating case....
        /// </summary>
        public static string CreateCaseProggress {
            get {
                return ResourceManager.GetString("CreateCaseProggress", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create the first case.
        /// </summary>
        public static string CreateFirstCase {
            get {
                return ResourceManager.GetString("CreateFirstCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new case.
        /// </summary>
        public static string CreateNewCase {
            get {
                return ResourceManager.GetString("CreateNewCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string CreateThisCaseButton {
            get {
                return ResourceManager.GetString("CreateThisCaseButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete case.
        /// </summary>
        public static string DeleteThisCase {
            get {
                return ResourceManager.GetString("DeleteThisCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deleting cases.
        /// </summary>
        public static string DeletingCases {
            get {
                return ResourceManager.GetString("DeletingCases", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit case.
        /// </summary>
        public static string EditCase {
            get {
                return ResourceManager.GetString("EditCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit the «{0}» case.
        /// </summary>
        public static string EditCaseHeader {
            get {
                return ResourceManager.GetString("EditCaseHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cases allow you to keep in one and the same place all the correspondence history, assign tasks, upload documents for the contacts who take part in a common event. For instance, it can be a team training or exhibition organization..
        /// </summary>
        public static string EmptyContentCasesDescribe {
            get {
                return ResourceManager.GetString("EmptyContentCasesDescribe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No cases matching your filter can be displayed in this section. Please select other filter options or clear filter to view all the cases in this section. Or you can create the case if it is absent from the list..
        /// </summary>
        public static string EmptyContentCasesFilterDescribe {
            get {
                return ResourceManager.GetString("EmptyContentCasesFilterDescribe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No cases to be displayed for this filter here.
        /// </summary>
        public static string EmptyContentCasesFilterHeader {
            get {
                return ResourceManager.GetString("EmptyContentCasesFilterHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The case list is empty.
        /// </summary>
        public static string EmptyContentCasesHeader {
            get {
                return ResourceManager.GetString("EmptyContentCasesHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The participant list is empty.
        /// </summary>
        public static string EmptyPeopleInCaseContent {
            get {
                return ResourceManager.GetString("EmptyPeopleInCaseContent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add participants to your case from the list of companies or persons. After this is done you will know who is going to take part in the upcoming events associated with this case..
        /// </summary>
        public static string EmptyPeopleInCaseDescript {
            get {
                return ResourceManager.GetString("EmptyPeopleInCaseDescript", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Import cases.
        /// </summary>
        public static string ImportCases {
            get {
                return ResourceManager.GetString("ImportCases", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to A properly formed CSV file should be selected on your computer HDD. It must contain the fields or columns separated by the selected delimiter which will be used to import cases. The files containing more than {0} rows should be divided into smaller parts for proper importing. Make sure you selected the portal users who need to be granted access to the information to be imported, otherwise the data from the CSV file will be available to all portal users..
        /// </summary>
        public static string ImportFromCSVStepOneDescription {
            get {
                return ResourceManager.GetString("ImportFromCSVStepOneDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select a CSV file and set access rights before you import cases.
        /// </summary>
        public static string ImportFromCSVStepOneHeader {
            get {
                return ResourceManager.GetString("ImportFromCSVStepOneHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Match your file columns with the corresponding ONLYOFFICE™ CRM fields. Please pay your attention to the fact that to import cases correctly you need to have at least one column from your file matched with the &apos;Case Title&apos; field of the ONLYOFFICE™ CRM. The fields containing the dates must have the following format: {0}..
        /// </summary>
        public static string ImportFromCSVStepTwoDescription {
            get {
                return ResourceManager.GetString("ImportFromCSVStepTwoDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, verify the fields.
        /// </summary>
        public static string ImportFromCSVStepTwoHeader {
            get {
                return ResourceManager.GetString("ImportFromCSVStepTwoHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to cases list.
        /// </summary>
        public static string ImportStartingPanelButton {
            get {
                return ResourceManager.GetString("ImportStartingPanelButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Import of  cases can take several minutes depending on the amount of your data..
        /// </summary>
        public static string ImportStartingPanelDescription {
            get {
                return ResourceManager.GetString("ImportStartingPanelDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Importing started.
        /// </summary>
        public static string ImportStartingPanelHeader {
            get {
                return ResourceManager.GetString("ImportStartingPanelHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Case participants.
        /// </summary>
        public static string MembersCase {
            get {
                return ResourceManager.GetString("MembersCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open case.
        /// </summary>
        public static string OpenCase {
            get {
                return ResourceManager.GetString("OpenCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Participants.
        /// </summary>
        public static string PeopleInCase {
            get {
                return ResourceManager.GetString("PeopleInCase", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Restrict access to the case.
        /// </summary>
        public static string PrivatePanelCheckBoxLabel {
            get {
                return ResourceManager.GetString("PrivatePanelCheckBoxLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save Changes.
        /// </summary>
        public static string SaveChanges {
            get {
                return ResourceManager.GetString("SaveChanges", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to profile.
        /// </summary>
        public static string ShowCaseProfile {
            get {
                return ResourceManager.GetString("ShowCaseProfile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open in a new tab.
        /// </summary>
        public static string ShowCaseProfileNewTab {
            get {
                return ResourceManager.GetString("ShowCaseProfileNewTab", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Start Importing.
        /// </summary>
        public static string StartImport {
            get {
                return ResourceManager.GetString("StartImport", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All cases.
        /// </summary>
        public static string TotalCases {
            get {
                return ResourceManager.GetString("TotalCases", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/Attachments/Attachments.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Web;
using System.Web.UI;

using ASC.Web.Core.Files;
using ASC.Web.Studio.Controls.Common;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Common.Attachments
{
    public partial class Attachments : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Common/Attachments/Attachments.ascx"; }
        }

        public string MenuNewDocument { get; set; }

        public string MenuUploadFile { get; set; }

        public string ModuleName { get; set; }

        public string EntityType { get; set; }

        public bool CanAddFile { get; set; }

        public bool EmptyScreenVisible { get; set; }

        protected string HelpLink { get; set; }

        protected string ExtsWebPreviewed = string.Join(", ", FileUtility.ExtsWebPreviewed.ToArray());
        protected string ExtsWebEdited = string.Join(", ", FileUtility.ExtsWebEdited.ToArray());

        protected static bool EnableAsUploaded
        {
            get { return FileUtility.ExtsMustConvert.Any() && !string.IsNullOrEmpty(FilesLinkUtility.DocServiceConverterUrl); }
        }

        public Attachments()
        {
            EmptyScreenVisible = true;
            MenuNewDocument = UserControlsCommonResource.NewFile;
            MenuUploadFile = UserControlsCommonResource.UploadFile;

            EntityType = "";
            ModuleName = "";
            CanAddFile = true;
        }

        private void InitScripts()
        {
            Page.RegisterStyle("~/UserControls/Common/Attachments/css/attachments.less")
                .RegisterBodyScripts("~/UserControls/Common/Attachments/js/attachments.js");
        }

        private void CreateEmptyPanel()
        {
            var buttons = "<a id='uploadFirstFile' class='baseLinkAction'>" + MenuUploadFile + "</a><br/>" +
                          "<a id='createFirstDocument' class='baseLinkAction'>" + MenuNewDocument + "</a>" +
                          "<span class='sort-down-black newDocComb'></span>";

            var emptyParticipantScreenControl = new EmptyScreenControl
            {
                ImgSrc = VirtualPathUtility.ToAbsolute("~/UserControls/Common/Attachments/images/documents-logo.png"),
                Header = UserControlsCommonResource.EmptyListDocumentsHead,
                Describe = String.Format(FileUtility.ExtsWebEdited.Any() ? UserControlsCommonResource.EmptyListDocumentsDescr.HtmlEncode() : UserControlsCommonResource.EmptyListDocumentsDescrPoor.HtmlEncode(),
                                             //create
                                             "<span class='hintCreate baseLinkAction' >", "</span>",
                                             //upload
                                             "<span class='hintUpload baseLinkAction' >", "</span>",
                                             //open
                                             "<span class='hintOpen baseLinkAction' >", "</span>",
                                             //edit
                                             "<span class='hintEdit baseLinkAction' >", "</span>"),
                ButtonHTML = buttons
            };
            _phEmptyDocView.Controls.Add(emptyParticipantScreenControl);
        }

        private void InitViewers()
        {
            MediaViewersPlaceHolder.Controls.Add(LoadControl(Common.MediaPlayer.Location));
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            InitScripts();
            InitViewers();

            if (EmptyScreenVisible)
                CreateEmptyPanel();

            HelpLink = CommonLinkUtility.GetHelpLink();
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Client/HttpHandlers/ClientScriptCustom.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Threading;

using ASC.Core;

namespace ASC.Web.Core.Client.HttpHandlers
{
    public abstract class ClientScriptCustom : ClientScript
    {
        protected override bool CheckAuth { get { return false; } }

        protected internal sealed override string GetCacheHash()
        {
            return ClientSettings.ResetCacheKey +
                   Thread.CurrentThread.CurrentCulture.Name +
                   CoreContext.TenantManager.GetCurrentTenant().TenantId;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Core/DebugInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Web.Core.Files;

namespace ASC.Web.Studio.Core
{
    public class DebugInfo
    {
        private static readonly string ChangeLogPatternFilePath = string.Concat(HttpContext.Current.Server.MapPath("~/"), "change.log");
        private static readonly string ChangeLogFilePath = string.Concat(HttpContext.Current.Server.MapPath("~/"), "changelog.xml");
        private static readonly string debugString;
        public static bool ShowDebugInfo;

        static DebugInfo()
        {
            try
            {
                var basePath = HttpContext.Current.Server.MapPath("~/");
                ChangeLogPatternFilePath = Path.Combine(basePath, "change.log");
                ChangeLogFilePath = Path.Combine(basePath, "changelog.xml");
#if DEBUGINFO
                ShowDebugInfo = File.Exists(ChangeLogPatternFilePath) && File.Exists(ChangeLogFilePath);
                debugString = GetStaticDebugString();
#else
                ShowDebugInfo = false;
                debugString = "";
#endif

            }
            catch (Exception)
            {

            }
        }

        private static string GetStaticDebugString()
        {
            var xmlLog = new XmlDocument();
            xmlLog.Load(ChangeLogFilePath);

            var logs = xmlLog.SelectNodes("//changeSet//item");
            if (logs == null) return "";
            var nodes = logs.Cast<XmlNode>().ToList();

            try
            {
                var fileContent = File.ReadAllText(ChangeLogPatternFilePath, Encoding.Default);
                fileContent = fileContent.Replace("{BuildVersion}", xmlLog.GetElementsByTagName("number")[0].InnerText);
                fileContent = fileContent.Replace("{BuildDate}", new DateTime(1970, 1, 1).AddMilliseconds(Convert.ToInt64(xmlLog.GetElementsByTagName("timestamp")[0].InnerText)).ToString("yyyy-MM-dd hh:mm"));
                fileContent = fileContent.Replace("{DocServiceApi}", FilesLinkUtility.DocServiceApiUrl.HtmlEncode());
                fileContent = fileContent.Replace("{DocServiceCommand}", FilesLinkUtility.DocServiceCommandUrl.HtmlEncode());
                fileContent = fileContent.Replace("{DocServiceConverter}", FilesLinkUtility.DocServiceConverterUrl.HtmlEncode());
                fileContent = fileContent.Replace("{DocServiceDocbuilder}", FilesLinkUtility.DocServiceDocbuilderUrl.HtmlEncode());

                var firstCommitIDNode = nodes.FirstOrDefault();
                if (firstCommitIDNode != null)
                {
                    var firstCommitID = firstCommitIDNode.SelectSingleNode("commitId");
                    if (firstCommitID != null)
                    {
                        fileContent = fileContent.Replace("{RevisionFirst}", firstCommitID.InnerText);
                    }
                }
                else
                {
                    fileContent = fileContent.Replace("{RevisionFirst}", "");
                }
                var lastCommitIDNode = nodes.LastOrDefault();
                if (lastCommitIDNode != null)
                {
                    var lastCommitID = lastCommitIDNode.SelectSingleNode("commitId");
                    if (lastCommitID != null)
                    {
                        fileContent = fileContent.Replace("{RevisionLast}", lastCommitID.InnerText);
                    }
                }
                else
                {
                    fileContent = fileContent.Replace("{RevisionLast}", "");
                }

                fileContent += GetChangeLogData(nodes).HtmlEncode();

                return fileContent;
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC").Error("DebugInfo", e);
            }

            return "";
        }

        private static string GetChangeLogData(IEnumerable<XmlNode> logs)
        {
            var hashTable = new Dictionary<string, HashSet<string>>();

            foreach (var log in logs)
            {
                var comment = log.SelectSingleNode("comment");
                if (comment == null || IsServiceLogItem(comment.InnerText)) continue;

                var author = log.SelectSingleNode("author//fullName");
                if (author == null) continue;

                var commentText = comment.InnerText.Replace("\n", " ") + "\n";
                if (!hashTable.ContainsKey(author.InnerText))
                    hashTable.Add(author.InnerText, new HashSet<string> { "author: " + author.InnerText + Environment.NewLine, commentText });
                else
                    hashTable[author.InnerText].Add(commentText);
            }

            return string.Join(Environment.NewLine, hashTable.Select(r => string.Join("", r.Value)).OrderBy(r => r));
        }

        private static bool IsServiceLogItem(string log)
        {
            return Regex.IsMatch(log, "(^Merged)|(^Sql)", RegexOptions.IgnoreCase);
        }

        public static string DebugString
        {
            get
            {
                try
                {
                    return debugString.Replace("{User}", SecurityContext.CurrentAccount.ToString().HtmlEncode())
                    .Replace("{UserAgent}", HttpContext.Current.Request.UserAgent)
                    .Replace("{Url}", HttpContext.Current.Request.Url.ToString().HtmlEncode())
                    .Replace("{RewritenUrl}", HttpContext.Current.Request.GetUrlRewriter().ToString().HtmlEncode());
                }
                catch (Exception e)
                {
                    LogManager.GetLogger("ASC").Error("DebugInfo", e);
                }

                return "";
            }
        }
    }
}


<|start_filename|>module/ASC.Notify/ASC.Notify/NotifyServiceLauncher.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.ServiceModel;

using ASC.Common.Data;
using ASC.Common.Logging;
using ASC.Common.Module;
using ASC.Notify.Config;
using ASC.Web.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Utility;

using TMResourceData;

namespace ASC.Notify
{
    public class NotifyServiceLauncher : IServiceController
    {
        private ServiceHost serviceHost;
        private NotifySender sender;
        private NotifyCleaner cleaner;


        public void Start()
        {
            serviceHost = new ServiceHost(typeof(NotifyService));
            serviceHost.Open();

            sender = new NotifySender();
            sender.StartSending();

            if (0 < NotifyServiceCfg.Schedulers.Count)
            {
                InitializeNotifySchedulers();
            }

            cleaner = new NotifyCleaner();
            cleaner.Start();
        }

        public void Stop()
        {
            if (sender != null)
            {
                sender.StopSending();
            }
            if (serviceHost != null)
            {
                serviceHost.Close();
            }
            if (cleaner != null)
            {
                cleaner.Stop();
            }
        }

        private void InitializeNotifySchedulers()
        {
            CommonLinkUtility.Initialize(NotifyServiceCfg.ServerRoot);
            DbRegistry.Configure();
            InitializeDbResources();
            NotifyConfiguration.Configure();
            WebItemManager.Instance.LoadItems();
            foreach (var pair in NotifyServiceCfg.Schedulers)
            {
                LogManager.GetLogger("ASC.Notify").DebugFormat("Start scheduler {0} ({1})", pair.Key, pair.Value);
                pair.Value.Invoke(null, null);
            }
        }

        private void InitializeDbResources()
        {
            DBResourceManager.PatchAssemblies();
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/AUTH/AUTH_SASL_ServerMechanism_Login.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.AUTH
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements "LOGIN" authenticaiton.
    /// </summary>
    public class AUTH_SASL_ServerMechanism_Login : AUTH_SASL_ServerMechanism
    {
        #region Events

        /// <summary>
        /// Is called when authentication mechanism needs to authenticate specified user.
        /// </summary>
        public event EventHandler<AUTH_e_Authenticate> Authenticate = null;

        #endregion

        #region Members

        private readonly bool m_RequireSSL;
        private bool m_IsAuthenticated;
        private bool m_IsCompleted;
        private string m_Password;
        private int m_State;
        private string m_UserName;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if the authentication exchange has completed.
        /// </summary>
        public override bool IsCompleted
        {
            get { return m_IsCompleted; }
        }

        /// <summary>
        /// Gets if user has authenticated sucessfully.
        /// </summary>
        public override bool IsAuthenticated
        {
            get { return m_IsAuthenticated; }
        }

        /// <summary>
        /// Returns always "LOGIN".
        /// </summary>
        public override string Name
        {
            get { return "LOGIN"; }
        }

        /// <summary>
        /// Gets if specified SASL mechanism is available only to SSL connection.
        /// </summary>
        public override bool RequireSSL
        {
            get { return m_RequireSSL; }
        }

        /// <summary>
        /// Gets user login name.
        /// </summary>
        public override string UserName
        {
            get { return m_UserName; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="requireSSL">Specifies if this mechanism is available to SSL connections only.</param>
        public AUTH_SASL_ServerMechanism_Login(bool requireSSL)
        {
            m_RequireSSL = requireSSL;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Continues authentication process.
        /// </summary>
        /// <param name="clientResponse">Client sent SASL response.</param>
        /// <returns>Retunrns challange response what must be sent to client or null if authentication has completed.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>clientResponse</b> is null reference.</exception>
        public override string Continue(string clientResponse)
        {
            if (clientResponse == null)
            {
                throw new ArgumentNullException("clientResponse");
            }

            /* RFC none.
                S: "Username:"
                C: userName
                S: "Password:"
                C: password
             
                NOTE: UserName may be included in initial client response.
            */

            // User name provided, so skip that state.
            if (m_State == 0 && !string.IsNullOrEmpty(clientResponse))
            {
                m_State++;
            }

            if (m_State == 0 && string.IsNullOrEmpty(clientResponse))
            {
                m_State++;

                return "UserName:";
            }
            else if (m_State == 1)
            {
                m_State++;
                m_UserName = clientResponse;

                return "Password:";
            }
            else
            {
                m_Password = clientResponse;

                AUTH_e_Authenticate result = OnAuthenticate("", m_UserName, m_Password);
                m_IsAuthenticated = result.IsAuthenticated;
                m_IsCompleted = true;
            }

            return null;
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Raises <b>Authenticate</b> event.
        /// </summary>
        /// <param name="authorizationID">Authorization ID.</param>
        /// <param name="userName">User name.</param>
        /// <param name="password">Password.</param>
        /// <returns>Returns authentication result.</returns>
        private AUTH_e_Authenticate OnAuthenticate(string authorizationID, string userName, string password)
        {
            AUTH_e_Authenticate retVal = new AUTH_e_Authenticate(authorizationID, userName, password);

            if (Authenticate != null)
            {
                Authenticate(this, retVal);
            }

            return retVal;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Core/Views/ISubscriberView.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Notify.Model;

namespace ASC.Forum
{
    public interface ISubscriberView
    {
        bool IsSubscribe { get; set; }

        event EventHandler<SubscribeEventArgs> Subscribe;

        event EventHandler<SubscribeEventArgs> UnSubscribe;

        event EventHandler<SubscribeEventArgs> GetSubscriptionState;
    }

    public class SubscribeEventArgs : EventArgs
    {
        public INotifyAction NotifyAction { get; private set; }

        public string ObjectID { get; private set; }

        public Guid UserID { get; private set; }

        public SubscribeEventArgs(INotifyAction notifyAction, string objectID, Guid userID)
        {
            this.NotifyAction = notifyAction;
            this.ObjectID = objectID;
            this.UserID = userID;
        }
    }
}


<|start_filename|>module/ASC.Socket.IO/app/hubs/voip.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = (io) => {
    const phones = new (require("./voipListPhones.js"))();
    const numberIdKey = "numberId";
    const voip = io.of("/voip");

    voip.on('connection', (socket) => {
        const request = socket.client.request;
        if(!request.user || !request.user.id) return;
        const user = request.user;
        const userId = user.id;
        const numberId = getNumberId(request);
        const numberRoom = request.portal.tenantId + numberId;

        socket.join([numberRoom, userId]);

        phones.addPhone(numberId);

        socket
            .on("status", status)
            .on("miss", miss.bind(null, numberId))
            .on("enqueue", enqueue.bind(null, numberId))
            .on("Dequeue", dequeue)
            .on("OnlineAgents", onlineAgents)
            .on("getStatus", getStatus)
            .on("getAgent", getAgent.bind(null, numberId))
            .on("incoming", incoming)
            .on("start", start)
            .on("end", end);

        function getNumberId(request) {
            let result = request._query[numberIdKey];
            if (!result) {
                result = request.headers[numberIdKey];
            }

            return result || "";
        }

        function status(agentStatus, fn) {
            voip.to(userId).emit("status", agentStatus);

            switch (agentStatus) {
                case 0:
                    socket.once('disconnect', () => {
                        status(2);
                    });
                    if (phones.anyCalls(numberId)) {
                        dequeue();
                    } else {
                        phones.addOrUpdateAgent(numberId, { id: userId, status: agentStatus });
                    }
                    break;
                case 1:
                    phones.addOrUpdateAgent(numberId, { id: userId, status: agentStatus });
                    break;
                case 2:
                    phones.removeAgent(numberId, userId);
                    break;
            }
            onlineAgents();
            if(fn) fn();

        }

        function dequeue() {
            voip.to(userId).emit('dequeue', phones.dequeueCall(numberId));
        }

        function onlineAgents() {
            voip.to(numberRoom).emit('onlineAgents', phones.onlineAgents(numberId));
        }

        function getStatus(fn) {
            const getStatusResult = phones.getStatus(numberId, userId);
            fn(getStatusResult);
        }

        function start() {
            voip.to(userId).emit('start');
        }

        function end() {
            voip.to(userId).emit('end');
        }
    });

    function enqueue(numberId, callId, agent) {
        const result = phones.enqueue(numberId, callId, agent);
        if (result) {
            voip.to(result).emit('dequeue', callId);
        }
    }

    function incoming(callId, agent) {
        voip.to(agent).emit('dequeue', callId);
    }

    function miss(numberId, callId, agent) {
        phones.removeCall(numberId, callId);

        voip.to(agent).emit('miss', callId);
    }

    function getAgent(numberId, contactsResponsibles, fn) {
        const result = phones.getAgent(numberId, contactsResponsibles);
        if (typeof fn === "function") fn(result);
        return result;
    }

    function reload(numberRoom, agent) {
        if (agent) {
            voip.to(agent).emit('reload');
        }else{
            voip.to(numberRoom).emit('reload');
        }
    }

    return { enqueue, incoming, miss, getAgent, reload };
}

<|start_filename|>web/studio/ASC.Web.Studio/Core/Backup/BackupAjaxHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using AjaxPro;

using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Common.Configuration;
using ASC.Core.Common.Contracts;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Notify.Cron;
using ASC.Web.Core.Security;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Core.Backup
{
    [AjaxNamespace("AjaxPro.Backup")]
    public class BackupAjaxHandler
    {
        #region backup

        [AjaxMethod]
        public BackupProgress StartBackup(BackupStorageType storageType, Dictionary<string, string> storageParams, bool backupMail)
        {
            DemandPermissionsBackup();

            var backupRequest = new StartBackupRequest
            {
                TenantId = GetCurrentTenantId(),
                UserId = SecurityContext.CurrentAccount.ID,
                BackupMail = backupMail,
                StorageType = storageType,
                StorageParams = storageParams
            };

            switch (storageType)
            {
                case BackupStorageType.ThridpartyDocuments:
                case BackupStorageType.Documents:
                    backupRequest.StorageBasePath = storageParams["folderId"];
                    break;
                case BackupStorageType.Local:
                    if (!CoreContext.Configuration.Standalone) throw new Exception("Access denied");
                    backupRequest.StorageBasePath = storageParams["filePath"];
                    break;
            }

            MessageService.Send(HttpContext.Current.Request, MessageAction.StartBackupSetting);

            using (var service = new BackupServiceClient())
            {
                return service.StartBackup(backupRequest);
            }
        }

        [AjaxMethod]
        [SecurityPassthrough]
        public BackupProgress GetBackupProgress()
        {
            DemandPermissionsBackup();

            using (var service = new BackupServiceClient())
            {
                return service.GetBackupProgress(GetCurrentTenantId());
            }
        }

        [AjaxMethod]
        public void DeleteBackup(Guid id)
        {
            DemandPermissionsBackup();

            using (var service = new BackupServiceClient())
            {
                service.DeleteBackup(id);
            }
        }

        [AjaxMethod]
        public void DeleteAllBackups()
        {
            DemandPermissionsBackup();

            using (var service = new BackupServiceClient())
            {
                service.DeleteAllBackups(GetCurrentTenantId());
            }
        }

        [AjaxMethod]
        public List<BackupHistoryRecord> GetBackupHistory()
        {
            DemandPermissionsBackup();

            using (var service = new BackupServiceClient())
            {
                return service.GetBackupHistory(GetCurrentTenantId());
            }
        }


        [AjaxMethod]
        public void CreateSchedule(BackupStorageType storageType, Dictionary<string, string> storageParams, int backupsStored, CronParams cronParams, bool backupMail)
        {
            DemandPermissionsBackup();

            if (!SetupInfo.IsVisibleSettings("AutoBackup"))
                throw new InvalidOperationException(Resource.ErrorNotAllowedOption);

            ValidateCronSettings(cronParams);

            var scheduleRequest = new CreateScheduleRequest
            {
                TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId,
                BackupMail = backupMail,
                Cron = cronParams.ToString(),
                NumberOfBackupsStored = backupsStored,
                StorageType = storageType,
                StorageParams = storageParams
            };

            switch (storageType)
            {
                case BackupStorageType.ThridpartyDocuments:
                case BackupStorageType.Documents:
                    scheduleRequest.StorageBasePath = storageParams["folderId"];
                    break;
                case BackupStorageType.Local:
                    if (!CoreContext.Configuration.Standalone) throw new Exception("Access denied");
                    scheduleRequest.StorageBasePath = storageParams["filePath"];
                    break;
            }

            using (var service = new BackupServiceClient())
            {
                service.CreateSchedule(scheduleRequest);
            }
        }

        [AjaxMethod]
        public Schedule GetSchedule()
        {
            DemandPermissionsBackup();

            ScheduleResponse response;
            using (var service = new BackupServiceClient())
            {
                response = service.GetSchedule(GetCurrentTenantId());
                if (response == null)
                {
                    return null;
                }
            }

            var schedule = new Schedule
            {
                StorageType = response.StorageType,
                StorageParams = response.StorageParams ?? new Dictionary<string, string>(),
                CronParams = new CronParams(response.Cron),
                BackupMail = response.BackupMail,
                BackupsStored = response.NumberOfBackupsStored,
                LastBackupTime = response.LastBackupTime
            };

            if (response.StorageType == BackupStorageType.CustomCloud)
            {
                var amazonSettings = CoreContext.Configuration.GetSection<AmazonS3Settings>();

                var consumer = ConsumerFactory.GetByName<DataStoreConsumer>("S3");
                if (!consumer.IsSet)
                {
                    consumer["acesskey"] = amazonSettings.AccessKeyId;
                    consumer["secretaccesskey"] = amazonSettings.SecretAccessKey;

                    consumer["bucket"] = amazonSettings.Bucket;
                    consumer["region"] = amazonSettings.Region;
                }

                schedule.StorageType = BackupStorageType.ThirdPartyConsumer;
                schedule.StorageParams = consumer.AdditionalKeys.ToDictionary(r => r, r => consumer[r]);
                schedule.StorageParams.Add("module", "S3");

                using (var service = new BackupServiceClient())
                {
                    service.CreateSchedule(new CreateScheduleRequest
                    {
                        TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId,
                        BackupMail = schedule.BackupMail,
                        Cron = schedule.CronParams.ToString(),
                        NumberOfBackupsStored = schedule.BackupsStored,
                        StorageType = schedule.StorageType,
                        StorageParams = schedule.StorageParams
                    });
                }

            }
            else if (response.StorageType != BackupStorageType.ThirdPartyConsumer)
            {
                schedule.StorageParams["folderId"] = response.StorageBasePath;
            }

            return schedule;
        }

        [AjaxMethod]
        public void DeleteSchedule()
        {
            DemandPermissionsBackup();

            using (var service = new BackupServiceClient())
            {
                service.DeleteSchedule(GetCurrentTenantId());
            }
        }

        private static void DemandPermissionsBackup()
        {
            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

            if (!SetupInfo.IsVisibleSettings(ManagementType.Backup.ToString()))
                throw new BillingException(Resource.ErrorNotAllowedOption, "Backup");
        }

        #endregion

        #region restore

        [AjaxMethod]
        public BackupProgress StartRestore(string backupId, BackupStorageType storageType, Dictionary<string, string> storageParams, bool notify)
        {
            DemandPermissionsRestore();

            var restoreRequest = new StartRestoreRequest
            {
                TenantId = GetCurrentTenantId(),
                NotifyAfterCompletion = notify,
                StorageParams = storageParams
            };

            Guid guidBackupId;
            if (Guid.TryParse(backupId, out guidBackupId))
            {
                restoreRequest.BackupId = guidBackupId;
            }
            else
            {
                restoreRequest.StorageType = storageType;
                restoreRequest.FilePathOrId = storageParams["filePath"];

                if (restoreRequest.StorageType == BackupStorageType.Local && !CoreContext.Configuration.Standalone)
                {
                    restoreRequest.FilePathOrId = BackupFileUploadHandler.GetFilePath();
                }
            }

            using (var service = new BackupServiceClient())
            {
                return service.StartRestore(restoreRequest);
            }
        }

        [AjaxMethod]
        [SecurityPassthrough]
        public BackupProgress GetRestoreProgress()
        {
            BackupProgress result;

            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            using (var service = new BackupServiceClient())
            {
                result = service.GetRestoreProgress(tenant.TenantId);
            }

            return result;
        }

        private static void DemandPermissionsRestore()
        {
            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

            if (!SetupInfo.IsVisibleSettings("Restore") ||
                (!CoreContext.Configuration.Standalone && !CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Restore))
                throw new BillingException(Resource.ErrorNotAllowedOption, "Restore");
        }

        #endregion

        #region transfer

        [AjaxMethod]
        public BackupProgress StartTransfer(string targetRegion, bool notifyUsers, bool transferMail)
        {
            DemandPermissionsTransfer();

            MessageService.Send(HttpContext.Current.Request, MessageAction.StartTransferSetting);

            using (var service = new BackupServiceClient())
            {
                return service.StartTransfer(
                    new StartTransferRequest
                    {
                        TenantId = GetCurrentTenantId(),
                        TargetRegion = targetRegion,
                        BackupMail = transferMail,
                        NotifyUsers = notifyUsers
                    });
            }
        }

        [AjaxMethod]
        [SecurityPassthrough]
        public BackupProgress GetTransferProgress()
        {
            using (var service = new BackupServiceClient())
            {
                return service.GetTransferProgress(GetCurrentTenantId());
            }
        }

        private static void DemandPermissionsTransfer()
        {
            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

            var currentUser = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
            if (!SetupInfo.IsVisibleSettings(ManagementType.Migration.ToString())
                || !currentUser.IsOwner()
                || !SetupInfo.IsSecretEmail(currentUser.Email) && !TenantExtra.GetTenantQuota().HasMigration)
                throw new InvalidOperationException(Resource.ErrorNotAllowedOption);
        }

        #endregion

        public string GetTmpFolder()
        {
            using (var service = new BackupServiceClient())
            {
                return service.GetTmpFolder();
            }
        }

        private static void ValidateCronSettings(CronParams cronParams)
        {
            new CronExpression(cronParams.ToString());
        }

        private static int GetCurrentTenantId()
        {
            return CoreContext.TenantManager.GetCurrentTenant().TenantId;
        }

        public class Schedule
        {
            public BackupStorageType StorageType { get; set; }
            public Dictionary<string, string> StorageParams { get; set; }
            public CronParams CronParams { get; set; }
            public bool BackupMail { get; set; }
            public int BackupsStored { get; set; }
            public DateTime LastBackupTime { get; set; }
        }

        public class CronParams
        {
            public BackupPeriod Period { get; set; }
            public int Hour { get; set; }
            public int Day { get; set; }

            public CronParams()
            {
            }

            public CronParams(string cronString)
            {
                var tokens = cronString.Split(' ');
                Hour = Convert.ToInt32(tokens[2]);
                if (tokens[3] != "?")
                {
                    Period = BackupPeriod.EveryMonth;
                    Day = Convert.ToInt32(tokens[3]);
                }
                else if (tokens[5] != "*")
                {
                    Period = BackupPeriod.EveryWeek;
                    Day = Convert.ToInt32(tokens[5]);
                }
                else
                {
                    Period = BackupPeriod.EveryDay;
                }
            }

            public override string ToString()
            {
                switch (Period)
                {
                    case BackupPeriod.EveryDay:
                        return string.Format("0 0 {0} ? * *", Hour);
                    case BackupPeriod.EveryMonth:
                        return string.Format("0 0 {0} {1} * ?", Hour, Day);
                    case BackupPeriod.EveryWeek:
                        return string.Format("0 0 {0} ? * {1}", Hour, Day);
                    default:
                        return base.ToString();
                }
            }
        }

        public enum BackupPeriod
        {
            EveryDay = 0,
            EveryWeek = 1,
            EveryMonth = 2
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/Wrappers/DataWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Runtime.Serialization;

using ASC.Files.Core;

namespace ASC.Web.Files.Services.WCFService
{
    [DataContract(Name = "composite_data", Namespace = "")]
    public class DataWrapper
    {
        [DataMember(IsRequired = false, Name = "entries", EmitDefaultValue = false)]
        public ItemList<FileEntry> Entries { get; set; }

        [DataMember(IsRequired = false, Name = "total")]
        public int Total { get; set; }

        [DataMember(IsRequired = false, Name = "path_parts")]
        public ItemList<object> FolderPathParts { get; set; }

        [DataMember(IsRequired = false, Name = "folder_info")]
        public Folder FolderInfo { get; set; }

        [DataMember(IsRequired = false, Name = "root_folders_id_marked_as_new")]
        public Dictionary<object, int> RootFoldersIdMarkedAsNew { get; set; }
    }
}

<|start_filename|>module/ASC.ElasticSearch/Engine/BaseIndexer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using ASC.Common.Caching;
using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch.Core;
using ASC.ElasticSearch.Service;

using Elasticsearch.Net;

using Nest;

namespace ASC.ElasticSearch
{
    public class BaseIndexer<T> : IIndexer where T : Wrapper, new()
    {
        private static bool IsExist;
        private static readonly object Locker = new object();
        private static readonly ILog Logger = LogManager.GetLogger("ASC.Indexer");
        private static readonly ICacheNotify Notify;
        private static CancellationTokenSource Cts;
        private static TaskScheduler Scheduler;

        private const int QueryLimit = 10000;

        private const string Alias = "_table";

        protected internal T Wrapper { get; set; }

        public string IndexName { get { return Wrapper.IndexName; } }

        static BaseIndexer()
        {
            Cts = new CancellationTokenSource();
            Notify = AscCache.Notify;
            Scheduler = new LimitedConcurrencyLevelTaskScheduler(4);
            Notify.Subscribe<BaseIndexer<T>>((a, b) =>
            {
                lock (Locker)
                {
                    IsExist = false;
                    Cts.Cancel();
                }
            });
        }

        public BaseIndexer(T wrapper)
        {
            Wrapper = wrapper;
        }

        internal void Index(T data, bool immediately = true)
        {
            BeforeIndex(data);

            Client.Instance.Index(data, idx => GetMeta(idx, data, immediately));
        }

        internal void Index(List<T> data, bool immediately = true)
        {
            CreateIfNotExist(data[0]);

            if (typeof(T).IsSubclassOf(typeof(WrapperWithDoc)))
            {
                var currentLength = 0L;
                var portion = new List<T>();
                var portionStart = 0;

                for (var i = 0; i < data.Count; i++)
                {
                    var t = data[i];
                    var runBulk = i == data.Count - 1;

                    BeforeIndex(t);

                    var wwd = t as WrapperWithDoc;

                    if (wwd == null || wwd.Document == null || string.IsNullOrEmpty(wwd.Document.Data))
                    {
                        portion.Add(t);
                    }
                    else
                    {
                        var dLength = wwd.Document.Data.Length;
                        if (dLength >= Settings.Default.MaxContentLength)
                        {
                            try
                            {
                                Index(t, immediately);
                            }
                            catch (ElasticsearchClientException e)
                            {
                                if (e.Response.HttpStatusCode == 429)
                                {
                                    throw;
                                }
                                LogManager.GetLogger("ASC.Indexer").Error(e);
                            }
                            catch (Exception e)
                            {
                                LogManager.GetLogger("ASC.Indexer").Error(e);
                            }
                            finally
                            {
                                wwd.Document.Data = null;
                                wwd.Document = null;
                                wwd = null;
                                GC.Collect();
                            }
                            continue;
                        }

                        if (currentLength + dLength < Settings.Default.MaxContentLength)
                        {
                            portion.Add(t);
                            currentLength += dLength;
                        }
                        else
                        {
                            runBulk = true;
                            i--;
                        }
                    }

                    if (runBulk)
                    {
                        var portion1 = portion.ToList();
                        Client.Instance.Bulk(r => r.IndexMany(portion1, GetMeta).SourceExcludes("attachments"));
                        for (var j = portionStart; j < i; j++)
                        {
                            var doc = data[j] as WrapperWithDoc;
                            if (doc != null && doc.Document != null)
                            {
                                doc.Document.Data = null;
                                doc.Document = null;
                            }
                            doc = null;
                        }

                        portionStart = i;
                        portion = new List<T>();
                        currentLength = 0L;
                        GC.Collect();
                    }
                }
            }
            else
            {
                foreach (var item in data)
                {
                    BeforeIndex(item);
                }

                Client.Instance.Bulk(r => r.IndexMany(data, GetMeta));
            }
        }

        internal async Task IndexAsync(List<T> data, bool immediately = true)
        {
            CreateIfNotExist(data[0]);

            if (typeof(T).IsSubclassOf(typeof(WrapperWithDoc)))
            {
                var currentLength = 0L;
                var portion = new List<T>();
                var portionStart = 0;

                for (var i = 0; i < data.Count; i++)
                {
                    var t = data[i];
                    var runBulk = i == data.Count - 1;

                    await BeforeIndexAsync(t).ConfigureAwait(false);

                    var wwd = t as WrapperWithDoc;

                    if (wwd == null || wwd.Document == null || string.IsNullOrEmpty(wwd.Document.Data))
                    {
                        portion.Add(t);
                    }
                    else
                    {
                        var dLength = wwd.Document.Data.Length;
                        if (dLength >= Settings.Default.MaxContentLength)
                        {
                            try
                            {
                                Index(t, immediately);
                            }
                            catch (ElasticsearchClientException e)
                            {
                                if (e.Response.HttpStatusCode == 429)
                                {
                                    throw;
                                }
                                LogManager.GetLogger("ASC.Indexer").Error(e);
                            }
                            catch (Exception e)
                            {
                                LogManager.GetLogger("ASC.Indexer").Error(e);
                            }
                            finally
                            {
                                wwd.Document.Data = null;
                                wwd.Document = null;
                                wwd = null;
                                GC.Collect();
                            }
                            continue;
                        }

                        if (currentLength + dLength < Settings.Default.MaxContentLength)
                        {
                            portion.Add(t);
                            currentLength += dLength;
                        }
                        else
                        {
                            runBulk = true;
                            i--;
                        }
                    }

                    if (runBulk)
                    {
                        var portion1 = portion.ToList();
                        await Client.Instance.BulkAsync(r => r.IndexMany(portion1, GetMeta).SourceExcludes("attachments"));
                        for (var j = portionStart; j < i; j++)
                        {
                            var doc = data[j] as WrapperWithDoc;
                            if (doc != null && doc.Document != null)
                            {
                                doc.Document.Data = null;
                                doc.Document = null;
                            }
                            doc = null;
                        }

                        portionStart = i;
                        portion = new List<T>();
                        currentLength = 0L;
                        GC.Collect();
                    }
                }
            }
            else
            {
                foreach (var item in data)
                {
                    BeforeIndex(item);
                }

                await Client.Instance.BulkAsync(r => r.IndexMany(data, GetMeta));
            }
        }

        internal void Update(T data, bool immediately = true, params Expression<Func<T, object>>[] fields)
        {
            CreateIfNotExist(data);
            Client.Instance.Update(DocumentPath<T>.Id(data), r => GetMetaForUpdate(r, data, immediately, fields));
        }

        internal void Update(T data, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
        {
            CreateIfNotExist(data);
            Client.Instance.Update(DocumentPath<T>.Id(data), r => GetMetaForUpdate(r, data, action, fields, immediately));
        }

        internal void Update(T data, Expression<Func<Selector<T>, Selector<T>>> expression, int tenantId, bool immediately = true, params Expression<Func<T, object>>[] fields)
        {
            CreateIfNotExist(data);
            Client.Instance.UpdateByQuery(GetDescriptorForUpdate(data, expression, tenantId, immediately, fields));
        }

        internal void Update(T data, Expression<Func<Selector<T>, Selector<T>>> expression, int tenantId, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
        {
            CreateIfNotExist(data);
            Client.Instance.UpdateByQuery(GetDescriptorForUpdate(data, expression, tenantId, action, fields, immediately));
        }

        internal void Delete(T data, bool immediately = true)
        {
            Client.Instance.Delete<T>(data, r => GetMetaForDelete(r, immediately));
        }

        internal void Delete(Expression<Func<Selector<T>, Selector<T>>> expression, int tenantId, bool immediately = true)
        {
            Client.Instance.DeleteByQuery(GetDescriptorForDelete(expression, tenantId, immediately));
        }

        public void Flush()
        {
            Client.Instance.Indices.Flush(new FlushRequest(IndexName));
        }

        public void Refresh()
        {
            Client.Instance.Indices.Refresh(new RefreshRequest(IndexName));
        }

        internal bool CheckExist(T data)
        {
            try
            {
                if (IsExist) return true;

                lock (Locker)
                {
                    if (IsExist) return true;

                    IsExist = Client.Instance.Indices.Exists(data.IndexName).Exists;
                    Cts = new CancellationTokenSource();
                    if (IsExist) return true;
                }
            }
            catch (Exception e)
            {
                Logger.Error("CheckExist " + data.IndexName, e);
            }
            return false;
        }

        void IIndexer.Check()
        {
            var data = new T();
            if (!CheckExist(data)) return;

            var result = false;
            var currentMappings = Client.Instance.Indices.GetMapping<T>(r => r.Index(data.IndexName));
            var newMappings = GetMappings(data).Invoke(new CreateIndexDescriptor(data.IndexName));

            var newMappingDict = new Dictionary<string, string>();
            var props = newMappings.Mappings.Properties.ToList();
            foreach (var prop in props.Where(r => r.Key.Property != null && r.Key.Property.Name != "Document"))
            {
                var propKey = prop.Key.Property.Name.ToLowerCamelCase();
                var key = newMappings.Index.Name + "." + propKey;
                if (prop.Key.Property.CustomAttributes.Any())
                {
                    newMappingDict.Add(key, props.Any(r => r.Key == propKey && r.Value is INestedProperty) ? FieldType.Nested.GetStringValue() : prop.Value.Type);
                }

                var obj = prop.Value as ObjectProperty;

                if (obj != null)
                {
                    foreach (var objProp in obj.Properties)
                    {
                        newMappingDict.Add(key + "." + objProp.Key.Property.Name.ToLowerCamelCase(), objProp.Value.Type);
                    }
                }
            }

            foreach (var ind in currentMappings.Indices)
            {
                foreach (var prop in ind.Value.Mappings.Properties.Where(r => r.Key.Name != "document"))
                {
                    var key = ind.Key.Name + "." + prop.Key.Name.ToLowerCamelCase();

                    if (!newMappingDict.Contains(new KeyValuePair<string, string>(key, prop.Value.Type)))
                    {
                        result = true;
                        break;
                    }

                    var nested = prop.Value as NestedProperty ?? prop.Value as ObjectProperty;

                    if (nested != null)
                    {
                        if (nested.Properties.Any(nProp => !newMappingDict.Contains(new KeyValuePair<string, string>(key + "." + nProp.Key.Name.ToLowerCamelCase(), nProp.Value.Type))))
                        {
                            result = true;
                        }
                    }
                }
            }


            if (result)
            {
                Clear();
            }
        }

        async Task IIndexer.ReIndex()
        {
            while (Launcher.IsStarted && Launcher.Indexing == Wrapper.IndexName)
            {
                await Task.Delay(10000);
            }

            Clear();
            //((IIndexer) this).IndexAll();
        }

        private void Clear()
        {
            using (var db = DbManager.FromHttpContext("default"))
            {
                db.ExecuteNonQuery(new SqlDelete("webstudio_index").Where("index_name", Wrapper.IndexName));
            }

            Logger.DebugFormat("Delete {0}", Wrapper.IndexName);
            Client.Instance.Indices.Delete(Wrapper.IndexName);
            Notify.Publish(this, CacheNotifyAction.Any);
            CreateIfNotExist(new T());
        }

        void IIndexer.IndexAll()
        {
            var now = DateTime.UtcNow;

            DateTime lastIndexed;

            using (var db = DbManager.FromHttpContext("default"))
            {
                lastIndexed = db.ExecuteScalar<DateTime>(new SqlQuery("webstudio_index").Select("last_modified").Where("index_name", Wrapper.IndexName));
            }

            if (lastIndexed.Equals(DateTime.MinValue))
            {
                CreateIfNotExist(new T());
            }

            var meta = Count(lastIndexed);
            Logger.DebugFormat("Index: {0},Count {1},Max: {2},Min: {3}", IndexName, meta.Item1, meta.Item2, meta.Item3);

            var ids = new List<long>() { meta.Item3 };
            ids.AddRange(Ids(lastIndexed));
            ids.Add(meta.Item2);

            var j = 0;
            var tasks = new List<Task>();

            for (var i = 0; i < ids.Count - 1; i ++)
            {
                if (Settings.Default.Threads == 1)
                {
                    IndexAllGetData(ids[i], ids[i+1], lastIndexed);
                }
                else
                {
                    tasks.Add(IndexAllGetDataAsync(ids[i], ids[i+1], lastIndexed));
                    j++;
                    if (j >= Settings.Default.Threads)
                    {
                        Task.WaitAll(tasks.ToArray());
                        tasks = new List<Task>();
                        j = 0;
                    }
                }
            }

            using (var db = DbManager.FromHttpContext("default"))
            {
                db.ExecuteNonQuery(
                    new SqlInsert("webstudio_index", true)
                    .InColumnValue("index_name", Wrapper.IndexName)
                    .InColumnValue("last_modified", now)
                    );
            }

            Logger.DebugFormat("index completed {0}", Wrapper.IndexName);
        }

        long IIndexer.Count()
        {
            var meta = Count(DateTime.MinValue);

            Logger.DebugFormat("Index: {0}, TotalCount {1}", IndexName, meta.Item1);

            return meta.Item1;
        }

        internal IReadOnlyCollection<T> Select(Expression<Func<Selector<T>, Selector<T>>> expression, bool onlyId = false)
        {
            var func = expression.Compile();
            var selector = new Selector<T>();
            var descriptor = func(selector).Where(r => r.TenantId, CoreContext.TenantManager.GetCurrentTenant().TenantId);
            return Client.Instance.Search(descriptor.GetDescriptor(this, onlyId)).Documents;
        }

        internal IReadOnlyCollection<T> Select(Expression<Func<Selector<T>, Selector<T>>> expression, bool onlyId, out long total)
        {
            var func = expression.Compile();
            var selector = new Selector<T>();
            var descriptor = func(selector).Where(r => r.TenantId, CoreContext.TenantManager.GetCurrentTenant().TenantId);
            var result = Client.Instance.Search(descriptor.GetDescriptor(this, onlyId));
            total = result.Total;
            return result.Documents;
        }

        private void BeforeIndex(T data)
        {
            CreateIfNotExist(data);

            var wrapperWithDoc = data as WrapperWithDoc;
            if (wrapperWithDoc != null)
            {
                wrapperWithDoc.InitDocument(SearchSettings.CanIndexByContent<T>(data.TenantId));
            }
        }

        private async Task BeforeIndexAsync(T data)
        {
            CreateIfNotExist(data);

            var wrapperWithDoc = data as WrapperWithDoc;
            if (wrapperWithDoc != null)
            {
                await wrapperWithDoc.InitDocumentAsync(SearchSettings.CanIndexByContent<T>(data.TenantId)).ConfigureAwait(false);
            }
        }

        private void CreateIfNotExist(T data)
        {
            try
            {
                if (CheckExist(data)) return;

                lock (Locker)
                {
                    var columns = data.GetAnalyzers();
                    var nestedColumns = data.GetNested();

                    if (!columns.Any() && !nestedColumns.Any())
                    {
                        Client.Instance.Indices.Create(data.IndexName);
                    }
                    else
                    {
                        Client.Instance.Indices.Create(data.IndexName, GetMappings(data));
                    }

                    IsExist = true;
                }
            }
            catch (Exception e)
            {
                Logger.Error("CreateIfNotExist", e);
            }
        }

        public Func<CreateIndexDescriptor, ICreateIndexRequest> GetMappings(T data)
        {
            var columns = data.GetAnalyzers();
            var nestedColumns = data.GetNested();

            Func<AnalyzersDescriptor, IPromise<IAnalyzers>> analyzers = b =>
            {
                foreach (var c in Enum.GetNames(typeof(Analyzer)))
                {
                    var c1 = c;
                    b.Custom(c1 + "custom", ca => ca.Tokenizer(c1).Filters(Filter.lowercase.ToString()).CharFilters(CharFilter.io.ToString()));
                }

                foreach (var c in columns)
                {
                    if (c.Value.CharFilter == CharFilter.io) continue;
                    var charFilters = new List<string>();
                    foreach (var r in Enum.GetValues(typeof(CharFilter)))
                    {
                        if ((c.Value.CharFilter & (CharFilter)r) == (CharFilter)r) charFilters.Add(r.ToString());
                    }

                    var c1 = c;
                    b.Custom(c1.Key, ca => ca.Tokenizer(c1.Value.Analyzer.ToString()).Filters(c1.Value.Filter.ToString()).CharFilters(charFilters));
                }

                if (data is WrapperWithDoc)
                {
                    b.Custom("document", ca => ca.Tokenizer(Analyzer.whitespace.ToString()).Filters(Filter.lowercase.ToString()).CharFilters(CharFilter.io.ToString()));
                }

                return b;
            };

            Func<PropertiesDescriptor<T>, IPromise<IProperties>> nestedSelector = p =>
            {
                foreach (var c in nestedColumns)
                {
                    var isNested = c.Key.IsGenericType;
                    Type prop;
                    MethodInfo nested;
                    Type typeDescriptor;

                    if (isNested)
                    {
                        prop = c.Key.GenericTypeArguments[0];
                        nested = p.GetType().GetMethod("Nested");
                        typeDescriptor = typeof(NestedPropertyDescriptor<,>);
                    }
                    else
                    {
                        prop = c.Key;
                        nested = p.GetType().GetMethod("Object");
                        typeDescriptor = typeof(ObjectTypeDescriptor<,>);
                    }

                    var desc = typeDescriptor.MakeGenericType(typeof(T), prop);

                    var methods = desc.GetMethods();
                    var name = methods.FirstOrDefault(r => r.Name == "Name" && r.GetParameters().FirstOrDefault(q => q.ParameterType == typeof(PropertyName)) != null);
                    var autoMap = methods.FirstOrDefault(r => r.Name == "AutoMap" && r.GetParameters().Length == 2);
                    var props = methods.FirstOrDefault(r => r.Name == "Properties");
                    if (name == null || autoMap == null || props == null) continue;

                    var param = Expression.Parameter(desc, "a");
                    var nameFunc = Expression.Call(param, name, Expression.Constant(new PropertyName(c.Value.ToLowerCamelCase()))); //a.Name(value(Nest.PropertyName))
                    var autoMapFunc = Expression.Call(param, autoMap, Expression.Constant(null, typeof(IPropertyVisitor)), Expression.Constant(0)); //a.AutoMap()

                    var inst = (Wrapper)Activator.CreateInstance(prop);
                    var instMethods = prop.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
                    var getProperties = instMethods.First(r => r.Name == "GetProperties").MakeGenericMethod(prop);
                    var propsFunc = Expression.Call(param, props, Expression.Constant(getProperties.Invoke(inst, null))); //a.AutoMap()

                    var nestedFunc = Expression.Lambda(Expression.Block(nameFunc, autoMapFunc, propsFunc), param).Compile();
                    var fooRef = nested.MakeGenericMethod(prop);
                    fooRef.Invoke(p, new object[] { nestedFunc });//p.Nested<Wrapper>(r=> r.Name(c.Value.ToLowerCamelCase()).AutoMap().Properties(getProperties()))
                }

                return p;
            };

            return c =>
               c.Settings(r => r.Analysis(a => a.Analyzers(analyzers).CharFilters(d => d.HtmlStrip(CharFilter.html.ToString()).Mapping(CharFilter.io.ToString(), m => m.Mappings("ё => е", "Ё => Е")))))
                .Map<T>(m => m.AutoMap<T>().Properties(data.GetProperties<T>()).Properties(nestedSelector));
        }

        private IIndexRequest<T> GetMeta(IndexDescriptor<T> request, T data, bool immediately = true)
        {
            var result = request.Index(IndexName).Id(data.Id);

            if (immediately)
            {
                result.Refresh(Elasticsearch.Net.Refresh.True);
            }

            if (data is WrapperWithDoc)
            {
                result.Pipeline("attachments");
            }

            return result;
        }
        private IBulkIndexOperation<T> GetMeta(BulkIndexDescriptor<T> desc, T data)
        {
            var result = desc.Index(IndexName).Id(data.Id);

            if (data is WrapperWithDoc)
            {
                result.Pipeline("attachments");
            }

            return result;
        }

        private IUpdateRequest<T, T> GetMetaForUpdate(UpdateDescriptor<T, T> request, T data, bool immediately = true, params Expression<Func<T, object>>[] fields)
        {
            var result = request.Index(IndexName);

            if (fields.Any())
            {
                result.Script(GetScriptUpdateByQuery(data, fields));
            }
            else
            {
                result.Doc(data);
            }

            if (immediately)
            {
                result.Refresh(Elasticsearch.Net.Refresh.True);
            }

            return result;
        }

        private Func<ScriptDescriptor, IScript> GetScriptUpdateByQuery(T data, params Expression<Func<T, object>>[] fields)
        {
            var source = new StringBuilder();
            var parameters = new Dictionary<string, object>();

            for (var i = 0; i < fields.Length; i++)
            {
                var func = fields[i].Compile();
                var newValue = func(data);
                string name;

                var expression = fields[i].Body;
                var isList = expression.Type.IsGenericType && expression.Type.GetGenericTypeDefinition() == typeof(List<>);


                MemberExpression member;
                var sourceExprText = "";

                while (!string.IsNullOrEmpty(name = TryGetName(expression, out member)))
                {
                    sourceExprText = "." + name + sourceExprText;
                    expression = member.Expression;
                }

                if (isList)
                {
                    UpdateByAction(UpdateAction.Add, (IList)newValue, sourceExprText, parameters, source);
                }
                else
                {
                    if (newValue == default(T))
                    {
                        source.AppendFormat("ctx._source.remove('{0}');", sourceExprText.Substring(1));
                    }
                    else
                    {
                        var pkey = "p" + sourceExprText.Replace(".", "");
                        source.AppendFormat("ctx._source{0} = params.{1};", sourceExprText, pkey);
                        parameters.Add(pkey, newValue);
                    }
                }
            }

            var sourceData = source.ToString();

            return r => r.Source(sourceData).Params(parameters);
        }

        private IUpdateRequest<T, T> GetMetaForUpdate(UpdateDescriptor<T, T> request, T data, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
        {
            var result = request.Index(IndexName).Script(GetScriptForUpdate(data, action, fields));

            if (immediately)
            {
                result.Refresh(Elasticsearch.Net.Refresh.True);
            }

            return result;
        }

        private Func<ScriptDescriptor, IScript> GetScriptForUpdate(T data, UpdateAction action, Expression<Func<T, IList>> fields)
        {
            var source = new StringBuilder();

            var func = fields.Compile();
            var newValue = func(data);
            string name;

            var expression = fields.Body;

            MemberExpression member;
            var sourceExprText = "";

            while (!string.IsNullOrEmpty(name = TryGetName(expression, out member)))
            {
                sourceExprText = "." + name + sourceExprText;
                expression = member.Expression;
            }

            var parameters = new Dictionary<string, object>();

            UpdateByAction(action, newValue, sourceExprText, parameters, source);

            return r => r.Source(source.ToString()).Params(parameters);
        }

        private void UpdateByAction(UpdateAction action, IList newValue, string key, Dictionary<string, object> parameters, StringBuilder source)
        {
            var paramKey = "p" + key.Replace(".", "");
            switch (action)
            {
                case UpdateAction.Add:
                    for (var i = 0; i < newValue.Count; i++)
                    {
                        parameters.Add(paramKey + i, newValue[i]);
                        source.AppendFormat("if (!ctx._source{0}.contains(params.{1})){{ctx._source{0}.add(params.{1})}}", key, paramKey + i);
                    }
                    break;
                case UpdateAction.Replace:
                    parameters.Add(paramKey, newValue);
                    source.AppendFormat("ctx._source{0} = params.{1};", key, paramKey);
                    break;
                case UpdateAction.Remove:
                    for (var i = 0; i < newValue.Count; i++)
                    {
                        parameters.Add(paramKey + i, newValue[i]);
                        source.AppendFormat("ctx._source{0}.removeIf(item -> item.id == params.{1}.id)", key, paramKey + i);
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException("action", action, null);
            }
        }

        private string TryGetName(Expression expr, out MemberExpression member)
        {
            member = expr as MemberExpression;
            if (member == null)
            {
                var unary = expr as UnaryExpression;
                if (unary != null)
                {
                    member = unary.Operand as MemberExpression;
                }
            }

            return member == null ? "" : member.Member.Name.ToLowerCamelCase();
        }

        private IDeleteRequest GetMetaForDelete(DeleteDescriptor<T> request, bool immediately = true)
        {
            var result = request.Index(IndexName);
            if (immediately)
            {
                result.Refresh(Elasticsearch.Net.Refresh.True);
            }
            return result;
        }

        private Func<string, string> SelectWithAlias(string alias)
        {
            return column => column.Contains('(') ? column : alias + "." + column;
        }

        private void AddJoins(Wrapper wrapper, SqlQuery dataQuery, string alias, bool sub = false)
        {
            var selectWithAliasWrapper = SelectWithAlias(alias);
            var joins = wrapper.GetJoins();
            var j = 0;

            foreach (var join in joins)
            {
                var joinWrapper = join.Key;
                var joinAttr = join.Value.GetCustomAttribute<JoinAttribute>();
                var joinAlias = alias + ++j;

                var tableWithAlias = joinWrapper.Table + " " + joinAlias;
                var selectWithAliasJoin = SelectWithAlias(joinAlias);

                Exp on = null;
                for (var k = 0; k < joinAttr.ColumnsFrom.Length; k++)
                {
                    on = on & Exp.EqColumns(selectWithAliasWrapper(joinAttr.ColumnsFrom[k]), selectWithAliasJoin(joinAttr.ColumnsTo[k]));
                }

                if (joinAttr.JoinType == JoinTypeEnum.Sub)
                {
                    var subQuery = new SqlQuery(tableWithAlias).Where(on);
                    var joinCols = joinWrapper.GetColumnNames(joinAlias);
                    if (joinCols.Any())
                    {
                        subQuery.Select("concat(\"[\", group_concat(JSON_ARRAY(" + string.Join(",", joinCols) + ") SEPARATOR ','), \"]\")");
                    }

                    joinWrapper.AddConditions(joinAlias, subQuery);

                    AddJoins(joinWrapper, subQuery, joinAlias, true);

                    dataQuery.Select(subQuery);
                }
                else
                {
                    if (sub)
                    {
                        var joinCols = joinWrapper.GetColumnNames(joinAlias);
                        if (joinCols.Any())
                        {
                            dataQuery.Select("concat(\"[\", group_concat(JSON_ARRAY(" + string.Join(",", joinCols) + ") SEPARATOR ','), \"]\")");
                        }
                    }
                    else
                    {
                        dataQuery.Select(joinWrapper.GetColumnNames(joinAlias));
                    }

                    switch (joinAttr.JoinType)
                    {
                        //case JoinTypeEnum.Left:
                        //    dataQuery.LeftOuterJoin(tableWithAlias, on);
                        //    break;
                        //case JoinTypeEnum.Right:
                        //    dataQuery.RightOuterJoin(tableWithAlias, on);
                        //    break;
                        case JoinTypeEnum.Inner:
                            dataQuery.InnerJoin(tableWithAlias, on);
                            break;
                    }

                    joinWrapper.AddConditions(joinAlias, dataQuery);
                }
            }
        }

        private Func<DeleteByQueryDescriptor<T>, IDeleteByQueryRequest> GetDescriptorForDelete(Expression<Func<Selector<T>, Selector<T>>> expression, int tenantId, bool immediately = true)
        {
            var func = expression.Compile();
            var selector = new Selector<T>();
            var descriptor = func(selector).Where(r => r.TenantId, tenantId);
            return descriptor.GetDescriptorForDelete(this, immediately);
        }

        private Func<UpdateByQueryDescriptor<T>, IUpdateByQueryRequest> GetDescriptorForUpdate(T data, Expression<Func<Selector<T>, Selector<T>>> expression, int tenantId, bool immediately = true, params Expression<Func<T, object>>[] fields)
        {
            var func = expression.Compile();
            var selector = new Selector<T>();
            var descriptor = func(selector).Where(r => r.TenantId, tenantId);
            return descriptor.GetDescriptorForUpdate(this, GetScriptUpdateByQuery(data, fields), immediately);
        }

        private Func<UpdateByQueryDescriptor<T>, IUpdateByQueryRequest> GetDescriptorForUpdate(T data, Expression<Func<Selector<T>, Selector<T>>> expression, int tenantId, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
        {
            var func = expression.Compile();
            var selector = new Selector<T>();
            var descriptor = func(selector).Where(r => r.TenantId, tenantId);
            return descriptor.GetDescriptorForUpdate(this, GetScriptForUpdate(data, action, fields), immediately);
        }

        private void IndexAllGetData(long start, long stop, DateTime lastIndexed)
        {
            try
            {
                var convertedData = GetDataFromDb(start, stop, lastIndexed);

                FactoryIndexer<T>.Index(convertedData);
            }
            catch (Exception e)
            {
                Logger.Error(e);
                throw;
            }
        }

        private async Task IndexAllGetDataAsync(long start, long stop, DateTime lastIndexed)
        {
            try
            {
                var convertedData = GetDataFromDb(start, stop, lastIndexed);

                await FactoryIndexer<T>.IndexAsync(convertedData).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                Logger.Error(e);
                throw;
            }
        }

        private List<T> GetDataFromDb(long start, long stop, DateTime lastIndexed)
        {
            var idColumn = Wrapper.GetColumnName(ColumnTypeEnum.Id, Alias);

            List<object[]> data;

            var dataQuery = GetBaseQuery(lastIndexed)
                .Select(Wrapper.GetColumnNames(Alias))
                .Where(Exp.Between(idColumn, start, stop));

            AddJoins(Wrapper, dataQuery, Alias);

            using (var db = new DbManager("default", 1800000))
            {
                db.ExecuteNonQuery("SET SESSION group_concat_max_len = 4294967295;");
                data = db.ExecuteList(dataQuery);
            }

            var converter = Wrapper.GetDataConverter();
            return data.Select(r => (T)converter(r)).ToList();
        }

        private Tuple<long, long, long> Count(DateTime lastIndexed)
        {
            var idColumn = Wrapper.GetColumnName(ColumnTypeEnum.Id, Alias);

            using (var db = new DbManager("default", 1800000))
            {
                var dataQuery = GetBaseQuery(lastIndexed)
                    .Select(idColumn)
                    .OrderBy(idColumn, true)
                    .SetMaxResults(1);

                var minid = db.ExecuteList(dataQuery).Select(r => Convert.ToInt64(r[0])).FirstOrDefault();

                dataQuery = GetBaseQuery(lastIndexed)
                    .Select(idColumn)
                    .OrderBy(idColumn, false)
                    .SetMaxResults(1);

                var maxid = db.ExecuteList(dataQuery).Select(r => Convert.ToInt64(r[0])).FirstOrDefault();

                dataQuery = GetBaseQuery(lastIndexed)
                    .SelectCount();

                var count = db.ExecuteList(dataQuery).Select(r => Convert.ToInt64(r[0])).FirstOrDefault();

                return new Tuple<long, long, long>(count, maxid, minid);
            }
        }

        private List<long> Ids(DateTime lastIndexed)
        {
            var idColumn = Wrapper.GetColumnName(ColumnTypeEnum.Id, Alias);
            long start = 0;
            var result = new List<long>();
            using (var db = new DbManager("default", 1800000))
            {
                while(true)
                {
                    var dataQuery = GetBaseQuery(lastIndexed)
                        .Select(idColumn)
                        .Where(Exp.Ge(idColumn, start))
                        .OrderBy(idColumn, true)
                        .SetFirstResult(QueryLimit)
                        .SetMaxResults(1);

                    var id = db.ExecuteList(dataQuery).Select(r => Convert.ToInt64(r[0])).FirstOrDefault();
                    if (id != 0)
                    {
                        start = id;
                        result.Add(id);
                    }
                    else
                    {
                        break;
                    }
                }

                return result;
            }
        }

        private SqlQuery GetBaseQuery(DateTime lastIndexed)
        {
            var dataQuery = new SqlQuery(Wrapper.Table + " " + Alias);
            var tenantIdColumn = Wrapper.GetColumnName(ColumnTypeEnum.TenantId, Alias);
            var lastModifiedColumn = Wrapper.GetColumnName(ColumnTypeEnum.LastModified, Alias);

            if (!string.IsNullOrEmpty(tenantIdColumn))
            {
                dataQuery.InnerJoin("tenants_tenants t", Exp.EqColumns(tenantIdColumn, "t.id"))
                    .Where("t.status", TenantStatus.Active);
            }


            Wrapper.AddConditions(Alias, dataQuery);

            if (!DateTime.MinValue.Equals(lastIndexed))
            {
                dataQuery.Where(Exp.Gt(lastModifiedColumn, lastIndexed));
            }

            return dataQuery;
        }
    }

    static class CamelCaseExtension
    {
        internal static string ToLowerCamelCase(this string str)
        {
            return str.ToLowerInvariant()[0] + str.Substring(1);
        }
    }


    public enum UpdateAction
    {
        Add,
        Replace,
        Remove
    }
}

<|start_filename|>common/ASC.ActiveDirectory/ASC.ActiveDirectory.Tests/Query/ParseTests.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.ActiveDirectory.Base.Expressions;
using NUnit.Framework;

namespace ASC.ActiveDirectory.Tests.Query
{
    [TestFixture]
    public class ParseTests
    {
        [Test]
        public void EscapeAsterisk()
        {
            const string cn_with_asterisk = "CN=test*";

            var exp = Expression.Parse(cn_with_asterisk);

            Assert.AreEqual("CN", exp.Name);
            Assert.AreEqual("test*", exp.Value);
            Assert.AreEqual(Op.Equal, exp.Operation);
            Assert.AreEqual("(CN=test\\2a)", exp.ToString());
        }

        [Test]
        public void EscapeParentheses()
        {
            const string cn_with_asterisk = "CN=ИТ-ПРЦ (Все домены)";

            var exp = Expression.Parse(cn_with_asterisk);

            Assert.AreEqual("CN", exp.Name);
            Assert.AreEqual("ИТ-ПРЦ (Все домены)", exp.Value);
            Assert.AreEqual(Op.Equal, exp.Operation);
            Assert.AreEqual("(CN=ИТ-ПРЦ \\28Все домены\\29)", exp.ToString());
        }

        [Test]
        public void EscapeNul()
        {
            var cnWithAsterisk = "CN=" + '\u0000';

            var exp = Expression.Parse(cnWithAsterisk);

            Assert.AreEqual("CN", exp.Name);
            Assert.AreEqual("\0", exp.Value);
            Assert.AreEqual(Op.Equal, exp.Operation);
            Assert.AreEqual("(CN=\\00)", exp.ToString());
        }

        [Test]
        public void EscapeSlash()
        {
            const string cn_with_asterisk = "CN=test/";

            var exp = Expression.Parse(cn_with_asterisk);

            Assert.AreEqual("CN", exp.Name);
            Assert.AreEqual("test/", exp.Value);
            Assert.AreEqual(Op.Equal, exp.Operation);
            Assert.AreEqual("(CN=test\\2f)", exp.ToString());
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/InviteLink/js/invitelink.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


jq(document).ready(function () {
    try {
        var inviteLinkShow = true;

        if (Teamlab.profile.isPortalOwner === true
            && !ASC.Desktop) {
            var users = window.UserManager.getAllUsers(true);
            for (var userId in users) {
                if (!users.hasOwnProperty(userId)) continue;
                var user = users[userId];
                if (user.isActivated === true && user.isOwner === false) {
                    inviteLinkShow = false;
                    break;
                }
            }
            if (inviteLinkShow) {
                jq("#menuInviteUsers").show();

                if (!ASC.Clipboard.enable) {
                    jq("#menuInviteUsersBtn").on("click", function () {
                        PopupKeyUpActionProvider.ClearActions();
                        StudioBlockUIManager.blockUI("#inviteLinkContainer", 550);
                        ASC.InvitePanel.bindClipboardEvent();
                    });
                } else {
                    window.menuInviteUsersClip = ASC.Clipboard.destroy(window.menuInviteUsersClip);

                    var url = jq("#shareInviteUserLink").val();
                    window.menuInviteUsersClip = ASC.Clipboard.create(url, "menuInviteUsersBtn", {
                        onComplete: function () {
                            PopupKeyUpActionProvider.ClearActions();
                            StudioBlockUIManager.blockUI("#inviteLinkContainer", 550);
                            ASC.InvitePanel.bindClipboardEvent();

                            if (typeof (window.toastr) !== "undefined") {
                                toastr.success(ASC.Resources.Master.ResourceJS.LinkCopySuccess);
                            } else {
                                jq("#shareInviteUserLink, #shareInviteUserLinkCopy").yellowFade();
                            }
                        }
                    });
                }
            }
        }
    } catch (e) { }
});

<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Infrastructure/HealthCheckAuthorizationFilter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Core;
using ASC.HealthCheck.Settings;
using log4net;
using System;
using System.Globalization;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Threading;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace ASC.HealthCheck.Infrastructure
{
    public class HealthCheckAuthorizationFilter : AuthorizationFilterAttribute
    {
        private readonly ILog log = LogManager.GetLogger(typeof(HealthCheckAuthorizationFilter));

        public override void OnAuthorization(HttpActionContext actionContext)
        {
            JsonMediaTypeFormatter jsonMediaTypeFormatter = new JsonMediaTypeFormatter();
            try
            {
                log.Debug("HealthCheckAuthorizationFilterAttribute OnActionExecuted");
                /*
                var healthCheckSettingsAccessor = new HealthCheckSettingsAccessor();
                var healthCheckSettings = healthCheckSettingsAccessor.GetHealthCheckSettings();
                
                var tenants = CoreContext.TenantManager.GetTenants().Where(t => t.TenantId != healthCheckSettings.FakeTenantId).ToList();

                if (!CoreContext.TenantManager.GetTenantQuota(tenants.First().TenantId).HealthCheck)
                {
                    log.Debug("There is no correct license for HealthCheck.");

                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Forbidden)
                    {
                        Content = new ObjectContent<object>(HealthCheckResource.ErrorNotAllowedOption, jsonMediaTypeFormatter)
                    };

                    return;
                }
                */
                string authorizationHeaderValue = null;
                foreach (var header in actionContext.Request.Headers)
                {
                    if (header.Key == "Authorization")
                    {
                        if (header.Value == null)
                        {
                            log.Error("User Unauthorized, Authorization header.Value is null");
                            actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                            return;
                        }
                        foreach (var headerValue in header.Value)
                        {
                            authorizationHeaderValue = headerValue;
                        }
                        break;
                    }
                }
                if (authorizationHeaderValue == null)
                {
                    log.Error("User Unauthorized, authorizationHeaderValue is null");
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }
                var authorization = authorizationHeaderValue.Split(',');
                if (authorization.Length != 2)
                {
                    log.ErrorFormat("User Unauthorized, authorization is null or authorization.Length = {0}", authorization.Length);
                    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
                    return;
                }
                var portalInfo = authorization[0].Split(' ');
                if (portalInfo.Length == 2)
                {
                    authorization[0] = portalInfo[1];
                }
                CoreContext.TenantManager.SetCurrentTenant(authorization[0]);
                SecurityContext.AuthenticateMe(authorization[1]);
                ResolveUserCulture();
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Unexpected error on HealthCheckAuthorizationFilterAttribute: {0} {1}",
                    ex.ToString(), ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
                {
                    Content = new ObjectContent<object>(ex.ToString(), jsonMediaTypeFormatter)
                };
            }
        }

        private void ResolveUserCulture()
        {
            CultureInfo culture = null;

            var tenant = CoreContext.TenantManager.GetCurrentTenant(false);
            if (tenant != null)
            {
                culture = tenant.GetCulture();
            }

            var user = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
            if (!string.IsNullOrEmpty(user.CultureName))
            {
                culture = CultureInfo.GetCultureInfo(user.CultureName);
            }

            if (culture != null && !Equals(Thread.CurrentThread.CurrentCulture, culture))
            {
                Thread.CurrentThread.CurrentCulture = culture;
            }
            if (culture != null && !Equals(Thread.CurrentThread.CurrentUICulture, culture))
            {
                Thread.CurrentThread.CurrentUICulture = culture;
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/Services/ASC.Mail.PasswordFinder/Program.Options.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using CommandLine;
using CommandLine.Text;

namespace ASC.Mail.PasswordFinder
{
    partial class Program
    {
        private sealed class Options
        {
            [Option('j', "json", Required = false, HelpText = "Save settings to mailbox.json")]
            public bool NeedJson { get; set; }

            [Option('e', "exit", Required = false, HelpText = "Exit on end of any operations")]
            public bool ExitOnEnd { get; set; }

            [ParserState]
            public IParserState LastParserState { get; set; }

            [HelpOption]
            public string GetUsage()
            {
                return HelpText.AutoBuild(this, current => HelpText.DefaultParsingErrorsHandler(this, current));
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Configuration/ProjectsSpaceUsageStatManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Files.Core;
using ASC.Web.Core;
using ASC.Web.Projects.Classes;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Projects.Configuration
{
    public class ProjectsSpaceUsageStatManager : SpaceUsageStatManager
    {
        public override List<UsageSpaceStatItem> GetStatData()
        {
            using (var filedb = new DbManager(FileConstant.DatabaseId))
            using (var projdb = new DbManager(Global.DbID))
            {
                var q = new SqlQuery("files_file f")
                    .Select("b.right_node")
                    .SelectSum("f.content_length")
                    .InnerJoin("files_folder_tree t", Exp.EqColumns("f.folder_id", "t.folder_id"))
                    .InnerJoin("files_bunch_objects b", Exp.EqColumns("t.parent_id", "b.left_node"))
                    .Where("b.tenant_id", TenantProvider.CurrentTenantID)
                    .Where(Exp.Like("b.right_node", "projects/project/", SqlLike.StartWith))
                    .GroupBy(1);

                var sizes = filedb.ExecuteList(q)
                    .Select(r => new { ProjectId = Convert.ToInt32(((string)r[0]).Substring(17)), Size = Convert.ToInt64(r[1]) })
                    .GroupBy(r => r.ProjectId)
                    .ToDictionary(g => g.Key, g => g.Sum(a => a.Size));

                q = new SqlQuery("projects_projects")
                    .Select("id", "title")
                    .Where("tenant_id", TenantProvider.CurrentTenantID)
                    .Where(Exp.In("id", sizes.Keys));

                return projdb.ExecuteList(q)
                    .Select(r => new UsageSpaceStatItem
                    {
                        Name = Convert.ToString(r[1]),
                        SpaceUsage = sizes[Convert.ToInt32(r[0])],
                        Url = String.Concat(PathProvider.BaseAbsolutePath, "Projects.aspx?prjID=" + Convert.ToInt32(r[0]))
                    })
                    .OrderByDescending(i => i.SpaceUsage)
                    .ToList();
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Iterators/MailboxMessagesIterator.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Mail.Core;
using ASC.Mail.Core.Dao.Expressions.Message;
using ASC.Mail.Data.Contracts;

namespace ASC.Mail.Iterators
{
    /// <summary>
    /// The 'Iterator' interface
    /// </summary>
    internal interface IMailboxMessagesIterator
    {
        MailMessageData First(bool unremoved = false);
        MailMessageData Next(bool unremoved = false);
        bool IsDone { get; }
        MailMessageData Current { get; }
    }

    /// <summary>
    /// The 'ConcreteIterator' class
    /// </summary>
    public class MailboxMessagesIterator : IMailboxMessagesIterator
    {
        private EngineFactory MailEngine { get; set; }
        private readonly int _minMessageId;
        private readonly int _maxMessageId;

        // Constructor
        public MailboxMessagesIterator(MailBoxData mailBoxData)
        {
            MailEngine = new EngineFactory(mailBoxData.TenantId, mailBoxData.UserId);
            var range = MailEngine
                .MessageEngine
                .GetRangeMessages(
                    SimpleMessagesExp.CreateBuilder(mailBoxData.TenantId)
                        .SetMailboxId(mailBoxData.MailBoxId)
                        .Build());

            _minMessageId = range.Item1;
            _maxMessageId = range.Item2;
        }

        // Gets first item
        public MailMessageData First(bool onlyUnremoved = false)
        {
            Current = MailEngine.MessageEngine.GetMessage(_minMessageId,
                new MailMessageData.Options
                {
                    LoadImages = false,
                    LoadBody = false,
                    NeedProxyHttp = false,
                    OnlyUnremoved = onlyUnremoved
                });

            return Current;
        }

        // Gets next item
        public MailMessageData Next(bool onlyUnremoved = false)
        {
            if (IsDone)
                return null;

            Current = MailEngine.MessageEngine.GetNextMessage(Current.Id,
                new MailMessageData.Options
                {
                    LoadImages = false,
                    LoadBody = false,
                    NeedProxyHttp = false,
                    OnlyUnremoved = onlyUnremoved
                });

            return Current;
        }

        // Gets current iterator item
        public MailMessageData Current { get; private set; }

        // Gets whether iteration is complete
        public bool IsDone
        {
            get { return _minMessageId == 0 || _maxMessageId < _minMessageId || Current == null || Current.Id > _maxMessageId; }
        }

    }
}


<|start_filename|>module/ASC.AuditTrail/BaseEvent.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using CsvHelper.Configuration;

namespace ASC.AuditTrail
{
    public class BaseEvent
    {
        public int Id { get; set; }

        public int TenantId { get; set; }

        public Guid UserId { get; set; }

        public bool Mobile { get; set; }

        public IList<string> Description { get; set; }

        [Event("IpCol")]
        public string IP { get; set; }

        [Event("BrowserCol")]
        public string Browser { get; set; }

        [Event("PlatformCol")]
        public string Platform { get; set; }

        [Event("DateCol")]
        public DateTime Date { get; set; }

        [Event("UserCol")]
        public string UserName { get; set; }

        [Event("PageCol")]
        public string Page { get; set; }

        [Event("ActionCol")]
        public string ActionText { get; set; }
    }

    internal class BaseEventMap<T> : ClassMap<T> where T : BaseEvent
    {
        public BaseEventMap()
        {
            var eventType = typeof(T);
            var eventProps = eventType
                .GetProperties()
                .Where(r => r.GetCustomAttribute<EventAttribute>() != null)
                .OrderBy(r => r.GetCustomAttribute<EventAttribute>().Order);

            foreach (var prop in eventProps)
            {
                var attr = prop.GetCustomAttribute<EventAttribute>().Resource;
                Map(eventType, prop).Name(AuditReportResource.ResourceManager.GetString(attr));
            }
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    internal class EventAttribute : Attribute
    {
        public string Resource { get; private set; }

        public int Order { get; private set; }

        public EventAttribute(string resource, int order = 0)
        {
            Resource = resource;
            Order = order;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Masters/CommonBodyScripts.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Web.Core.Client.Bundling;
using ASC.Web.Studio.Masters.MasterResources;

namespace ASC.Web.Studio.Masters
{
    public class CommonBodyScripts : ResourceScriptBundleControl, IStaticBundle
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            SetData(GetStaticJavaScript());
        }

        public ScriptBundleData GetStaticJavaScript()
        {
            return (ScriptBundleData)
                new ScriptBundleData("studio", "common")
                    .AddSource(ResolveUrl, new MasterTemplateResources())
                    .AddSource(ResolveUrl,
                        "~/js/asc/core/asc.customevents.js",
                        "~/js/asc/api/api.factory.js",
                        "~/js/asc/api/api.helper.js",
                        "~/js/asc/api/asc.teamlab.js",
                        "~/js/asc/plugins/jquery.base64.js",
                        "~/js/asc/plugins/jquery-customcombobox.js",
                        "~/js/asc/plugins/jquery-advansedfilter.js",
                        "~/js/asc/plugins/jquery-advansedselector.js",
                        "~/js/asc/plugins/jquery-useradvansedselector.js",
                        "~/js/asc/plugins/jquery-groupadvansedselector.js",
                        "~/js/asc/plugins/jquery-contactadvansedselector.js",
                        "~/js/asc/plugins/jquery-emailadvansedselector.js",
                        "~/js/asc/plugins/jquery.tlblock.js",
                        "~/js/asc/plugins/popupbox.js",
                        "~/js/asc/core/asc.files.utility.js",
                        "~/js/asc/core/basetemplate.master.init.js",
                        "~/UserControls/Common/HelpCenter/js/help-center.js",
                        "~/js/asc/core/groupselector.js",
                        "~/js/asc/core/asc.mail.utility.js",
                        "~/js/third-party/async.js",
                        "~/js/third-party/clipboard.js",
                        "~/js/asc/core/clipboard.js",
                        "~/js/third-party/email-addresses.js",
                        "~/js/third-party/punycode.js",
                        "~/js/third-party/purify.min.js",
                        "~/js/asc/core/asc.mailreader.js",
                        "~/UserControls/Common/VideoGuides/js/videoguides.js",
                        "~/js/asc/core/asc.feedreader.js",
                        "~/addons/talk/js/talk.navigationitem.js",
                        "~/UserControls/Common/InviteLink/js/invitelink.js",
                        "~/UserControls/Management/InvitePanel/js/invitepanel.js"
                        );
        }

        public StyleBundleData GetStaticStyleSheet()
        {
            return null;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Handlers/WikiPageHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

namespace ASC.Web.UserControls.Wiki.Handlers
{

    public class WikiPageHandler : IHttpModule
    {

        #region IHttpModule Members

        public void Dispose()
        {
            //throw new NotImplementedException();
        }

        public void Init(HttpApplication application)
        {
            application.BeginRequest += new EventHandler(Application_BeginRequest);
        }

        void Application_BeginRequest(object sender, EventArgs e)
        {
            string wikiView = WikiSection.Section.MainPage.WikiView;
            string wikiEdit = WikiSection.Section.MainPage.WikiEdit;

            HttpApplication app = (HttpApplication)sender;
            string path = app.Request.RawUrl;
            if (path.Contains(wikiView))
            {
                path = path.Substring(path.IndexOf(wikiView) + wikiView.Length).TrimStart('/').Split('?')[0].Trim();
                if(string.IsNullOrEmpty(path))
                {
                    path = WikiSection.Section.MainPage.Url.Split('?')[0];
                }
                else
                {
                    path = string.Format(WikiSection.Section.MainPage.Url, path);
                }

                app.Context.RewritePath(path);
            }
            else if (path.Contains(wikiEdit))
            {
                path = path.Substring(path.IndexOf(wikiEdit) + wikiEdit.Length).TrimStart('/').Trim();
                path = path.Replace("?", "&");
                if(path[0] == '&')
                {
                    path = string.Format("?{0}", path.Substring(1));
                    path = string.Format("{0}{1}", WikiSection.Section.MainPage.Url.Split('?')[0], path);

                }
                else
                {
                    path = string.Format(WikiSection.Section.MainPage.Url, path);
                }
                
                app.Context.RewritePath(path);
            }
            
        }

        #endregion
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTP_Utils.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    #region usings

    using System;
    using System.Net;

    #endregion

    /// <summary>
    /// This class provides utility methods for RTP.
    /// </summary>
    public class RTP_Utils
    {
        #region Methods

        /// <summary>
        /// Generates random SSRC value.
        /// </summary>
        /// <returns>Returns random SSRC value.</returns>
        public static uint GenerateSSRC()
        {
            return (uint) new Random().Next(100000, int.MaxValue);
        }

        /// <summary>
        /// Generates random CNAME value.
        /// </summary>
        /// <returns></returns>
        public static string GenerateCNAME()
        {
            // user@host.randomTag

            return Environment.UserName + "@" + Dns.GetHostName() + "." +
                   Guid.NewGuid().ToString().Substring(0, 8);
        }

        /// <summary>
        /// Converts specified DateTime value to short NTP time. Note: NTP time is in UTC.
        /// </summary>
        /// <param name="value">DateTime value to convert. This value must be in local time.</param>
        /// <returns>Returns NTP value.</returns>
        public static uint DateTimeToNTP32(DateTime value)
        {
            /*
                In some fields where a more compact representation is
                appropriate, only the middle 32 bits are used; that is, the low 16
                bits of the integer part and the high 16 bits of the fractional part.
                The high 16 bits of the integer part must be determined
                independently.
            */

            return (uint) ((DateTimeToNTP64(value) >> 16) & 0xFFFFFFFF);
        }

        /// <summary>
        /// Converts specified DateTime value to long NTP time. Note: NTP time is in UTC.
        /// </summary>
        /// <param name="value">DateTime value to convert. This value must be in local time.</param>
        /// <returns>Returns NTP value.</returns>
        public static ulong DateTimeToNTP64(DateTime value)
        {
            /*
                Wallclock time (absolute date and time) is represented using the
                timestamp format of the Network Time Protocol (NTP), which is in
                seconds relative to 0h UTC on 1 January 1900 [4].  The full
                resolution NTP timestamp is a 64-bit unsigned fixed-point number with
                the integer part in the first 32 bits and the fractional part in the
                last 32 bits. In some fields where a more compact representation is
                appropriate, only the middle 32 bits are used; that is, the low 16
                bits of the integer part and the high 16 bits of the fractional part.
                The high 16 bits of the integer part must be determined
                independently.
            */

            TimeSpan ts = ((value.ToUniversalTime() - new DateTime(1900, 1, 1, 0, 0, 0)));

            return ((ulong) (ts.TotalMilliseconds%1000) << 32) | (uint) (ts.Milliseconds << 22);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Proxy/SIP_Presence.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Proxy
{
    #region usings

    using Stack;

    #endregion

    /// <summary>
    /// This class implements SIP presence server.
    /// </summary>
    public class SIP_Presence
    {
        #region Internal methods

        /// <summary>
        /// Handles SUBSCRIBE method.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        internal void Subscribe(SIP_RequestReceivedEventArgs e) {}

        /// <summary>
        /// Handles NOTIFY method.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        internal void Notify(SIP_RequestReceivedEventArgs e) {}

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/init.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function($) {

    $(function () {
        TMMail.init();

        window.MailResource = ASC.Mail.Resources.MailResource;
        window.MailScriptResource = ASC.Mail.Resources.MailScriptResource;
        window.MailAttachmentsResource = ASC.Mail.Resources.MailAttachmentsResource;
        window.MailActionCompleteResource = ASC.Mail.Resources.MailActionCompleteResource;
        window.MailAdministrationResource = ASC.Mail.Resources.MailAdministrationResource;
        window.MailApiErrorsResource = ASC.Mail.Resources.MailApiErrorsResource;
        window.MailApiResource = ASC.Mail.Resources.MailApiResource;

        folderPanel.init();

        blankPages.init();
        popup.init();

        MailFilter.init();
        tagsManager.init();
        accountsManager.init();
        settingsPanel.init();
        helpPanel.init();
        helpPage.init();
        accountsPanel.init();
        administrationManager.init();

        filterCache.init();
        mailBox.init();
        folderFilter.init();
        contactsPage.init();
        contactsPanel.init();
        commonSettingsPage.init();

        userFoldersManager.init();
        filtersManager.init();

        if (ASC.Mail.Presets.Accounts && ASC.Mail.Presets.Accounts.length) {
            contactsManager.init();
        }

        accountsPage.setDefaultAccountIfItDoesNotExist();

        $('#createNewMailBtn').click(function (e) {
            if (e.isPropagationStopped()) {
                return;
            }
            createNewMail();
        });

        $('#check_email_btn').click(function (e) {
            if (e.isPropagationStopped()) {
                return;
            }

            if (!accountsManager.any()) {
                return;
            }

            if (!TMMail.pageIs('inbox')) {
                mailBox.unmarkAllPanels();
                ASC.Controls.AnchorController.move(TMMail.sysfolders.inbox.name);
            }
            serviceManager.updateFolders({}, {}, ASC.Resources.Master.ResourceJS.LoadingProcessing);
            mailAlerts.check();
        });

        $('#settingsLabel').click(function () {
            var $settingsPanel = $(this).parents('.menu-item.sub-list');
            if ($settingsPanel.hasClass('open')) {
                $settingsPanel.removeClass('open');
            } else {
                $settingsPanel.addClass('open');
            }
        });

        $('#addressBookLabel').click(function () {
            var $settingsPanel = $(this).parents('.menu-item.sub-list');
            if ($settingsPanel.hasClass('open')) {
                $settingsPanel.removeClass('open');
            } else {
                $settingsPanel.addClass('open');
            }
        });

        mailBox.groupButtonsMenuHandlers();

        if (accountsManager.getAccountList().length > 0) {
            trustedAddresses.init();

            if (window.blankModal)
                window.blankModal.close();

        } else {
            if (window.blankModal && ASC.Controls.AnchorController.getAnchor().indexOf("help") !== 0)
                window.blankModal.show();
        }

        $(document).on("mousedown", function (e) {
            if (e.ctrlKey) { // Dirty trick: hide FF blue selection of some tags
                if (e.preventDefault)
                    e.preventDefault();
                else
                    e.returnValue = false;
            }
        });

        $(".mainPageTableSidePanel").on("resize", function (event, ui) {
            TMMail.resizeContent();
        });

        $(window).resize(function () {
            TMMail.resizeContent();
        });

        setupSelectable();
    });

    var createNewMail = function () {
        messagePage.compose();
    };

    function setupSelectable() {
        function deselectAll() {
            $(window).click(); // initiate global event for other dropdowns close

            if (TMMail.pageIs("sysfolders") || TMMail.pageIs("userfolder")) {
                mailBox.deselectAll();
            } else if (TMMail.pageIs("tlContact") ||
                TMMail.pageIs("crmContact") ||
                TMMail.pageIs("personalContact")) {
                contactsPage.deselectAll();
            }
        }

        function updateSelection() {
            if (TMMail.pageIs("sysfolders") || TMMail.pageIs("userfolder")) {
                mailBox.selectRow($(this));
            }
            else if (TMMail.pageIs("tlContact") || TMMail.pageIs("crmContact") || TMMail.pageIs("personalContact")) {
                contactsPage.selectRow($(this));
            }
        }

        if(!jq.browser.mobile)
        {
            $('main')
                .selectable({
                    delay: 150,
                    filter: ".row",
                    cancel:
                        "a, button, select, label, input, .checkbox, .importance, .from, .subject, .menuAction, .menu_column, " +
                            ".contentMenu, .entity-menu, .filterPanel, #id_accounts_page, #id_tags_page, #id_administration_page, " +
                            "#mailCommonSettings, #user_folders_page, #editMessagePage, .itemWrapper, #filtersEmptyScreen, " +
                            "#editFilterPage, #filtersContainer",
                    start: deselectAll,
                    selecting: function(event, ui) {
                        $(ui.selecting)
                            .each(updateSelection);
                    },
                    unselecting: function(event, ui) {
                        $(ui.unselecting)
                            .each(updateSelection);
                    }
                });
        }
    }
})(jQuery);

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailBoxData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Mail;
using System.Runtime.Serialization;

using ASC.Common.Logging;
using ASC.FederatedLogin;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.Mail.Authorization;
using ASC.Mail.Data.Imap;
using ASC.Mail.Enums;
using ASC.Mail.Utils;

using Newtonsoft.Json;

namespace ASC.Mail.Data.Contracts
{
    [DataContract(Namespace = "")]
    public class MailBoxData : IEquatable<MailBoxData>
    {
        public enum AuthProblemType
        {
            NoProblems = 0,
            ConnectError = 1,
            TooManyErrors = 2
        }

        public int TenantId { get; set; }

        [DataMember(Name = "id")]
        public int MailBoxId { get; set; }

        private string _userId;

        public string UserId
        {
            get { return _userId; }
            set { _userId = value.ToLowerInvariant(); }
        }

        [IgnoreDataMember]
        public MailAddress EMail { get; set; }

        [DataMember(Name = "email")]
        public string EMailView
        {
            get { return EMail == null ? string.Empty : EMail.ToString(); }
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    EMail = new MailAddress(value);
                }
            }
        }

        [DataMember(Name = "name")]
        public string Name { get; set; }

        [DataMember(Name = "account")]
        public string Account { get; set; }

        [DataMember(Name = "password")]
        public string Password { get; set; }

        [DataMember(Name = "server")]
        public string Server { get; set; }

        [DataMember(Name = "smtp_server")]
        public string SmtpServer { get; set; }

        public int SmtpPort
        {
            get
            {
                int port;
                if (!string.IsNullOrEmpty(SmtpPortStr) && int.TryParse(SmtpPortStr, out port))
                {
                    return port;
                }
                return SmtpEncryption != EncryptionType.None ? WellKnownPorts.SMTP_SSL : WellKnownPorts.SMTP;
            }
            set { SmtpPortStr = value.ToString(CultureInfo.InvariantCulture); }
        }

        [DataMember(Name = "smtp_port")]
        public string SmtpPortStr { get; set; }

        [DataMember(Name = "smtp_account")]
        public string SmtpAccount { get; set; }

        [DataMember(Name = "smtp_password")]
        public string SmtpPassword { get; set; }

        [DataMember(Name = "smtp_auth")]
        public bool SmtpAuth
        {
            get { return SmtpAuthentication != SaslMechanism.None; }
        }

        public int Port
        {
            get
            {
                int port;
                if (!string.IsNullOrEmpty(PortStr) && int.TryParse(PortStr, out port))
                {
                    return port;
                }
                return Encryption != EncryptionType.None ? WellKnownPorts.POP3_SSL : WellKnownPorts.POP3;
            }
            set { PortStr = value.ToString(CultureInfo.InvariantCulture); }
        }

        [DataMember(Name = "port")]
        public string PortStr { get; set; }

        [DataMember(Name = "incoming_encryption_type")]
        public EncryptionType Encryption { get; set; }

        [DataMember(Name = "outcoming_encryption_type")]
        public EncryptionType SmtpEncryption { get; set; }

        [DataMember(Name = "auth_type_in")]
        public SaslMechanism Authentication { get; set; }

        [DataMember(Name = "auth_type_smtp")]
        public SaslMechanism SmtpAuthentication { get; set; }

        public long Size { get; set; }

        public int MessagesCount { get; set; }

        public bool Enabled { get; set; }
        public bool Active { get; set; }

        public bool QuotaError { get; set; }
        public bool QuotaErrorChanged { get; set; }

        public DateTime? AuthErrorDate { get; set; }

        /// <summary>
        /// This value is the initialized while testing a created mail account. 
        /// It is obtained from "LOGIN-DELAY" tag of CAPA command
        /// Measured in seconds
        /// </summary>
        public int ServerLoginDelay { get; set; }

        /// <summary>
        /// Limiting the period of time when limiting download emails
        /// Measured in seconds
        /// </summary>
        public Int64 MailLimitedTimeDelta { get; set; }

        /// <summary>
        /// Begin timestamp loading mails
        /// </summary>
        public DateTime MailBeginTimestamp { get; set; }

        /// <summary>
        /// This default value is assumed based on experiments on the following mail servers: qip.ru, 
        /// </summary>
// ReSharper disable InconsistentNaming
        public const int DefaultServerLoginDelay = 30;
        // ReSharper restore InconsistentNaming

        /// <summary>
        /// Limiting the period of time when limiting download emails
        /// </summary>
        // ReSharper disable InconsistentNaming
        public const Int64 DefaultMailLimitedTimeDelta = 25920000000000; // 30 days;
                                                                         // ReSharper restore InconsistentNaming

        /// <summary>
        /// Default begin timestamp loading emails
        /// </summary>
        // ReSharper disable InconsistentNaming
        public const Int64 DefaultMailBeginTimestamp = 622933632000000000; // 01/01/1975 00:00:00
                                                                           // ReSharper restore InconsistentNaming

        public int AuthorizeTimeoutInMilliseconds
        {
            get { return 10000; }
        }

        private string _oAuthToken;

        private OAuth20Token _token;

        [DataMember(Name = "imap")]
        public bool Imap { get; set; }

        [DataMember(Name = "begin_date")]
        public DateTime BeginDate { get; set; }

        [DataMember(Name = "is_oauth")]
        public bool IsOAuth
        {
            get { return !string.IsNullOrEmpty(_oAuthToken); }
        }

        [IgnoreDataMember]
        public byte OAuthType { get; set; }

        [IgnoreDataMember]
        public string OAuthToken
        {
            get { return _oAuthToken; }
            set
            {
                _oAuthToken = value;

                try
                {
                    _token = OAuth20Token.FromJson(_oAuthToken);
                }
                catch (Exception)
                {
                    try
                    {
                        if ((AuthorizationServiceType)OAuthType != AuthorizationServiceType.Google)
                            return;

                        // If it is old refresh token then change to oAuthToken
                        var auth = new GoogleOAuth2Authorization(new NullLog());
                        _token = auth.RequestAccessToken(_oAuthToken);

                        AccessTokenRefreshed = true;
                    }
                    catch (Exception)
                    {
                        // skip
                    }
                }
            }
        }

        [IgnoreDataMember]
        public string AccessToken
        {
            get
            {
                if (_token == null)
                    throw new Exception("Cannot create OAuth session with given token");

                if (!_token.IsExpired)
                    return _token.AccessToken;

                switch ((AuthorizationServiceType)OAuthType)
                {
                    case AuthorizationServiceType.Google:
                        _token = OAuth20TokenHelper.RefreshToken<GoogleLoginProvider>(_token);
                        break;
                    case AuthorizationServiceType.None:
                        _token = OAuth20TokenHelper.RefreshToken("", _token);
                        break;
                    default:
                        _token = OAuth20TokenHelper.RefreshToken("", _token);
                        break;
                }

                OAuthToken = _token.ToJson();

                AccessTokenRefreshed = true;

                return _token.AccessToken;
            }
        }

        [IgnoreDataMember]
        public bool AccessTokenRefreshed { get; set; }

        [DataMember(Name = "restrict")]
        public bool Restrict
        {
            get { return !(BeginDate.Equals(MailBeginTimestamp)); }
        }

        public bool ImapFolderChanged { get; set; }

        public bool BeginDateChanged { get; set; }

        public Dictionary<string, ImapFolderUids> ImapIntervals { get; set; }

        public int SmtpServerId { get; set; }

        public int InServerId { get; set; }

        public string ImapIntervalsJson
        {
            get
            {
                var contentJson = JsonConvert.SerializeObject(ImapIntervals);
                return contentJson;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                    return;

                try
                {
                    ImapIntervals = MailUtil.ParseImapIntervals(value);
                }
                catch (Exception)
                {
                    // skip
                }
            }
        }

        [DataMember(Name = "email_in_folder")]
        public string EMailInFolder { get; set; }

        [DataMember(Name = "is_teamlab")]
        public bool IsTeamlab { get; set; }

        public bool IsRemoved { get; set; }

        [IgnoreDataMember]
        public MailSignatureData MailSignature { get; set; }

        [IgnoreDataMember]
        public MailAutoreplyData MailAutoreply { get; set; }

        [IgnoreDataMember]
        public List<string> MailAutoreplyHistory { get; set; }

        [IgnoreDataMember]
        public List<MailAddressInfo> Aliases { get; set; }

        [IgnoreDataMember]
        public List<MailAddressInfo> Groups { get; set; }

        [IgnoreDataMember]
        public DateTime? LastSignalrNotify { get; set; }

        [IgnoreDataMember]
        public bool LastSignalrNotifySkipped { get; set; }

        public MailBoxData()
        {
            ServerLoginDelay = DefaultServerLoginDelay; //This value can be changed in test mailbox connection
            ImapIntervals = new Dictionary<string, ImapFolderUids>();
        }

        public MailBoxData(int tenant, string user, int mailboxId, string name,
            MailAddress email, string account, string password, string server,
            EncryptionType encryption, SaslMechanism authentication, bool imap,
            string smtpAccount, string smtpPassword, string smtpServer,
            EncryptionType smtpEncryption, SaslMechanism smtpAuthentication,
            byte oAuthType, string oAuthToken)
        {
            if (string.IsNullOrEmpty(user)) throw new ArgumentNullException("user");
            if (email == null) throw new ArgumentNullException("email");
            if (string.IsNullOrEmpty(account)) throw new ArgumentNullException("account");
            if (string.IsNullOrEmpty(server)) throw new ArgumentNullException("server");
            if (!server.Contains(":")) throw new FormatException("Invalid server string format is <server:port>");
            if (!smtpServer.Contains(":")) throw new FormatException("Invalid smtp server string format is <server:port>");

            TenantId = tenant;
            UserId = user;
            MailBoxId = mailboxId;

            Name = name;
            EMail = email;

            Account = account;
            Password = password;
            Server = server.Split(':')[0];
            Port = int.Parse(server.Split(':')[1]);
            Encryption = encryption;
            Authentication = authentication;
            Imap = imap;

            SmtpAccount = smtpAccount;
            SmtpPassword = smtpPassword;
            SmtpServer = smtpServer.Split(':')[0];
            SmtpPort = int.Parse(smtpServer.Split(':')[1]);
            SmtpEncryption = smtpEncryption;
            SmtpAuthentication = smtpAuthentication;

            OAuthType = oAuthType;
            OAuthToken = oAuthToken;

            MailLimitedTimeDelta = DefaultMailLimitedTimeDelta;
            MailBeginTimestamp = new DateTime(DefaultMailBeginTimestamp);

            ServerLoginDelay = DefaultServerLoginDelay;
            BeginDate = MailBeginTimestamp;

            ImapIntervals = new Dictionary<string, ImapFolderUids>();
        }

        public override string ToString()
        {
            return EMail.ToString();
        }

        public override int GetHashCode()
        {
            return (TenantId.GetHashCode() + UserId.GetHashCode()) ^ EMail.Address.ToLowerInvariant().GetHashCode();
        }

        public bool Equals(MailBoxData other)
        {
            if (ReferenceEquals(this, other)) return true;
            if (ReferenceEquals(null, other)) return false;

            return
                TenantId == other.TenantId &&
                string.Compare(UserId, other.UserId, StringComparison.InvariantCultureIgnoreCase) == 0 &&
                string.Compare(EMail.Address, other.EMail.Address, StringComparison.InvariantCultureIgnoreCase) == 0;
        }

        public override bool Equals(object obj)
        {
            return ReferenceEquals(this, obj) || Equals(obj as MailBoxData);
        }

        //TODO: Remove this struct
        public struct MailboxInfo
        {
            public FolderType folder_id;
            public bool skip;
        }
    }
}


<|start_filename|>module/ASC.Files.Thirdparty/ProviderAccountDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using AppLimit.CloudComputing.SharpBox;
using AppLimit.CloudComputing.SharpBox.StorageProvider.DropBox;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.Files.Core;
using ASC.Files.Core.Data;
using ASC.Files.Thirdparty.Box;
using ASC.Files.Thirdparty.Dropbox;
using ASC.Files.Thirdparty.GoogleDrive;
using ASC.Files.Thirdparty.OneDrive;
using ASC.Files.Thirdparty.SharePoint;
using ASC.Files.Thirdparty.Sharpbox;
using ASC.Security.Cryptography;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Helpers;
using ASC.Web.Files.Resources;

namespace ASC.Files.Thirdparty
{
    internal class ProviderAccountDao : IProviderDao
    {
        private enum ProviderTypes
        {
            Box,
            BoxNet,
            DropBox,
            DropboxV2,
            Google,
            GoogleDrive,
            OneDrive,
            SharePoint,
            SkyDrive,
            WebDav,
            kDrive,
            Yandex,
        }


        private const string TableTitle = "files_thirdparty_account";
        private readonly string storageKey;

        protected int TenantID { get; private set; }

        public ProviderAccountDao(int tenantID, String storageKey)
        {
            TenantID = tenantID;
            this.storageKey = storageKey;
        }

        public virtual IProviderInfo GetProviderInfo(int linkId)
        {
            return GetProvidersInfoInternal(linkId).Single();
        }

        public virtual List<IProviderInfo> GetProvidersInfo()
        {
            return GetProvidersInfoInternal();
        }

        public virtual List<IProviderInfo> GetProvidersInfo(FolderType folderType, string searchText = null)
        {
            return GetProvidersInfoInternal(folderType: folderType, searchText: searchText);
        }

        public virtual List<IProviderInfo> GetProvidersInfo(Guid userId)
        {
            var querySelect = new SqlQuery(TableTitle)
                .Select("id", "provider", "customer_title", "user_name", "password", "token", "user_id", "folder_type", "create_on", "url")
                .Where("tenant_id", TenantID)
                .Where(Exp.Eq("user_id", userId.ToString()));

            try
            {
                using (var db = GetDb())
                {
                    return db.ExecuteList(querySelect).ConvertAll(ToProviderInfo).Where(p => p != null).ToList();
                }
            }
            catch (Exception e)
            {
                Global.Logger.Error(string.Format("GetProvidersInfoInternal: user = {0}", userId), e);
                return new List<IProviderInfo>();
            }
        }


        protected DbManager GetDb()
        {
            return new DbManager(storageKey);
        }

        private List<IProviderInfo> GetProvidersInfoInternal(int linkId = -1, FolderType folderType = FolderType.DEFAULT, string searchText = null)
        {
            var querySelect = new SqlQuery(TableTitle)
                .Select("id", "provider", "customer_title", "user_name", "password", "token", "user_id", "folder_type", "create_on", "url")
                .Where("tenant_id", TenantID);

            if (folderType == FolderType.USER || folderType == FolderType.DEFAULT && linkId == -1)
                querySelect.Where(Exp.Eq("user_id", SecurityContext.CurrentAccount.ID.ToString()));

            if (linkId != -1)
                querySelect.Where("id", linkId);

            if (folderType != FolderType.DEFAULT)
                querySelect.Where("folder_type", (int)folderType);

            if (!string.IsNullOrEmpty(searchText))
                querySelect.Where(AbstractDao.BuildSearch("customer_title", searchText));

            try
            {
                using (var db = GetDb())
                {
                    return db.ExecuteList(querySelect).ConvertAll(ToProviderInfo).Where(p => p != null).ToList();
                }
            }
            catch (Exception e)
            {
                Global.Logger.Error(string.Format("GetProvidersInfoInternal: linkId = {0} , folderType = {1} , user = {2}",
                                                  linkId, folderType, SecurityContext.CurrentAccount.ID), e);
                return new List<IProviderInfo>();
            }
        }

        public virtual int SaveProviderInfo(string providerKey, string customerTitle, AuthData authData, FolderType folderType)
        {
            ProviderTypes prKey;
            try
            {
                prKey = (ProviderTypes)Enum.Parse(typeof(ProviderTypes), providerKey, true);
            }
            catch (Exception)
            {
                throw new ArgumentException("Unrecognize ProviderType");
            }

            authData = GetEncodedAccesToken(authData, prKey);

            if (!CheckProviderInfo(ToProviderInfo(0, providerKey, customerTitle, authData, SecurityContext.CurrentAccount.ID.ToString(), folderType, TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()))))
                throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, providerKey));

            var queryInsert = new SqlInsert(TableTitle, true)
                .InColumnValue("id", 0)
                .InColumnValue("tenant_id", TenantID)
                .InColumnValue("provider", prKey.ToString())
                .InColumnValue("customer_title", Global.ReplaceInvalidCharsAndTruncate(customerTitle))
                .InColumnValue("user_name", authData.Login ?? "")
                .InColumnValue("password", EncryptPassword(authData.Password))
                .InColumnValue("folder_type", (int)folderType)
                .InColumnValue("create_on", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()))
                .InColumnValue("user_id", SecurityContext.CurrentAccount.ID.ToString())
                .InColumnValue("token", EncryptPassword(authData.Token ?? ""))
                .InColumnValue("url", authData.Url ?? "")
                .Identity(0, 0, true);
            using (var db = GetDb())
            {
                return Int32.Parse(db.ExecuteScalar<string>(queryInsert));
            }
        }

        public bool CheckProviderInfo(IProviderInfo providerInfo)
        {
            return providerInfo != null && providerInfo.CheckAccess();
        }

        public virtual int UpdateProviderInfo(int linkId, AuthData authData)
        {
            var queryUpdate = new SqlUpdate(TableTitle)
                .Set("user_name", authData.Login ?? "")
                .Set("password", EncryptPassword(authData.Password))
                .Set("token", EncryptPassword(authData.Token ?? ""))
                .Set("url", authData.Url ?? "")
                .Where("id", linkId)
                .Where("tenant_id", TenantID);

            using (var db = GetDb())
            {
                return db.ExecuteNonQuery(queryUpdate) == 1 ? linkId : default(int);
            }
        }

        public virtual int UpdateProviderInfo(int linkId, string customerTitle, AuthData newAuthData, FolderType folderType, Guid? userId = null)
        {
            var authData = new AuthData();
            if (newAuthData != null && !newAuthData.IsEmpty())
            {
                var querySelect = new SqlQuery(TableTitle)
                    .Select("provider", "url", "user_name", "password")
                    .Where("tenant_id", TenantID)
                    .Where("id", linkId);

                object[] input;
                try
                {
                    using (var db = GetDb())
                    {
                        input = db.ExecuteList(querySelect).Single();
                    }
                }
                catch (Exception e)
                {
                    Global.Logger.Error(string.Format("UpdateProviderInfo: linkId = {0} , user = {1}", linkId, SecurityContext.CurrentAccount.ID), e);
                    throw;
                }

                var providerKey = (string)input[0];
                ProviderTypes key;
                if (!Enum.TryParse(providerKey, true, out key))
                {
                    throw new ArgumentException("Unrecognize ProviderType");
                }

                authData = new AuthData(
                    !string.IsNullOrEmpty(newAuthData.Url) ? newAuthData.Url : (string)input[1],
                    (string)input[2],
                    !string.IsNullOrEmpty(newAuthData.Password) ? newAuthData.Password : DecryptPassword(input[3] as string),
                    newAuthData.Token);

                if (!string.IsNullOrEmpty(newAuthData.Token))
                {
                    authData = GetEncodedAccesToken(authData, key);
                }

                if (!CheckProviderInfo(ToProviderInfo(0, providerKey, customerTitle, authData, SecurityContext.CurrentAccount.ID.ToString(), folderType, TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()))))
                    throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, providerKey));
            }

            var queryUpdate = new SqlUpdate(TableTitle)
                .Where("id", linkId)
                .Where("tenant_id", TenantID);

            if (!string.IsNullOrEmpty(customerTitle))
            {
                queryUpdate
                    .Set("customer_title", customerTitle);
            }

            if (folderType != FolderType.DEFAULT)
            {
                queryUpdate
                    .Set("folder_type", (int)folderType);
            }

            if (userId.HasValue)
            {
                queryUpdate
                    .Set("user_id", userId.Value.ToString());
            }

            if (!authData.IsEmpty())
            {
                queryUpdate
                    .Set("user_name", authData.Login ?? "")
                    .Set("password", EncryptPassword(authData.Password))
                    .Set("token", EncryptPassword(authData.Token ?? ""))
                    .Set("url", authData.Url ?? "");
            }

            using (var db = GetDb())
            {
                return db.ExecuteNonQuery(queryUpdate) == 1 ? linkId : default(int);
            }
        }

        public virtual void RemoveProviderInfo(int linkId)
        {
            using (var db = GetDb())
            using (var tx = db.BeginTransaction())
            {
                var folderId = GetProviderInfo(linkId).RootFolderId.ToString();

                var entryIDs = db.ExecuteList(new SqlQuery("files_thirdparty_id_mapping")
                                                         .Select("hash_id")
                                                         .Where(Exp.Eq("tenant_id", TenantID) &
                                                                Exp.Like("id", folderId, SqlLike.StartWith)))
                                        .ConvertAll(x => x[0]);


                db.ExecuteNonQuery(new SqlDelete("files_security")
                                              .Where(
                                                  Exp.Eq("tenant_id", TenantID) &
                                                  Exp.In("entry_id", entryIDs)));

                var sqlQuery = new SqlDelete("files_tag_link")
                    .Where(Exp.Eq("tenant_id", TenantID) & Exp.In("entry_id", entryIDs));

                db.ExecuteNonQuery(sqlQuery);

                sqlQuery = new SqlDelete(TableTitle)
                    .Where("id", linkId)
                    .Where("tenant_id", TenantID);


                db.ExecuteNonQuery(sqlQuery);

                tx.Commit();
            }
        }

        private static IProviderInfo ToProviderInfo(int id, string providerKey, string customerTitle, AuthData authData, string owner, FolderType type, DateTime createOn)
        {
            return ToProviderInfo(new object[] { id, providerKey, customerTitle, authData.Login, EncryptPassword(authData.Password), EncryptPassword(authData.Token), owner, (int)type, createOn, authData.Url });
        }

        private static IProviderInfo ToProviderInfo(object[] input)
        {
            ProviderTypes key;
            if (!Enum.TryParse((string)input[1], true, out key)) return null;

            var id = Convert.ToInt32(input[0]);
            var providerTitle = (string)input[2] ?? string.Empty;
            var token = DecryptToken(input[5] as string);
            var owner = input[6] == null ? Guid.Empty : new Guid((input[6] as string) ?? "");
            var folderType = (FolderType)Convert.ToInt32(input[7]);
            var createOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(input[8]));

            if (key == ProviderTypes.Box)
            {
                return new BoxProviderInfo(
                    id,
                    key.ToString(),
                    providerTitle,
                    token,
                    owner,
                    folderType,
                    createOn);
            }

            if (key == ProviderTypes.DropboxV2)
            {
                return new DropboxProviderInfo(
                    id,
                    key.ToString(),
                    providerTitle,
                    token,
                    owner,
                    folderType,
                    createOn);
            }

            if (key == ProviderTypes.SharePoint)
            {
                return new SharePointProviderInfo(
                    id,
                    key.ToString(),
                    providerTitle,
                    new AuthData(input[9] as string, input[3] as string, DecryptPassword(input[4] as string), token),
                    owner,
                    folderType,
                    createOn);
            }

            if (key == ProviderTypes.GoogleDrive)
            {
                return new GoogleDriveProviderInfo(
                    id,
                    key.ToString(),
                    providerTitle,
                    token,
                    owner,
                    folderType,
                    createOn);
            }

            if (key == ProviderTypes.OneDrive)
            {
                return new OneDriveProviderInfo(
                    id,
                    key.ToString(),
                    providerTitle,
                    token,
                    owner,
                    folderType,
                    createOn);
            }

            return new SharpBoxProviderInfo(
                id,
                key.ToString(),
                providerTitle,
                new AuthData(input[9] as string, input[3] as string, DecryptPassword(input[4] as string), token),
                owner,
                folderType,
                createOn);
        }

        public void Dispose()
        {
        }

        private static AuthData GetEncodedAccesToken(AuthData authData, ProviderTypes provider)
        {
            switch (provider)
            {
                case ProviderTypes.GoogleDrive:

                    var code = authData.Token;

                    var token = OAuth20TokenHelper.GetAccessToken<GoogleLoginProvider>(code);

                    if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider));

                    return new AuthData(token: token.ToJson());

                case ProviderTypes.Box:

                    code = authData.Token;

                    token = OAuth20TokenHelper.GetAccessToken<BoxLoginProvider>(code);

                    if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider));

                    return new AuthData(token: token.ToJson());

                case ProviderTypes.DropboxV2:

                    code = authData.Token;

                    token = OAuth20TokenHelper.GetAccessToken<DropboxLoginProvider>(code);

                    if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider));

                    return new AuthData(token: token.ToJson());

                case ProviderTypes.DropBox:

                    var dropBoxRequestToken = DropBoxRequestToken.Parse(authData.Token);

                    var config = CloudStorage.GetCloudConfigurationEasy(nSupportedCloudConfigurations.DropBox);
                    var accessToken = DropBoxStorageProviderTools.ExchangeDropBoxRequestTokenIntoAccessToken(config as DropBoxConfiguration,
                                                                                                             ThirdpartyConfiguration.DropboxAppKey,
                                                                                                             ThirdpartyConfiguration.DropboxAppSecret,
                                                                                                             dropBoxRequestToken);

                    var base64Token = new CloudStorage().SerializeSecurityTokenToBase64Ex(accessToken, config.GetType(), new Dictionary<string, string>());

                    return new AuthData(token: base64Token);

                case ProviderTypes.OneDrive:

                    code = authData.Token;

                    token = OAuth20TokenHelper.GetAccessToken<OneDriveLoginProvider>(code);

                    if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider));

                    return new AuthData(token: token.ToJson());

                case ProviderTypes.SkyDrive:

                    code = authData.Token;

                    token = OAuth20TokenHelper.GetAccessToken<OneDriveLoginProvider>(code);

                    if (token == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider));

                    accessToken = AppLimit.CloudComputing.SharpBox.Common.Net.oAuth20.OAuth20Token.FromJson(token.ToJson());

                    if (accessToken == null) throw new UnauthorizedAccessException(string.Format(FilesCommonResource.ErrorMassage_SecurityException_Auth, provider));

                    config = CloudStorage.GetCloudConfigurationEasy(nSupportedCloudConfigurations.SkyDrive);
                    var storage = new CloudStorage();
                    base64Token = storage.SerializeSecurityTokenToBase64Ex(accessToken, config.GetType(), new Dictionary<string, string>());

                    return new AuthData(token: base64Token);

                case ProviderTypes.SharePoint:
                case ProviderTypes.WebDav:
                    break;

                default:
                    authData.Url = null;
                    break;
            }

            return authData;
        }

        private static string EncryptPassword(string password)
        {
            return string.IsNullOrEmpty(password) ? string.Empty : InstanceCrypto.Encrypt(password);
        }

        private static string DecryptPassword(string password)
        {
            return string.IsNullOrEmpty(password) ? string.Empty : InstanceCrypto.Decrypt(password);
        }

        private static string DecryptToken(string token)
        {
            try
            {
                return DecryptPassword(token);
            }
            catch
            {
                //old token in base64 without encrypt
                return token ?? "";
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Employee/EmployeeWraper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Api.Impl;
using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Core.Users;
using ASC.Web.Studio.Utility;

namespace ASC.Api.Employee
{
    [DataContract(Name = "person", Namespace = "")]
    public class EmployeeWraper
    {
        protected EmployeeWraper()
        {
        }

        public EmployeeWraper(UserInfo userInfo)
            : this(userInfo, null)
        {
        }

        public EmployeeWraper(UserInfo userInfo, ApiContext context)
        {
            Id = userInfo.ID;
            DisplayName = DisplayUserSettings.GetFullUserName(userInfo);
            if (!string.IsNullOrEmpty(userInfo.Title))
            {
                Title = userInfo.Title;
            }

            if (EmployeeWraperFull.CheckContext(context, "avatarSmall"))
            {
                AvatarSmall = UserPhotoManager.GetSmallPhotoURL(userInfo.ID) + "?_=" + userInfo.LastModified.GetHashCode();
            }
        }

        [DataMember(Order = 1)]
        public Guid Id { get; set; }

        [DataMember(Order = 10)]
        public string DisplayName { get; set; }

        [DataMember(Order = 11, EmitDefaultValue = false)]
        public string Title { get; set; }

        [DataMember(Order = 20)]
        public string AvatarSmall { get; set; }

        [DataMember(Order = 30)]
        public string ProfileUrl
        {
            get
            {
                if (Id == Guid.Empty) return string.Empty;
                var profileUrl = CommonLinkUtility.GetUserProfile(Id.ToString(), false);
                return CommonLinkUtility.GetFullAbsolutePath(profileUrl);
            }
        }

        public static EmployeeWraper Get(Guid userId)
        {
            try
            {
                return Get(CoreContext.UserManager.GetUsers(userId));
            }
            catch (Exception)
            {
                return Get(Core.Users.Constants.LostUser);
            }
        }

        public static EmployeeWraper Get(UserInfo userInfo)
        {
            return new EmployeeWraper(userInfo);
        }

        public static EmployeeWraper GetSample()
        {
            return new EmployeeWraper
            {
                Id = Guid.Empty,
                DisplayName = "<NAME>",
                Title = "Manager",
                AvatarSmall = "url to small avatar",
            };
        }
    }
}

<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/GosUslugiLoginProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Web;

using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.Profile;

using JWT;

using Newtonsoft.Json.Linq;

namespace ASC.FederatedLogin.LoginProviders
{
    public class GosUslugiLoginProvider : BaseLoginProvider<GosUslugiLoginProvider>
    {
        public string BaseDomain
        {
            get { return this["gosUslugiDomain"]; }
        }

        public override string CodeUrl
        {
            get { return BaseDomain + "/aas/oauth2/ac"; }
        }

        public override string AccessTokenUrl
        {
            get { return BaseDomain + "/aas/oauth2/te"; }
        }

        public override string ClientID
        {
            get { return this["gosUslugiClientId"]; }
        }

        public override string ClientSecret
        {
            get { return this["gosUslugiCert"]; }
        }

        public override string RedirectUri
        {
            get { return this["gosUslugiRedirectUrl"]; }
        }

        public override string Scopes
        {
            get { return "fullname birthdate gender email"; }
        }

        private string GosUslugiProfileUrl
        {
            get { return BaseDomain + "/rs/prns/"; }
        }

        public GosUslugiLoginProvider()
        {
        }

        public GosUslugiLoginProvider(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
            : base(name, order, props, additional)
        {
        }


        public override LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params)
        {
            try
            {
                var token = Auth(context, Scopes);

                if (token == null)
                {
                    throw new Exception("Login failed");
                }

                return GetLoginProfile(token.AccessToken);
            }
            catch (ThreadAbortException)
            {
                throw;
            }
            catch (Exception ex)
            {
                return LoginProfile.FromError(ex);
            }
        }

        protected override OAuth20Token Auth(HttpContext context, string scopes, Dictionary<string, string> additionalArgs = null)
        {
            var error = context.Request["error"];
            if (!string.IsNullOrEmpty(error))
            {
                if (error == "access_denied")
                {
                    error = "Canceled at provider";
                }
                throw new Exception(error);
            }

            var code = context.Request["code"];
            if (string.IsNullOrEmpty(code))
            {
                RequestCode(HttpContext.Current, scopes);
                return null;
            }
            var state = context.Request["state"];
            return GetAccessToken(state, code);
        }

        private void RequestCode(HttpContext context, string scope = null)
        {
            var timestamp = DateTime.UtcNow.ToString("yyyy.MM.dd HH:mm:ss +0000");
            var state = Guid.NewGuid().ToString();//HttpContext.Current.Request.GetUrlRewriter().AbsoluteUri;

            var msg = scope + timestamp + ClientID + state;
            var encodedSignature = SignMsg(msg);
            var clientSecret = HttpServerUtility.UrlTokenEncode(encodedSignature);

            var requestParams = new Dictionary<string, string>
                {
                    { "client_id", ClientID },
                    { "client_secret", clientSecret },
                    { "redirect_uri", RedirectUri },
                    { "scope", scope },
                    { "response_type", "code" },
                    { "state", state },
                    { "timestamp", timestamp },
                    { "access_type", "online" },
                    { "display", "popup" }
                };
            var requestQuery = string.Join("&", requestParams.Select(pair => pair.Key + "=" + HttpUtility.UrlEncode(pair.Value)));//.Replace("+", "%2b");

            var redURL = CodeUrl + "?" + requestQuery;
            context.Response.Redirect(redURL, true);
        }

        private OAuth20Token GetAccessToken(string state, string code)
        {
            var timestamp = DateTime.UtcNow.ToString("yyyy.MM.dd HH:mm:ss +0000");

            var msg = Scopes + timestamp + ClientID + state;
            var encodedSignature = SignMsg(msg);
            var clientSecret = HttpServerUtility.UrlTokenEncode(encodedSignature);

            var requestParams = new Dictionary<string, string>
                {
                    { "client_id", ClientID },
                    { "code", code },
                    { "grant_type", "authorization_code" },
                    { "client_secret", clientSecret },
                    { "state", state },
                    { "redirect_uri", RedirectUri },
                    { "scope", Scopes },
                    { "timestamp", timestamp },
                    { "token_type", "Bearer" }
                };
            var requestQuery = string.Join("&", requestParams.Select(pair => pair.Key + "=" + HttpUtility.UrlEncode(pair.Value)));

            var result = RequestHelper.PerformRequest(AccessTokenUrl, "application/x-www-form-urlencoded", "POST", requestQuery);

            return OAuth20Token.FromJson(result);
        }

        public override LoginProfile GetLoginProfile(string accessToken)
        {
            var tokenPayloadString = JsonWebToken.Decode(accessToken, string.Empty, false);
            var tokenPayload = JObject.Parse(tokenPayloadString);
            if (tokenPayload == null)
            {
                throw new Exception("Payload is incorrect");
            }
            var oid = tokenPayload.Value<string>("urn:esia:sbj_id");

            var userInfoString = RequestHelper.PerformRequest(GosUslugiProfileUrl + oid, "application/x-www-form-urlencoded", headers: new Dictionary<string, string> { { "Authorization", "Bearer " + accessToken } });
            var userInfo = JObject.Parse(userInfoString);
            if (userInfo == null)
            {
                throw new Exception("userinfo is incorrect");
            }

            var profile = new LoginProfile
            {
                Id = oid,
                FirstName = userInfo.Value<string>("firstName"),
                LastName = userInfo.Value<string>("lastName"),

                Provider = ProviderConstants.GosUslugi,
            };

            var userContactsString = RequestHelper.PerformRequest(GosUslugiProfileUrl + oid + "/ctts", "application/x-www-form-urlencoded", headers: new Dictionary<string, string> { { "Authorization", "Bearer " + accessToken } });
            var userContacts = JObject.Parse(userContactsString);
            if (userContacts == null)
            {
                throw new Exception("usercontacts is incorrect");
            }

            var contactElements = userContacts.Value<JArray>("elements");
            if (contactElements == null)
            {
                throw new Exception("usercontacts elements is incorrect");
            }

            foreach (var contactElement in contactElements.ToObject<List<string>>())
            {
                var userContactString = RequestHelper.PerformRequest(contactElement, "application/x-www-form-urlencoded", headers: new Dictionary<string, string> { { "Authorization", "Bearer " + accessToken } });

                var userContact = JObject.Parse(userContactString);
                if (userContact == null)
                {
                    throw new Exception("usercontacts is incorrect");
                }

                var type = userContact.Value<string>("type");
                if (type != "EML") continue;

                profile.EMail = userContact.Value<string>("value");
                break;
            }

            return profile;
        }

        private X509Certificate2 GetSignerCert()
        {
            var storeMy = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
            storeMy.Open(OpenFlags.ReadOnly);
            var certColl = storeMy.Certificates.Find(X509FindType.FindBySubjectKeyIdentifier, ClientSecret, false);
            storeMy.Close();
            if (certColl.Count == 0)
            {
                throw new Exception("Certificate not found");
            }
            return certColl[0];
        }

        private byte[] SignMsg(string msg)
        {
            var signerCert = GetSignerCert();

            var msgBytes = Encoding.UTF8.GetBytes(msg);
            var contentInfo = new ContentInfo(msgBytes);
            var signedCms = new SignedCms(contentInfo, true);
            var cmsSigner = new CmsSigner(signerCert);
            signedCms.ComputeSignature(cmsSigner);
            return signedCms.Encode();
        }

        //private static bool VerifyMsg(Byte[] msg, byte[] encodedSignature)
        //{
        //    ContentInfo contentInfo = new ContentInfo(msg);
        //    SignedCms signedCms = new SignedCms(contentInfo, true);
        //    signedCms.Decode(encodedSignature);

        //    try
        //    {
        //        signedCms.CheckSignature(true);
        //    }
        //    catch (System.Security.Cryptography.CryptographicException e)
        //    {
        //        return false;
        //    }

        //    return true;
        //}
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/MIME/MIME_DispositionTypes .cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.MIME
{
    /// <summary>
    /// This class holds MIME content disposition types. Defined in RFC 2183.
    /// </summary>
    public class MIME_DispositionTypes
    {
        #region Members

        /// <summary>
        /// Bodyparts can be designated `attachment' to indicate that they are separate from the main body of the mail message, 
        /// and that their display should not be automatic, but contingent upon some further action of the user.
        /// </summary>
        public static readonly string Attachment = "attachment";

        /// <summary>
        /// A bodypart should be marked `inline' if it is intended to be displayed automatically upon display of the message. 
        /// Inline bodyparts should be presented in the order in which they occur, subject to the normal semantics of multipart messages.
        /// </summary>
        public static readonly string Inline = "inline";

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Interfaces/IUserFolderDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Core.Dao.Expressions.UserFolder;
using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao.Interfaces
{
    public interface IUserFolderDao
    {
        UserFolder Get(uint id);

        UserFolder GetByMail(uint mailId);

        List<UserFolder> GetList(IUserFoldersExp exp);

        uint Save(UserFolder folder);

        int Remove(uint id);

        int Remove(IUserFoldersExp exp);

        void RecalculateFoldersCount(uint id);

        int SetFolderCounters(uint folderId, int? unreadMess = null, int? totalMess = null,
            int? unreadConv = null, int? totalConv = null);

        /// <summary>
        ///     Update folder counters
        /// </summary>
        int ChangeFolderCounters(uint folderId, int? unreadMessDiff = null, int? totalMessDiff = null,
            int? unreadConvDiff = null, int? totalConvDiff = null);
    }
}


<|start_filename|>module/ASC.ElasticSearch/Config/ElasticSection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;

namespace ASC.ElasticSearch.Config
{
    class ElasticSection : ConfigurationSection
    {
        [ConfigurationProperty("host", IsRequired = true, DefaultValue = "localhost")]
        public string Host
        {
            get { return (string)this["host"]; }
        }

        [ConfigurationProperty("port", IsRequired = false, DefaultValue = "9200")]
        public int Port
        {
            get { return Convert.ToInt32(this["port"]); }
        }

        [ConfigurationProperty("scheme", IsRequired = false, DefaultValue = "http")]
        public string Scheme
        {
            get { return (string)this["scheme"]; }
        }

        [ConfigurationProperty("period", IsRequired = false, DefaultValue = 1)]
        public int Period
        {
            get { return Convert.ToInt32(this["period"]); }
        }

        [ConfigurationProperty("maxContentLength", IsRequired = false, DefaultValue = 100 * 1024 * 1024L)]
        public long MaxContentLength
        {
            get { return Convert.ToInt64(this["maxContentLength"]); }
        }

        [ConfigurationProperty("maxFileSize", IsRequired = false, DefaultValue = 10 * 1024 * 1024L)]
        public long MaxFileSize
        {
            get { return Convert.ToInt64(this["maxFileSize"]); }
        }

        [ConfigurationProperty("threads", IsRequired = false, DefaultValue = 1)]
        public int Threads
        {
            get { return Convert.ToInt32(this["threads"]); }
        }

        [ConfigurationProperty("compression", IsRequired = false, DefaultValue = true)]
        public bool HttpCompression
        {
            get { return Convert.ToBoolean(this["compression"]); }
        }
    }
}


<|start_filename|>module/ASC.Files.Thirdparty/Dropbox/DropboxStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;

using ASC.Common;
using ASC.FederatedLogin;

using Dropbox.Api;
using Dropbox.Api.Files;

namespace ASC.Files.Thirdparty.Dropbox
{
    internal class DropboxStorage
    {
        private OAuth20Token _token;

        private DropboxClient _dropboxClient;

        public bool IsOpened { get; private set; }

        public long MaxChunkedUploadFileSize = 20L * 1024L * 1024L * 1024L;

        public void Open(OAuth20Token token)
        {
            if (IsOpened)
                return;

            _token = token;

            _dropboxClient = new DropboxClient(_token.AccessToken);

            IsOpened = true;
        }

        public void Close()
        {
            _dropboxClient.Dispose();

            IsOpened = false;
        }



        public string MakeDropboxPath(string parentPath, string name)
        {
            return (parentPath ?? "") + "/" + (name ?? "");
        }

        public long GetUsedSpace()
        {
            return (long)_dropboxClient.Users.GetSpaceUsageAsync().Result.Used;
        }

        public FolderMetadata GetFolder(string folderPath)
        {
            if (string.IsNullOrEmpty(folderPath) || folderPath == "/")
            {
                return new FolderMetadata(string.Empty, "/");
            }
            try
            {
                return _dropboxClient.Files.GetMetadataAsync(folderPath).Result.AsFolder;
            }
            catch (AggregateException ex)
            {
                if (ex.InnerException is ApiException<GetMetadataError>
                    && ex.InnerException.Message.StartsWith("path/not_found/"))
                {
                    return null;
                }
                throw;
            }
        }

        public FileMetadata GetFile(string filePath)
        {
            if (string.IsNullOrEmpty(filePath) || filePath == "/")
            {
                return null;
            }
            try
            {
                return _dropboxClient.Files.GetMetadataAsync(filePath).Result.AsFile;
            }
            catch (AggregateException ex)
            {
                if (ex.InnerException is ApiException<GetMetadataError>
                    && ex.InnerException.Message.StartsWith("path/not_found/"))
                {
                    return null;
                }
                throw;
            }
        }

        public List<Metadata> GetItems(string folderPath)
        {
            return new List<Metadata>(_dropboxClient.Files.ListFolderAsync(folderPath).Result.Entries);
        }

        public Stream DownloadStream(string filePath, int offset = 0)
        {
            if (string.IsNullOrEmpty(filePath)) throw new ArgumentNullException("file");

            using (var response = _dropboxClient.Files.DownloadAsync(filePath).Result)
            {
                var tempBuffer = TempStream.Create();
                using (var str = response.GetContentAsStreamAsync().Result)
                {
                    if (str != null)
                    {
                        str.CopyTo(tempBuffer);
                        tempBuffer.Flush();
                        tempBuffer.Seek(offset, SeekOrigin.Begin);
                    }
                }
                return tempBuffer;
            }
        }

        public FolderMetadata CreateFolder(string title, string parentPath)
        {
            var path = MakeDropboxPath(parentPath, title);
            var result = _dropboxClient.Files.CreateFolderV2Async(path, true).Result;
            return result.Metadata;
        }

        public FileMetadata CreateFile(Stream fileStream, string title, string parentPath)
        {
            var path = MakeDropboxPath(parentPath, title);
            return _dropboxClient.Files.UploadAsync(path, WriteMode.Add.Instance, true, body: fileStream).Result;
        }

        public void DeleteItem(Metadata dropboxItem)
        {
            _dropboxClient.Files.DeleteV2Async(dropboxItem.PathDisplay).Wait();
        }

        public FolderMetadata MoveFolder(string dropboxFolderPath, string dropboxFolderPathTo, string folderName)
        {
            var pathTo = MakeDropboxPath(dropboxFolderPathTo, folderName);
            var result = _dropboxClient.Files.MoveV2Async(dropboxFolderPath, pathTo, autorename: true).Result;
            return (FolderMetadata)result.Metadata;
        }

        public FileMetadata MoveFile(string dropboxFilePath, string dropboxFolderPathTo, string fileName)
        {
            var pathTo = MakeDropboxPath(dropboxFolderPathTo, fileName);
            var result = _dropboxClient.Files.MoveV2Async(dropboxFilePath, pathTo, autorename: true).Result;
            return (FileMetadata)result.Metadata;
        }

        public FolderMetadata CopyFolder(string dropboxFolderPath, string dropboxFolderPathTo, string folderName)
        {
            var pathTo = MakeDropboxPath(dropboxFolderPathTo, folderName);
            var result = _dropboxClient.Files.CopyV2Async(dropboxFolderPath, pathTo, autorename: true).Result;
            return (FolderMetadata)result.Metadata;
        }

        public FileMetadata CopyFile(string dropboxFilePath, string dropboxFolderPathTo, string fileName)
        {
            var pathTo = MakeDropboxPath(dropboxFolderPathTo, fileName);
            var result = _dropboxClient.Files.CopyV2Async(dropboxFilePath, pathTo, autorename: true).Result;
            return (FileMetadata)result.Metadata;
        }

        public FileMetadata SaveStream(string filePath, Stream fileStream)
        {
            return _dropboxClient.Files.UploadAsync(filePath, WriteMode.Overwrite.Instance, body: fileStream).Result.AsFile;
        }

        public string CreateResumableSession()
        {
            return _dropboxClient.Files.UploadSessionStartAsync(body: new MemoryStream()).Result.SessionId;
        }

        public void Transfer(string dropboxSession, long offset, Stream stream)
        {
            _dropboxClient.Files.UploadSessionAppendV2Async(new UploadSessionCursor(dropboxSession, (ulong)offset), body: stream).Wait();
        }

        public Metadata FinishResumableSession(string dropboxSession, string dropboxFolderPath, string fileName, long offset)
        {
            var dropboxFilePath = MakeDropboxPath(dropboxFolderPath, fileName);
            return FinishResumableSession(dropboxSession, dropboxFilePath, offset);
        }

        public Metadata FinishResumableSession(string dropboxSession, string dropboxFilePath, long offset)
        {
            return _dropboxClient.Files.UploadSessionFinishAsync(
                new UploadSessionCursor(dropboxSession, (ulong)offset),
                new CommitInfo(dropboxFilePath, WriteMode.Overwrite.Instance),
                new MemoryStream()).Result;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/JabberWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Linq;

using ASC.Core;
using ASC.ElasticSearch;
using ASC.ElasticSearch.Core;
using ASC.Web.Talk.Resources;

namespace ASC.Web.Talk
{
    public class JabberWrapper : WrapperWithDoc
    {
        protected override string Table
        {
            get { return "jabber_archive"; }
        }

        [ColumnLastModified("stamp")]
        public override DateTime LastModifiedOn { get; set; }

        [ColumnMeta("jid", 1)]
        public string Jid { get; set; }

        [ColumnTenantId("")]
        public override int TenantId
        {
            get
            {
                try
                {
                    var alias = Jid.Split('|')[0].Split('@')[1];
                    var index = alias.IndexOf(CoreContext.Configuration.BaseDomain, StringComparison.Ordinal);
                    if (CoreContext.Configuration.BaseDomain != alias && index > 0)
                    {
                        alias = alias.Substring(0, index);
                    }

                    var tenant = CoreContext.TenantManager.GetTenant(alias);
                    return tenant.TenantId;
                }
                catch (Exception)
                {
                    return -1;
                }
            }
        }

        private string message;

        [Column("message", 1)]
        public string Message { get { return ""; } set { message = value; } }

        protected override Stream GetDocumentStream()
        {
            if (!string.IsNullOrEmpty(message))
            {
                var doc = XDocument.Parse(message);
                if (doc.Declaration == null)
                {
                    doc.Declaration = new XDeclaration("1.0", "utf-8", "yes");
                }

                var result = new MemoryStream();
                doc.Save(result);
                result.Position = 0;
                return result;
            }

            return new MemoryStream(new byte[0]);
        }

        protected override Task<Stream> GetDocumentStreamAsync()
        {
            return Task.FromResult(GetDocumentStream());
        }

        public override string SettingsTitle
        {
            get { return TalkResource.IndexTitle; }
        }
    }
}


<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/MailRuLoginProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Web;

using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.Profile;

using Newtonsoft.Json.Linq;

namespace ASC.FederatedLogin.LoginProviders
{
    public class MailRuLoginProvider : BaseLoginProvider<MailRuLoginProvider>
    {
        public override string CodeUrl
        {
            get { return "https://connect.mail.ru/oauth/authorize"; }
        }

        public override string AccessTokenUrl
        {
            get { return "https://connect.mail.ru/oauth/token"; }
        }

        public override string ClientID
        {
            get { return this["mailRuClientId"]; }
        }

        public override string ClientSecret
        {
            get { return this["mailRuClientSecret"]; }
        }

        public override string RedirectUri
        {
            get { return this["mailRuRedirectUrl"]; }
        }

        private const string MailRuApiUrl = "http://www.appsmail.ru/platform/api";

        public MailRuLoginProvider()
        {
        }

        public MailRuLoginProvider(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
            : base(name, order, props, additional)
        {
        }

        public override LoginProfile ProcessAuthoriztion(HttpContext context, IDictionary<string, string> @params)
        {
            try
            {
                var token = Auth(context, Scopes);

                if (token == null)
                {
                    throw new Exception("Login failed");
                }

                var uid = GetUid(token);

                return RequestProfile(token.AccessToken, uid);
            }
            catch (ThreadAbortException)
            {
                throw;
            }
            catch (Exception ex)
            {
                return LoginProfile.FromError(ex);
            }
        }

        public override LoginProfile GetLoginProfile(string accessToken)
        {
            throw new NotImplementedException();
        }

        private LoginProfile RequestProfile(string accessToken, string uid)
        {
            var queryDictionary = new Dictionary<string, string>
                {
                    { "app_id", ClientID },
                    { "method", "users.getInfo" },
                    { "secure", "1" },
                    { "session_key", accessToken },
                    { "uids", uid },
                };

            var sortedKeys = queryDictionary.Keys.ToList();
            sortedKeys.Sort();

            var mailruParams = string.Join("", sortedKeys.Select(key => key + "=" + queryDictionary[key]).ToList());
            var sig = string.Join("", MD5.Create().ComputeHash(Encoding.ASCII.GetBytes(mailruParams + ClientSecret)).Select(b => b.ToString("x2")));

            var mailRuProfile = RequestHelper.PerformRequest(
                MailRuApiUrl
                + "?" + string.Join("&", queryDictionary.Select(pair => pair.Key + "=" + HttpUtility.UrlEncode(pair.Value)))
                + "&sig=" + HttpUtility.UrlEncode(sig));
            var loginProfile = ProfileFromMailRu(mailRuProfile);

            return loginProfile;
        }

        private static LoginProfile ProfileFromMailRu(string strProfile)
        {
            var jProfile = JArray.Parse(strProfile);
            if (jProfile == null) throw new Exception("Failed to correctly process the response");

            var mailRuProfiles = jProfile.ToObject<List<MailRuProfile>>();
            if (mailRuProfiles.Count == 0) throw new Exception("Failed to correctly process the response");

            var profile = new LoginProfile
            {
                EMail = mailRuProfiles[0].email,
                Id = mailRuProfiles[0].uid,
                FirstName = mailRuProfiles[0].first_name,
                LastName = mailRuProfiles[0].last_name,

                Provider = ProviderConstants.MailRu,
            };

            return profile;
        }

        private class MailRuProfile
        {
            public string uid = null;
            public string first_name = null;
            public string last_name = null;
            public string email = null;
        }

        private static string GetUid(OAuth20Token token)
        {
            if (string.IsNullOrEmpty(token.OriginJson)) return null;
            var parser = JObject.Parse(token.OriginJson);

            return
                parser == null
                    ? null
                    : parser.Value<string>("x_mailru_vid");
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/mail.servicemanager.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof window.serviceManager === 'undefined') {

    window.serviceManager = (function ($) {
        var isInit = false;

        function init() {
            if (true === isInit) {
                return;
            }

            isInit = true;
            if (!ASC.Resources.Master.Hub.Url) {
                setInterval(function() {
                    getMailFolders({ check_conversations_on_changes: true });
                }, ASC.Mail.Constants.CHECK_NEWS_TIMEOUT);
                setInterval(function () {
                    getAccounts();
                }, ASC.Mail.Constants.CHECK_NEWS_TIMEOUT * 10);
            }
        }

        function hideCallback() {
            window.LoadingBanner.hideLoading();
        }

        function errorCallback() {
        }

        function wrapHideCallback(orig) {
            return function() {
                window.LoadingBanner.hideLoading();
                orig.apply(this, arguments);
            };
        }

        function wrapper(paramsCount, orig) {
            return function() {
                var loadingMessage = arguments.length > paramsCount ? arguments[arguments.length - 1] : undefined;
                var options;
                if (loadingMessage) {
                    window.LoadingBanner.displayMailLoading(loadingMessage);
                    options = arguments[arguments.length - 2] || {};
                    options.success = options.hasOwnProperty('success') && typeof options.success === 'function' ?
                        wrapHideCallback(options.success) : hideCallback;
                    options.error = options.hasOwnProperty('error') && typeof options.error === 'function' ? wrapHideCallback(options.error) : hideCallback;
                } else {
                    options = arguments[arguments.length - 1] || {};
                    options.error = options.hasOwnProperty('error') && typeof options.error === 'function' ? options.error : errorCallback;
                }

                return orig.apply(this, arguments);
            };
        }

        function checkNew(params, options) {
            params = params || {};
            params.forced = params.forced || MailFilter.getFolder() == TMMail.sysfolders.userfolder.id;

            window.Teamlab.getMailFolders(params, options);

            if (commonSettingsPage.isConversationsEnabled())
                window.Teamlab.getMailFilteredConversations({ folder_id: MailFilter.getFolder() }, MailFilter.toData(),
                {
                    error: function (p, errors) {
                        console.error("getMailFilteredConversations()", errors);

                        if (errors[0] === "Folder not found") {
                            if (MailFilter.getFolder() !== TMMail.sysfolders.inbox.id) {
                                window.toastr.error(MailScriptResource.UserFolderNotFoundError);
                                TMMail.moveToInbox();
                            }
                            userFoldersManager.reloadTree(0);
                        }
                    }
                });
            else
                window.Teamlab.getMailFilteredMessages({ folder_id: MailFilter.getFolder() }, MailFilter.toData(),
                {
                    error: function (p, errors) {
                        console.error("getMailFilteredMessages()", errors);

                        if (errors[0] === "Folder not found") {
                            if (MailFilter.getFolder() !== TMMail.sysfolders.inbox.id) {
                                window.toastr.error(MailScriptResource.UserFolderNotFoundError);
                                TMMail.moveToInbox();
                            }
                            userFoldersManager.reloadTree(0);
                        }
                    }
                });
        }

        var updateFolders = wrapper(2, function (params, options) {
            checkNew(params, options);
        });

        var getTags = wrapper(2, function(params, options) {
            window.Teamlab.getMailTags(params, options);
        });

        var createTag = wrapper(5, function(name, style, addresses, params, options) {
            window.Teamlab.createMailTag(params, name, style, addresses, options);
        });

        var updateTag = wrapper(6, function(id, name, style, addresses, params, options) {
            window.Teamlab.updateMailTag(params, id, name, style, addresses, options);
        });

        var deleteTag = wrapper(3, function(id, params, options) {
            window.Teamlab.removeMailTag(params, id, options);
        });

        var setTag = wrapper(4, function(messageIds, tagId, params, options) {
            window.Teamlab.setMailTag(params, messageIds, tagId, options);
        });

        var setConverstationsTag = wrapper(4, function(messageIds, tagId, params, options) {
            window.Teamlab.setMailConversationsTag(params, messageIds, tagId, options);
        });

        var unsetTag = wrapper(4, function(messageIds, tagId, params, options) {
            window.Teamlab.unsetMailTag(params, messageIds, tagId, options);
        });

        var unsetConverstationsTag = wrapper(4, function(messageIds, tagId, params, options) {
            window.Teamlab.unsetMailConversationsTag(params, messageIds, tagId, options);
        });

        var getAccounts = wrapper(2, function(params, options) {
            window.Teamlab.getAccounts(params, options);
        });

        var createBox = wrapper(19, function(name, email, pop3Account, pop3Password, pop3Port, pop3Server,
            smtpAccount, smtpPassword, smtpPort, smtpServer, smtpAuth, imap, restrict, incomingEncyptionType,
            outcomingEncryptionType, authTypeIn, authTypeSmtp, params, options) {
            window.Teamlab.createMailMailbox(params, name, email, pop3Account, pop3Password, pop3Port, pop3Server,
                smtpAccount, smtpPassword, smtpPort, smtpServer, smtpAuth, imap, restrict, incomingEncyptionType,
                outcomingEncryptionType, authTypeIn, authTypeSmtp, options);
        });

        var createMinBox = wrapper(4, function(email, password, params, options) {
            window.Teamlab.createMailMailboxSimple(params, email, password, options);
        });

        var createOAuthBox = wrapper(5, function(code, serviceType, params, options) {
            window.Teamlab.createMailMailboxOAuth(params, code, serviceType, options);
        });

        var updateOAuthBox = wrapper(6, function (code, serviceType, mailboxId, params, options) {
            window.Teamlab.updateMailMailboxOAuth(params, code, serviceType, mailboxId, options);
        });

        var getDefaultMailboxSettings = wrapper(3, function(email, params, options) {
            window.Teamlab.getMailDefaultMailboxSettings(params, email, options);
        });

        var updateBox = wrapper(19, function(name, email, pop3Account, pop3Password, pop3Port, pop3Server,
            smtpAccount, smtpPassword, smtpPort, smtpServer, smtpAuth, beginDate, incomingEncyptionType,
            outcomingEncryptionType, authTypeIn, authTypeSmtp, params, options) {
            window.Teamlab.updateMailMailbox(params, name, email, pop3Account, pop3Password, pop3Port, pop3Server,
                smtpAccount, smtpPassword, smtpPort, smtpServer, smtpAuth, beginDate, incomingEncyptionType,
                outcomingEncryptionType, authTypeIn, authTypeSmtp, options);
        });

        var setMailboxState = wrapper(4, function(email, state, params, options) {
            window.Teamlab.setMailMailboxState(params, email, state, options);
        });

        var removeBox = wrapper(3, function(email, params, options) {
            window.Teamlab.removeMailMailbox(params, email, options);
        });

        var getBox = wrapper(3, function(email, params, options) {
            window.Teamlab.getMailMailbox(params, email, options);
        });

        var setDefaultAccount = wrapper(4, function (email, setDefault, params, options) {
            window.Teamlab.setDefaultAccount(params, setDefault, email, options);
        });

        var getMailFolders = wrapper(2, function(params, options) {
            window.Teamlab.getMailFolders(params, options);
        });

        var getMailFilteredConversations = wrapper(2, function(params, options) {
            window.Teamlab.getMailFilteredConversations({ folder_id: MailFilter.getFolder() }, MailFilter.toData(), options || {});
        });

        var getMailFilteredMessages = wrapper(2, function (params, options) {
            window.Teamlab.getMailFilteredMessages({ folder_id: MailFilter.getFolder() }, MailFilter.toData(), options || {});
        });

        var getMessage = wrapper(4, function (id, loadImages, params, options) {
            var data = { loadImages: loadImages, markRead: true };
            window.Teamlab.getMailMessage(params, id, data, options);
        });

        var getMailboxSignature = wrapper(3, function(id, params, options) {
            window.Teamlab.getMailboxSignature(params, id, {}, options);
        });

        var updateMailboxSignature = wrapper(5, function(id, html, isActive, params, options) {
            var data = {};
            data.html = html;
            data.is_active = isActive;
            window.Teamlab.updateMailboxSignature(params, id, data, options);
        });

        var updateMailboxAutoreply = wrapper(10, function (id, turnOn, onlyContacts, turnOnToDate, fromDate, toDate, subject, html, params, options) {
            var data = {};
            data.turnOn = turnOn;
            data.onlyContacts = onlyContacts;
            data.turnOnToDate = turnOnToDate;
            data.fromDate = fromDate;
            data.toDate = toDate;
            data.subject = subject;
            data.html = html;
            window.Teamlab.updateMailboxAutoreply(params, id, data, options);
        });

        var getLinkedCrmEntitiesInfo = wrapper(3, function(id, params, options) {
            var data = {};
            data.message_id = id;
            window.Teamlab.getLinkedCrmEntitiesInfo(params, data, options);
        });

        var getConversation = wrapper(4, function (id, loadAll, params, options) {
            var data = { loadAll: loadAll, markRead: true };
            window.Teamlab.getMailConversation(params, id, data, options);
        });

        var getNextMessageId = wrapper(3, function(prevMessageId, params, options) {
            Teamlab.getNextMailMessageId(params, prevMessageId, MailFilter.toData(), options);
        });

        var getPrevMessageId = wrapper(3, function(nextMessageId, params, options) {
            Teamlab.getPrevMailMessageId(params, nextMessageId, MailFilter.toData(), options);
        });

        var getNextConversationId = wrapper(3, function(prevMessageId, params, options) {
            Teamlab.getNextMailConversationId(params, prevMessageId, MailFilter.toData(), options);
        });

        var getPrevConversationId = wrapper(3, function(nextMessageId, params, options) {
            Teamlab.getPrevMailConversationId(params, nextMessageId, MailFilter.toData(), options);
        });

        var sendMessage = wrapper(3, function(message, params, options) {
            if (!(message instanceof ASC.Mail.Message)) {
                console.error("Unsupported message format");
                return;
            }

            window.Teamlab.sendMailMessage(params, message, options);
        });

        var saveMessage = wrapper(3, function (message, params, options) {
            if (!(message instanceof ASC.Mail.Message)) {
                console.error("Unsupported message format");
                return;
            }

            window.Teamlab.saveMailMessage(params, message, options);
        });

        // possible 'status' values: read/unread/important/normal
        var markMessages = wrapper(4, function(ids, status, params, options) {
            window.Teamlab.markMailMessages(params, ids, status, options);
        });

        // possible 'status' values: read/unread/important/normal
        var markConversations = wrapper(4, function(ids, status, params, options) {
            window.Teamlab.markMailConversations(params, ids, status, options);
        });

        var moveMailMessages = wrapper(5, function (ids, toFolder, userFolderId, params, options) {
            window.Teamlab.moveMailMessages(params, ids, toFolder, userFolderId, options);
        });

        var moveMailConversations = wrapper(5, function (ids, toFolder, userFolderId, params, options) {
            window.Teamlab.moveMailConversations(params, ids, toFolder, userFolderId, options);
        });

        var restoreMailMessages = wrapper(3, function (ids, params, options) {
            var data = { ids: ids };
            window.Teamlab.restoreMailMessages(params, data, options);
        });

        var restoreMailConversations = wrapper(3, function (ids, params, options) {
            var data = { ids: ids };
            var current = MailFilter.getFolder();
            if (current == TMMail.sysfolders.spam.id)
                data.learnSpamTrainer = true;
            window.Teamlab.restoreMailConversations(params, data, options);
        });

        var deleteMessages = wrapper(3, function(ids, params, options) {
            window.Teamlab.removeMailMessages(params, ids, options);
        });

        var deleteConversations = wrapper(3, function(ids, params, options) {
            window.Teamlab.removeMailConversations(params, ids, options);
        });

        var deleteMessageAttachment = wrapper(4, function(messageId, attachmentId, params, options) {
            window.Teamlab.removeMailMessageAttachment(params, messageId, attachmentId, options);
        });

        var removeMailFolderMessages = wrapper(3, function(folderId, params, options) {
            window.Teamlab.removeMailFolderMessages(params, folderId, options);
        });

        var attachDocuments = wrapper(4, function(id, data, params, options) {
            window.Teamlab.addMailDocument(params, id, data, options);
        });

        var getAlerts = wrapper(2, function(params, options) {
            window.Teamlab.getMailAlerts(params, options);
        });

        var deleteAlert = wrapper(3, function(alertId, params, options) {
            window.Teamlab.deleteMailAlert(params, alertId, options);
        });

        var getProfiles = wrapper(2, function(params, options) {
            window.Teamlab.getProfiles(params, options);
        });

        var getProfilesByFilter = wrapper(2, function(params, options) {
            window.Teamlab.getProfilesByFilter(params, options);
        });

        var getCrmContacts = wrapper(2, function(params, options) {
            window.Teamlab.getCrmContacts(params, options);
        });

        var getCrmContactsById = wrapper(2, function(params, ids, options) {
            window.Teamlab.getCrmContactsForMail(params, ids, options);
        });

        var getTlGroups = wrapper(2, function(params, options) {
            window.Teamlab.getGroups(params, options);
        });

        var searchEmails = wrapper(3, function (params, term, options) {
            window.Teamlab.searchEmails(params, term, options);
        });

        var getMailContacts = wrapper(3, function (filterData, params, options) {
            window.Teamlab.getMailContacts(params, filterData, options);
        });
        
        var getMailContactsByInfo = wrapper(3, function (data, params, options) {
            window.Teamlab.getMailContactsByInfo(params, data, options);
        });

        var createMailContact = wrapper(6, function (name, description, emails, phoneNumbers, params, options) {
            window.Teamlab.createMailContact(params, name, description, emails, phoneNumbers, options);
        });

        var deleteMailContacts = wrapper(3, function (ids, params, options) {
            window.Teamlab.deleteMailContacts(params, ids, options);
        });

        var updateMailContact = wrapper(7, function (id, name, description, emails, phoneNumbers, params, options) {
            window.Teamlab.updateMailContact(params, id, name, description, emails, phoneNumbers, options);
        });

        var getCrmContactStatus = wrapper(2, function(params, options) {
            window.Teamlab.getCrmListItem(params, 1 /*ContactStatus*/, options);
        });

        var linkChainToCrm = wrapper(4, function(idMessage, crmContactIds, params, options) {
            window.Teamlab.linkChainToCrm(params, idMessage, crmContactIds, options);
        });

        var markChainAsCrmLinked = wrapper(4, function(idMessage, crmContactIds, params, options) {
            window.Teamlab.markChainAsCrmLinked(params, idMessage, crmContactIds, options);
        });

        var unmarkChainAsCrmLinked = wrapper(4, function(idMessage, crmContactIds, params, options) {
            window.Teamlab.unmarkChainAsCrmLinked(params, idMessage, crmContactIds, options);
        });

        var exportMessageToCrm = wrapper(4, function(idMessage, crmContactIds, params, options) {
            window.Teamlab.exportMessageToCrm(params, idMessage, crmContactIds, options);
        });

        var isConversationLinkedWithCrm = wrapper(3, function(idMessage, params, options) {
            window.Teamlab.isConversationLinkedWithCrm(params, idMessage, options);
        });

        var getHelpCenterHtml = wrapper(2, function(params, options) {
            window.Teamlab.getMailHelpCenterHtml(params, options);
        });

        var getMailServer = wrapper(2, function(params, options) {
            window.Teamlab.getMailServer(params, options);
        });

        var getMailServerFullInfo = wrapper(2, function(params, options) {
            window.Teamlab.getMailServerFullInfo(params, options);
        });

        var getMailServerFreeDns = wrapper(2, function(params, options) {
            window.Teamlab.getMailServerFreeDns(params, options);
        });

        var exportAllAttachmentsToMyDocuments = wrapper(3, function(idMessage, params, options) {
            window.Teamlab.exportAllAttachmentsToMyDocuments(params, idMessage, options);
        });

        var exportAllAttachmentsToDocuments = wrapper(3, function (idMessage, idFolder, params, options) {
            window.Teamlab.exportAllAttachmentsToDocuments(params, idMessage, idFolder, options);
        });

        var exportAttachmentToMyDocuments = wrapper(3, function(idAttachment, params, options) {
            window.Teamlab.exportAttachmentToMyDocuments(params, idAttachment, options);
        });

        var exportAttachmentToDocuments = wrapper(3, function (idAttachment, idFolder, params, options) {
            window.Teamlab.exportAttachmentToDocuments(params, idAttachment, idFolder, options);
        });

        var setEMailInFolder = wrapper(4, function(idAccount, emailInFolder, params, options) {
            window.Teamlab.setEMailInFolder(params, idAccount, emailInFolder, options);
        });

        var getMailDomains = wrapper(2, function(params, options) {
            window.Teamlab.getMailDomains(params, options);
        });

        var getCommonMailDomain = wrapper(2, function (params, options) {
            window.Teamlab.getCommonMailDomain(params, options);
        });

        var addMailDomain = wrapper(4, function(domainName, dnsId, params, options) {
            window.Teamlab.addMailDomain(params, domainName, dnsId, options);
        });

        var removeMailDomain = wrapper(3, function(idDomain, params, options) {
            window.Teamlab.removeMailDomain(params, idDomain, options);
        });

        var addMailbox = wrapper(8, function (name, localPart, domainId, userId, notifyCurrent, notifyProfile, params, options) {
            window.Teamlab.addMailbox(params, name, localPart, domainId, userId, notifyCurrent, notifyProfile, options);
        });

        var addMyMailbox = wrapper(3, function (mailboxName, params, options) {
            window.Teamlab.addMyMailbox(params, mailboxName, options);
        });

        var changeMailboxPassword = wrapper(4, function (mailboxId, password, params, options) {
            window.Teamlab.changeMailboxPassword(params, mailboxId, password, options);
        });

        var getRandomPassword = wrapper(2, function (params, options) {
            window.Teamlab.getRandomPassword(params, options);
        });
        var getMailboxes = wrapper(2, function(params, options) {
            window.Teamlab.getMailboxes(params, options);
        });

        var removeMailbox = wrapper(3, function(idMailbox, params, options) {
            window.Teamlab.removeMailbox(params, idMailbox, options);
        });

        var addMailBoxAlias = wrapper(4, function(mailboxId, aliasName, params, options) {
            window.Teamlab.addMailBoxAlias(params, mailboxId, aliasName, options);
        });

        var updateMailbox = wrapper(4, function (mailboxId, senderName, params, options) {
            window.Teamlab.updateMailbox(params, mailboxId, senderName, options);
        });

        var removeMailBoxAlias = wrapper(4, function(mailboxId, addressId, params, options) {
            window.Teamlab.removeMailBoxAlias(params, mailboxId, addressId, options);
        });

        var addMailGroup = wrapper(5, function(groupName, domainId, addressIds, params, options) {
            window.Teamlab.addMailGroup(params, groupName, domainId, addressIds, options);
        });

        var addMailGroupAddress = wrapper(4, function(groupId, addressId, params, options) {
            window.Teamlab.addMailGroupAddress(params, groupId, addressId, options);
        });

        var removeMailGroupAddress = wrapper(4, function(groupId, addressId, params, options) {
            window.Teamlab.removeMailGroupAddress(params, groupId, addressId, options);
        });

        var getMailGroups = wrapper(2, function(params, options) {
            window.Teamlab.getMailGroups(params, options);
        });

        var removeMailGroup = wrapper(3, function(idGroup, params, options) {
            window.Teamlab.removeMailGroup(params, idGroup, options);
        });

        var isDomainExists = wrapper(3, function(domainName, params, options) {
            window.Teamlab.isDomainExists(params, domainName, options);
        });

        var checkDomainOwnership = wrapper(3, function(domainName, params, options) {
            window.Teamlab.checkDomainOwnership(params, domainName, options);
        });

        var getDomainDnsSettings = wrapper(3, function(domainId, params, options) {
            window.Teamlab.getDomainDnsSettings(params, domainId, options);
        });

        var setConversationEnabledFlag = wrapper(3, function(enabled, params, options) {
            window.Teamlab.setMailConversationEnabledFlag(params, enabled, options);
        });

        var setAlwaysDisplayImagesFlag = wrapper(3, function (enabled, params, options) {
            window.Teamlab.setMailAlwaysDisplayImagesFlag(params, enabled, options);
        });

        var setCacheUnreadMessagesFlag = wrapper(3, function (enabled, params, options) {
            window.Teamlab.setMailCacheUnreadMessagesFlag(params, enabled, options);
        });

        var setEnableGoNextAfterMove = wrapper(3, function (enabled, params, options) {
            window.Teamlab.setMailEnableGoNextAfterMove(params, enabled, options);
        });

        var getMailOperationStatus = wrapper(3, function (id, params, options) {
            window.Teamlab.getMailOperationStatus(params, id, options);
        });

        var setEnableReplaceMessageBody = wrapper(3, function (enabled, params, options) {
            window.Teamlab.setMailEnableReplaceMessageBody(params, enabled, options);
        });

        return {
            init: init,

            getAccounts: getAccounts,
            createBox: createBox,
            createMinBox: createMinBox,
            createOAuthBox: createOAuthBox,
            updateOAuthBox: updateOAuthBox,
            getDefaultMailboxSettings: getDefaultMailboxSettings,
            removeBox: removeBox,
            updateBox: updateBox,
            setMailboxState: setMailboxState,
            getBox: getBox,
            setDefaultAccount: setDefaultAccount,
            getMailFolders: getMailFolders,
            getMessage: getMessage,
            getConversation: getConversation,
            getNextMessageId: getNextMessageId,
            getPrevMessageId: getPrevMessageId,
            getNextConversationId: getNextConversationId,
            getPrevConversationId: getPrevConversationId,
            sendMessage: sendMessage,
            saveMessage: saveMessage,
            markMessages: markMessages,
            markConversations: markConversations,
            moveMailMessages: moveMailMessages,
            moveMailConversations: moveMailConversations,
            restoreMailMessages: restoreMailMessages,
            restoreMailConversations: restoreMailConversations,
            deleteMessages: deleteMessages,
            deleteConversations: deleteConversations,
            deleteMessageAttachment: deleteMessageAttachment,
            getTags: getTags,
            createTag: createTag,
            setTag: setTag,
            setConverstationsTag: setConverstationsTag,
            unsetTag: unsetTag,
            unsetConverstationsTag: unsetConverstationsTag,
            deleteTag: deleteTag,
            updateTag: updateTag,
            removeMailFolderMessages: removeMailFolderMessages,
            updateFolders: updateFolders,
            attachDocuments: attachDocuments,
            getAlerts: getAlerts,
            deleteAlert: deleteAlert,
            getProfiles: getProfiles,
            getProfilesByFilter: getProfilesByFilter,
            getCrmContacts: getCrmContacts,
            getCrmContactsById: getCrmContactsById,
            getCrmContactStatus: getCrmContactStatus,
            searchEmails: searchEmails,
            getMailContacts: getMailContacts,
            getMailContactsByInfo: getMailContactsByInfo,
            createMailContact: createMailContact,
            deleteMailContacts: deleteMailContacts,
            updateMailContact: updateMailContact,
            getTLGroups: getTlGroups,
            linkChainToCrm: linkChainToCrm,
            markChainAsCrmLinked: markChainAsCrmLinked,
            unmarkChainAsCrmLinked: unmarkChainAsCrmLinked,
            exportMessageToCrm: exportMessageToCrm,
            getLinkedCrmEntitiesInfo: getLinkedCrmEntitiesInfo,
            isConversationLinkedWithCrm: isConversationLinkedWithCrm,
            getHelpCenterHtml: getHelpCenterHtml,
            getMailboxSignature: getMailboxSignature,
            updateMailboxSignature: updateMailboxSignature,
            updateMailboxAutoreply: updateMailboxAutoreply,
            exportAllAttachmentsToMyDocuments: exportAllAttachmentsToMyDocuments,
            exportAllAttachmentsToDocuments: exportAllAttachmentsToDocuments,
            exportAttachmentToMyDocuments: exportAttachmentToMyDocuments,
            exportAttachmentToDocuments: exportAttachmentToDocuments,
            setEMailInFolder: setEMailInFolder,
            getMailServer: getMailServer,
            getMailServerFullInfo: getMailServerFullInfo,
            getMailServerFreeDns: getMailServerFreeDns,
            getMailDomains: getMailDomains,
            getCommonMailDomain: getCommonMailDomain,
            addMailDomain: addMailDomain,
            removeMailDomain: removeMailDomain,
            addMailbox: addMailbox,
            addMyMailbox: addMyMailbox,
            changeMailboxPassword: changeMailboxPassword,
            getRandomPassword: <PASSWORD>,
            getMailboxes: getMailboxes,
            removeMailbox: removeMailbox,
            addMailBoxAlias: addMailBoxAlias,
            updateMailbox: updateMailbox,
            removeMailBoxAlias: removeMailBoxAlias,
            addMailGroup: addMailGroup,
            addMailGroupAddress: addMailGroupAddress,
            removeMailGroupAddress: removeMailGroupAddress,
            getMailGroups: getMailGroups,
            removeMailGroup: removeMailGroup,
            isDomainExists: isDomainExists,
            checkDomainOwnership: checkDomainOwnership,
            getDomainDnsSettings: getDomainDnsSettings,
            getMailFilteredConversations: getMailFilteredConversations,
            getMailFilteredMessages: getMailFilteredMessages,

            setConversationEnabledFlag: setConversationEnabledFlag,
            setAlwaysDisplayImagesFlag: setAlwaysDisplayImagesFlag,
            setCacheUnreadMessagesFlag: setCacheUnreadMessagesFlag,
            setEnableGoNextAfterMove: setEnableGoNextAfterMove,
            setEnableReplaceMessageBody: setEnableReplaceMessageBody,

            getMailOperationStatus: getMailOperationStatus
        };
    })(jQuery);
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/Comments/js/comments.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var CommentsManagerObj = new function() {
    this.obj = null;
    this.editorInstance = null;

    this.javaScriptCallBackAddComment = "";

    this.OnEditedCommentJS = "";
    this.OnRemovedCommentJS = "";
    this.OnCanceledCommentJS = "";


    this.FckDomainName = "";
    this.currentCommentID = "";

    this.CkUploadHandlerPath = "";

    this.mainLoader = "";

    this.maxLevel = 8;

    this._jsObjName = "";

    this.onLoadComplete = null;

    function hideAddButton() {
        jq('#add_comment_btn').addClass("display-none");
    };

    function showAddButton() {
        setTimeout(function () { jq('#add_comment_btn').removeClass("display-none"); }, 500);
    };

    function previewClick() {
        if (jq("#btnPreview").hasClass("disable")) return;

        var commentId = jq('#hdnCommentID').val(),
            commentContent = CommentsManagerObj.editorInstance.getData(),
            ajax_opts = {
                before: function () {
                    CommentsManagerObj.BlockCommentsBox();
                },
                after: function () {
                    CommentsManagerObj.UnblockCommentsBox();
                },
                error: function (params, errors) {
                    toastr.error(errors[0]);
                },
                success: callBackPreview
            };


        switch (CommentsManagerObj.moduleName) {
            case "projects_Message":
            case "projects_Task":
                Teamlab.getPrjCommentPreview({}, commentId, commentContent, ajax_opts);
                break;
            case "wiki":
                Teamlab.getWikiCommentPreview({}, commentId, commentContent, ajax_opts);
                break;
            case "blogs":
                Teamlab.getBlogCommentPreview({}, commentId, commentContent, ajax_opts);
                break;
            case "news":
                Teamlab.getNewsCommentPreview({}, commentId, commentContent, ajax_opts);
                break;
            case "bookmarks":
                Teamlab.getBookmarksCommentPreview({}, commentId, commentContent, ajax_opts);
                break;
        }
    };

    function cancelClick() {
        if (CommentsManagerObj.editorInstance.mode == "source") {
            CommentsManagerObj.editorInstance.commands.source.exec();
        }

        CommentsManagerObj.CallActionHandlerJS('cancel', 'CommentsManagerObj.UnblockCommentsBox');

        jq('#commentBox').hide();
        showAddButton();
    };

    function addCommentClick() {

        var text = CommentsManagerObj.editorInstance.getData();
        if (text.trim().length == 0) {
            toastr.error(ASC.Resources.Master.ResourceJS.EmptyCommentErrorMessage);
            return false;
        }

        if (text != "") {

            var ajax_opts =
                {
                    before: function () {
                        CommentsManagerObj.BlockCommentsBox();
                    },
                    after: function () {
                        CommentsManagerObj.UnblockCommentsBox();
                    },
                    error: function (params, errors) {
                        toastr.error(errors[0]);
                    },
                    success: (jq("#hdnAction").val() == "add" ? callBackAddComment : callBackUpdateComment)
                };


            if (jq("#hdnAction").val() == "add") {
                var data = {
                    parentcommentid: jq('#hdnParentComment').val(),
                    entityid: jq('#hdnObjectID').val(),
                    content: CommentsManagerObj.editorInstance.getData()
                };

                switch (CommentsManagerObj.moduleName) {
                    case "projects_Message":
                    case "projects_Task":
                        data = jq.extend(data, { type: CommentsManagerObj.moduleName .split('_')[1]});
                        Teamlab.addPrjComment(data, data, ajax_opts);
                        break;
                    case "wiki":
                        data.entityid = jq("#hdnPageName").val();
                        Teamlab.addWikiComment(data, data, ajax_opts);
                        break;
                    case "blogs":
                        Teamlab.addBlogComment(data, data, ajax_opts);
                        break;
                    case "news":
                        Teamlab.addNewsComment(data, data, ajax_opts);
                        break;
                    case "bookmarks":
                        Teamlab.addBookmarksComment(data, data, ajax_opts);
                        break;
                }
            } else if (jq('#hdnAction').val() == "update") {

                var data = {
                    commentid: jq('#hdnCommentID').val(),
                    content: CommentsManagerObj.editorInstance.getData()
                };

                switch (CommentsManagerObj.moduleName) {
                    case "projects_Message":
                    case "projects_Task":
                        Teamlab.updatePrjComment(data, data.commentid, data, ajax_opts);
                        break;
                    case "wiki":
                        Teamlab.updateWikiComment(data, data.commentid, data, ajax_opts);
                        break;
                    case "blogs":
                        Teamlab.updateBlogComment(data, data.commentid, data, ajax_opts);
                        break;
                    case "news":
                        Teamlab.updateNewsComment(data, data.commentid, data, ajax_opts);
                        break;
                    case "bookmarks":
                        Teamlab.updateBookmarksComment(data, data.commentid, data, ajax_opts);
                        break;
                }
            }
        }
        jq('#noComments').hide();
    };

    function removeCommentClick(elt) {
        var id = jq(elt).attr("id").replace("remove_", ""),
                ajax_opts = {
                    before: function () {
                        CommentsManagerObj.BlockCommentsBox();
                    },
                    after: function () {
                        CommentsManagerObj.UnblockCommentsBox();
                    },
                    error: function (params, errors) {
                        toastr.error(errors[0]);
                    },
                    success: callbackRemove
                },
                fn = null;
        switch (CommentsManagerObj.moduleName) {
            case "projects_Message":
            case "projects_Task":
                fn = function () { Teamlab.removePrjComment({ commentid: id }, id, ajax_opts); };
                break;
            case "wiki":
                fn = function () { Teamlab.removeWikiComment({ commentid: id }, id, ajax_opts); };
                break;
            case "blogs":
                fn = function () { Teamlab.removeBlogComment({ commentid: id }, id, ajax_opts); };
                break;
            case "news":
                fn = function () { Teamlab.removeNewsComment({ commentid: id }, id, ajax_opts); };
                break;
            case "bookmarks":
                fn = function () { Teamlab.removeBookmarksComment({ commentid: id }, id, ajax_opts); };
                break;
        }

        StudioConfirm.OpenDialog('', fn);
    };

    function changeUploadHandlerPath(commentId) {
        var uploadUrl = CommentsManagerObj.CkUploadHandlerPath;

        if (commentId) {
            var url = new URL(CommentsManagerObj.CkUploadHandlerPath);
            var searchParams = url.searchParams;
            searchParams.set("iid", commentId);
            url.search = searchParams.toString();
            uploadUrl = url.toString();
        }

        if (CommentsManagerObj.editorInstance &&
            CommentsManagerObj.editorInstance.status == "ready" &&
            uploadUrl != CommentsManagerObj.editorInstance.config.filebrowserUploadUrl) {
            CommentsManagerObj.editorInstance.destroy();
            buildEditorInstance(uploadUrl);
        }
    }

    function editCommentClick(elt) {
        var id = jq(elt).attr("id").replace("edit_", "");

        CommentsManagerObj.obj = id;
        changeUploadHandlerPath(id);
        setParentComment("");
        setAction("update", id);
        showCommentBox(id);
        CommentsManagerObj.currentCommentID = id;
        return false;
    };

    function responseCommentClick(elt) {
        var id = jq(elt).attr("id").replace("response_", "");

        CommentsManagerObj.obj = id;
        changeUploadHandlerPath(null);
        setParentComment(id);
        setAction("add", null);
        showCommentBox("", elt);

        return false;
    };

    function copyToClipboard(elt) {
        var id = jq(elt).attr("id").replace("clip_", "");
        var link = window.location.href.replace(window.location.hash, '') + '#comment_' + id
        jq('#commentsClip').val(link).select();
        document.execCommand('copy');
        window.toastr.success(ASC.Resources.Master.ResourceJS.LinkCopySuccess);
    };

    function redraw() {
        oddcnt = jq('#mainCommentsContainer div[id^=comment_]:even')
                    .css({ 'border-top': '1px solid #DDD', 'border-bottom': '1px solid #DDD' })
                    .length;
        evencnt = jq('#mainCommentsContainer div[id^=comment_]:odd')
                    .css({ 'border-top': '', 'border-bottom': '' })
                    .length;

        if (oddcnt == evencnt) {
            jq('#mainCommentsContainer').css('border-bottom', '1px solid #DDD');
        } else {
            jq('#mainCommentsContainer').css('border-bottom', '');
        }
    };

    function scrollToElement(target) {
        var parent = jq(jq("body").css("overflow") == "hidden" ? '.mainPageContent' : 'body');
        parent.scrollTo(target, 500);
    }

    function hidePreview() {
        scrollToElement('#commentBox', 500);
        jq('#previewBox').hide("slow");
    };

    function addNewComment() {
        if (CommentsManagerObj.editorInstance) {
            CommentsManagerObj.obj = null;
            changeUploadHandlerPath(null);
            setParentComment("");
            setAction("add", null);
            showCommentBox("", null);

            CommentsManagerObj.currentCommentID = "";
            jq('#hdnCommentID').val('');
        } else {
            setTimeout(function() { addNewComment(); }, 100);
        }
    };

    function callBackPreview(params, comment) {
        var html = jq.tmpl('template-comment',
        {
            comment: comment,
            index: 0,
            commentLevel: 1,
            maxDepthLevel: CommentsManagerObj.maxDepthLevel
        });

        jq('#previewBoxBody').html(html);
        scrollToElement(jq('#previewBox').show(), 500);
    };

    function callBackAddComment(params, response) {
        if (response == null) return;

        var comment = response;

        if (params.parentcommentid === "") {

            var html = jq.tmpl('template-comment',
            {
                comment: comment,
                index: 0,
                commentLevel: 1,
                maxDepthLevel: CommentsManagerObj.maxDepthLevel
            });

            jq('#mainCommentsContainer').append(html);

        } else {
            var level = 1,
                obj = jq('#container_' + params.parentcommentid);

            while (obj.attr("id") != "mainCommentsContainer") {
                level = level + 1;
                obj = obj.parent();
            }

            var html = jq.tmpl("template-comment",
            {
                comment: comment,
                index: 0,
                commentLevel: level,
                maxDepthLevel: CommentsManagerObj.maxDepthLevel
            });

            jq("#container_" + params.parentcommentid).append(html);
        }

        if (CommentsManagerObj.javaScriptCallBackAddComment != "")
            eval(CommentsManagerObj.javaScriptCallBackAddComment);

        jq('#commentBox').hide();

        redraw();

        jq("#mainCommentsContainer").show();
        jq("#commentsTitle").show();
        showAddButton();

        var obj;
        if (params.parentcommentid == "") {
            obj = jq('#mainCommentsContainer > div:last-child').children();
        } else {
            obj = jq('#container_' + params.parentcommentid + ' > div:last-child').children();
        }

        CommentsManagerObj.currentCommentID = obj.attr("id").replace("comment_", "");


        scrollToElement(obj, 500);

        obj.css({ "background-color": "#ffffcc" });
        obj.animate({ backgroundColor: '#ffffff' }, 1000);

        CommentsManagerObj.CallFCKComplete();
    };

    function callBackUpdateComment(params, response) {
        if (response == null) return;

        jq('#content_' + params.commentid).html(response);

        jq('#commentBox').hide("slow");
        showAddButton();

        var obj = jq('#comment_' + params.commentid);

        CommentsManagerObj.currentCommentID = params.commentid;

        scrollToElement(obj, 500);

        obj.css({ "background-color": "#ffffcc" });
        obj.animate({ backgroundColor: '#ffffff' }, 1000);

        CommentsManagerObj.CallFCKComplete();
    };

    function callbackRemove(params, response) {
        var html = jq.tmpl("template-comment-inactive",{});
        jq('#comment_' + params.commentid).html(html);
        CommentsManagerObj.currentCommentID = params.commentid;
        CommentsManagerObj.CallActionHandlerJS('remove', 'CommentsManagerObj.UnblockCommentsBox');

        redraw();
        cancelClick();
    };

    function showCommentBox(id) {
        hideAddButton();

        var ContentDiv = document.getElementById('content_' + id),
            timeOut = 500;

        if (CommentsManagerObj.editorInstance.mode == "source") {
            CommentsManagerObj.editorInstance.commands.source.exec();
        }

        if (ContentDiv != null) {
            CommentsManagerObj.editorInstance.setData(ContentDiv.innerHTML);
        } else {
            CommentsManagerObj.editorInstance.setData('');
            timeOut = 600;
        }

        jq('#commentBox').show();

        scrollToElement(jq('#commentBox .middle-button-container'), 500);
        jq('#previewBox').hide();

        setTimeout(function () {
            CommentsManagerObj.editorInstance.focus();
        }, timeOut);
    };

    function setParentComment(value) {
        jq('#hdnParentComment').val(value);
    };

    function setAction(action, comment_id) {
        jq('#hdnAction').val(action);

        if (comment_id != null)
            jq('#hdnCommentID').val(comment_id);
    };

    function buildEditorInstance(uploadUrl) {
        CommentsManagerObj.editorInstance =
            jq("#commentEditor" + CommentsManagerObj._jsObjName)
                .ckeditor(
                    {
                        toolbar: "Comment",
                        extraPlugins: "teamlabquote,codemirror",
                        filebrowserUploadUrl: uploadUrl || CommentsManagerObj.CkUploadHandlerPath,
                        height: "200"
                    })
                .editor;

        CommentsManagerObj.editorInstance.keystrokeHandler.keystrokes[window.CKEDITOR.CTRL + 13] = "ctrlEnter";
        CommentsManagerObj.editorInstance.addCommand("ctrlEnter", {
            exec: function (editor, data) {
                addCommentClick();
            }
        });

        CommentsManagerObj.editorInstance.on("change", function () {
            if (this.getData() == "") {
                jq("#btnPreview").addClass("disable");
            } else {
                jq("#btnPreview").removeClass("disable");
            }
        });
    };

    this.Init = function () {
        try {
            CommentsManagerObj.comments = jq.parseJSON(jq.base64.decode(CommentsManagerObj.comments));
        } catch (e) {
            console.log(e);
            CommentsManagerObj.comments = [];
        }

        jq("#commentsTempContainer_" + CommentsManagerObj.objectID).html(jq.tmpl("template-commentsList", CommentsManagerObj));

        jq("code").each(function () { hljs.highlightBlock(jq(this).get(0)); });

        redraw();

        jq("#btnPreview").on("click", function () { previewClick(); return false; });
        jq("#btnCancel").on("click", function () { cancelClick(); });
        jq("#btnAddComment").on("click", function () { addCommentClick(); return false; });

        jq("#add_comment_btn").on("click", function () { addNewComment(); });

        jq("#previewBox .middle-button-container > .button.blue").on("click", function () { hidePreview(); return false; });

        jq("#mainCommentsContainer").on("click", "[id^=remove_]", function () { removeCommentClick(this); });

        jq("#mainCommentsContainer").on("click", "[id^=edit_]", function () { editCommentClick(this); });

        jq("#mainCommentsContainer").on("click", "[id^=response_]", function () { responseCommentClick(this); });

        jq("#mainCommentsContainer").on("click", "[id^=clip_]", function () { copyToClipboard(this); });

        ckeditorConnector.load(buildEditorInstance);

        if (CommentsManagerObj.onLoadComplete && typeof CommentsManagerObj.onLoadComplete == "function") {
            CommentsManagerObj.onLoadComplete();
        }

        var hash = window.location.hash;
        if (hash) {
            setTimeout(function () { window.scrollTo(0, 0); }, 0);
            if (hash.indexOf("#comment_") == 0) {
                setTimeout(function () {
                    scrollToElement(hash, 500);
                    jq(hash).css({ "background-color": "#ffffcc" }).animate({ backgroundColor: '#ffffff' }, 1000);
                }, 1000);
            }
        }
    };

    this.BlockCommentsBox = function() {
        LoadingBanner.showLoaderBtn("#commentBoxContainer");
        CommentsManagerObj.mainLoader = jq.blockUI.defaults.message;
        jq.blockUI.defaults.message = '';
        jq.blockUI();
    };

    this.UnblockCommentsBox = function () {
        LoadingBanner.hideLoaderBtn("#commentBoxContainer");
        jq.blockUI.defaults.message = CommentsManagerObj.mainLoader;
        jq.unblockUI();
    };

    this.CallActionHandlerJS = function(action, callBack) {
        switch (action) {
            case "add":
                if (CommentsManagerObj.OnEditedCommentJS != "")
                    eval(CommentsManagerObj.OnEditedCommentJS)(CommentsManagerObj.currentCommentID, CommentsManagerObj.editorInstance.getData() , CommentsManagerObj.FckDomainName, false, callBack);
                return;

            case "edit":
                if (CommentsManagerObj.OnEditedCommentJS != "")
                    eval(CommentsManagerObj.OnEditedCommentJS)(CommentsManagerObj.currentCommentID, CommentsManagerObj.editorInstance.getData(), CommentsManagerObj.FckDomainName, true, callBack);
                return;

            case "remove":
                if (CommentsManagerObj.OnRemovedCommentJS != "")
                    eval(CommentsManagerObj.OnRemovedCommentJS)(CommentsManagerObj.currentCommentID, CommentsManagerObj.FckDomainName, callBack);
                return;

            case "cancel":
                if (CommentsManagerObj.OnCanceledCommentJS != "")
                    eval(CommentsManagerObj.OnCanceledCommentJS)(CommentsManagerObj.currentCommentID, CommentsManagerObj.FckDomainName, (CommentsManagerObj.currentCommentID != ''), callBack);
                return;
        }

        eval(callBack)();
    };

    this.CallFCKComplete = function() {
        if (jq('#hdnAction').val() == "update") {
            CommentsManagerObj.CallActionHandlerJS('edit', 'CommentsManagerObj.UnblockCommentsBox');
        } else {
            CommentsManagerObj.CallActionHandlerJS('add', 'CommentsManagerObj.UnblockCommentsBox');
        }
    };

    this.AddNewComment = addNewComment;
};

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/Core/Business/BookmarkingService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;

using ASC.Bookmarking.Business.Subscriptions;
using ASC.Bookmarking.Common;
using ASC.Bookmarking.Common.Util;
using ASC.Bookmarking.Dao;
using ASC.Bookmarking.Pojo;
using ASC.Common.Caching;
using ASC.Core;
using ASC.Core.Common.Notify;
using ASC.Core.Users;
using ASC.ElasticSearch;
using ASC.Notify;
using ASC.Notify.Model;
using ASC.Notify.Patterns;
using ASC.Notify.Recipients;
using ASC.Web.Community.Search;
using ASC.Web.Core.Users;
using ASC.Web.Studio.Utility;

using Tag = ASC.Bookmarking.Pojo.Tag;

namespace ASC.Bookmarking.Business
{
    public class BookmarkingService : BookmarkingSessionObject<BookmarkingService>, IBookmarkingService
    {
        #region Fields

        private BookmarkingHibernateDao dao;

        public BookmarkingHibernateDao Dao
        {
            get { return dao ?? (dao = BookmarkingHibernateDao.GetCurrentInstanse()); }
            set { dao = value; }
        }

        private IList<Tag> tagsList;

        public BookmarkingService()
        {

        }

        public BookmarkingService(BookmarkingHibernateDao dao)
        {
            this.dao = dao;
            BookmarkingService.UpdateCurrentInstanse(this);
        }

        #endregion

        #region Get Bookmarks

        public UserInfo GetCurrentUser()
        {
            return Dao.GetCurrentUser();
        }

        public IList<Bookmark> GetAllBookmarks(int firstResult, int maxResults)
        {
            return Dao.GetAllBookmarks(firstResult, maxResults);
        }

        public IList<Bookmark> GetAllBookmarks()
        {
            return Dao.GetAllBookmarks();
        }

        public Bookmark GetBookmarkByUrl(string url)
        {
            return Dao.GetBookmarkByUrl(url);
        }

        public Bookmark GetBookmarkByID(long id)
        {
            return Dao.GetBookmarkByID(id);
        }
        public long GetBookmarksCountCreatedByUser(Guid userID)
        {
            return Dao.GetBookmarksCountCreatedByUser(userID);
        }

        public UserBookmark GetCurrentUserBookmark(Bookmark b)
        {
            return Dao.GetCurrentUserBookmark(b);
        }

        public IList<Bookmark> GetBookmarksCreatedByUser(Guid userID, int firstResult, int maxResults)
        {
            return Dao.GetBookmarksCreatedByUser(userID, firstResult, maxResults);
        }

        public IList<Bookmark> GetMostPopularBookmarksCreatedByUser(Guid userID, int firstResult, int maxResults)
        {
            var bookmarks = Dao.GetBookmarksCreatedByUser(userID, 0, int.MaxValue);
            var ids = (from b in bookmarks
                       select b.ID).ToList<long>();
            return Dao.GetMostPopularBookmarks(ids, firstResult, maxResults);
        }

        public IList<UserBookmark> GetUserBookmarks(Bookmark b)
        {
            return Dao.GetUserBookmarks(b);
        }

        public Bookmark GetBookmarkWithUserBookmarks(string url)
        {
            return Dao.GetBookmarkWithUserBookmarks(url);
        }

        #endregion

        #region Get Tags

        public IList<Tag> GetAllTags(string startSymbols, int limit)
        {
            return Dao.GetAllTags(startSymbols, limit);
        }

        public IList<Tag> GetAllTags()
        {
            tagsList = Dao.GetAllTags(null, Int32.MaxValue);
            return tagsList;
        }

        #endregion

        #region Add Bookmark

        public Bookmark AddBookmark(Bookmark b, IList<Tag> tags)
        {
            Dao.UpdateBookmark(b, tags);
            SendRecentBookmarkUpdates(b);
            SubscribeOnBookmarkComments(b);
            return b;
        }

        #endregion

        #region Update Bookmark

        public Bookmark UpdateBookmark(UserBookmark userBookmark, IList<Tag> tags)
        {
            Dao.UpdateBookmark(userBookmark, tags);
            var b = GetBookmarkByID(userBookmark.BookmarkID);
            SubscribeOnBookmarkComments(b);
            FactoryIndexer<BookmarksUserWrapper>.IndexAsync(BookmarksUserWrapper.Create(userBookmark, b));
            return b;
        }

        public Bookmark UpdateBookmark(Bookmark bookmark, IList<Tag> tags)
        {
            Dao.UpdateBookmark(bookmark, tags);
            var b = GetBookmarkByID(bookmark.ID);
            return b;
        }

        #endregion

        #region Remove Bookmark from Favourite

        public static string DeletedBookmarkUrl { get; set; }

        public Bookmark RemoveBookmarkFromFavourite(long bookmarkID, Guid? userID = null)
        {
            var b = Dao.GetBookmarkByID(bookmarkID);
            var comments = GetBookmarkComments(b);
            var result = Dao.RemoveBookmarkFromFavourite(bookmarkID, userID);
            if (b != null)
            {
                DeletedBookmarkUrl = b.URL;
                UnSubscribe(b.ID.ToString(CultureInfo.InvariantCulture), BookmarkingBusinessConstants.NotifyActionNewComment);
            }
            if (result == null)
            {
                foreach (var comment in comments)
                {
                    CommonControlsConfigurer.FCKUploadsRemoveForItem("bookmarking_comments", comment.ID.ToString());
                }

                AscCache.Default.Remove("communityScreen" + TenantProvider.CurrentTenantID);
            }
            return result;
        }
        #endregion

        #region Sorting

        public IList<Bookmark> GetFavouriteBookmarksSortedByRaiting(int firstResult, int maxResults)
        {
            return Dao.GetFavouriteBookmarksSortedByRaiting(firstResult, maxResults);
        }
        public IList<Bookmark> GetFavouriteBookmarksSortedByDate(int firstResult, int maxResults)
        {
            return Dao.GetFavouriteBookmarksSortedByDate(firstResult, maxResults);
        }

        public IList<Bookmark> GetMostRecentBookmarks(int firstResult, int maxResults)
        {
            return Dao.GetMostRecentBookmarks(firstResult, maxResults);
        }

        public IList<Bookmark> GetMostRecentBookmarksWithRaiting(int firstResult, int maxResults)
        {
            return Dao.GetMostRecentBookmarksWithRaiting(firstResult, maxResults);
        }

        public IList<Bookmark> GetTopOfTheDay(int firstResult, int maxResults)
        {
            var d = GetDateTimeToUtcWithShift(-1);
            return Dao.GetBookmarksSortedByRaiting(d, firstResult, maxResults);
        }

        public IList<Bookmark> GetTopOfTheWeek(int firstResult, int maxResults)
        {
            var d = GetDateTimeToUtcWithShift(-7);
            return Dao.GetBookmarksSortedByRaiting(d, firstResult, maxResults);
        }

        public IList<Bookmark> GetTopOfTheMonth(int firstResult, int maxResults)
        {
            var d = GetDateTimeToUtcWithShift(-31);
            return Dao.GetBookmarksSortedByRaiting(d, firstResult, maxResults);
        }

        public IList<Bookmark> GetTopOfTheYear(int firstResult, int maxResults)
        {
            var d = GetDateTimeToUtcWithShift(-365);
            return Dao.GetBookmarksSortedByRaiting(d, firstResult, maxResults);
        }

        private static DateTime GetDateTimeToUtcWithShift(int days)
        {
            var now = DateTime.UtcNow;
            return now.Date.AddDays(days);
        }

        #endregion

        #region Tags
        private static IList<Tag> SortTagsCloud(List<Tag> tags)
        {
            tags.Sort((t1, t2) => string.CompareOrdinal(t1.Name, t2.Name));
            return tags;
        }


        public IList<Bookmark> GetMostPopularBookmarksByTag(Tag t)
        {
            return Dao.GetMostPopularBookmarksByTag(t, BookmarkingBusinessConstants.MostPopularBookmarksByTagLimit);
        }

        public IList<Bookmark> GetMostPopularBookmarksByTag(IList<Tag> tags)
        {
            return Dao.SearchMostPopularBookmarksByTag(tags, 0, Int32.MaxValue);
        }

        public IList<Tag> GetBookmarkTags(Bookmark b)
        {
            return Dao.GetBookmarkTags(b);
        }

        public IList<Tag> GetUserBookmarkTags(UserBookmark ub)
        {
            return Dao.GetUserBookmarkTags(ub);
        }
        #endregion

        #region Comments

        public Comment GetCommentById(Guid commentID)
        {
            return Dao.GetCommentById(commentID);
        }

        public void AddComment(Comment comment)
        {
            var c = Dao.AddComment(comment);

            if (c == null)
            {
                return;
            }
            var b = GetCommentBookmark(c);

            SendCommentUpdates(c, b);
            SubscribeOnBookmarkComments(b, true);
        }

        public void UpdateComment(Guid commentID, string text)
        {
            Dao.UpdateComment(commentID, text);
        }

        public void RemoveComment(Guid commentID)
        {
            Dao.RemoveComment(commentID);
        }

        public long GetCommentsCount(long bookmarkID)
        {
            return Dao.GetCommentsCount(bookmarkID);
        }

        public IList<Comment> GetBookmarkComments(Bookmark b)
        {
            return Dao.GetBookmarkComments(b);
        }

        private Bookmark GetCommentBookmark(Comment c)
        {
            return Dao.GetCommentBookmark(c);
        }

        public IList<Comment> GetChildComments(Comment c)
        {
            return Dao.GetChildComments(c);
        }

        #endregion

        #region Notifications
        private static void SendCommentUpdates(Comment c, Bookmark b)
        {
            if (c == null || b == null)
            {
                return;
            }
            var url = ModifyBookmarkUrl(b);
            var tags = new[]{
                    new TagValue(BookmarkSubscriptionConstants.BookmarkTitle, b.Name),
                    new TagValue(BookmarkSubscriptionConstants.BookmarkUrl, url),
                    new TagValue(BookmarkSubscriptionConstants.UserURL,
                                                     BookmarkingBusinessUtil.RenderProfileLink(c.UserID)),
                    new TagValue(BookmarkSubscriptionConstants.Date, c.Datetime.ToShortString()),
                    new TagValue(BookmarkSubscriptionConstants.CommentBody, c.Content),GetReplyToTag(b,c)
                            };

            var objectID = b.ID.ToString(CultureInfo.InvariantCulture);

            var action = BookmarkingBusinessConstants.NotifyActionNewComment;

            SendBookmarkNoticeAsync(action, objectID, tags);
        }

        private void SendRecentBookmarkUpdates(Bookmark b)
        {
            var url = ModifyBookmarkUrl(b);
            var tags = new[]
                           {
                               new TagValue(BookmarkSubscriptionConstants.BookmarkTitle, HttpUtility.HtmlDecode(b.Name)),
                               new TagValue(BookmarkSubscriptionConstants.BookmarkUrl, url),
                               new TagValue(BookmarkSubscriptionConstants.UserURL,
                                            string.Format("\"{0}\":\"{1}\"",
                                                          CommonLinkUtility.GetFullAbsolutePath(
                                                              CommonLinkUtility.GetUserProfile(b.UserCreatorID)),
                                                          DisplayUserSettings.GetFullUserName(b.UserCreatorID))),
		                       //TODO: Rewrite patterns
		                       new TagValue(BookmarkSubscriptionConstants.Date, b.Date.ToShortString()),
                               new TagValue(BookmarkSubscriptionConstants.BookmarkDescription, HttpUtility.HtmlDecode(b.Description)),
                               GetReplyToTag(b, null)
                           };

            const string objectID = BookmarkingBusinessConstants.SubscriptionRecentBookmarkID;

            var action = BookmarkingBusinessConstants.NotifyActionNewBookmark;

            SendBookmarkNoticeAsync(action, objectID, tags);
        }

        private static TagValue GetReplyToTag(Bookmark bookmark, Comment comment)
        {
            return ReplyToTagProvider.Comment("bookmark", bookmark.ID.ToString(CultureInfo.InvariantCulture), comment != null ? comment.ID.ToString() : null);
        }

        internal static string ModifyBookmarkUrl(Bookmark b)
        {
            var bookmarkUrl = HttpUtility.UrlEncode(HttpUtility.HtmlDecode(b.URL));
            var bookmarkingAbsolutePath = CommonLinkUtility.GetFullAbsolutePath(BookmarkingBusinessConstants.BookmarkingBasePath + "/BookmarkInfo.aspx");

            var url = string.Format("{0}?Url={1}", bookmarkingAbsolutePath, bookmarkUrl);
            return url;
        }

        private static void SendBookmarkNoticeAsync(INotifyAction action, string objectID, TagValue[] tags)
        {
            var initatorInterceptor = new InitiatorInterceptor(GetCurrentRecipient());
            var notifyClient = BookmarkingNotifyClient.NotifyClient;
            try
            {
                notifyClient.AddInterceptor(initatorInterceptor);
                notifyClient.SendNoticeAsync(action, objectID, null, tags);
            }
            finally
            {
                notifyClient.RemoveInterceptor(initatorInterceptor.Name);
            }
        }

        private static IRecipient GetCurrentRecipient()
        {
            return GetRecipient(SecurityContext.CurrentAccount.ID);
        }

        private static IRecipient GetRecipient(Guid userID)
        {
            var user = CoreContext.UserManager.GetUsers(userID);
            return new DirectRecipient(user.ID.ToString(), user.ToString());
        }

        #endregion

        #region Subscriptions
        public void Subscribe(string objectID, INotifyAction notifyAction)
        {
            var provider = BookmarkingNotifySource.Instance.GetSubscriptionProvider();
            provider.Subscribe(notifyAction, objectID, GetCurrentRecipient());
        }

        public bool IsSubscribed(string objectID, INotifyAction notifyAction)
        {
            var provider = BookmarkingNotifySource.Instance.GetSubscriptionProvider();
            var isSubscribed = provider.IsSubscribed(notifyAction, GetCurrentRecipient(), objectID);
            return isSubscribed;
        }

        public void UnSubscribe(string objectID, INotifyAction notifyAction, Guid? userID = null)
        {
            var provider = BookmarkingNotifySource.Instance.GetSubscriptionProvider();
            provider.UnSubscribe(notifyAction, objectID, GetRecipient(userID ?? SecurityContext.CurrentAccount.ID));
        }

        private void SubscribeOnBookmarkComments(Bookmark b)
        {
            SubscribeOnBookmarkComments(b, false);
        }

        private void SubscribeOnBookmarkComments(Bookmark b, bool checkIfUnsubscribed)
        {
            if (b == null)
            {
                return;
            }
            var id = b.ID.ToString();
            var provider = BookmarkingNotifySource.Instance.GetSubscriptionProvider();
            var subsribe = true;
            if (checkIfUnsubscribed)
            {
                if (provider.IsUnsubscribe(GetCurrentRecipient() as DirectRecipient, BookmarkingBusinessConstants.NotifyActionNewComment, id))
                {
                    subsribe = false;
                }
            }
            if (subsribe)
            {
                provider.Subscribe(BookmarkingBusinessConstants.NotifyActionNewComment, id, GetCurrentRecipient());
            }
        }
        #endregion

        #region Search

        public IList<Bookmark> SearchBookmarks(IList<string> searchStringList, int firstResult, int maxResults)
        {
            return Dao.SearchBookmarks(searchStringList, firstResult, maxResults);
        }

        public IList<Bookmark> SearchAllBookmarks(IList<string> searchStringList)
        {
            return Dao.SearchBookmarks(searchStringList, 0, Int32.MaxValue, true);
        }

        public IList<Bookmark> SearchBookmarksSortedByRaiting(IList<string> searchStringList, int firstResult, int maxResults)
        {
            var bookmarks = Dao.SearchBookmarks(searchStringList, 0, int.MaxValue);
            var ids = (from b in bookmarks
                       select b.ID).ToList<long>();
            return Dao.GetMostPopularBookmarks(ids, firstResult, maxResults);
        }

        public IList<Bookmark> SearchBookmarksByTag(string searchString, int firstResult, int maxResults)
        {
            return Dao.SearchBookmarksByTag(searchString, firstResult, maxResults);
        }

        public IList<Bookmark> SearchMostPopularBookmarksByTag(string tagName, int firstResult, int maxResults)
        {
            return Dao.SearchMostPopularBookmarksByTag(tagName, firstResult, maxResults);
        }

        #endregion

        #region IBookmarkingService Members


        public IList<Bookmark> GetFullBookmarksInfo(IList<long> bookmarkIds)
        {
            return Dao.GetFullBookmarksInfo(bookmarkIds);
        }

        public IList<Bookmark> GetFullBookmarksInfo(IList<Bookmark> bookmarks)
        {
            if (bookmarks == null || bookmarks.Count == 0)
            {
                return new List<Bookmark>();
            }
            var ids = (from b in bookmarks
                       select b.ID).Distinct<long>().ToList<long>();
            return GetFullBookmarksInfo(ids);
        }

        #endregion

        #region IBookmarkingService Members


        public void SetBookmarkTags(Bookmark b)
        {
            Dao.SetBookmarkTags(b);
        }

        #endregion

        public IList<Bookmark> GetBookmarks(DateTime from, DateTime to)
        {
            return Dao.GetBookmarksUpdates(from, to);
        }

        public IList<Comment> GetComments(DateTime from, DateTime to)
        {
            return Dao.GetCommentsUpdates(from, to);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Common/WikiObjectsSecurityObject.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Security;
using ASC.Common.Security.Authorizing;
using ASC.Web.UserControls.Wiki;

namespace ASC.Web.Community.Wiki.Common
{
    public class WikiObjectsSecurityObject : ISecurityObject
    {
        public IWikiObjectOwner Object { get; private set; }
        public WikiObjectsSecurityObject(IWikiObjectOwner obj)
        {
            Object = obj;
        }

        #region ISecurityObjectId Members

        public Type ObjectType
        {
            get { return this.GetType(); }
        }

        public object SecurityId
        {
            get { return Object.GetObjectId(); }
        }

        #endregion

        #region ISecurityObjectProvider Members

        public IEnumerable<ASC.Common.Security.Authorizing.IRole> GetObjectRoles(ASC.Common.Security.Authorizing.ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext)
        {
            var roles = new List<IRole>();

            if (!Guid.Empty.Equals(Object.OwnerID) && Object.OwnerID.Equals(account.ID))
            {
                roles.Add(ASC.Common.Security.Authorizing.Constants.Owner);
            }

            return roles;
        }

        public ISecurityObjectId InheritFrom(ISecurityObjectId objectId)
        {
            throw new NotImplementedException();
        }

        public bool InheritSupported
        {
            get { return false; }
        }

        public bool ObjectRolesSupported
        {
            get { return true; }
        }

        #endregion
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/FolderDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Enums;

namespace ASC.Mail.Core.Dao
{
    public class FolderDao : BaseDao, IFolderDao
    {
        protected static ITable table = new MailTableFactory().Create<FolderCountersTable>();

        protected string CurrentUserId { get; private set; }

        public FolderDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public Folder GetFolder(FolderType folder)
        {
            var query = Query()
                .Where(FolderCountersTable.Columns.Folder, (int)folder)
                .Where(FolderCountersTable.Columns.Tenant, Tenant)
                .Where(FolderCountersTable.Columns.User, CurrentUserId);

            return Db.ExecuteList(query)
                .ConvertAll(ToFolder)
                .SingleOrDefault();
        }

        public List<Folder> GetFolders()
        {
            var query = Query()
                .Where(FolderCountersTable.Columns.Tenant, Tenant)
                .Where(FolderCountersTable.Columns.User, CurrentUserId);

            return Db.ExecuteList(query)
                .ConvertAll(ToFolder);
        }

        public int Save(Folder folder)
        {
            var query = new SqlInsert(FolderCountersTable.TABLE_NAME, true)
                .InColumnValue(FolderCountersTable.Columns.Tenant, folder.Tenant)
                .InColumnValue(FolderCountersTable.Columns.User, folder.UserId)
                .InColumnValue(FolderCountersTable.Columns.Folder, (int)folder.FolderType)
                .InColumnValue(FolderCountersTable.Columns.UnreadMessagesCount, folder.UnreadCount)
                .InColumnValue(FolderCountersTable.Columns.UnreadConversationsCount, folder.UnreadChainCount)
                .InColumnValue(FolderCountersTable.Columns.TotalMessagesCount, folder.TotalCount)
                .InColumnValue(FolderCountersTable.Columns.TotalConversationsCount, folder.TotalChainCount);

            return Db.ExecuteNonQuery(query);
        }

        private const string INCR_VALUE_FORMAT = "{0}={0}+({1})";
        private const string SET_VALUE_FORMAT = "{0}={1}";

        public int ChangeFolderCounters(
            FolderType folder,
            int? unreadMessDiff = null,
            int? totalMessDiff = null,
            int? unreadConvDiff = null,
            int? totalConvDiff = null)
        {
            if (!unreadMessDiff.HasValue
                && !totalMessDiff.HasValue
                && !unreadConvDiff.HasValue
                && !totalConvDiff.HasValue)
            {
                return -1;
            }

            var updateQuery = new SqlUpdate(FolderCountersTable.TABLE_NAME)
                .Where(FolderCountersTable.Columns.Tenant, Tenant)
                .Where(FolderCountersTable.Columns.User, CurrentUserId)
                .Where(FolderCountersTable.Columns.Folder, (int)folder);

            Action<string, int?> setColumnValue = (column, item) =>
            {
                if (!item.HasValue)
                    return;

                updateQuery.Set(item.Value != 0
                    ? string.Format(INCR_VALUE_FORMAT, column, item.Value)
                    : string.Format(SET_VALUE_FORMAT, column, 0));
            };

            setColumnValue(FolderCountersTable.Columns.UnreadMessagesCount, unreadMessDiff);

            setColumnValue(FolderCountersTable.Columns.TotalMessagesCount, totalMessDiff);

            setColumnValue(FolderCountersTable.Columns.UnreadConversationsCount, unreadConvDiff);

            setColumnValue(FolderCountersTable.Columns.TotalConversationsCount, totalConvDiff);

            var result = Db.ExecuteNonQuery(updateQuery);

            return result;
        }

        public int Delete()
        {
            var query = new SqlDelete(FolderCountersTable.TABLE_NAME)
                .Where(MailTable.Columns.Tenant, Tenant)
                .Where(MailTable.Columns.User, CurrentUserId);

            return Db.ExecuteNonQuery(query);
        }

        protected Folder ToFolder(object[] r)
        {
            var f = new Folder
            {
                Tenant = Convert.ToInt32(r[0]),
                UserId = Convert.ToString(r[1]),
                FolderType = (FolderType)Convert.ToInt32(r[2]),
                TimeModified = Convert.ToDateTime(r[3]),
                UnreadCount = Convert.ToInt32(r[4]),
                TotalCount = Convert.ToInt32(r[5]),
                UnreadChainCount = Convert.ToInt32(r[6]),
                TotalChainCount = Convert.ToInt32(r[7])
            };

            return f;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/LoginWithThirdParty.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.UI;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Users;
using ASC.FederatedLogin;
using ASC.FederatedLogin.Profile;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Core.Users;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Users.UserProfile;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Common
{
    public partial class LoginWithThirdParty : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Common/LoginWithThirdParty.ascx"; }
        }

        protected string LoginMessage;
        public bool RenderDisabled { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            var accountLink = (AccountLinkControl)LoadControl(AccountLinkControl.Location);
            accountLink.ClientCallback = "loginJoinCallback";
            accountLink.SettingsView = false;
            accountLink.RenderDisabled = RenderDisabled;
            ThirdPartyList.Controls.Add(accountLink);

            var loginProfile = Request.Url.GetProfile();

            if (loginProfile == null && !IsPostBack || SecurityContext.IsAuthenticated) return;

            string cookiesKey;
            try
            {
                if (loginProfile == null)
                {
                    if (string.IsNullOrEmpty(Request["__EVENTARGUMENT"]) || Request["__EVENTTARGET"] != "thirdPartyLogin")
                    {
                        return;
                    }

                    loginProfile = new LoginProfile(Request["__EVENTARGUMENT"]);
                }

                var userInfo = GetUserByThirdParty(loginProfile);
                if (!CoreContext.UserManager.UserExists(userInfo.ID)) return;

                cookiesKey = SecurityContext.AuthenticateMe(userInfo.ID);
                CookiesManager.SetCookies(CookiesType.AuthKey, cookiesKey);
                MessageService.Send(HttpContext.Current.Request, MessageAction.LoginSuccessViaSocialAccount);
            }
            catch (System.Security.SecurityException)
            {
                LoginMessage = Resource.InvalidUsernameOrPassword;
                MessageService.Send(HttpContext.Current.Request, loginProfile != null ? loginProfile.EMail : AuditResource.EmailNotSpecified, MessageAction.LoginFailDisabledProfile);
                return;
            }
            catch (Exception exception)
            {
                LoginMessage = exception.Message;
                MessageService.Send(HttpContext.Current.Request, AuditResource.EmailNotSpecified, MessageAction.LoginFail);
                return;
            }

            var refererURL = (string)Session["refererURL"];

            if (String.IsNullOrEmpty(refererURL))
            {
                refererURL = CommonLinkUtility.GetDefault();
            }
            if (Request.DesktopApp())
            {
                refererURL += (refererURL.Contains("?") ? "&" : "?") + "token=" + HttpUtility.HtmlEncode(cookiesKey);
            }

            Session["refererURL"] = null;
            Response.Redirect(refererURL);
        }

        public static UserInfo GetUserByThirdParty(LoginProfile loginProfile)
        {
            try
            {
                if (!string.IsNullOrEmpty(loginProfile.AuthorizationError))
                {
                    // ignore cancellation
                    if (loginProfile.AuthorizationError != "Canceled at provider")
                    {
                        throw new Exception(loginProfile.AuthorizationError);
                    }
                    return Constants.LostUser;
                }

                var userInfo = Constants.LostUser;

                Guid userId;
                if (TryGetUserByHash(loginProfile.HashId, out userId))
                {
                    userInfo = CoreContext.UserManager.GetUsers(userId);
                }

                var isNew = false;
                if (CoreContext.Configuration.Personal)
                {
                    if (CoreContext.UserManager.UserExists(userInfo.ID) && SetupInfo.IsSecretEmail(userInfo.Email))
                    {
                        try
                        {
                            SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);
                            CoreContext.UserManager.DeleteUser(userInfo.ID);
                            userInfo = Constants.LostUser;
                        }
                        finally
                        {
                            SecurityContext.Logout();
                        }
                    }

                    if (!CoreContext.UserManager.UserExists(userInfo.ID))
                    {
                        userInfo = JoinByThirdPartyAccount(loginProfile);

                        isNew = true;
                    }
                }

                if (isNew)
                {
                    var spam = HttpContext.Current.Request["spam"];
                    if (spam != "on")
                    {
                        try
                        {
                            const string _databaseID = "com";
                            using (var db = DbManager.FromHttpContext(_databaseID))
                            {
                                db.ExecuteNonQuery(new SqlInsert("template_unsubscribe", false)
                                                       .InColumnValue("email", userInfo.Email.ToLowerInvariant())
                                                       .InColumnValue("reason", "personal")
                                    );
                                LogManager.GetLogger("ASC.Web").Debug(String.Format("Write to template_unsubscribe {0}", userInfo.Email.ToLowerInvariant()));
                            }
                        }
                        catch (Exception ex)
                        {
                            LogManager.GetLogger("ASC.Web").Debug(String.Format("ERROR write to template_unsubscribe {0}, email:{1}", ex.Message, userInfo.Email.ToLowerInvariant()));
                        }
                    }

                    StudioNotifyService.Instance.UserHasJoin();
                    UserHelpTourHelper.IsNewUser = true;
                    PersonalSettings.IsNewUser = true;
                }

                return userInfo;
            }
            catch (Exception)
            {
                Auth.ProcessLogout();
                throw;
            }
        }

        public static bool TryGetUserByHash(string hashId, out Guid userId)
        {
            userId = Guid.Empty;
            if (string.IsNullOrEmpty(hashId)) return false;

            var linkedProfiles = new AccountLinker("webstudio").GetLinkedObjectsByHashId(hashId);
            var tmp = Guid.Empty;
            if (linkedProfiles.Any(profileId => Guid.TryParse(profileId, out tmp) && CoreContext.UserManager.UserExists(tmp)))
                userId = tmp;
            return true;
        }

        public static UserInfo ProfileToUserInfo(LoginProfile loginProfile)
        {
            if (string.IsNullOrEmpty(loginProfile.EMail)) throw new Exception(Resource.ErrorNotCorrectEmail);

            var firstName = loginProfile.FirstName;
            if (string.IsNullOrEmpty(firstName)) firstName = loginProfile.DisplayName;

            var userInfo = new UserInfo
            {
                FirstName = string.IsNullOrEmpty(firstName) ? UserControlsCommonResource.UnknownFirstName : firstName,
                LastName = string.IsNullOrEmpty(loginProfile.LastName) ? UserControlsCommonResource.UnknownLastName : loginProfile.LastName,
                Email = loginProfile.EMail,
                Title = string.Empty,
                Location = string.Empty,
                CultureName = CoreContext.Configuration.CustomMode ? "ru-RU" : Thread.CurrentThread.CurrentUICulture.Name,
                ActivationStatus = EmployeeActivationStatus.Activated,
            };

            var gender = loginProfile.Gender;
            if (!string.IsNullOrEmpty(gender))
            {
                userInfo.Sex = gender == "male";
            }

            return userInfo;
        }

        private static UserInfo JoinByThirdPartyAccount(LoginProfile loginProfile)
        {
            if (string.IsNullOrEmpty(loginProfile.EMail))
            {
                throw new Exception(Resource.ErrorNotCorrectEmail);
            }

            var userInfo = CoreContext.UserManager.GetUserByEmail(loginProfile.EMail);
            if (!CoreContext.UserManager.UserExists(userInfo.ID))
            {
                var newUserInfo = ProfileToUserInfo(loginProfile);

                try
                {
                    SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);
                    userInfo = UserManagerWrapper.AddUser(newUserInfo, UserManagerWrapper.GeneratePassword());
                }
                finally
                {
                    SecurityContext.Logout();
                }
            }

            var linker = new AccountLinker("webstudio");
            linker.AddLink(userInfo.ID.ToString(), loginProfile);

            return userInfo;
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Data/DbSubscriptionService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Tenants;

namespace ASC.Core.Data
{
    public class DbSubscriptionService : DbBaseService, ISubscriptionService
    {
        public DbSubscriptionService(ConnectionStringSettings connectionString)
            : base(connectionString, "tenant")
        {

        }
        public string[] GetRecipients(int tenant, string sourceId, string actionId, string objectId)
        {
            if (sourceId == null) throw new ArgumentNullException("sourceId");
            if (actionId == null) throw new ArgumentNullException("actionId");

            var q = new SqlQuery("core_subscription")
                .Select("recipient")
                .Where(Exp.Eq("tenant", -1) | Exp.Eq("tenant", tenant))
                .Where("source", sourceId)
                .Where("action", actionId)
                .Where("object", objectId ?? string.Empty)
                .Where("unsubscribed", false)
                .OrderBy("tenant", true)
                .Distinct();

            return ExecList(q).Select(r => Convert.ToString(r[0])).ToArray();
        }

        public IEnumerable<SubscriptionRecord> GetSubscriptions(int tenant, string sourceId, string actionId)
        {
            if (sourceId == null) throw new ArgumentNullException("sourceId");
            if (actionId == null) throw new ArgumentNullException("actionId");

            var q = GetQuery(tenant, sourceId, actionId);
            return GetSubscriptions(q, tenant);
        }

        public IEnumerable<SubscriptionRecord> GetSubscriptions(int tenant, string sourceId, string actionId, string recipientId, string objectId)
        {
            var q = GetQuery(tenant, sourceId, actionId);
            if (!string.IsNullOrEmpty(recipientId))
            {
                q.Where("recipient", recipientId);
            }
            else
            {
                q.Where("object", objectId ?? string.Empty);
            }

            return GetSubscriptions(q, tenant);
        }

        public SubscriptionRecord GetSubscription(int tenant, string sourceId, string actionId, string recipientId, string objectId)
        {
            if (recipientId == null) throw new ArgumentNullException("recipientId");

            var q = GetQuery(tenant, sourceId, actionId)
                .Where("recipient", recipientId)
                .Where("object", objectId ?? string.Empty)
                .SetMaxResults(1);

            return GetSubscriptions(q, tenant).FirstOrDefault();
        }

        public bool IsUnsubscribe(int tenant, string sourceId, string actionId, string recipientId, string objectId)
        {
            if (recipientId == null) throw new ArgumentNullException("recipientId");
            if (sourceId == null) throw new ArgumentNullException("sourceId");
            if (actionId == null) throw new ArgumentNullException("actionId");

            var q = new SqlQuery("core_subscription")
                .SelectCount()
                .Where("tenant", tenant)
                .Where("source", sourceId)
                .Where("action", actionId)
                .Where("recipient", recipientId)
                .Where("unsubscribed", true);

            if (!string.IsNullOrEmpty(objectId))
            {
                q = q.Where(Exp.Eq("object", objectId) | Exp.Eq("object", string.Empty));
            }
            else
            {
                q = q.Where(Exp.Eq("object", string.Empty));
            }

            return ExecScalar<int>(q) > 0;
        }

        public string[] GetSubscriptions(int tenant, string sourceId, string actionId, string recipientId, bool checkSubscribe)
        {
            if (recipientId == null) throw new ArgumentNullException("recipientId");
            if (sourceId == null) throw new ArgumentNullException("sourceId");
            if (actionId == null) throw new ArgumentNullException("actionId");

            var q = new SqlQuery("core_subscription")
                .Select("object")
                .Where(Exp.Eq("tenant", -1) | Exp.Eq("tenant", tenant))
                .Where("source", sourceId)
                .Where("action", actionId)
                .Where("recipient", recipientId)
                .OrderBy("tenant", true)
                .Distinct();

            if (checkSubscribe)
            {
                q = q.Where("unsubscribed", false);
            }

            return ExecList(q).Select(r => Convert.ToString(r[0])).ToArray();
        }

        public void SaveSubscription(SubscriptionRecord s)
        {
            if (s == null) throw new ArgumentNullException("s");

            var i = Insert("core_subscription", s.Tenant)
                .InColumnValue("source", s.SourceId)
                .InColumnValue("action", s.ActionId)
                .InColumnValue("recipient", s.RecipientId)
                .InColumnValue("object", s.ObjectId ?? string.Empty)
                .InColumnValue("unsubscribed", !s.Subscribed);

            ExecNonQuery(i);
        }

        public void RemoveSubscriptions(int tenant, string sourceId, string actionId)
        {
            RemoveSubscriptions(tenant, sourceId, actionId, string.Empty);
        }

        public void RemoveSubscriptions(int tenant, string sourceId, string actionId, string objectId)
        {
            if (sourceId == null) throw new ArgumentNullException("sourceId");
            if (actionId == null) throw new ArgumentNullException("actionId");

            var d = Delete("core_subscription", tenant).Where("source", sourceId).Where("action", actionId);
            if (objectId != string.Empty)
            {
                d.Where("object", objectId ?? string.Empty);
            }
            ExecNonQuery(d);
        }


        public IEnumerable<SubscriptionMethod> GetSubscriptionMethods(int tenant, string sourceId, string actionId, string recipientId)
        {
            if (sourceId == null) throw new ArgumentNullException("sourceId");
            if (actionId == null) throw new ArgumentNullException("actionId");

            var q = new SqlQuery("core_subscriptionmethod")
                .Select("tenant", "recipient", "sender", "action")
                .Where(Exp.Eq("tenant", -1) | Exp.Eq("tenant", tenant))
                .Where("source", sourceId)
                .GroupBy("recipient", "action")
                .OrderBy("tenant", true);

            if (recipientId != null) q.Where("recipient", recipientId);

            var methods = ExecList(q);
            var result = new List<SubscriptionMethod>();
            var common = new Dictionary<string, SubscriptionMethod>();

            foreach (var r in methods)
            {
                var m = new SubscriptionMethod
                {
                    Tenant = Convert.ToInt32(r[0]),
                    SourceId = sourceId,
                    ActionId = Convert.ToString(r[3]),
                    RecipientId = (string)r[1],
                    Methods = Convert.ToString(r[2]).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries),
                };

                var key = m.SourceId + m.ActionId + m.RecipientId;
                if (m.Tenant == Tenant.DEFAULT_TENANT)
                {
                    m.Tenant = tenant;
                    common.Add(key, m);
                    result.Add(m);
                }
                else
                {
                    SubscriptionMethod rec;
                    if (!common.TryGetValue(key, out rec))
                    {
                        result.Add(m);
                    }
                }
            }

            return result;
        }

        public void SetSubscriptionMethod(SubscriptionMethod m)
        {
            if (m == null) throw new ArgumentNullException("m");

            ISqlInstruction i;
            if (m.Methods == null || m.Methods.Length == 0)
            {
                i = Delete("core_subscriptionmethod", m.Tenant)
                    .Where("source", m.SourceId)
                    .Where("action", m.ActionId)
                    .Where("recipient", m.RecipientId);
            }
            else
            {
                i = Insert("core_subscriptionmethod", m.Tenant)
                    .InColumnValue("source", m.SourceId)
                    .InColumnValue("action", m.ActionId)
                    .InColumnValue("recipient", m.RecipientId)
                    .InColumnValue("sender", string.Join("|", m.Methods));
            }
            ExecNonQuery(i);
        }

        private SqlQuery GetQuery(int tenant, string sourceId, string actionId)
        {
            if (sourceId == null) throw new ArgumentNullException("sourceId");
            if (actionId == null) throw new ArgumentNullException("actionId");

            return new SqlQuery("core_subscription")
                .Select("tenant", "source", "action", "recipient", "object", "unsubscribed")
                .Where(Exp.Eq("tenant", -1) | Exp.Eq("tenant", tenant))
                .Where("source", sourceId)
                .Where("action", actionId)
                .OrderBy("tenant", true);
        }

        private IEnumerable<SubscriptionRecord> GetSubscriptions(ISqlInstruction q, int tenant)
        {
            var subs = ExecList(q);
            var result = new List<SubscriptionRecord>();
            var common = new Dictionary<string, SubscriptionRecord>();

            foreach (var r in subs)
            {
                var s = new SubscriptionRecord
                {
                    Tenant = Convert.ToInt32(r[0]),
                    SourceId = (string)r[1],
                    ActionId = (string)r[2],
                    RecipientId = (string)r[3],
                    ObjectId = string.Empty.Equals(r[4]) ? null : (string)r[4],
                    Subscribed = !Convert.ToBoolean(r[5]),
                };

                var key = s.SourceId + s.ActionId + s.RecipientId + s.ObjectId;
                if (s.Tenant == Tenant.DEFAULT_TENANT)
                {
                    s.Tenant = tenant;
                    common.Add(key, s);
                    result.Add(s);
                }
                else
                {
                    SubscriptionRecord rec;
                    if (!common.TryGetValue(key, out rec))
                    {
                        result.Add(s);
                    }
                }
            }

            return result;
        }
    }
}


<|start_filename|>module/ASC.Socket.IO/app/controllers/index.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = (counters, chat, voip, files) => {
    const router = require('express').Router(),
        bodyParser = require('body-parser'),
        authService = require('../middleware/authService.js')();

    router.use(bodyParser.json());
    router.use(bodyParser.urlencoded({ extended: false }));
    router.use(require('cookie-parser')());
    router.use((req, res, next) => {
        if (!authService(req)) {
            res.sendStatus(403);
            return;
        }
    
        next();
    });

    router
        .use("/counters", require(`./counters.js`)(counters))
        .use("/mail", require(`./mail.js`)(counters))
        .use("/chat", require(`./chat.js`)(chat))
        .use("/voip", require(`./voip.js`)(voip))
        .use("/files", require(`./files.js`)(files));

    return router;
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/GreetingSettings/js/greetingsettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var GreetingSettingsManager = new function () {

    var _bindAjaxProOnLoading = function () {
        AjaxPro.onLoading = function (b) {
            if (b) {
                LoadingBanner.showLoaderBtn("#studio_greetingSettings");
            } else {
                LoadingBanner.hideLoaderBtn("#studio_greetingSettings");
            }
        };
    };

    var _saveGreetingOptions = function () {
        _bindAjaxProOnLoading();
        GreetingSettingsController.SaveGreetingSettings(jq('#studio_greetingHeader').val(),
                                                function (result) {
                                                    LoadingBanner.showMesInfoBtn("#studio_greetingSettings", result.value.Message, result.value.Status == 1 ? "success" : "error");
                                                });
      };

    var _restoreGreetingOptions = function () {
        _bindAjaxProOnLoading();

        GreetingSettingsController.RestoreGreetingSettings(function (result) {
            if (result.value.Status == 1) {
                jq('#studio_greetingHeader').val(result.value.CompanyName);
            }
            LoadingBanner.showMesInfoBtn("#studio_greetingSettings", result.value.Message, result.value.Status == 1 ? "success" : "error");

        });
    };

    var _uploadCompleteGreetingLogo = function (file, response) {
        LoadingBanner.hideLoaderBtn("#studio_greetingSettings");

        var result = eval("(" + response + ")");

        if (!result.Success) {
            LoadingBanner.showMesInfoBtn("#studio_greetingSettings", result.Message, "error");
        }
    };

    this.Init = function () {
        jq('#saveGreetSettingsBtn').on("click", _saveGreetingOptions);
        jq('#restoreGreetSettingsBtn').on("click", _restoreGreetingOptions);
    }
};


jq(function () {
    GreetingSettingsManager.Init();
});

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/TaskEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Services.NotifyService;
using ASC.Web.Projects;
using ASC.Web.Projects.Core.Engine;
using ASC.Web.Projects.Core.Search;

namespace ASC.Projects.Engine
{
    public class TaskEngine : ProjectEntityEngine
    {
        public IDaoFactory DaoFactory { get; set; }
        public EngineFactory EngineFactory { get; set; }
        public SubtaskEngine SubtaskEngine { get { return EngineFactory.SubtaskEngine; } }
        public StatusEngine StatusEngine { get { return EngineFactory.StatusEngine; } }

        private readonly Func<Task, bool> canReadDelegate;

        public TaskEngine(bool disableNotifications)
            : base(NotifyConstants.Event_NewCommentForTask, disableNotifications)
        {
            canReadDelegate = CanRead;
        }

        #region Get Tasks

        public IEnumerable<Task> GetAll()
        {
            return DaoFactory.TaskDao.GetAll().Where(canReadDelegate);
        }

        public IEnumerable<Task> GetByProject(int projectId, TaskStatus? status, Guid participant)
        {
            var listTask = DaoFactory.TaskDao.GetByProject(projectId, status, participant).Where(canReadDelegate).ToList();
            DaoFactory.SubtaskDao.GetSubtasksForTasks(ref listTask);
            return listTask;
        }

        public TaskFilterOperationResult GetByFilter(TaskFilter filter)
        {
            if (filter.Offset < 0 || filter.Max < 0)
                return null;

            var isAdmin = ProjectSecurity.IsAdministrator(SecurityContext.CurrentAccount.ID);
            var anyOne = ProjectSecurity.IsPrivateDisabled;
            var count = DaoFactory.TaskDao.GetByFilterCount(filter, isAdmin, anyOne);

            var filterLimit = filter.Max;
            var filterOffset = filter.Offset;

            if (filterOffset > count.TasksTotal)
                return new TaskFilterOperationResult(count); //there are some records but we cant see them due to offset

            var taskList = new List<Task>();
            if (filter.HasTaskStatuses)
            {
                taskList = DaoFactory.TaskDao.GetByFilter(filter, isAdmin, anyOne);
            }
            else if (filterOffset > count.TasksOpen && count.TasksClosed != 0)
            {
                filter.TaskStatuses.Add(TaskStatus.Closed);
                filter.SortBy = "status_changed";
                filter.SortOrder = false;
                filter.Offset = filterOffset - count.TasksOpen;
                taskList = DaoFactory.TaskDao.GetByFilter(filter, isAdmin, anyOne);
            }
            else
            {
                //TODO: to one sql query using UNION ALL
                if (count.TasksOpen != 0)
                {
                    filter.TaskStatuses.Add(TaskStatus.Open);
                    taskList = DaoFactory.TaskDao.GetByFilter(filter, isAdmin, anyOne);
                }

                if (taskList.Count < filterLimit && count.TasksClosed != 0)
                {
                    filter.TaskStatuses.Clear();
                    filter.TaskStatuses.Add(TaskStatus.Closed);
                    //filter.SortBy = "status_changed";
                    //filter.SortOrder = false;
                    filter.Offset = 0;
                    filter.Max = filterLimit - taskList.Count;
                    taskList.AddRange(DaoFactory.TaskDao.GetByFilter(filter, isAdmin, anyOne));
                }
            }

            filter.Offset = filterOffset;
            filter.Max = filterLimit;
            filter.TaskStatuses.Clear();

            DaoFactory.SubtaskDao.GetSubtasksForTasks(ref taskList);

            var taskLinks = DaoFactory.TaskDao.GetLinks(taskList);

            Func<Task, int> idSelector = task => task.ID;
            Func<Task, IEnumerable<TaskLink>, Task> resultSelector = (task, linksCol) =>
                                                          {
                                                              task.Links.AddRange(linksCol);
                                                              return task;
                                                          };

            taskList = taskList.GroupJoin(taskLinks, idSelector, link => link.DependenceTaskId, resultSelector).ToList();
            taskList = taskList.GroupJoin(taskLinks, idSelector, link => link.ParentTaskId, resultSelector).ToList();

            return new TaskFilterOperationResult(taskList, count);
        }

        public TaskFilterCountOperationResult GetByFilterCount(TaskFilter filter)
        {
            return DaoFactory.TaskDao.GetByFilterCount(filter, ProjectSecurity.CurrentUserAdministrator, ProjectSecurity.IsPrivateDisabled);
        }

        public List<Tuple<Guid, int, int>> GetByFilterCountForReport(TaskFilter filter)
        {
            return DaoFactory.TaskDao.GetByFilterCountForReport(filter, ProjectSecurity.CurrentUserAdministrator, ProjectSecurity.IsPrivateDisabled);
        }

        public IEnumerable<TaskFilterCountOperationResult> GetByFilterCountForStatistic(TaskFilter filter)
        {
            return DaoFactory.TaskDao.GetByFilterCountForStatistic(filter, ProjectSecurity.CurrentUserAdministrator, ProjectSecurity.IsPrivateDisabled);
        }

        public IEnumerable<Task> GetByResponsible(Guid responsibleId, params TaskStatus[] statuses)
        {
            var listTask = DaoFactory.TaskDao.GetByResponsible(responsibleId, statuses).Where(canReadDelegate).ToList();
            DaoFactory.SubtaskDao.GetSubtasksForTasks(ref listTask);
            return listTask;
        }

        public IEnumerable<Task> GetMilestoneTasks(int milestoneId)
        {
            var listTask = DaoFactory.TaskDao.GetMilestoneTasks(milestoneId).Where(canReadDelegate).ToList();
            DaoFactory.SubtaskDao.GetSubtasksForTasks(ref listTask);
            return listTask;
        }

        public override ProjectEntity GetEntityByID(int id)
        {
            return GetByID(id);
        }

        public Task GetByID(int id)
        {
            return GetByID(id, true);
        }

        public Task GetByID(int id, bool checkSecurity)
        {
            var task = DaoFactory.TaskDao.GetById(id);

            if (task != null)
            {
                task.SubTasks = DaoFactory.SubtaskDao.GetSubtasks(task.ID);
                task.Links = DaoFactory.TaskDao.GetLinks(task.ID).ToList();
            }

            if (!checkSecurity)
                return task;

            return CanRead(task) ? task : null;
        }

        public IEnumerable<Task> GetByID(ICollection<int> ids)
        {
            var listTask = DaoFactory.TaskDao.GetById(ids).Where(canReadDelegate).ToList();
            DaoFactory.SubtaskDao.GetSubtasksForTasks(ref listTask);
            return listTask;

        }

        public bool IsExists(int id)
        {
            return DaoFactory.TaskDao.IsExists(id);
        }

        private bool CanRead(Task task)
        {
            return ProjectSecurity.CanRead(task);
        }

        #endregion

        #region Save, Delete, Notify

        public Task SaveOrUpdate(Task task, IEnumerable<int> attachedFileIds, bool notifyResponsible, bool isImport = false)
        {
            if (task == null) throw new ArgumentNullException("task");
            if (task.Project == null) throw new Exception("task.Project");

            var milestone = task.Milestone != 0 ? DaoFactory.MilestoneDao.GetById(task.Milestone) : null;
            var milestoneResponsible = milestone != null ? milestone.Responsible : Guid.Empty;

            var removeResponsibles = new List<Guid>();
            var inviteToResponsibles = new List<Guid>();

            task.Responsibles.RemoveAll(r => r.Equals(Guid.Empty));

            if (task.Deadline.Kind != DateTimeKind.Local && task.Deadline != DateTime.MinValue)
                task.Deadline = TenantUtil.DateTimeFromUtc(task.Deadline);

            if (task.StartDate.Kind != DateTimeKind.Local && task.StartDate != DateTime.MinValue)
                task.StartDate = TenantUtil.DateTimeFromUtc(task.StartDate);

            var isNew = task.ID == default(int); //Task is new

            if (isNew)
            {
                foreach (var responsible in task.Responsibles)
                {
                    if (ProjectSecurity.IsVisitor(responsible))
                    {
                        ProjectSecurity.CreateGuestSecurityException();
                    }

                    if (!ProjectSecurity.IsInTeam(task.Project, responsible))
                    {
                        ProjectSecurity.CreateSecurityException();
                    }
                }

                if (task.CreateBy == default(Guid)) task.CreateBy = SecurityContext.CurrentAccount.ID;
                if (task.CreateOn == default(DateTime)) task.CreateOn = TenantUtil.DateTimeNow();

                ProjectSecurity.DemandCreate<Task>(task.Project);

                task = DaoFactory.TaskDao.Create(task);

                inviteToResponsibles.AddRange(task.Responsibles.Distinct());
            }
            else
            {
                var oldTask = DaoFactory.TaskDao.GetById(new[] { task.ID }).FirstOrDefault();

                if (oldTask == null) throw new ArgumentNullException("task");
                ProjectSecurity.DemandEdit(oldTask);

                var newResponsibles = task.Responsibles.Distinct().ToList();
                var oldResponsibles = oldTask.Responsibles.Distinct().ToList();

                foreach (var responsible in newResponsibles.Except(oldResponsibles))
                {
                    if (ProjectSecurity.IsVisitor(responsible))
                    {
                        ProjectSecurity.CreateGuestSecurityException();
                    }

                    if (!ProjectSecurity.IsInTeam(task.Project, responsible))
                    {
                        ProjectSecurity.CreateSecurityException();
                    }
                }

                removeResponsibles.AddRange(oldResponsibles.Where(p => !newResponsibles.Contains(p)));
                inviteToResponsibles.AddRange(newResponsibles.Where(participant => !oldResponsibles.Contains(participant)));

                task.LastModifiedBy = SecurityContext.CurrentAccount.ID;
                task.LastModifiedOn = TenantUtil.DateTimeNow();

                task = DaoFactory.TaskDao.Update(task);
            }

            FactoryIndexer<TasksWrapper>.IndexAsync(task);

            if (attachedFileIds != null && attachedFileIds.Any())
            {
                foreach (var attachedFileId in attachedFileIds)
                {
                    AttachFile(task, attachedFileId);
                }
            }

            var senders = new HashSet<Guid>(task.Responsibles) { task.Project.Responsible, milestoneResponsible, task.CreateBy };
            senders.Remove(Guid.Empty);

            foreach (var subscriber in senders)
            {
                Subscribe(task, subscriber);
            }

            inviteToResponsibles.RemoveAll(r => r.Equals(Guid.Empty));
            removeResponsibles.RemoveAll(r => r.Equals(Guid.Empty));

            NotifyTask(task, inviteToResponsibles, removeResponsibles, isNew, notifyResponsible);

            return task;
        }

        public Task ChangeStatus(Task task, CustomTaskStatus newStatus)
        {
            ProjectSecurity.DemandEdit(task);

            if (task == null) throw new ArgumentNullException("task");
            if (task.Project == null) throw new Exception("Project can't be null.");
            if (task.Project.Status == ProjectStatus.Closed) throw new Exception(EngineResource.ProjectClosedError);

            if (task.Status == newStatus.StatusType && task.CustomTaskStatus == newStatus.Id) return task;

            var status = StatusEngine.Get().FirstOrDefault(r => r.Id == newStatus.Id);
            var cannotChange =
                status != null &&
                status.Available.HasValue && !status.Available.Value &&
                task.CreateBy != SecurityContext.CurrentAccount.ID &&
                task.Project.Responsible != SecurityContext.CurrentAccount.ID &&
                !ProjectSecurity.CurrentUserAdministrator;

            if (cannotChange)
            {
                ProjectSecurity.CreateSecurityException();
            }


            var senders = GetSubscribers(task);

            if (newStatus.StatusType == TaskStatus.Closed && !DisableNotifications && senders.Count != 0)
                NotifyClient.Instance.SendAboutTaskClosing(senders, task);

            if (newStatus.StatusType == TaskStatus.Open && !DisableNotifications && senders.Count != 0)
                NotifyClient.Instance.SendAboutTaskResumed(senders, task);

            task.Status = newStatus.StatusType;
            task.CustomTaskStatus = newStatus.Id < 0 ? null : (int?)newStatus.Id;
            task.LastModifiedBy = SecurityContext.CurrentAccount.ID;
            task.LastModifiedOn = TenantUtil.DateTimeNow();
            task.StatusChangedOn = TenantUtil.DateTimeNow();

            //subtask
            if (newStatus.StatusType == TaskStatus.Closed)
            {
                if (!task.Responsibles.Any())
                    task.Responsibles.Add(SecurityContext.CurrentAccount.ID);

                DaoFactory.SubtaskDao.CloseAllSubtasks(task);
                foreach (var subTask in task.SubTasks)
                {
                    subTask.Status = TaskStatus.Closed;
                }
            }

            return DaoFactory.TaskDao.Update(task);
        }

        public Task CopySubtasks(Task @from, Task to, IEnumerable<Participant> team)
        {
            if (from.Status == TaskStatus.Closed) return to;

            var subtaskEngine = SubtaskEngine;
            var subTasks = DaoFactory.SubtaskDao.GetSubtasks(@from.ID);

            to.SubTasks = new List<Subtask>();

            foreach (var subtask in subTasks)
            {
                to.SubTasks.Add(subtaskEngine.Copy(subtask, to, team));
            }

            return to;
        }

        public Task CopyFiles(Task from, Task to)
        {
            if (from.Project.ID != to.Project.ID) return to;

            var files = GetFiles(from);

            foreach (var file in files)
            {
                AttachFile(to, file.ID);
            }

            return to;
        }

        public Task MoveToMilestone(Task task, int milestoneID)
        {
            ProjectSecurity.DemandEdit(task);

            if (task == null) throw new ArgumentNullException("task");
            if (task.Project == null) throw new Exception("Project can be null.");

            var newMilestone = milestoneID != 0;
            var milestone = DaoFactory.MilestoneDao.GetById(newMilestone ? milestoneID : task.Milestone);

            var senders = GetSubscribers(task);

            if (!DisableNotifications && senders.Count != 0)
                NotifyClient.Instance.SendAboutTaskRemoved(senders, task, milestone, newMilestone);

            task.Milestone = milestoneID;
            task.LastModifiedBy = SecurityContext.CurrentAccount.ID;
            task.LastModifiedOn = TenantUtil.DateTimeNow();

            return DaoFactory.TaskDao.Update(task);
        }

        public void NotifyTask(Task task, IEnumerable<Guid> inviteToResponsibles, IEnumerable<Guid> removeResponsibles, bool isNew, bool notifyResponsible)
        {
            if (DisableNotifications) return;

            var senders = GetSubscribers(task);
            senders = senders.FindAll(r => !inviteToResponsibles.Contains(new Guid(r.ID)) && !removeResponsibles.Contains(new Guid(r.ID)));

            if (senders.Any())
            {
                if (isNew)
                {
                    NotifyClient.Instance.SendAboutTaskCreating(senders, task);
                }
                else
                {
                    NotifyClient.Instance.SendAboutTaskEditing(senders, task);
                }
            }

            if (notifyResponsible)
                NotifyResponsible(task, inviteToResponsibles.ToList(), removeResponsibles.ToList());
        }

        private void NotifyResponsible(Task task, List<Guid> inviteToResponsibles, List<Guid> removeResponsibles)
        {
            if (DisableNotifications) return;

            if (inviteToResponsibles.Any())
                NotifyClient.Instance.SendAboutResponsibleByTask(inviteToResponsibles, task);

            if (removeResponsibles.Any())
                NotifyClient.Instance.SendAboutRemoveResponsibleByTask(removeResponsibles, task);
        }

        public void SendReminder(Task task)
        {
            //Don't send anything if notifications are disabled
            if (DisableNotifications || task.Responsibles == null || !task.Responsibles.Any()) return;

            NotifyClient.Instance.SendReminderAboutTask(task.Responsibles.Where(r => !r.Equals(SecurityContext.CurrentAccount.ID)).Distinct(), task);
        }


        public void Delete(Task task)
        {
            if (task == null) throw new ArgumentNullException("task");

            ProjectSecurity.DemandDelete(task);
            DaoFactory.TaskDao.Delete(task);

            var recipients = GetSubscribers(task);

            if (recipients.Count != 0)
            {
                NotifyClient.Instance.SendAboutTaskDeleting(recipients, task);
            }

            UnSubscribeAll(task);

            FactoryIndexer<TasksWrapper>.DeleteAsync(task);
        }

        #endregion

        #region Link

        public void AddLink(Task parentTask, Task dependentTask, TaskLinkType linkType)
        {
            CheckLink(parentTask, dependentTask, linkType);

            var link = new TaskLink
            {
                ParentTaskId = parentTask.ID,
                DependenceTaskId = dependentTask.ID,
                LinkType = linkType
            };

            if (DaoFactory.TaskDao.IsExistLink(link))
                throw new Exception("link already exist");

            ProjectSecurity.DemandEdit(dependentTask);
            ProjectSecurity.DemandEdit(parentTask);

            parentTask.Links.Add(link);
            dependentTask.Links.Add(link);

            DaoFactory.TaskDao.AddLink(link);
        }

        public void RemoveLink(Task dependentTask, Task parentTask)
        {
            ProjectSecurity.DemandEdit(dependentTask);

            DaoFactory.TaskDao.RemoveLink(new TaskLink { DependenceTaskId = dependentTask.ID, ParentTaskId = parentTask.ID });
            dependentTask.Links.RemoveAll(r => r.ParentTaskId == parentTask.ID && r.DependenceTaskId == dependentTask.ID);
            parentTask.Links.RemoveAll(r => r.ParentTaskId == parentTask.ID && r.DependenceTaskId == dependentTask.ID);
        }

        private static void CheckLink(Task parentTask, Task dependentTask)
        {
            if (parentTask == null) throw new ArgumentNullException("parentTask");
            if (dependentTask == null) throw new ArgumentNullException("dependentTask");

            if (parentTask.ID == dependentTask.ID)
            {
                throw new Exception("it is impossible to create a link between one and the same task");
            }

            /*            if (parentTask.Status == TaskStatus.Closed || dependentTask.Status == TaskStatus.Closed)
                        {
                            throw new Exception("Such link don't be created. Task closed.");
                        }*/

            if (parentTask.Milestone != dependentTask.Milestone)
            {
                throw new Exception("Such link don't be created. Different Milestones");
            }

        }

        private static void CheckLink(Task parentTask, Task dependentTask, TaskLinkType linkType)
        {
            CheckLink(parentTask, dependentTask);

            switch (linkType)
            {
                case TaskLinkType.End:
                    if ((parentTask.Deadline.Equals(DateTime.MinValue) && parentTask.Milestone == 0) || (dependentTask.Deadline.Equals(DateTime.MinValue) && dependentTask.Milestone == 0))
                    {
                        throw new Exception("Such link don't be created. Incorrect task link type.");
                    }
                    break;

                case TaskLinkType.EndStart:
                    if ((parentTask.Deadline.Equals(DateTime.MinValue) && parentTask.Milestone == 0))
                    {
                        throw new Exception("Such link don't be created. Incorrect task link type.");
                    }
                    break;
            }
        }

        #endregion
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Projects/Wrappers/ProjectWrapperFull.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Runtime.Serialization;

using ASC.Api.Employee;
using ASC.Projects.Core.Domain;
using ASC.Specific;
using ASC.Web.Projects.Classes;

namespace ASC.Api.Projects.Wrappers
{
    [DataContract(Name = "project", Namespace = "")]
    public class ProjectWrapperFull : ObjectWrapperFullBase
    {
        [DataMember]
        public bool CanEdit { get; set; }

        [DataMember]
        public bool CanDelete { get; set; }

        [DataMember]
        public ProjectSecurityInfo Security { get; set; }

        [DataMember(EmitDefaultValue = false)]
        public object ProjectFolder { get; set; }

        [DataMember(Order = 32)]
        public bool IsPrivate { get; set; }

        [DataMember(Order = 33)]
        public int TaskCount { get; set; }

        [DataMember(Order = 33)]
        public int TaskCountTotal { get; set; }

        [DataMember(Order = 34)]
        public int MilestoneCount { get; set; }

        [DataMember(Order = 34)]
        public int DiscussionCount { get; set; }

        [DataMember(Order = 35)]
        public int ParticipantCount { get; set; }

        [DataMember(Order = 35)]
        public string TimeTrackingTotal { get; set; }

        [DataMember(Order = 35)]
        public int DocumentsCount { get; set; }

        [DataMember(Order = 36)]
        public bool IsFollow { get; set; }

        [DataMember(Order = 37, EmitDefaultValue = false)]
        public IEnumerable<string> Tags { get; set; }


        private ProjectWrapperFull()
        {
        }

        public ProjectWrapperFull(ProjectApiBase projectApiBase, Project project, object filesRoot = null, bool isFollow = false, IEnumerable<string> tags = null)
        {
            Id = project.ID;
            Title = project.Title;
            Description = project.Description;
            Status = (int)project.Status;
            if (projectApiBase.Context.GetRequestValue("simple") != null)
            {
                ResponsibleId = project.Responsible;
                CreatedById = project.CreateBy;
                UpdatedById = project.LastModifiedBy;
            }
            else
            {
                Responsible = projectApiBase.GetEmployeeWraperFull(project.Responsible);
                CreatedBy = projectApiBase.GetEmployeeWraper(project.CreateBy);
                if (project.CreateBy != project.LastModifiedBy)
                {
                    UpdatedBy = projectApiBase.GetEmployeeWraper(project.LastModifiedBy);
                }
            }

            Created = (ApiDateTime)project.CreateOn;
            Updated = (ApiDateTime)project.LastModifiedOn;


            if (project.Security == null)
            {
                projectApiBase.ProjectSecurity.GetProjectSecurityInfo(project);
            }
            Security = project.Security;
            CanEdit = Security.CanEdit;
            CanDelete = Security.CanDelete;
            ProjectFolder = filesRoot;
            IsPrivate = project.Private;

            TaskCount = project.TaskCount;
            TaskCountTotal = project.TaskCountTotal;
            MilestoneCount = project.MilestoneCount;
            DiscussionCount = project.DiscussionCount;
            TimeTrackingTotal = project.TimeTrackingTotal ?? "";
            DocumentsCount = project.DocumentsCount;
            ParticipantCount = project.ParticipantCount;
            IsFollow = isFollow;
            Tags = tags;
        }

        public static ProjectWrapperFull GetSample()
        {
            return new ProjectWrapperFull
            {
                Id = 10,
                Title = "Sample Title",
                Description = "Sample description",
                Status = (int)MilestoneStatus.Open,
                Responsible = EmployeeWraper.GetSample(),
                Created = ApiDateTime.GetSample(),
                CreatedBy = EmployeeWraper.GetSample(),
                Updated = ApiDateTime.GetSample(),
                UpdatedBy = EmployeeWraper.GetSample(),
                ProjectFolder = 13234
            };
        }
    }
}

<|start_filename|>module/ASC.ElasticSearch/Attributes/ColumnAttribute.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.ElasticSearch
{
    [AttributeUsage(AttributeTargets.Property)]
    public class ColumnAttribute : Attribute
    {
        public string ColumnName { get; private set; }

        public ColumnTypeEnum ColumnType { get; private set; }

        public int Order { get; private set; }

        public Analyzer Analyzer { get; set; }

        public Filter Filter { get; set; }

        public CharFilter CharFilter { get; set; }

        public ColumnAttribute(string columnName, int order, ColumnTypeEnum columnType = ColumnTypeEnum.Content, Filter filter = Filter.lowercase, CharFilter charFilter = CharFilter.io)
        {
            ColumnName = columnName;
            ColumnType = columnType;
            Order = order;
            Analyzer = Analyzer.whitespace;
            Filter = filter;
            CharFilter = charFilter;

        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class ColumnIdAttribute : ColumnAttribute
    {
        public ColumnIdAttribute(string columnName)
            : base(columnName, -3, ColumnTypeEnum.Id)
        {
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class ColumnTenantIdAttribute : ColumnAttribute
    {
        public ColumnTenantIdAttribute(string columnName)
            : base(columnName, -2, ColumnTypeEnum.TenantId)
        {
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class ColumnLastModifiedAttribute : ColumnAttribute
    {
        public ColumnLastModifiedAttribute(string columnName)
            : base(columnName, -1, ColumnTypeEnum.LastModified)
        {
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class ColumnConditionAttribute : ColumnAttribute
    {
        internal object Value { get; private set; }
        public ColumnConditionAttribute(string columnName, int order, object value = null)
            : base(columnName, order, ColumnTypeEnum.Condition)
        {
            Value = value;
        }

        public ColumnConditionAttribute(string columnName, int order, params object[] value)
            : base(columnName, order, ColumnTypeEnum.Condition)
        {
            Value = value;
        }
    }

    [AttributeUsage(AttributeTargets.Property)]
    public class ColumnMeta : ColumnAttribute
    {
        public ColumnMeta(string columnName, int order)
            : base(columnName, order, ColumnTypeEnum.Meta)
        {
        }
    }

    public enum ColumnTypeEnum
    {
        Id,
        TenantId,
        LastModified,
        Content,
        Condition,
        Meta
    }

    public enum Analyzer
    {
        standard,
        whitespace,
        uax_url_email
    }

    [Flags]
    public enum CharFilter
    {
        io,
        html
    }

    [Flags]
    public enum Filter
    {
        lowercase
    }
}


<|start_filename|>module/ASC.VoipService/Dao/VoIPCallFilter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

namespace ASC.VoipService.Dao
{
    public class VoipCallFilter
    {
        public string Type { get; set; }

        public DateTime? FromDate { get; set; }

        public DateTime? ToDate { get; set; }

        public Guid? Agent { get; set; }

        public int? Client { get; set; }

        public int? ContactID { get; set; }

        public string Id { get; set; }

        public string ParentId { get; set; }

        public string SortBy { get; set; }

        public bool SortOrder { get; set; }

        public string SearchText { get; set; }

        public long Offset { get; set; }

        public long Max { get; set; }

        public int? TypeStatus
        {
            get
            {
                if (string.IsNullOrWhiteSpace(Type)) return null;
                if (TypeStatuses.ContainsKey(Type)) return TypeStatuses[Type];

                return null;
            }
        }

        public string SortByColumn
        {
            get
            {
                if (string.IsNullOrWhiteSpace(SortBy)) return null;
                return SortColumns.ContainsKey(SortBy) ? SortColumns[SortBy] : null;
            }
        }

        private static Dictionary<string, int> TypeStatuses
        {
            get
            {
                return new Dictionary<string, int>
                    {
                        {
                            "answered", (int)VoipCallStatus.Answered
                        },
                        {
                            "missed", (int)VoipCallStatus.Missed
                        },
                        {
                            "outgoing", (int)VoipCallStatus.Outcoming
                        }
                    };
            }
        }

        private static Dictionary<string, string> SortColumns
        {
            get
            {
                return new Dictionary<string, string>
                    {
                        {
                            "date", "dial_date"
                        },
                        {
                            "duration", "dial_duration"
                        },
                        {
                            "price", "price"
                        },
                    };
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_EventType.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements SIP "event-type" value. Defined in RFC 3265.
    /// </summary>
    public class SIP_t_EventType : SIP_t_Value
    {
        #region Members

        private string m_EventType = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets event type.
        /// </summary>
        /// <exception cref="ArgumentNullException">Is raised when null value passed as value.</exception>
        public string EventType
        {
            get { return m_EventType; }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("EventType");
                }

                m_EventType = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "event-type" from specified value.
        /// </summary>
        /// <param name="value">SIP "event-type" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>value</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "event-type" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // Get Method
            string word = reader.ReadWord();
            if (word == null)
            {
                throw new SIP_ParseException("Invalid 'event-type' value, event-type is missing !");
            }
            m_EventType = word;
        }

        /// <summary>
        /// Converts this to valid "event-type" value.
        /// </summary>
        /// <returns>Returns "event-type" value.</returns>
        public override string ToStringValue()
        {
            return m_EventType;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTCP_Packet_RR.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Text;

    #endregion

    /// <summary>
    /// This class represents RR: Receiver Report RTCP Packet.
    /// </summary>
    public class RTCP_Packet_RR : RTCP_Packet
    {
        #region Members

        private readonly List<RTCP_Packet_ReportBlock> m_pReportBlocks;
        private uint m_SSRC;
        private int m_Version = 2;

        #endregion

        #region Properties

        /// <summary>
        /// Gets RTCP version.
        /// </summary>
        public override int Version
        {
            get { return m_Version; }
        }

        /// <summary>
        /// Gets RTCP packet type.
        /// </summary>
        public override int Type
        {
            get { return RTCP_PacketType.RR; }
        }

        /// <summary>
        /// Gets or sets sender(local reporting) synchronization source identifier.
        /// </summary>
        public uint SSRC
        {
            get { return m_SSRC; }

            set { m_SSRC = value; }
        }

        /// <summary>
        /// Gets reports blocks.
        /// </summary>
        public List<RTCP_Packet_ReportBlock> ReportBlocks
        {
            get { return m_pReportBlocks; }
        }

        /// <summary>
        /// Gets number of bytes needed for this packet.
        /// </summary>
        public override int Size
        {
            get { return 8 + (24*m_pReportBlocks.Count); }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        internal RTCP_Packet_RR()
        {
            m_pReportBlocks = new List<RTCP_Packet_ReportBlock>();
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="ssrc">SSRC of this packet sender.</param>
        internal RTCP_Packet_RR(uint ssrc)
        {
            m_pReportBlocks = new List<RTCP_Packet_ReportBlock>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Stores receiver report(RR) packet to the specified buffer.
        /// </summary>
        /// <param name="buffer">Buffer where to store RR packet.</param>
        /// <param name="offset">Offset in buffer.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public override void ToByte(byte[] buffer, ref int offset)
        {
            /* RFC 3550 6.4.2 RR: Receiver Report RTCP Packet.
                    0                   1                   2                   3
                    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            header |V=2|P|    RC   |   PT=RR=201   |             length            |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                     SSRC of packet sender                     |
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            report |                 SSRC_1 (SSRC of first source)                 |
            block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              1    | fraction lost |       cumulative number of packets lost       |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |           extended highest sequence number received           |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                      interarrival jitter                      |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                         last SR (LSR)                         |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                   delay since last SR (DLSR)                  |
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            report |                 SSRC_2 (SSRC of second source)                |
            block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              2    :                               ...                             :
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
                   |                  profile-specific extensions                  |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            */

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0)
            {
                throw new ArgumentException("Argument 'offset' value must be >= 0.");
            }

            // NOTE: Size in 32-bit boundary, header not included.
            int length = (4 + (m_pReportBlocks.Count*24))/4;

            // V P RC
            buffer[offset++] = (byte) (2 << 6 | 0 << 5 | (m_pReportBlocks.Count & 0x1F));
            // PT=RR=201
            buffer[offset++] = 201;
            // length
            buffer[offset++] = (byte) ((length >> 8) & 0xFF);
            buffer[offset++] = (byte) ((length) & 0xFF);
            // SSRC
            buffer[offset++] = (byte) ((m_SSRC >> 24) & 0xFF);
            buffer[offset++] = (byte) ((m_SSRC >> 16) & 0xFF);
            buffer[offset++] = (byte) ((m_SSRC >> 8) & 0xFF);
            buffer[offset++] = (byte) ((m_SSRC) & 0xFF);
            // Report blocks
            foreach (RTCP_Packet_ReportBlock block in m_pReportBlocks)
            {
                block.ToByte(buffer, ref offset);
            }
        }

        /// <summary>
        /// Returns RR packet as string.
        /// </summary>
        /// <returns>Returns RR packet as string.</returns>
        public override string ToString()
        {
            StringBuilder retVal = new StringBuilder();
            retVal.AppendLine("Type: RR");
            retVal.AppendLine("Version: " + m_Version);
            retVal.AppendLine("SSRC: " + m_SSRC);
            retVal.AppendLine("Report blocks: " + m_pReportBlocks.Count);

            return retVal.ToString();
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Parses receiver report(RR) from byte buffer.
        /// </summary>
        /// <param name="buffer">Buffer wihich contains receiver report.</param>
        /// <param name="offset">Offset in buufer.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        protected override void ParseInternal(byte[] buffer, ref int offset)
        {
            /* RFC 3550 6.4.2 RR: Receiver Report RTCP Packet.
                    0                   1                   2                   3
                    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            header |V=2|P|    RC   |   PT=RR=201   |             length            |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                     SSRC of packet sender                     |
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            report |                 SSRC_1 (SSRC of first source)                 |
            block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              1    | fraction lost |       cumulative number of packets lost       |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |           extended highest sequence number received           |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                      interarrival jitter                      |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                         last SR (LSR)                         |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                   delay since last SR (DLSR)                  |
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            report |                 SSRC_2 (SSRC of second source)                |
            block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              2    :                               ...                             :
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
                   |                  profile-specific extensions                  |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            */

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0)
            {
                throw new ArgumentException("Argument 'offset' value must be >= 0.");
            }

            m_Version = buffer[offset] >> 6;
            bool isPadded = Convert.ToBoolean((buffer[offset] >> 5) & 0x1);
            int reportBlockCount = buffer[offset++] & 0x1F;
            int type = buffer[offset++];
            int length = buffer[offset++] << 8 | buffer[offset++];
            if (isPadded)
            {
                PaddBytesCount = buffer[offset + length];
            }

            m_SSRC =
                (uint)
                (buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);
            for (int i = 0; i < reportBlockCount; i++)
            {
                RTCP_Packet_ReportBlock reportBlock = new RTCP_Packet_ReportBlock();
                reportBlock.Parse(buffer, offset);
                m_pReportBlocks.Add(reportBlock);
                offset += 24;
            }
            // TODO: profile-specific extensions
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/MailboxDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Utils;

namespace ASC.Mail.Core.Dao
{
    public class MailboxDao : BaseDao, IMailboxDao
    {
        protected static ITable table = new MailTableFactory().Create<MailboxTable>();

        public MailboxDao(IDbManager dbManager) :
            base(table, dbManager, -1)
        {
        }

        public Mailbox GetMailBox(IMailboxExp exp)
        {
            var query = Query()
                .Where(exp.GetExpression());

            return Db.ExecuteList(query)
                .ConvertAll(ToMailbox)
                .SingleOrDefault();
        }

        public List<Mailbox> GetMailBoxes(IMailboxesExp exp)
        {
            var query = Query()
                .Where(exp.GetExpression());

            if (!string.IsNullOrEmpty(exp.OrderBy) && exp.OrderAsc.HasValue)
            {
                query.OrderBy(exp.OrderBy, exp.OrderAsc.Value);
            }

            if (exp.Limit.HasValue)
            {
                query.SetMaxResults(exp.Limit.Value);
            }

            return Db.ExecuteList(query)
                .ConvertAll(ToMailbox);
        }

        public Mailbox GetNextMailBox(IMailboxExp exp)
        {
            var query = Query()
                .Where(exp.GetExpression())
                .OrderBy(MailboxTable.Columns.Id, true)
                .SetMaxResults(1);

            var mailbox = Db.ExecuteList(query)
                .ConvertAll(ToMailbox)
                .SingleOrDefault();

            return mailbox;
        }

        public Tuple<int, int> GetRangeMailboxes(IMailboxExp exp)
        {
            var query = new SqlQuery(MailboxTable.TABLE_NAME)
                .SelectMin(MailboxTable.Columns.Id)
                .SelectMax(MailboxTable.Columns.Id)
                .Where(exp.GetExpression());

            var range = Db.ExecuteList(query)
                .ConvertAll(r => new Tuple<int, int>(Convert.ToInt32(r[0]), Convert.ToInt32(r[1])))
                .SingleOrDefault();

            return range;
        }

        public List<Tuple<int, string>> GetMailUsers(IMailboxExp exp)
        {
            var query = Query()
                .Select(MailboxTable.Columns.Tenant, MailboxTable.Columns.User)
                .Where(exp.GetExpression());

            var list = Db.ExecuteList(query)
                .ConvertAll(r => new Tuple<int, string>(Convert.ToInt32(r[0]), Convert.ToString(r[1])));

            return list;
        }

        public int SaveMailBox(Mailbox mailbox)
        {
            var query = new SqlInsert(MailboxTable.TABLE_NAME, true)
                .InColumnValue(MailboxTable.Columns.Id, mailbox.Id)
                .InColumnValue(MailboxTable.Columns.Tenant, mailbox.Tenant)
                .InColumnValue(MailboxTable.Columns.User, mailbox.User)
                .InColumnValue(MailboxTable.Columns.Address, mailbox.Address)
                .InColumnValue(MailboxTable.Columns.Name, mailbox.Name)
                .InColumnValue(MailboxTable.Columns.Enabled, mailbox.Enabled)
                .InColumnValue(MailboxTable.Columns.IsRemoved, mailbox.IsRemoved)
                .InColumnValue(MailboxTable.Columns.IsProcessed, mailbox.IsProcessed)
                .InColumnValue(MailboxTable.Columns.IsServerMailbox, mailbox.IsTeamlabMailbox)
                .InColumnValue(MailboxTable.Columns.Imap, mailbox.Imap)
                .InColumnValue(MailboxTable.Columns.UserOnline, mailbox.UserOnline)
                .InColumnValue(MailboxTable.Columns.IsDefault, mailbox.IsDefault)
                .InColumnValue(MailboxTable.Columns.MsgCountLast, mailbox.MsgCountLast)
                .InColumnValue(MailboxTable.Columns.SizeLast, mailbox.SizeLast)
                .InColumnValue(MailboxTable.Columns.LoginDelay, mailbox.LoginDelay)
                .InColumnValue(MailboxTable.Columns.QuotaError, mailbox.QuotaError)
                .InColumnValue(MailboxTable.Columns.ImapIntervals, mailbox.ImapIntervals)
                .InColumnValue(MailboxTable.Columns.BeginDate, mailbox.BeginDate)
                .InColumnValue(MailboxTable.Columns.EmailInFolder, mailbox.EmailInFolder)
                .InColumnValue(MailboxTable.Columns.Password, MailUtil.EncryptPassword(mailbox.Password))
                .InColumnValue(MailboxTable.Columns.SmtpPassword,
                    !string.IsNullOrEmpty(mailbox.SmtpPassword)
                        ? MailUtil.EncryptPassword(mailbox.SmtpPassword)
                        : "")
                .InColumnValue(MailboxTable.Columns.OAuthToken,
                    !string.IsNullOrEmpty(mailbox.OAuthToken)
                        ? MailUtil.EncryptPassword(mailbox.OAuthToken)
                        : "")
                .InColumnValue(MailboxTable.Columns.OAuthType, mailbox.OAuthType)
                .InColumnValue(MailboxTable.Columns.SmtpServerId, mailbox.SmtpServerId)
                .InColumnValue(MailboxTable.Columns.ServerId, mailbox.ServerId)
                .InColumnValue(MailboxTable.Columns.DateChecked, mailbox.DateChecked)
                .InColumnValue(MailboxTable.Columns.DateUserChecked, mailbox.DateUserChecked)
                .InColumnValue(MailboxTable.Columns.DateLoginDelayExpires, mailbox.DateLoginDelayExpires)
                .InColumnValue(MailboxTable.Columns.DateAuthError, mailbox.DateAuthError)
                .InColumnValue(MailboxTable.Columns.DateCreated, mailbox.DateCreated)
                .Identity(0, 0, true);

            var result = Db.ExecuteScalar<int>(query);

            return result;
        }

        public bool SetMailboxRemoved(Mailbox mailbox)
        {
            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Set(MailboxTable.Columns.IsRemoved, true)
                .Where(MailboxTable.Columns.Id, mailbox.Id)
                .Where(MailboxTable.Columns.Tenant, mailbox.Tenant)
                .Where(MailTable.Columns.User, mailbox.User);

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public bool RemoveMailbox(Mailbox mailbox)
        {
            var query = new SqlDelete(MailboxTable.TABLE_NAME)
                .Where(MailboxTable.Columns.Id, mailbox.Id)
                .Where(MailboxTable.Columns.Tenant, mailbox.Tenant)
                .Where(MailTable.Columns.User, mailbox.User);
            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public bool Enable(IMailboxExp exp, bool enabled)
        {
            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Set(MailboxTable.Columns.Enabled, enabled)
                .Where(exp.GetExpression());

            if (enabled)
                query.Set(MailboxTable.Columns.DateAuthError, null);

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public bool SetNextLoginDelay(IMailboxExp exp, TimeSpan delay)
        {
            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Set(MailboxTable.Columns.IsProcessed, false)
                .Set(string.Format(SET_LOGIN_DELAY_EXPIRES, (int)delay.TotalSeconds))
                .Where(exp.GetExpression());

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public bool SetMailboxEmailIn(Mailbox mailbox, string emailInFolder)
        {
            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Set(MailboxTable.Columns.EmailInFolder, "" != emailInFolder ? emailInFolder : null)
                .Where(MailboxTable.Columns.Id, mailbox.Id)
                .Where(MailboxTable.Columns.Tenant, mailbox.Tenant)
                .Where(MailboxTable.Columns.User, mailbox.User)
                .Where(MailboxTable.Columns.IsRemoved, false);

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public bool SetMailboxesActivity(int tenant, string user, bool userOnline = true)
        {
            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Where(MailboxTable.Columns.Tenant, tenant)
                .Where(MailboxTable.Columns.User, user)
                .Where(MailboxTable.Columns.IsRemoved, false)
                .Set(SET_DATE_USER_CHECKED)
                .Set(MailboxTable.Columns.UserOnline, userOnline);

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        private const string SET_DATE_CHECKED = MailboxTable.Columns.DateChecked + " = UTC_TIMESTAMP()";
        private const string SET_DATE_USER_CHECKED = MailboxTable.Columns.DateUserChecked + " = UTC_TIMESTAMP()";

        private const string SET_LOGIN_DELAY_EXPIRES =
            MailboxTable.Columns.DateLoginDelayExpires + " = DATE_ADD(UTC_TIMESTAMP(), INTERVAL {0} SECOND)";

        private static readonly string SetDefaultLoginDelayExpires =
            MailboxTable.Columns.DateLoginDelayExpires + " = DATE_ADD(UTC_TIMESTAMP(), INTERVAL " +
            Defines.DefaultServerLoginDelayStr + " SECOND)";

        public bool SetMailboxInProcess(int id)
        {
            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Set(MailboxTable.Columns.IsProcessed, true)
                .Set(SET_DATE_CHECKED)
                .Where(MailboxTable.Columns.Id, id)
                .Where(MailboxTable.Columns.IsProcessed, false)
                .Where(MailboxTable.Columns.IsRemoved, false);

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public bool SetMailboxProcessed(Mailbox mailbox, int nextLoginDelay, bool? enabled = null,
            int? messageCount = null, long? size = null, bool? quotaError = null, string oAuthToken = null,
            string imapIntervalsJson = null, bool? resetImapIntervals = false)
        {
            if (nextLoginDelay < Defines.DefaultServerLoginDelay)
                nextLoginDelay = Defines.DefaultServerLoginDelay;

            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Set(MailboxTable.Columns.IsProcessed, false)
                .Set(SET_DATE_CHECKED)
                .Set(nextLoginDelay > Defines.DefaultServerLoginDelay
                    ? string.Format(SET_LOGIN_DELAY_EXPIRES, nextLoginDelay)
                    : SetDefaultLoginDelayExpires)
                .Where(MailboxTable.Columns.Id, mailbox.Id);

            if (enabled.HasValue)
            {
                query.Set(MailboxTable.Columns.Enabled, enabled.Value);
            }

            if (messageCount.HasValue)
            {
                query.Set(MailboxTable.Columns.MsgCountLast, messageCount.Value);
            }

            if (size.HasValue)
            {
                query.Set(MailboxTable.Columns.SizeLast, size.Value);
            }

            if (quotaError.HasValue)
            {
                query.Set(MailboxTable.Columns.QuotaError, quotaError.Value);
            }

            if (!string.IsNullOrEmpty(oAuthToken))
            {
                query.Set(MailboxTable.Columns.OAuthToken, MailUtil.EncryptPassword(oAuthToken));
            }

            if (resetImapIntervals.HasValue)
            {
                query.Set(MailboxTable.Columns.ImapIntervals, null);
            }
            else
            {
                if (!string.IsNullOrEmpty(imapIntervalsJson))
                {
                    query.Set(MailboxTable.Columns.ImapIntervals, imapIntervalsJson);
                }
            }

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public bool SetMailboxAuthError(int id, DateTime? authErroDate)
        {
            var query = new SqlUpdate(MailboxTable.TABLE_NAME)
                .Set(MailboxTable.Columns.DateAuthError, authErroDate)
                .Where(MailboxTable.Columns.Id, id);

            if (authErroDate.HasValue)
                query.Where(MailboxTable.Columns.DateAuthError, null);

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        private const string SET_PROCESS_EXPIRES =
            "TIMESTAMPDIFF(MINUTE, " + MailboxTable.Columns.DateChecked + ", UTC_TIMESTAMP()) > {0}";

        public List<int> SetMailboxesProcessed(int timeoutInMinutes)
        {
            var query = new SqlQuery(MailboxTable.TABLE_NAME)
                .Select(MailboxTable.Columns.Id)
                .Where(MailboxTable.Columns.IsProcessed, true)
                .Where(!Exp.Eq(MailboxTable.Columns.DateChecked, null))
                .Where(string.Format(SET_PROCESS_EXPIRES, timeoutInMinutes));

            var ids = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToInt32(r[0]));

            if (!ids.Any())
                return ids;

            var update = new SqlUpdate(MailboxTable.TABLE_NAME)
                        .Set(MailboxTable.Columns.IsProcessed, false)
                        .Where(Exp.In(MailboxTable.Columns.Id, ids.ToArray()));

            Db.ExecuteNonQuery(update);

            return ids;
        }

        public bool CanAccessTo(IMailboxExp exp)
        {
            var query = new SqlQuery(MailboxTable.TABLE_NAME)
                .Select(MailboxTable.Columns.Id)
                .Where(exp.GetExpression());

            var foundIds = Db.ExecuteList(query)
                .ConvertAll(res => Convert.ToInt32(res[0]));

            return foundIds.Any();
        }

        public MailboxStatus GetMailBoxStatus(IMailboxExp exp)
        {
            var query = new SqlQuery(MailboxTable.TABLE_NAME)
                .Select(MailboxTable.Columns.Id,
                    MailboxTable.Columns.IsRemoved,
                    MailboxTable.Columns.Enabled,
                    MailboxTable.Columns.BeginDate)
                .Where(exp.GetExpression());

            return Db.ExecuteList(query)
                .ConvertAll(ToMMailboxStatus)
                .SingleOrDefault();
        }

        protected MailboxStatus ToMMailboxStatus(object[] r)
        {
            var status = new MailboxStatus
            {
                Id = Convert.ToInt32(r[0]),
                IsRemoved = Convert.ToBoolean(r[1]),
                Enabled = Convert.ToBoolean(r[2]),
                BeginDate = Convert.ToDateTime(r[3])
            };

            return status;
        }

        protected Mailbox ToMailbox(object[] r)
        {
            var mb = new Mailbox
            {
                Id = Convert.ToInt32(r[0]),
                User = Convert.ToString(r[1]),
                Tenant = Convert.ToInt32(r[2]),
                Address = Convert.ToString(r[3]),
                Enabled = Convert.ToBoolean(r[4]),

                MsgCountLast = Convert.ToInt32(r[6]),
                SizeLast = Convert.ToInt32(r[7]),

                Name = Convert.ToString(r[9]),
                LoginDelay = Convert.ToInt32(r[10]),
                IsProcessed = Convert.ToBoolean(r[11]),
                IsRemoved = Convert.ToBoolean(r[12]),
                IsDefault = Convert.ToBoolean(r[13]),
                QuotaError = Convert.ToBoolean(r[14]),
                Imap = Convert.ToBoolean(r[15]),
                BeginDate = Convert.ToDateTime(r[16]),
                OAuthType = Convert.ToInt32(r[17]),

                ImapIntervals = Convert.ToString(r[19]),
                SmtpServerId = Convert.ToInt32(r[20]),
                ServerId = Convert.ToInt32(r[21]),
                EmailInFolder = Convert.ToString(r[22]),
                IsTeamlabMailbox = Convert.ToBoolean(r[23]),
                DateCreated = Convert.ToDateTime(r[24]),
                DateChecked = Convert.ToDateTime(r[25]),
                DateUserChecked = Convert.ToDateTime(r[26]),
                UserOnline = Convert.ToBoolean(r[27]),
                DateLoginDelayExpires = Convert.ToDateTime(r[28]),
                DateAuthError = r[29] == null ? (DateTime?)null : Convert.ToDateTime(r[29])
            };

            string password = Convert.ToString(r[5]),
                smtpPassword = Convert.ToString(r[8]),
                oAuthToken = Convert.ToString(r[18]);

            MailUtil.TryDecryptPassword(password, out password);

            mb.Password = password;

            if (!string.IsNullOrEmpty(smtpPassword))
            {
                MailUtil.TryDecryptPassword(smtpPassword, out smtpPassword);
            }

            mb.SmtpPassword = smtpPassword ?? "";

            MailUtil.TryDecryptPassword(oAuthToken, out oAuthToken);

            mb.OAuthToken = oAuthToken;

            return mb;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/calendar/UserControls/fullcalendar/fullcalendar.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/**
 * @preserve
 * FullCalendar v1.5.1
 * http://arshaw.com/fullcalendar/
 *
 * Use fullcalendar.css for basic styling.
 * For event drag & drop, requires jQuery UI draggable.
 * For event resizing, requires jQuery UI resizable.
 *
 * Copyright (c) 2011 <NAME>
 * Dual licensed under the MIT and GPL licenses, located in
 * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
 *
 * Date: Sat Apr 9 14:09:51 2011 -0700
 *
 */

(function($, undefined) {

// such structure of code is used only for code folding in NetBeans IDE
var defaults = function defaultsModule() {return {
		
		// display
		defaultView: "month",
		aspectRatio: 1.35,
		minHeight:   500,
		header: {
		    left:   "prev,next,title",
			center: "",
			right:  ""
		},
		weekends: true,
		weekMode: "fixed",

		// editing
		editable: true,
		//disableDragging: false,
		//disableResizing: false,

		allDayDefault: true,
		ignoreTimezone: true,

		// event ajax
		lazyFetching: true,
		startParam: 'start',
		endParam: 'end',

		// time formats
		titleFormat: {
			month: "MMMM yyyy",
			week:  "MMM d",
			day:   "ddd, MMM d, yyyy"
		},
		columnFormat: {
			month: "dddd",
			week:  "'<div style=\"white-space: nowrap;\"><div class=\"fc-head-col-name\">'dddd'</div>' '<span class=\"number fc-head-col-number\">'dd'</span></div>'",
			day:   "'<div class=\"center\">'dddd'&nbsp;&nbsp;'d'</div>'"
		},
		timeFormat: { // for event elements
			"":     "h(:mm)t", // default
			agenda: "h:mm{ - h:mm}"
		},

		allDaySlot: true,
		allDayText: "all-day",
		firstHour: 6,
		slotMinutes: 30,
		defaultEventMinutes: 1,
		axisFormat: "h(:mm)tt",
		dragOpacity: {
			agenda: .5
		},
		minTime: 0,
		maxTime: 24,

		// locale
		isRTL: false,
		firstDay: 0,
		monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'],
		monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
		dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
		dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],
		buttonText: {
			prev: '<span class="triangle-w">&nbsp;</span>',
			next: '<span class="triangle-e">&nbsp;</span>',
			prevYear: '&nbsp;&lt;&lt;&nbsp;',
			nextYear: '&nbsp;&gt;&gt;&nbsp;',
			today: 'Today',
			month: 'Month',
			week: 'Week',
			day: 'Day',
			//list: 'Period',
			list: 'List',
			todo: "Todo"
			
		},
		defaultTimeZone: {name: "UTC:00", id: "UTC", offset: 0},

		// jquery-ui theming
		theme: false,
		buttonIcons: {
			prev: 'circle-triangle-w',
			next: 'circle-triangle-e'
		},

		selectable: true,
		selectHelper: true,
		unselectAuto: true,

		dropAccept: '*',

		eventTextColor:       "#000",
		eventBackgroundColor: "#87CEFA",
		eventBorderColor:     "#297FB4",
		eventBg2BorderRatio:  0.8,
		eventMaxTitleLength:  250,

		todayLabel:           "Today",
		moreEventsLabel:      "events",
		addNewEventLabel:     "Add event",
		addNewLabel:          "Create",

		modes: {
			calendarViewLabel: "Calendar view",
			listViewLabel:     "List view"
		},		

		sharedList: {
			title:    "Shared with:",
			moreLink: "Show %d more users",
			addLink:  "Add users for sharing",
			shortListLength: 5
		},

		categories: {
			width: 201,
			// list items
			itemBullet:      "&#9632;",
			inactiveColor:   "#aaa",
			defaultTitle:    "New calendar",
			
			// list of calendars
			title:                                  "My Calendars",
			addNewCategoryLabel:                    "Add",
			dialogTemplate:                         "",
			dialogHeader_add:                       "Add new calendar",
			dialogHeader_edit:                      "Edit calendar",
			dialogColor_label:                      "Color:",
			dialogTextColor_label:                  "Text color:",
			dialogTimezoneLabel:                    "Timezone:",
			dialogButton_save:                      "Save",
			dialogButton_cancel:                    "Cancel",
            dialogButton_delete:                    "Delete",

            dialogErrorMassageSpecCharacter:        "The title cannot contain any of the following characters: {0}",
            dialogCopyMessage:                      "Link has been copied to the clipboard",
			// list of subscriptions
			subscriptionsTitle:                     "Subscriptions",
			subscriptionsDialog:                    "",
			subscriptionsDialogHeader:              "Edit subscription",
			subscriptionsDialogOwnerLabel:          "Owner:",
			subscriptionsDialogButton_unsubscribe:  "Unsubscribe",
			// subscriptions dialog
			subscriptionsManageLabel:               "Manage",
			subscriptionsManageDialog:              "",
			subscriptionsManageDialog_title:        "Manage subscriptions",
			subscriptionsManageDialog_qsearchText:  "Quick search",
			subscriptionsManageDialogButton_save:   "Save",
			subscriptionsManageDialogButton_cancel: "Cancel",
			// datepicker
			datepickerHideLabel: 'Hide mini calendar',
			datepickerShowLabel: 'Show mini calendar',
			// date box
			dayFormat: 'd',
			monthFormat: 'MMMM',
			yearFormat: 'yyyy'
		},

		todoList: {
			title:         'To-do',
			hideLabel:     'Hide ToDo List',
			showLabel:     'Show ToDo List',
			addTodoLabel:  'New todo',
			newTodoTitle: 'new todo',
			
			overdue: 'Overdue',
			noDueDate: 'No due date',

			menuTemplate: "",
			deleteIcon: "",
			editIcon: "",
			settingsIcon:"",

			menu: {
				hideColmpletedTodos: {hide: 'Hide completed items', show: 'Show completed items'},
				deleteCompletedTodos: 'Delete completed items'
			},
			sortByCalendarLabel: 'Sort by calendar',
			sortByPriorityLabel: 'Sort by priority',
			sortAlphabeticallyLabel: 'Sort alphabetically',
			
			menuTodoInCalendar: 'Show to-do in calendar',
			menuDeleteMarkedTodo: 'Hide to-do marked as done on page load',
			menuSyncLinks: 'Export and Sync'
		},
        deleteTodoDialog: {
            dialogTemplate: "",
            dialogHeader: "Delete todo",

            dialogSingleBody: "The deleted todo cannot be restored. Are you sure you want to continue?",

            dialogButton_apply: "Apply",
            dialogButton_cancel: "Cancel",
        },
		todoEditor: {
		    dialogTemplate: "",
		    
		    dialogHeader_add: "Create todo",
		    dialogHeader_edit: "Edit todo",
		    
		    dialogDateLabel: "Date",
		    
		    titleLabel: "Title",
		    descriptionLabel: "Description",

		    dialogButton_save: "Save",
		    dialogButton_cancel: "Cancel",
		},
		todoViewer:{
		    dialogTemplate: "",

		    dialogButton_mark_on: "Mark as done",
		    dialogButton_mark_off: "Mark as not done",
            dialogButton_edit: "Edit",
            dialogButton_delete: "Delete"
		},
		
		eventEditor: {
			dateFormat:                  "yyyy-MM-dd",
			timeFormat:                  "HH:mm",
			newEventTitle:               "New event",
			
			// dialog
			dialogTemplate:              "",
			dialogHeader_add:            "Add new event",
			dialogSummaryLabel:          "Event name:",
			eventButton:                 "Event",
			todoButton:                  "Todo",
			dialogLocationLabel:         "Where:",
			dialogAttendeesLabel:        "Guests:",
			dialogOwnerLabel:            "Owner:",
			dialogOrganizerLabel:        "Organizer:",
			dialogAllDayLabel:           "All-day event",
			dialogSentInvitations:       "Sent invitations",
			dialogAllDay_no:             "This event is not all-day.",
			dialogAllDay_yes:            "This is all-day event.",
			dialogFromLabel:             "From:",
			dialogToLabel:               "To:",
			dialogRepeatLabel:           "Repeat:",
			dialogStatusLabel:           "Status:",
			dialogRepeatOption_never:    "never",
			dialogRepeatOption_day:      "every day",
			dialogRepeatOption_week:     "every week",
			dialogRepeatOption_month:    "every month",
			dialogRepeatOption_year:     "every year",
			dialogAlertLabel:            "Alert:",
			dialogAlertOption_default:   "default",
			dialogAlertOption_never:     "never",
			dialogAlertOption_5minutes:  "5 minutes",
			dialogAlertOption_15minutes: "15 minutes",
			dialogAlertOption_30minutes: "half an hour",
			dialogAlertOption_hour:      "an hour",
			dialogAlertOption_2hours:    "2 hours",
			dialogAlertOption_day:       "a day",
			dialogSharing_no:            "This event is not shared.",
			dialogCalendarLabel:         "Calendar:",
			dialogDescriptionLabel:      "Description:",
			dialogButton_edit:           "Edit",
			dialogButton_save:           "Save",
			dialogButton_close:          "Close",
			dialogButton_cancel:         "Cancel",
			dialogButton_delete:         "Delete",
			dialogButton_unsubscribe:    "Unsubscribe",
			dialogButton_moreDetails:    "More details",
		    dialogButton_details:        "Details",
			
			// new option
			dialogRepeatOption_custom:   "настройка",
			dialogHeader_createEvent: "Create new event",
			dialogHeader_editEvent: "Edit event",
			dialogHeader_viewEvent: "View event",
		},		
		
		repeatSettings: {
			dateFormat:                   "yyyy-MM-dd",
			timeFormat:                   "HH:mm",
			
			// dialog
			dialogTemplate:               "",
			dialogHeader:                 "Recurrence setup",
			
			// start date
			dialogFromLabel:              "starting with",
			
			// end of repeat
			dialogToLabel:                "end",
			dialogOptionNever:            "never",
			dialogOptionDate:             "date",
			dialogOptionCount:            "number of times",
			
			dialogAfterLabel:             "after",
			dialogTimesLabel:             "times",
			
			// repeat by 
			dialogRepeatOnLabel:          "by",
			dialogRepeatOn_days:          "days",
			dialogRepeatOn_weeks:         "weeks",
			dialogRepeatOn_months:        "months",
			dialogRepeatOn_years:         "years",
			
			// interval
			dialogEachLabel:              "every",
			dialogAliasLabel:             "every",
			dialogIntervalOption_day:     "day",
			dialogIntervalOption_week:    "week",
			dialogIntervalOption_month:   "month",
			dialogIntervalOption_year:    "yesr",
			
			dayNames:                     ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
			
			dayIndexResponse: {
									su: 0,
									mo: 1,
									tu: 2,
									we: 3,
									th: 4,
									fr: 5,
									sa: 6
			},
			dayNamesShort:                ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
			dayAliasNames:                ['first','second','third','last but one','last'],
			
			// buttons
			dialogButton_save:            "Save",
			dialogButton_cancel:          "Cancel"
		},
		
		deleteSettings: {
			// dialog
			dialogTemplate:               "",
			dialogHeader:                 "Delete recurring event",
			dialogSingleHeader:           "Delete event",
			dialogSingleBody:             "The deleted event cannot be restored. Are you sure you want to continue?",
			
			dialogDeleteOnlyThisLabel:    "This event only",
			dialogDeleteFollowingLabel:   "This event and all that follow",
			dialogDeleteAllLabel:         "All events in the series",
			
			// buttons
			dialogButton_save:            "Apply",
			dialogButton_cancel:          "Cancel"
		},
		
		confirmPopup: {
		    // dialog
		    dialogTemplate:               "",
		    dialogAddEventHeader:         "Sending invitations",
		    dialogUpdateEventHeader:      "Sending updates",
		    dialogDeleteEventHeader:      "Sending cancellations",
		    dialogAddEventBody:           "Would you like to send invitations to guests?",
		    dialogUpdateEventBody:        "Would you like to send updates to existing guests?",
		    dialogUpdateGuestsBody:       "Would you like to send updates only to new guests and cancellations or just everyone?",
		    dialogDeleteEventBody:        "Would you like to send cancellations to existing guests?",
		    
		    dialogSuccessToastText:       "Notifications successfully sent",
		    dialogErrorToastText:         "An error occurred while sending notifications",
		    
		    // buttons
		    dialogButtonSend:            "Send",
		    dialogButtonSendCustoms:     "New guests and cancellations",
		    dialogButtonSendEveryone:    "Everyone",
		    dialogButtonDontSend:        "Don't Send"
		},

		icalStream: {
			// dialog
			dialogTemplate:                       "",
			newiCalTitle:                         "Calendar from iCal feed",
			importEventsTitle:                    "Import events",

			dialogHeader:                         "Calendar event export",
			dialogDescription:                    "Use the following address to access your calendar from other applications. You can copy and enter this information into any calendar supporting iCal format. You can save the data into a file in iCal format and export the events into another calendar or application.",
            dialogCaldavHelp:                     "Connection instructions in the ",
            dialogHelpCenter:                     "Help Center",
			dialogTodoDescription:                "To configure the export of todos  to another calendar, copy the corresponding link and add it to the required calendar.",


			dialogImportExportLabel:              "Import/Export",
			dialogStreamLink:                     "Export events from ONLYOFFICE calendar",
			dialogImportLabel:                    "Import events into ONLYOFFICE calendar",
			dialogImportLabelNew:                 "Select iCal file",
			dialogExportLink:                     "Export and Sync",
			dialogButton_fileSelected:            "file is selected",
			dialogButton_fileNotSelected:         "no file is selected",
			dialog_incorrectFormat:               "Wrong format of the iCal file",
			
			dialogInputiCalLabel:                 "Enter the iCal feed link",
			dialogSavediCalLabel:                 "iCal feed link:",
			
			// buttons
			dialogButton_close:                   "Close",
			dialogButton_browse:                  "Select file"
		},

		dayView: {
			dateFormat: {
				topText:    "dddd",
				bigText:    "d",
				bottomText: "MMMM,'<br/>' yyyy"
			},
			todayTasksTitle:  "Today's tasks",
			alldayTasksTitle: "All-day tasks"
		},

		taskListTimeFormat: 'HH:mm{[ - HH:mm]}',

		listView: {
			headerDateFormat: 'MM/dd/yy',
			monthTitleFormat: 'MMMM yyyy',
			dayTitleFormat:   'ddd, MMM d, yyyy',
			timeFormat:       'HH:mm',
			noEventsMessage:  'There are no events to show.'
		},

		popupCellFormat: "dd.MM.yy"

	};
}();

// right-to-left defaults
// such structure of code is used only for code folding in NetBeans IDE
var rtlDefaults = function rtlDefaultsModule() {return {

		header: {
			left:   '',
			center: 'next,title,prev',
			right:  ''
		},
		buttonText: {
			prev: '&nbsp;&#9658;&nbsp;',
			next: '&nbsp;&#9668;&nbsp;',
			prevYear: '&nbsp;&gt;&gt;&nbsp;',
			nextYear: '&nbsp;&lt;&lt;&nbsp;'
		},
		buttonIcons: {
			prev: 'circle-triangle-e',
			next: 'circle-triangle-w'
		}

	};
}();


var fc = $.fullCalendar = {version: "2.0.1"};

var fcColors = function fcColorModule()
{
var _this = {};
_this.DefaultPicker = [
					"#F48454", "#FFB45E", "#FFD267", "#B7D269", "#6BBD72", "#77CF9A", "#6AC6DD",
					"#4682B6", "#6A9AD2", "#8A98D8", "#7E6EB2", "#B58FD6", "#D28CC8", "#E795C1",
					"#F2A9BE", "#DF7895"];
_this.TextPicker = ["#FFF","#000"];					
	return _this;

}();

var fcViews = fc.views = {};

var fcMenus = function fcMenusModule() {

	var _this = {};

	_this.hideMenus = function(m) {
		for (var i in this) if (this.hasOwnProperty(i)) {
			if (typeof this[i] == "function") {continue;}
			if ((/.+Menu$/i).test(i)) {
				if (m !== undefined && m == this[i]) {continue;}
				this[i].popupMenu("close");
			}
		}
	};

	_this.createHeaderYearMenu = function(calendar) {
		var year = calendar.getDate().getFullYear();
		if (!this.headerYearMenu || this.headerYearMenu.length < 1) {
			this.headerYearMenu = $("<div id='fc_header_year_menu'/>");
		} else {
			this.headerYearMenu.popupMenu("close");
			this.headerYearMenu.popupMenu("destroy");
		}
		this.headerYearMenu.popupMenu({
			anchor: "left,bottom",
			direction: "right,down",
			arrow: "up",
			arrowPosition: "50%",
			showArrow: false,
			cssClassName: "asc-popupmenu",
            items: [
                (year + 3).toString(), (year + 2).toString(), (year + 1).toString(),
                "divider",
                (year - 1).toString(), (year - 2).toString(), (year - 3).toString()
			],
			itemClick: function(event, data) {
				var d = calendar.getDate();
				d.setFullYear(parseInt(data.item, 10));
				calendar.gotoDate(d);
			}
		});
	};

	_this.createHeaderMonthMenu = function(calendar) {
		if (!this.headerMonthMenu || this.headerMonthMenu.length < 1) {
			this.headerMonthMenu = $("<div id='fc_header_month_menu'/>");
		} else {
			this.headerMonthMenu.popupMenu("close");
			this.headerMonthMenu.popupMenu("destroy");
		}
		this.headerMonthMenu.popupMenu({
			anchor: "left,bottom",
			direction: "right,down",
			arrow: "up",
			arrowPosition: "50%",
			showArrow: false,
			cssClassName: "asc-popupmenu",
			items: calendar.options.monthNames,
			itemClick: function(event, data) {
				var d = calendar.getDate();
				d.setMonth(data.itemIndex);
				calendar.gotoDate(d);
			}
		});
	};

	_this.buildTitleMenus = function(calendar, title) {
		var self = this;

		var monthLabel = undefined;
		title.find(".month").click(
				function() {
					if (!monthLabel || monthLabel != this) {
						monthLabel = this;
						self.createHeaderMonthMenu(calendar);
					}
					self.hideMenus(self.headerMonthMenu);
					self.headerMonthMenu.popupMenu("open", this);
				});

		var yearLabel = undefined;
		title.find(".year").click(
				function() {
					if (!yearLabel || yearLabel != this) {
						yearLabel = this;
						self.createHeaderYearMenu(calendar);
					}
					self.hideMenus(self.headerYearMenu);
					self.headerYearMenu.popupMenu("open", this);
				});
	};

	return _this;

}();

var fcUtil = function fcUtilModule() {

	var _this = {};

	/**
	 * Converts an RGB color value to HSV. Conversion formula
	 * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
	 * Assumes r, g, and b are contained in the set [0, 255] and
	 * returns h, s, and v in the set [0, 1].
	 *
	 * @param   r       (Number) The red color value
	 * @param   g       (Number) The green color value
	 * @param   b       (Number) The blue color value
	 * @return  Array   The HSV representation
	 */
	_this.rgbToHsv = function(r, g, b){
			r = r/255, g = g/255, b = b/255;
			var max = Math.max(r, g, b), min = Math.min(r, g, b);
			var h, s, v = max;

			var d = max - min;
			s = max == 0 ? 0 : d / max;

			if(max == min){
					h = 0; // achromatic
			}else{
					switch(max){
							case r:h = (g - b) / d + (g < b ? 6 : 0);break;
							case g:h = (b - r) / d + 2;break;
							case b:h = (r - g) / d + 4;break;
					}
					h /= 6;
			}

			return [h, s, v];
	};

	/**
	 * Converts an HSV color value to RGB. Conversion formula
	 * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
	 * Assumes h, s, and v are contained in the set [0, 1] and
	 * returns r, g, and b in the set [0, 255].
	 *
	 * @param   h       (Number) The hue
	 * @param   s       (Number) The saturation
	 * @param   v       (Number) The value
	 * @return  Array   The RGB representation
	 */
	_this.hsvToRgb = function(h, s, v){
			var r, g, b;

			var i = Math.floor(h * 6);
			var f = h * 6 - i;
			var p = v * (1 - s);
			var q = v * (1 - f * s);
			var t = v * (1 - (1 - f) * s);

			switch(i % 6){
					case 0:r = v, g = t, b = p;break;
					case 1:r = q, g = v, b = p;break;
					case 2:r = p, g = v, b = t;break;
					case 3:r = p, g = q, b = v;break;
					case 4:r = t, g = p, b = v;break;
					case 5:r = v, g = p, b = q;break;
			}

			return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
	};

	/**
	 * Converts an RGB color value to HSL. Conversion formula
	 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
	 * Assumes r, g, and b are contained in the set [0, 255] and
	 * returns h, s, and l in the set [0, 1].
	 *
	 * @param   r       (Number) The red color value
	 * @param   g       (Number) The green color value
	 * @param   b       (Number) The blue color value
	 * @return  Array   The HSL representation
	 */
	_this.rgbToHsl = function(r, g, b) {
			r /= 255, g /= 255, b /= 255;
			var max = Math.max(r, g, b), min = Math.min(r, g, b);
			var h = 0, s = 0, l = (max + min) / 2;

			if(max == min){
					h = s = 0; // achromatic
			}else{
					var d = max - min;
					s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
					switch(max){
							case r:h = (g - b) / d + (g < b ? 6 : 0);break;
							case g:h = (b - r) / d + 2;break;
							case b:h = (r - g) / d + 4;break;
					}
					h /= 6;
			}

			return [h, s, l];
	};

	/**
	 * Converts an HSL color value to RGB. Conversion formula
	 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
	 * Assumes h, s, and l are contained in the set [0, 1] and
	 * returns r, g, and b in the set [0, 255].
	 *
	 * @param   h       (Number) The hue
	 * @param   s       (Number) The saturation
	 * @param   l       (Number) The lightness
	 * @return  Array   The RGB representation
	 */
	_this.hslToRgb = function(h, s, l) {
			var r, g, b;

			if(s == 0){
					r = g = b = l; // achromatic
			}else{
					function hue2rgb(p, q, t){
							if(t < 0) t += 1;
							if(t > 1) t -= 1;
							if(t < 1/6) return p + (q - p) * 6 * t;
							if(t < 1/2) return q;
							if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
							return p;
					}

					var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
					var p = 2 * l - q;
					r = hue2rgb(p, q, h + 1/3);
					g = hue2rgb(p, q, h);
					b = hue2rgb(p, q, h - 1/3);
			}

			return [Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255)];
	};

    _this.randomHex = function (isFont) {
        if(isFont)
            return fcColors.TextPicker[1];

        return fcColors.DefaultPicker[Math.floor(Math.random() * fcColors.DefaultPicker.length)];
    };

	_this.parseCssColor = function(c) {
		var reColor =
				/\s*#([0-9a-f]{6}\s*$|[0-9a-f]{3}\s*$)|\s*rgba?\(\s*([0-9]+\s*,\s*[0-9]+\s*,\s*[0-9]+\s*(?:,\s*(?:[0-9]+(?:\.[0-9]+)?|[0-9]*\.[0-9]+))?)\s*\)/i;
		var m = reColor.exec(c);
		if (!m) {return null;}

		var reRgb =
				/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$|^([0-9a-f])([0-9a-f])([0-9a-f])$|^([0-9]{1,3}),\s*([0-9]{1,3}),\s*([0-9]{1,3})(?:,\s*([0-9.]+))?$/i;
		var x = reRgb.exec(m[1] || m[2]);

		var type = (typeof x[1] === "string" || typeof x[4] === "string") ? 0 :
				(typeof x[10] === "string" ? 2 : 1);

		var r = x[1] || x[4];
		var g = x[2] || x[5];
		var b = x[3] || x[6];
		r = r ? parseInt(r.length > 1 ? r : r + r, 16) : parseInt(x[7], 10);
		g = g ? parseInt(g.length > 1 ? g : g + g, 16) : parseInt(x[8], 10);
		b = b ? parseInt(b.length > 1 ? b : b + b, 16) : parseInt(x[9], 10);

		var a = x[10];
		a = a ? (Math.round(parseFloat(a) * 100) * 0.01) : 1;

		var color2 = ((r << 16) | (g << 8) | b).toString(16);
		while (color2.length < 6) {color2 = "0" + color2;}
		color2 = "#" + color2;

		var rgb1 = r + ", " + g + ", " + b;
		var rgb2 = "rgb(" + rgb1 + ")";
		var rgba2 = "rgba(" + rgb1 + ", " + a + ")";

		return {
			type: type,
			r: r,
			g: g,
			b: b,
			a: a,
			rgb: rgb2,
			rgba: rgba2,
			color: color2,
			origColor: type === 0 ? color2 : (type === 1 ? rgb2 : rgba2)
		};
	};

	_this.changeColorLightness = function(r, g, b, ratio) {
		//var h = _this.rgbToHsv(r, g, b);
		//var rgb = _this.hslToRgb(h[0], h[1], h[2] * ratio);
		var rgb = [Math.round(r * ratio), Math.round(g * ratio), Math.round(b * ratio)];
		var bc = ((rgb[0] << 16) | (rgb[1] << 8) | rgb[2]).toString(16);
		while (bc.length < 6) {bc = "0" + bc;}
		return {
			r: rgb[0],
			g: rgb[1],
			b: rgb[2],
			color: "#" + bc
		};
	};

	_this.EventSourcesIterator = function(eventSources, arrayName) {
		var _curSource = 0;
		var _curIndex= 0;

		function _next() {
			for (; eventSources && eventSources.length > 0 &&
			       _curSource < eventSources.length; ++_curSource) {
				var source = eventSources[_curSource];
				for (; source && source[arrayName] && source[arrayName].length > 0 &&
				       _curIndex < source[arrayName].length; ++_curIndex) {
					if (source[arrayName][_curIndex] != undefined) {
						return source[arrayName][_curIndex++];
					}
				}
				_curIndex = 0;
			}
			return undefined;
		}

		function _prev() {
			if (eventSources && eventSources.length > 0) {
				if (_curSource == undefined) {
					_curSource = eventSources.length - 1;
				}
				for (; _curSource >= 0; --_curSource) {
					var source = eventSources[_curSource];
					if (source && source[arrayName] && source[arrayName].length > 0) {
						if (_curIndex == undefined) {
							_curIndex = source[arrayName].length - 1;
						}
						for (; _curIndex >= 0; --_curIndex) {
							if (source[arrayName][_curIndex] != undefined) {
								return source[arrayName][_curIndex--];
							}
						}
					}
					_curIndex = undefined;
				}
			}
			return undefined;
		}

		this.first = function() {
			_curSource = 0;
			_curIndex = 0;
			return _next.call(this);
		};

		this.next = function() {
			return _next.call(this);
		};

		this.last = function() {
			_curSource = undefined;
			_curIndex = undefined;
			return _prev.call(this);
		};

		this.prev = function() {
			return _prev.call(this);
		};
	};

	_this.objectIsValid = function(obj) {
		return obj !== undefined && obj !== null &&
		       obj.objectId !== undefined && obj.objectId !== null;
	};

	_this.objectIsEditable = function(obj) {
		return obj !== undefined && obj !== null && obj.isEditable;
	};

	_this.eventIsEditable = function(event) {
		return event.source === undefined || event.source === null ||
		       _this.objectIsEditable(event) ||
		       _this.objectIsEditable(event.source) ||
		       event.source && !event.source.isSubscription;
	};

	_this.getElementRect = function(elem) {
		var o = elem.offset();
		return {
			left:   o.left,
			top:    o.top,
			right:  o.left + elem.outerWidth(),
			bottom: o.top + elem.outerHeight()
		};
	};

	_this.isLeapYear = function(y) {
		return (y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0));
	};

	_this.validateDateString = function(s) {
		var m = s.replace(/^\s+|\s+$/g, "").match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/i);
		if (!m) {return null;}
		var mon = parseInt(m[2], 10);
		if (mon < 1 || mon > 12) {return null;}
		var leap = _this.isLeapYear(parseInt(m[1], 10));
		var day = parseInt(m[3], 10);
		var maxDay = [31,(leap?29:28),31,30,31,30,31,31,30,31,30,31];
		if (day < 1 || day > maxDay[mon-1]) {return null;}
		return m[1] + "-" +
				(m[2].length > 1 ? m[2] : "0" + m[2]) + "-" +
				(m[3].length > 1 ? m[3] : "0" + m[3]);
	};

	_this.validateTimeString = function(s) {
		var s1 = s.replace(/^\s+|\s+$/g, "");
		if (s1.length < 1) {return "00:00";}
		var m = s1.match(/^(\d{1,2}):(\d{1,2})$/i);
		if (!m) {return null;}
		var hh = parseInt(m[1], 10);
		if (hh < 0 || hh > 23) {return null;}
		var mm = parseInt(m[2], 10);
		if (mm < 0 || mm > 59) {return null;}
		return (m[1].length > 1 ? m[1] : "0" + m[1]) + ":" +
				(m[2].length > 1 ? m[2] : "0" + m[2]);
	};

	_this.validateNonemptyString = function(s) {
		var r = s.replace(/^\s+|\s+$/g, "");
		return r.length > 0 ? r : null;
	};

	_this.validateInput = function (elem, fn, result) {
		var inp = $(elem);
		var res = fn(inp.val());

		if (null == res) {
			inp.css("color", "#cc3300").css("border-color", "#cc3300");
			return false;
		}
	    
		inp.css("color", "").css("border-color", "");

		if (result) {
			result.value = res;
		}
		return true;
	};
	
	_this.validateInputHttp = function(elem, fn, result) {
		var inp = $(elem);
		var res = fn(inp.val());
		if (null === res) {
			inp.css("color", "#cc3300").css("border-color", "#cc3300");
			return false;
		}
		else {
			if (res.indexOf("http://") && res.indexOf("https://") && res.indexOf("webcal://")) {
				inp.css("color", "#cc3300").css("border-color", "#cc3300");
				return false;
			}
		}
	    
		inp.css("color", "").css("border-color", "");
	    
		if (result) {result.value = res;}
		return true;
	};

	_this.makeBullet = function(isActive, activeColor, inactiveColor, isShared) {
		var bg = htmlEscape(activeColor);
		var bullet =
				'<div class="bullet" style="border: 1px solid ' + bg + ';' +
						(isActive ? "background-color:" + bg : "") + '">' +
					(isShared ? '<div class="shared"/>' : '') +
				'</div>';
		return bullet;
	};

	_this.updateBullet = function(elem, isActive, activeColor, inactiveColor, isShared) {
		var bg = htmlEscape(activeColor),
		    s = elem.find(".shared");
		elem.css("background-color", isActive ? bg : "");
		elem.next(".label").css("color", isActive ? "" : inactiveColor);
		if (isShared && s.length < 1) {
			elem.append('<div class="shared"/>');
		} else if (!isShared && s.length > 0) {
			s.remove();
		}
	};

	return _this;

}();

var fcColorPicker = function fcCPModule() {
	var _this = {};

	var _cp;
	var _oldElem;

	function _init(colors) {
		//if (!_cp || _cp.length < 1) {
			_cp = $("<div id='fc_color_picker'/>").colorPicker({
			    arrowPosition:  "50%",
			    showArrow: false,
				anchorToBorder: true,
				showModal:      true,
				colors: {1: colors},
				colorSet: 1});
		//}
	}

	_this.open = function(iconElem, onColorSelect, colors) {
		_init(colors);
		if (_oldElem != iconElem) {
			_cp.colorPicker("close");
		}
		_oldElem = iconElem;
		var icon = $(iconElem);

		// to round all float numbers to 2nd digit after point do not use directly css(...)
		var rgb = fcUtil.parseCssColor(icon.css("background-color"));
		_cp.colorPicker("option", "selectedColor", rgb.origColor);

		_cp.colorPicker("option", "select", function(ev, c) {
			if ($.isFunction(onColorSelect)) {onColorSelect(c);}
		});
		_cp.colorPicker("open", icon.parent());
	};

	_this.close = function() {
		if (_cp && _cp.length > 0) {
			_cp.colorPicker("close");
			_oldElem = undefined;
		}
	};

	return _this;
}();

var fcDatepicker = function fcDPModule() {
	var _this = {};

	var _frame;
	var _dp;

// show calendar
	function _init(calendar) {
		if (!_frame || _frame.length < 1) {
			_frame = $(
				'<div id="fc_common_dp">' +
					'<div class="asc-datepicker"/>' +
				'</div>')
				.popupFrame({
						anchor: "left,bottom",
						direction: "right,down",
						arrow: "up",
						arrowPosition: "50%",
						showArrow: false,
						showModal: true});
			_dp = _frame.find(".asc-datepicker").datepicker({
					firstDay: calendar.options.firstDay});
		}
	}

	function _fixDatepickerUI() {
		setTimeout(
				function() {
					_dp.find(".ui-datepicker-prev .ui-icon")
							.removeClass("ui-icon-circle-triangle-w")
							.addClass("ui-icon-carat-1-w");
					_dp.find(".ui-datepicker-next .ui-icon")
							.removeClass("ui-icon-circle-triangle-e")
							.addClass("ui-icon-carat-1-e");
				},
				0);
	}

	_this.open = function(calendar, label, onShow, onSelect) {
		_init(calendar);
		_dp.datepicker('option', 'onSelect', function(){onSelect.call(_this, label, _dp);});
		_dp.datepicker('option', 'onChangeMonthYear', _fixDatepickerUI);
		onShow.call(_this, _dp);
		_fixDatepickerUI();
		_frame.popupFrame("open", label);
	};

	_this.close = function() {
		isOpenCommonDatePicker = false;
		if (_frame && _frame.length > 0) {
			_frame.popupFrame("close");
		}
	};

	return _this;
}();

var fcDebugMode = 0;

function debugOutput(channel) {
	if (fcDebugMode && console && $.isFunction(console[channel])) {
		console[channel].apply(this, Array.prototype.slice.call(arguments, 1));
	}
}


var kCalendarAddAction        = 1;
var kCalendarChangeAction     = 2;
var kCalendarDeleteAction     = 3;
var kCalendarHideAction       = 4;
var kCalendarCancelAction     = 5;

var kEventAddAction           = 1;
var kEventChangeAction        = 2;
var kEventDeleteAction        = 3;
var kEventUnsubscribeAction   = 4;
var kEventCancelAction        = 5;
    
var kTodoAddAction            = 1;
var kTodoChangeAction         = 2;
var kTodoDeleteAction         = 3;
var kTodoUnsubscribeAction    = 4;
var kTodoCancelAction         = 5;

var kCalendarPermissions      = 1;
var kEventPermissions         = 2;

var kSubscriptionAddAction    = 1;
var kSubscriptionChangeAction = 2;
var kSubscriptionRemoveAction = 3;

var kAlertDefault             = -1;
var kAlertNever               = 0;

var kRepeatNever              = 0;

var AjaxUploader = undefined;

function initTemplates(options) {

	var c = options.categories;
	var e = options.eventEditor;
	var t = options.todoEditor;
	var tv = options.todoViewer;
	var dt = options.deleteTodoDialog;
	var tl = options.todoList;
	var rs = options.repeatSettings;
	var ds = options.deleteSettings;
	var ic = options.icalStream;
	var cp = options.confirmPopup;

    var templateData = {
        dialogHeaderAdd: htmlEscape(c.dialogHeader_add),
        dialogHeaderImport: htmlEscape(c.dialogHeader_import),
        dialogHeaderEdit: htmlEscape(c.dialogHeader_edit),
        defaultCalendarName: htmlEscape(c.defaultTitle),
        dialogBgColorLabel: htmlEscape(c.dialogColor_label),
        dialogFontColorLabel: htmlEscape(c.dialogTextColor_label),
        dialogAlertLabel: e.dialogAlertLabel,
        alertOptions: [
							{ value:kAlertNever, text:e.dialogAlertOption_never },
							{ value:1, text:e.dialogAlertOption_5minutes },
							{ value:2, text:e.dialogAlertOption_15minutes },
							{ value:3, text:e.dialogAlertOption_30minutes },
							{ value:4, text:e.dialogAlertOption_hour },
							{ value:5, text:e.dialogAlertOption_2hours },
							{ value:6, text:e.dialogAlertOption_day }
        ],
        dialogTimezoneLabel: c.dialogTimezoneLabel,
        dialogInputiCalLabel: ic.dialogInputiCalLabel,
        dialogImportExportLabel: ic.dialogImportExportLabel,
        dialogImportLabel: ic.dialogImportLabel,
        dialogImportLabelNew: ic.dialogImportLabelNew,
        fileNotSelected: ic.dialogButton_fileNotSelected,
        dialogStreamLink: ic.dialogStreamLink,
        dialogExportLink: ic.dialogExportLink,
        dialogButtonSave: c.dialogButton_save,
        dialogButtonCancel: c.dialogButton_cancel,
        dialogButtonDelete: c.dialogButton_delete,
        maxlength: defaults.eventMaxTitleLength
    };

    options.categories.dialogTemplate = $("#categoriesDialogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");

    templateData = {
        dialogHeader: htmlEscape(c.subscriptionsDialogHeader),
        dialogBgColorLabel: htmlEscape(c.dialogColor_label),
        dialogFontColorLabel: htmlEscape(c.dialogTextColor_label),
        dialogAlertLabel: htmlEscape(e.dialogAlertLabel),
        alertOptions: [
							{ value:kAlertNever, text:e.dialogAlertOption_never },
							{ value:1, text:e.dialogAlertOption_5minutes },
							{ value:2, text:e.dialogAlertOption_15minutes },
							{ value:3, text:e.dialogAlertOption_30minutes },
							{ value:4, text:e.dialogAlertOption_hour },
							{ value:5, text:e.dialogAlertOption_2hours },
							{ value:6, text:e.dialogAlertOption_day }
        ],
        dialogTimezoneLabel: htmlEscape(c.dialogTimezoneLabel),
        dialogOwnerLabel: c.subscriptionsDialogOwnerLabel,
        dialogSavediCalLabel: htmlEscape(ic.dialogSavediCalLabel),
        dialogImportExportLabel: htmlEscape(ic.dialogImportExportLabel),
        dialogImportLabel: htmlEscape(ic.dialogImportLabel),
        dialogImportLabelNew: htmlEscape(ic.dialogImportLabelNew),
        fileNotSelected: htmlEscape(ic.dialogButton_fileNotSelected),
        dialogStreamLink: htmlEscape(ic.dialogStreamLink),
        dialogExportLink: htmlEscape(ic.dialogExportLink),
        dialogButtonSave: c.dialogButton_save,
        dialogButtonCancel: c.dialogButton_cancel,
        dialogButtonDelete: c.dialogButton_delete,
        dialogButtonUnsubscribe: c.subscriptionsDialogButton_unsubscribe,
        maxlength: defaults.eventMaxTitleLength
    };

    options.categories.subscriptionsDialog = $("#categoriesSubscriptionsDialogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");

    templateData = {
        dialogTitle: htmlEscape(c.subscriptionsManageDialog_title),
        dialogSearchText: htmlEscape(c.subscriptionsManageDialog_qsearchText),
        dialogButtonSave: htmlEscape(c.subscriptionsManageDialogButton_save),
        dialogButtonCancel: htmlEscape(c.subscriptionsManageDialogButton_cancel),
        maxlength: defaults.eventMaxTitleLength
    };

    options.categories.subscriptionsManageDialog = $("#categoriesSubscriptionsManageDialogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");

    templateData = {
        dialogHeaderAdd: htmlEscape(e.dialogHeader_add),
        defaultEventSummary: htmlEscape(e.newEventTitle),
        eventButton: htmlEscape(e.eventButton),
        todoButton: htmlEscape(e.todoButton),
        dialogLocationLabel: htmlEscape(e.dialogLocationLabel),
        dialogAttendeesLabel: htmlEscape(e.dialogAttendeesLabel),
        dialogOwnerLabel: htmlEscape(e.dialogOwnerLabel),
        dialogOrganizerLabel: htmlEscape(e.dialogOrganizerLabel),
        dialogAllDayNoText: htmlEscape(e.dialogAllDay_no),
        dialogAllDayYesText: htmlEscape(e.dialogAllDay_yes),
        dialogFromLabel: htmlEscape(e.dialogFromLabel),
        dialogToLabel: htmlEscape(e.dialogToLabel),
        dialogAlertLabel: htmlEscape(e.dialogAlertLabel),
        dialogRepeatLabel: htmlEscape(e.dialogRepeatLabel),
        dialogSharingNoText: htmlEscape(e.dialogSharing_no),
        dialogSharingYesText: htmlEscape(options.sharedList.title),
        dialogCalendarLabel: htmlEscape(e.dialogCalendarLabel),
        dialogDescriptionLabel: htmlEscape(e.dialogDescriptionLabel),
        dialogSummaryLabel: htmlEscape(e.dialogSummaryLabel),
        dialogAllDayLabel: htmlEscape(e.dialogAllDayLabel),
        dialogSentInvitations: htmlEscape(e.dialogSentInvitations),
        dialogAlertOptionDefault: htmlEscape(e.dialogAlertOption_default),
        dialogRepeatOptionNever: htmlEscape(e.dialogRepeatOption_never),
        dialogStatusLabel: htmlEscape(e.dialogStatusLabel),
        dialogStatusOptionTentative: htmlEscape(e.dialogStatusOption_tentative),
        dialogStatusOptionConfirmed: htmlEscape(e.dialogStatusOption_confirmed),
        dialogStatusOptionCancelled: htmlEscape(e.dialogStatusOption_cancelled),
        repeatFromLabel: htmlEscape(rs.dialogFromLabel),
        repeatRepeatOnLabel: htmlEscape(rs.dialogRepeatOnLabel),
        repeatRepeatOnDays: htmlEscape(rs.dialogRepeatOn_days),
        repeatEachLabel: htmlEscape(rs.dialogEachLabel),
        repeatIntervalOptionDay: htmlEscape(rs.dialogIntervalOption_day),
        repeatToLabel: htmlEscape(rs.dialogToLabel),
        repeatOptionNever: htmlEscape(rs.dialogOptionNever),
        repeatAfterLabel: htmlEscape(rs.dialogAfterLabel),
        repeatTimesLabel: htmlEscape(rs.dialogTimesLabel),
        dialogButtonEdit: htmlEscape(e.dialogButton_edit),
        dialogButtonSave: htmlEscape(e.dialogButton_save),
        dialogButtonClose: htmlEscape(e.dialogButton_close),
        dialogButtonCancel: htmlEscape(e.dialogButton_cancel),
        dialogButtonDelete: htmlEscape(e.dialogButton_delete),
        dialogButtonUnsubscribe: htmlEscape(e.dialogButton_unsubscribe),
        dialogButtonMoreDetails: htmlEscape(e.dialogButton_moreDetails),
        dialogButtonDetails: htmlEscape(e.dialogButton_details),
        maxlength: defaults.eventMaxTitleLength,
        
        dialogTodoDate: htmlEscape(t.dialogDateLabel),
        dialogTodoNameLabel: htmlEscape(t.titleLabel),
        
    };

    options.eventEditor.dialogTemplate = $("#eventEditorDialogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");
	
    templateData = {
        dialogHeader: htmlEscape(ds.dialogHeader),
        dialogSingleHeader: htmlEscape(ds.dialogSingleHeader),
        dialogSingleBody: htmlEscape(ds.dialogSingleBody),
        dialogDeleteOnlyThisLabel: htmlEscape(ds.dialogDeleteOnlyThisLabel),
        dialogDeleteFollowingLabel: htmlEscape(ds.dialogDeleteFollowingLabel),
        dialogDeleteAllLabel: htmlEscape(ds.dialogDeleteAllLabel),
        dialogButtonSave: htmlEscape(ds.dialogButton_save),
        dialogButtonCancel: htmlEscape(ds.dialogButton_cancel)
    };

    options.deleteSettings.dialogTemplate = $("#deleteSettingsDalogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");

    templateData = {
        dialogHeader: htmlEscape(ic.dialogHeader),
        
        dialogTodoDescription: htmlEscape(ic.dialogTodoDescription),
        
        dialogDescription: htmlEscape(ic.dialogDescription),
        dialogCaldavHelp: htmlEscape(ic.dialogCaldavHelp),
        dialogHelpCenter: htmlEscape(ic.dialogHelpCenter),
        dialogPreparingMessage: htmlEscape(ic.dialogPreparingMessage),
        dialogPreparingErrorMessage: htmlEscape(ic.dialogPreparingErrorMessage),
        dialogButtonClose: htmlEscape(ic.dialogButton_close),
        dialogExportCalDav: htmlEscape(ic.dialogExportCalDav),
        dialogCopyButton: htmlEscape(ic.dialogCopyButton),
        dialogTryAgainButton: htmlEscape(ic.dialogTryAgainButton),
        dialogExportIcal: htmlEscape(ic.dialogExportIcal)
    };

    options.icalStream.dialogTemplate = $("#icalStreamDialogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    
    templateData = {
        dialogHeader: htmlEscape(cp.dialogAddEventHeader),
        dialogBody: htmlEscape(cp.dialogAddEventBody),
        dialogButtonSend: htmlEscape(cp.dialogButtonSend),
        dialogButtonSendCustoms: htmlEscape(cp.dialogButtonSendCustoms),
        dialogButtonSendEveryone: htmlEscape(cp.dialogButtonSendEveryone),
        dialogButtonDontSend: htmlEscape(cp.dialogButtonDontSend)
    };

    options.confirmPopup.dialogTemplate = $("#attendeeConfirmNotificationTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    
    templateData = {
        dialogTitle: htmlEscape(t.dialogHeader_add),
        dialogDate: htmlEscape(t.dialogDateLabel),
        
        dialogNameLabel: htmlEscape(t.titleLabel),
        dialogDescriptionLabel: htmlEscape(t.descriptionLabel),
        
        dialogButtonSave: htmlEscape(t.dialogButton_save),
        dialogButtonCancel: htmlEscape(t.dialogButton_cancel),
    };
    options.todoEditor.dialogTemplate = $("#todoEditorDialogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    
    templateData = {
        dialogButtonMarkOn: htmlEscape(tv.dialogButton_mark_on),
        dialogButtonMarkOff: htmlEscape(tv.dialogButton_mark_off),
        dialogButtonEdit: htmlEscape(tv.dialogButton_edit),
        dialogButtonDelete: htmlEscape(tv.dialogButton_delete),
    };
    options.todoViewer.dialogTemplate = $("#todoViewDialogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    
    templateData = {
        
        dialogHeader: htmlEscape(dt.dialogHeader),
        dialogText: htmlEscape(dt.deleleDialogText),
        
        dialogSingleBody: htmlEscape(dt.dialogSingleBody),
        
        dialogButton_apply: htmlEscape(dt.dialogButton_apply),
        dialogButton_cancel: htmlEscape(dt.dialogButton_cancel),

    };
    options.deleteTodoDialog.dialogTemplate = $("#deleteTodoDalogTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    
    templateData = {
        menuTodoInCalendar: htmlEscape(tl.menuTodoInCalendar),
        menuDeleteMarkedTodo: htmlEscape(tl.menuDeleteMarkedTodo),
        menuSyncLinks: htmlEscape(tl.menuSyncLinks)
    };
    options.todoList.menuTemplate = $("#todoMenuTemplate").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    options.todoList.deleteIcon = $("#delete_todo_icon").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    options.todoList.editIcon = $("#edit_todo_icon").tmpl(templateData).html().replace(/\>\s+\</g, "><");
    options.todoList.settingsIcon = $("#settings_todo_icon").tmpl(templateData).html().replace(/\>\s+\</g, "><");

}


$.fn.fullCalendar = function(options) {


	// method calling
	if (typeof options == 'string') {
		var args = Array.prototype.slice.call(arguments, 1);
		var res = undefined;
		this.each(function() {
			var calendar = $.data(this, 'fullCalendar');
			if (calendar && $.isFunction(calendar[options])) {
				var r = calendar[options].apply(calendar, args);
				if (res === undefined) {
					res = r;
				}
				if (options == 'destroy') {
					$.removeData(this, 'fullCalendar');
				}
			}
		});
		return res !== undefined ? res : this;
	}


	// would like to have this logic in EventManager, but needs to happen before options are recursively extended
	var eventSources = options.eventSources || [];
	delete options.eventSources;
	if (options.events) {
		eventSources.push(options.events);
		delete options.events;
	}


	options = $.extend(true, {},
		defaults,
		(options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {},
		window.g_fcOptions ? window.g_fcOptions : {},
		options
	);

	initTemplates(options);

	if ($.isFunction(options.loadEvents)) {
		fc.sourceFetchers[0] = options.loadEvents;
	}

	options.eventResize = options.eventResize ||
			function(event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view) {
				if (!fcUtil.eventIsEditable(event)) {
					revertFunc();
				}
			};

	options.eventDrop = options.eventDrop ||
			function(event, dayDelta, minuteDelta, allDay, revertFunc, jsEvent, ui, view) {
				if (!fcUtil.eventIsEditable(event)) {
					revertFunc();
				}
			};


	this.each(function(i, _element) {
		var element = $(_element);
		var calendar = new Calendar(element, options, eventSources);
		element.data('fullCalendar', calendar); // TODO: look into memory leak implications
		calendar.render();
	});


	return this;

};



// function for adding/overriding defaults
function setDefaults(d) {
	$.extend(true, defaults, d);
}



function Calendar(element, options, eventSources) {
	var t = this;

	// exports
	t.options = options;
	t.render = render;
	t.destroy = destroy;
	t.refetchEvents = refetchEvents;
	t.reportEvents = reportEvents;
	t.reportEventChange = reportEventChange;
	t.rerenderEvents = rerenderEvents;
	t.rerenderCategories = rerenderCategories;
	t.changeView = changeView;
	t.openTodoList = openTodoList;
	t.changeViewAndMode = changeViewAndMode;
	t.select = select;
	t.unselect = unselect;
	t.prev = prev;
	t.next = next;
	t.prevYear = prevYear;
	t.nextYear = nextYear;
	t.today = today;
	t.gotoDate = gotoDate;
	t.incrementDate = incrementDate;
	t.formatDate = function(date, format) {return formatDate(date, format, options);};
	t.formatDates = function(date1, date2, format) {return formatDates(date1, date2, format, options);};
	t.getDate = getDate;
	t.getView = getView;
	t.option = option;
	t.trigger = trigger;
	t.updateSize = updateSize;
	t.updateEventWin = updateEventWin;
	t.editEvent = editEvent;
	t.addAndEditEvent = addAndEditEvent;
	t.addNewCalendar = addNewCalendar;
	t.addiCalCalendar = addiCalCalendar;
	t.isEditingEvent = isEditingEvent;
	t.showTodo = showTodo;
	t.showEventPageEditor = showEventPageEditor;
	t.showEventPageViewer = showEventPageViewer;


	// imports
	EventManager.call(t, options, eventSources);
	var isFetchNeeded = t.isFetchNeeded;
	var fetchEvents = t.fetchEvents;


	// locals
	var _element = element[0];
	var catlist;
	var todolist;
	var eventEditor;
    
	var eventPage;

	var header;
	var headerElement;
	var content;
	var tm; // for making theme classes
	var currentView;
	var viewInstances = {};
	var elementOuterWidth;
	var suggestedViewHeight;
	var absoluteViewElement;
	var resizeUID = 0;
	var ignoreWindowResize = 0;
	var date = new Date();
	var events = [];
	var _dragElement;
	var _confirmPopup;



	/* Main Rendering
	-----------------------------------------------------------------------------*/

	setYMD(date, options.year, options.month, options.date);


	function render(inc) {
		if (!content) {
			initialRender();
		}else{
			calcSize();
			markSizesDirty();
			markEventsDirty();
			renderView(inc);
		}
	}


	function initialRender() {
		tm = options.theme ? 'ui' : 'fc';
		element.addClass('fc');
		if (options.isRTL) {
			element.addClass('fc-rtl');
		}
		if (options.theme) {
			element.addClass('ui-widget');
		}

		var fc_container = $(
				'<div id="fc_container">' +
					'<table cellpadding="0" cellspacing="0" width="100%" class="fc_table"><tbody><tr>' +
						'<td class="fc-main"/>' +
				       // '<td class="_fc-todo-list"/>' +
					'</tr></tbody></table>'+
				    '<div class="fc-todo-list-container"></div>'+
				'</div>'
				
		);
		var fc_todo_container = fc_container.find(".fc-todo-list-container");
	    
		fc_todo_container.on('transitionend MSTransitionEnd webkitTransitionEnd oTransitionEnd', function (event) {
		    updateSize();
		});

		header = new Header(t, options);
		headerElement = header.render();
		if (headerElement && headerElement.length > 0) {
			fc_container.prepend(headerElement);
		}

		catlist = new CategoriesList(t);
		$("#calendarSidePanelContent").append(catlist.render());

		todolist = new TodoList(t);
		t.todolist = todolist;
	    fc_todo_container.append(todolist.render());

	    content = $(
	        "<div class='fc-content' style='position:relative'>" +
	            "<div class='fc-modal'/>" +
	            "</div>")
	        .appendTo(fc_container.find("td.fc-main"));

		eventEditor = new EventEditor(t, content.children(".fc-modal"));

		fc_container.appendTo(element);

		var targetView = defaults.defaultView;

		if (options.defaultView) {
			targetView = options.defaultView;
		} else {
			var savedView = $.cookie('fc_current_view');
			if(savedView && savedView.length > 0 && savedView.search(/\w/) >= 0)
				targetView = savedView;
		}

		changeView(targetView);

		$(window).resize(windowResize);

		catlist.showMiniCalendar(parseInt($.cookie('fc_show_minicalendar'), 10) !== 0);

		// needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize
		if (!bodyVisible()) {
			lateRender();
		}
	    
		if (options.targetEventId) {
		    displayTargetEvent();
		}

	    function displayTargetEvent() {
	        if (!ASC.Mail.Initialized) {
	            setTimeout(displayTargetEvent, 500);
	        } else {
	            prepare();
	        }
	        
	        function prepare() {
	            var targetEvent = t.clientEvents(options.targetEventId)[0];
	            
                if (!targetEvent) return;
                    
	            if (targetEvent && !isNaN(targetEvent.objectId) && targetEvent.uniqueId) {
	                window.Teamlab.getCalendarEventById({},
                        targetEvent.objectId,
                        {
                            success: function(p, eventInfo) {
                                if (eventInfo.eventUid === targetEvent.uniqueId && eventInfo.mergedIcs) {
                                    console.info(eventInfo);
                                    var evt = parseIcs(eventInfo.mergedIcs);
                                    targetEvent = jq.extend(targetEvent, evt || {});
                                    show();
                                }
                            },
                            error: function(p, e) {
                                console.error(e);
                            },
                            max_request_attempts: 1
                        });
	            } else {
	                show();
	            }
	            
	            function show() {
	                var canDelete = fcUtil.objectIsEditable(targetEvent) || fcUtil.objectIsEditable(targetEvent.source) || targetEvent.source && !targetEvent.source.isSubscription;
	                var canEdit = targetEvent.source == undefined || canDelete;
	                showEventPageViewer(canEdit, null, targetEvent);
	            }
            }
	    }
	}


	// called when we know the calendar couldn't be rendered when it was initialized,
	// but we think it's ready now
	function lateRender() {
		setTimeout(function() { // IE7 needs this so dimensions are calculated correctly
			if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once
				renderView();
			}
		},0);
	}


	function destroy() {
		$(window).unbind('resize', windowResize);
		header.destroy();
		content.remove();
		element.removeClass('fc fc-rtl ui-widget');
	}


	function elementVisible() {
		return _element.style.display != "none";
	}


	function bodyVisible() {
		return $('body')[0].offsetWidth !== 0;
	}

	function openTodoList() {
	    currentView.clearEvents();
	    var fc_container = $('#fc_container');
	    fc_container.toggleClass('open-todo-list');
	    fc_container.find('.fc-button-todo').toggleClass('fc-state-active');
	}


	/* View Rendering
	-----------------------------------------------------------------------------*/

	// TODO: improve view switching (still weird transition in IE, and FF has whiteout problem)

	function changeView(newViewName) {
		if (!currentView || newViewName != currentView.name) {
			ignoreWindowResize++; // because setMinHeight might change the height before render (and subsequently setSize) is reached

			unselect();

			var oldView = currentView;
			var newViewElement;

			if (oldView) {
				(oldView.beforeHide || noop)(); // called before changing min-height. if called after, scroll state is reset (in Opera)
				setMinHeight(content, content.height());
				oldView.element.hide();
			}else{
				setMinHeight(content, 1); // needs to be 1 (not 0) for IE7, or else view dimensions miscalculated
			}
			content.css('overflow', 'hidden');

			currentView = viewInstances[newViewName];
			if (currentView) {
				currentView.element.show();
			}else{
				currentView = viewInstances[newViewName] = new fcViews[newViewName](
					newViewElement =
						$("<div class='fc-view fc-view-" + newViewName + "'/>")
							.appendTo(content),
					t // the calendar object
				);
			}
			$.cookie('fc_current_view', newViewName + "", {expires: 365});

			if (oldView) {
				header.deactivateButton(oldView.name);
			}
			header.activateButton(newViewName);
			header.resize();

			renderView();

			content.css('overflow', '');
			if (oldView) {
				setMinHeight(content, 1);
			}

			if (!newViewElement) {
				(currentView.afterShow || noop)(); // called after setting min-height/overflow, so in final scroll state (for Opera)
			}

			ignoreWindowResize--;
		}
	}


	function changeViewAndMode(viewName, mode) {
		header.clickButton(viewName, mode);
	}


	function renderView(inc) {
		if (elementVisible()) {
			ignoreWindowResize++; // because renderEvents might temporarily change the height before setSize is reached

			unselect();

			if (suggestedViewHeight === undefined) {
				calcSize();
			}

			var forceEventRender = false;
			if (!currentView.start || inc || date < currentView.start || date >= currentView.end) {
				// view must render an entire new date range (and refetch/render events)
				currentView.render(date, inc || 0); // responsible for clearing events
				setSize(true);
				forceEventRender = true;
				
				// opera fix
				var unsel = jq(document).find(".fc-main");
				if ((unsel != undefined) && (unsel.length > 0)) {
					preventSelection.call(this, unsel[0]);
				}
			}
			else if (currentView.sizeDirty) {
				// view must resize (and rerender events)
				currentView.clearEvents();
				setSize();
				forceEventRender = true;
			}
			else if (currentView.eventsDirty) {
				currentView.clearEvents();
				forceEventRender = true;
			}
			currentView.sizeDirty = false;
			currentView.eventsDirty = false;
			updateEvents(forceEventRender);

			elementOuterWidth = element.outerWidth();

			header.updateTitle(currentView.title, currentView.name);
			var today = new Date();
			if (today >= currentView.start && today < currentView.end) {
				header.disableButton('today');
			}else{
				header.enableButton('today');
			}

			catlist.updateDatepicker(date);

			ignoreWindowResize--;
			currentView.trigger('viewDisplay', _element);

			trigger("viewChanged", currentView, currentView.name, getDate());
		}
	}



	/* Resizing
	-----------------------------------------------------------------------------*/
	function updateEventWin() {
	    var eventObj = eventEditor.getEventObj();
	    var todoObj = t.todolist.getTodoElem();
	    if (t.openEventWin) {
	        if (!t.openEventWin.isTodo && eventObj != undefined) {
	            if (!eventObj.objectId) {
	                eventEditor.closePopupEvent(true);
	                eventEditor.addEvent(eventObj.start, eventObj.end, eventObj.allDay, true);
	            } else {
	                var eventOpenElement = jQuery('.fc-event-open');
	                if (eventOpenElement.length > 0) {
	                    eventEditor.openEvent(eventOpenElement, eventObj);
	                }
	            }
	        } else if (t.openEventWin.objectId != null && t.openEventWin.isTodo && todoObj != undefined) {
	            var todoOpenElement = jQuery('.fc-todo-open');
	            if (todoOpenElement.length > 0) {
	                eventEditor.openEvent(todoOpenElement, todoObj);
	            }
	        }
	    }
	    
    }
	function updateSize() {
		if (currentView.name == "agendaWeek") {
		    currentView.updateHeader();
		}
		header.resize();
		markSizesDirty();
		if (elementVisible()) {
			currentView.clearEvents();
			calcSize();
			setSize();
			unselect();
			currentView.renderEvents(events);
			currentView.sizeDirty = false;
			updateFcHeader()
		}
	}


	function markSizesDirty() {
		$.each(viewInstances, function(i, inst) {
			inst.sizeDirty = true;
		});
	}


	function calcSize() {
		if (options.contentHeight) {
			suggestedViewHeight = Math.max(options.contentHeight, options.minHeight || 0);
		}
		else if (options.height) {
			if ($.isFunction(options.onHeightChange)) {options.onHeightChange();}
			suggestedViewHeight = Math.max(options.height, options.minHeight || 0) - ASC.CalendarSizeManager.cache.fcHeaderHeight;
		}
		else {
			suggestedViewHeight = Math.max(
					Math.round(content.width() / Math.max(options.aspectRatio, .5)), options.minHeight || 0);
		}
	}


	function setSize(dateChanged, bResize) { // todo: dateChanged?
		ignoreWindowResize++;
		currentView.setHeight(suggestedViewHeight, dateChanged);

		var oldWidth = content.width();

		currentView.setWidth(oldWidth, dateChanged);
		ignoreWindowResize--;

		var paddingStudioPageContent = jq("#studioPageContent .mainPageLayout:not(.studio-top-panel)").outerHeight(true) - jq("#studioPageContent .mainPageLayout:not(.studio-top-panel)").height();
		var paddingmainPageTable = jq(".mainPageTable .mainPageTableSidePanel.ui-resizable").outerHeight(true) - jq(".mainPageTable .mainPageTableSidePanel.ui-resizable").height();
		var smallChatDownPanel = jq('.small_chat_down_panel').length > 0 ? jq('.small_chat_down_panel').height() : 0;

		catlist.resize(suggestedViewHeight - paddingStudioPageContent - paddingmainPageTable - smallChatDownPanel);

		if (todolist && todolist.length > 0) {todolist.resize(suggestedViewHeight);}
		var newWidth = content.width();
		if (oldWidth != newWidth) {
			if (!bResize) {calcSize();}
			setSize(false, oldWidth > newWidth);
		}
	}

	function updateFcHeader() {
		var fcHeader = document.querySelector('.fc-header');

		if (!fcHeader || window.innerWidth > 1200) return;

		var left = fcHeader.querySelector('.fc-header-left');
		var center = fcHeader.querySelector('.fc-header-center');
		var right = fcHeader.querySelector('.fc-header-right');
		var diff = fcHeader.clientWidth - left.clientWidth - right.clientWidth;
		center.style.width = diff + "px";
	}

    function windowResize() {
        if (!ignoreWindowResize) {
            //eventEditor.closePopupEvent();
            if (currentView.start) { // view has already been rendered
                var uid = ++resizeUID;
                setTimeout(function () { // add a delay
                    if (uid == resizeUID && !ignoreWindowResize && elementVisible()) {
                        if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) {
                            ignoreWindowResize++; // in case the windowResize callback changes the height
                            updateSize();
                            currentView.trigger('windowResize', _element);
                            setTimeout(function () {
                                updateEventWin();
                                ignoreWindowResize--;
                            }, 200);
                        } else {
                            updateEventWin();
                        }
                    }
                }, 200);
            } else {
                // calendar must have been initialized in a 0x0 iframe that has just been resized
                lateRender();
            }
        } else {
            setTimeout(function () {
                $(window).resize();
            }, 200);
        }
	}



	/* Event Fetching/Rendering
	-----------------------------------------------------------------------------*/

	// fetches events if necessary, rerenders events if necessary (or if forced)
	function updateEvents(forceRender) {
		if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) {
			refetchEvents();
		}
		else if (forceRender) {
			rerenderEvents();
		}
	}


	function refetchEvents() {
		fetchEvents(currentView.visStart, currentView.visEnd); // will call reportEvents
	}


	// called when event data arrives
	function reportEvents(_events) {
		events = _events;
		rerenderEvents();
	}


	// called when a single event's data has been changed
	function reportEventChange(eventID, event) {
		
	    if (event && !isNaN(event.objectId) && event.uniqueId) {
	        Teamlab.getCalendarEventById({},
	            event.objectId,
	            {
	                success: function(p, eventInfo) {
	                    if (eventInfo.eventUid === event.uniqueId && eventInfo.mergedIcs) {
	                        console.info(eventInfo);
	                        var evt = parseIcs(eventInfo.mergedIcs);
	                        event = jq.extend(event, evt || {});

	                        var isOrganizer = false;
	                        var organizerEmail = event.organizer ? event.organizer[3].replace(new RegExp("mailto:", "ig"), "").toLowerCase() : "";

	                        jq.each(ASC.Mail.Accounts, function(index, account) {
	                            if (account.enabled && organizerEmail == account.email.toLowerCase()) {
	                                isOrganizer = true;
	                                return false;
	                            }
	                            return true;
	                        });

	                        var attendees = [];
	                        jq.each(event.attendees || [], function(index, attendeeObj) {
	                            var attendeeEmail = attendeeObj[3].replace(new RegExp("mailto:", "ig"), "");
	                            if (attendeeEmail.toLowerCase() != organizerEmail)
	                                attendees.push(attendeeEmail);
	                        });

	                        if (isOrganizer && attendees.length && !event.source.isSubscription)
	                            openConfirmPopup(event);
	                        else
	                            edit(event, false);
	                    }
	                },
	                error: function(p, e) {
	                    console.error(e);
	                },
	                max_request_attempts: 1
	            });
	    } else {
	        edit(event, false);
	    }
	    
	    function createConfirmPopup(eventObj) {

	        if (!_confirmPopup) {
	            _confirmPopup = $(options.confirmPopup.dialogTemplate)
	                .addClass("asc-dialog")
	                .popupFrame({
	                    anchor: "right,top",
	                    direction: "right,down",
	                    offset: "0,0",
	                    showArrow: false
	                });

	            _confirmPopup.find(".title").text(options.confirmPopup.dialogUpdateEventHeader);
	            _confirmPopup.find(".body").text(options.confirmPopup.dialogUpdateEventBody);
	            _confirmPopup.find(".send-customs-btn, .send-everyone-btn").remove();
	        }
	        
	        _confirmPopup.find(".buttons .send-btn").unbind("click").bind("click", function() {
	            edit(eventObj, true);
	        });

	        _confirmPopup.find(".buttons .dont-send-btn").unbind("click").bind("click", function() {
	            edit(eventObj, false);
	        });

	    }

	    function openConfirmPopup(eventObj) {

	        createConfirmPopup(eventObj);
	        
	        var uiBlocker = jq(".fc-content .fc-modal");
            
            _confirmPopup.popupFrame("close");
            uiBlocker.removeClass("fc-modal-transparent");;
		
	        _confirmPopup.popupFrame("open", { pageX: "center", pageY: "center" });
	        _confirmPopup.css("position","fixed");

	        if (_confirmPopup.popupFrame("isVisible")) {
	            uiBlocker.show();
	        } else {
	            uiBlocker.hide();
	        }
	    }

	    function closeConfirmPopup() {
	        if(_confirmPopup)
	            _confirmPopup.popupFrame("close");
	        jq(".fc-content .fc-modal").hide();
	    }

	    function sendGuestsNotification(eventObj) {

	        var attendeesEmails = jq.map(eventObj.attendees, function (attendee) {
	            return attendee[3].replace(new RegExp("mailto:", "ig"), "");
	        });

	        if (attendeesEmails.length) {
	            ASC.CalendarController.Busy = true;
	            window.LoadingBanner.displayLoading();
	        
	            ASC.Mail.Utility.SendCalendarUpdate(eventObj.sourceId, eventObj.uniqueId, attendeesEmails)
                    .done(function() {
                        console.log(options.confirmPopup.dialogSuccessToastText, arguments);
                    })
                    .fail(function() {
                        toastr.error(options.confirmPopup.dialogErrorToastText);
                        console.error(options.confirmPopup.dialogErrorToastText, arguments);
                    })
	                .always(function () {
	                    ASC.CalendarController.Busy = false;
	                    window.LoadingBanner.hideLoading();
	                });
	        }
	    }

	    function edit(eventObj, send) {
	        closeConfirmPopup();
	        
	        if (eventObj && eventObj.source) {
	            // update event
	            eventObj.newSourceId = eventObj.sourceId;
	            trigger("editEvent", t,
                        $.extend(
                                {
                                    action: kEventChangeAction,
                                    sourceId: eventObj.source.objectId,
                                    newSourceId: eventObj.source.objectId
                                },
                                eventObj),
                        function(response) {
                            if (!response.result) {return;}
                            
                             var cache = t.getCache();
                             for (var j = 0; j < cache.length; ++j) {
                                 if (cache[j].objectId == eventObj.eventId) {
                                     cache.splice(j, 1);
                                 }
                             }

                            cache.concat(response.event);
                            t.refetchEvents();
                            rerenderEvents();

                            if (send)
                                sendGuestsNotification(eventObj);
                        });
	            return;
	        }
	        rerenderEvents(eventID);
	    }
	}


	// attempts to rerenderEvents
	function rerenderEvents(modifiedEventID) {
		markEventsDirty();
		if (elementVisible()) {
			currentView.clearEvents();
			currentView.renderEvents(events, modifiedEventID);
			currentView.eventsDirty = false;
			//catlist.updateDatepickerCells();
		}
	}


	function rerenderCategories(resolveTodoList) {
		catlist.rerenderList();
		catlist.updateDatepickerSize();
		todolist.rerenderList(resolveTodoList);
		//if (todolist && todolist.length > 0) {todolist.rerenderList();}
	}


	function markEventsDirty() {
		$.each(viewInstances, function(i, inst) {
			inst.eventsDirty = true;
		});
	}


	function editEvent(elem, event) {
		eventEditor.openEvent(elem, event);
	}


	function addAndEditEvent(startDate, endDate, allDay) {
		eventEditor.addEvent(startDate, endDate, allDay);
	}
	
	function addiCalCalendar(anchor) {
		catlist.addiCalCalendar(anchor);
	}
	
	function addNewCalendar(anchor) {
		catlist.addNewCalendar(anchor);
	}


	function isEditingEvent() {
		return eventEditor.isVisible();
	}


	function showTodo(show) {
		if (todolist && todolist.length > 0) {
			return show === false ? todolist.hide() : todolist.show();
		}
		return false;
	}

	function initEventPage() {
		if (eventPage) return;
		eventPage = new EventPage(t);
	}

	function showEventPageEditor() {
		initEventPage();
		if (jq("#asc_event .event-editor .editor").is(":visible")) {
			if(confirm(ASC.Resources.Master.ResourceJS.WarningMessageBeforeUnload))
				eventPage.addEvent();
		} else {
			eventPage.addEvent();
		}
	}

	function showEventPageViewer(canEdit, elem, event) {
		initEventPage();
		eventPage.openEvent(canEdit, elem, event);
	}


	/* Selection
	-----------------------------------------------------------------------------*/

	function select(start, end, allDay) {
		currentView.select(start, end, allDay===undefined ? true : allDay);
	}


	function unselect() { // safe to be called before renderView
		if (currentView) {
			currentView.unselect();
		}
	}



	/* Date
	-----------------------------------------------------------------------------*/

	function prev(inc) {
		renderView(undefined === inc ? -1: inc);
	}


	function next(inc) {
		renderView(undefined === inc ? 1: inc);
	}


	function prevYear() {
		addYears(date, -1);
		renderView();
	}


	function nextYear() {
		addYears(date, 1);
		renderView();
	}


	function today() {
		date = new Date();
		renderView();
	}


	function gotoDate(year, month, dateOfMonth) {
		if (year instanceof Date) {
			date = cloneDate(year); // provided 1 argument, a Date
		}else{
			setYMD(date, year, month, dateOfMonth);
		}
		renderView();
	}


	function incrementDate(years, months, days) {
		if (years !== undefined) {
			addYears(date, years);
		}
		if (months !== undefined) {
			addMonths(date, months);
		}
		if (days !== undefined) {
			addDays(date, days);
		}
		renderView();
	}


	function getDate() {
		return cloneDate(date);
	}



	/* Misc
	-----------------------------------------------------------------------------*/

	function getView() {
		return currentView;
	}


	function option(name, value) {
		if (value === undefined) {
			return options[name];
		}
		if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {
			options[name] = value;
			updateSize();
		}
		return value;
	}


	function trigger(name, thisObj) {
		if (options[name]) {
			return options[name].apply(
				thisObj || _element,
				Array.prototype.slice.call(arguments, 2)
			);
		}
		return undefined;
	}



	/* External Dragging
	------------------------------------------------------------------------*/

	if (options.droppable) {
		$(document)
			.bind('dragstart', function(ev, ui) {
				var _e = ev.target;
				var e = $(_e);
				if (!e.parents('.fc').length) { // not already inside a calendar
					var accept = options.dropAccept;
					if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) {
						_dragElement = _e;
						currentView.dragStart(_dragElement, ev, ui);
					}
				}
			})
			.bind('dragstop', function(ev, ui) {
				if (_dragElement) {
					currentView.dragStop(_dragElement, ev, ui);
					_dragElement = null;
				}
			});
	}


}


function Header(calendar, options) {
	var _this = this;

	// locals
	var element = $([]);
	var tm;

	var _viewSelectorLabel;
	var _viewSelectorIcon;
	var _labels = [];
	var _modes = [];
	var _classes = [];
	var _switchTable = [];
	var _nameToMode = {};
	var _activeButtonName;
	var _activeMode;


	var formatDate = calendar.formatDate;
	var formatDates = calendar.formatDates;


	function _renderButton(buttonName) {
		var buttonClick;
		var button;

		if (calendar[buttonName]) {
			buttonClick = calendar[buttonName]; // calendar method
		}
		else if (fcViews[buttonName]) {
			buttonClick = function() {
				button.removeClass(tm + '-state-hover'); // forget why
				calendar.changeView(buttonName);
			};
		}else if (buttonName == 'todo') {
		    buttonClick = function() {
		        calendar.openTodoList();
		    };
		}

		if (buttonClick) {
			var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here?
			var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here?
			button = $(
				"<span class='fc-button fc-button-" + buttonName + " " + tm + "-state-default'>" +
					"<span class='fc-button-inner'>" +
						"<span class='fc-button-content'>" +
							(icon ?
								"<span class='fc-icon-wrap'>" +
									"<span class='ui-icon ui-icon-" + icon + "'/>" +
								"</span>" :
								text
								) +
						"</span>" +
					"</span>" +
				"</span>"
			);
			if (button) {
				button
					.click(function() {
						if (!button.hasClass(tm + '-state-disabled')) {
							buttonClick();
						}
					})
					.mousedown(function() {
						button
							.not('.' + tm + '-state-active')
							.not('.' + tm + '-state-disabled')
							.addClass(tm + '-state-down');
					})
					.mouseup(function() {
						button.removeClass(tm + '-state-down');
					})
					.hover(
						function() {
							button
								.not('.' + tm + '-state-active')
								.not('.' + tm + '-state-disabled')
								.addClass(tm + '-state-hover');
						},
						function() {
							button
								.removeClass(tm + '-state-hover')
								.removeClass(tm + '-state-down');
						}
					)
					.addClass(tm + '-corner-left')
					.addClass(tm + '-corner-right');
			}
		}
		return button;
	}

	function _renderSection(position) {
		var e = $("<div class='fc-header-" + position + "'/>");
		var buttonStr = options.header[position];
		if (buttonStr) {
			$.each(buttonStr.split(' '), function(i) {
				if (i > 0) {
					e.append("<span class='fc-header-space'/>");
				}
				$.each(this.split(','), function(j, buttonName) {
					if (buttonName == 'title') {
						e.append("<span class='fc-header-title'>&nbsp;</span>");
					}
					else {
						var button = _renderButton.call(_this, buttonName);
						if (button) {
							button.appendTo(e);
						}
					}
				});
			});
		}
		return e;
	}

	function _renderTodoLabel(elem) {
		var visible = true;
		$("<span class='todo-label'>" +
				htmlEscape(options.todoList.hideLabel) +
			"</span>")
			.click(function() {
				if (visible) {
					$(this).text(options.todoList.showLabel);
				} else {
					$(this).text(options.todoList.hideLabel);
				}
				visible = !visible;
				calendar.showTodo(visible);
			})
			.appendTo(elem.find(".fc-header-right"));
	}

	function _renderNewSelectorLabel(elem) {
	    var mainButtonText = htmlEscape(calendar.options.addNewLabel);

	    $('<ul class="menu-actions">' +
        '<li class="menu-main-button without-separator big" title="' + mainButtonText + '">' +
            '<span class="main-button-text">' + mainButtonText + '</span>' +
            '<span class="white-combobox">&nbsp;</span>'+
        '</li>'+
        '</ul>').appendTo(elem);

		var _addSelectorLabel = elem.find(".menu-main-button");

		_addSelectorLabel.on("click", function (event) {
			fcMenus.hideMenus(fcMenus.modeMenuAddNew);
			fcMenus.modeMenuAddNew.popupMenu("open", _addSelectorLabel);
			event.stopPropagation();
		});

		if (!fcMenus.modeMenuAddNew || fcMenus.modeMenuAddNew.length < 1) {
			fcMenus.modeMenuAddNew = $('<div id="fc_mode_menu_add_new"/>');
		} else {
			fcMenus.modeMenuAddNew.popupMenu("close");
			fcMenus.modeMenuAddNew.popupMenu("destroy");
		}

		fcMenus.modeMenuAddNew.popupMenu({
			anchor: "left,bottom",
			direction: "right,down",
			arrow: "up",
			showArrow: false,
			closeTimeout: -1,
			cssClassName: "asc-popupmenu",
			items: [
				{
					label: calendar.options.eventEditor.newEventTitle,
					click: function() {
					    calendar.showEventPageEditor();
					}
				},
				{
					label: calendar.options.categories.defaultTitle,
					click: function() {
						calendar.addNewCalendar( {pageX: "center", pageY: "center"} );
					}
				},
			    {
					label: '',
					cssClass: "dropdown-item-seporator"
				},
				{
					label: calendar.options.icalStream.importEventsTitle,
					click: function() {
					    calendar.addiCalCalendar( {pageX: "center", pageY: "center"} );
					},
				}
			]
		});
	}

	function _renderToday(elem) {
		var op = calendar.options.categories;
		var today = new Date();
		var day;
	    
		var daynames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
		if (window.moment) {
		    day = window.moment(today).calendar(null, {
		        lastWeek: 'dddd DD.MM.YYYY',
		        sameElse: 'dddd DD.MM.YYYY',
		        nextWeek: 'dddd DD.MM.YYYY'
		    }).split(' ')[0];
		  
		} else {
		    day = daynames[today.getDay()];
		}
	    
		var r = $(
				'<div class="fc-header-today">' +
					'<div class="date-box">' +
				        '<div class="today">' + day + ', ' + '</div>' +
						'<div class="today-day">' + htmlEscape(formatDate(today, op.dayFormat)) + '</div>' +
						'<div class="today-month">' + htmlEscape(formatDate(today, 'MMM')) + '</div>' +
						//'<div class="today-year">' + htmlEscape(formatDate(today, op.yearFormat)) + '</div>' +
					'</div>' +
				'</div>');
		r.find(".date-box").children().click(function() {calendar.today();});
		r.appendTo(elem.find(".fc-header-center"));
	}

	function _updateViewSelector(mode) {
		_viewSelectorLabel.text(_labels[mode]);
		_viewSelectorIcon
				.removeClass()
				.addClass("icon")
				.addClass(_classes[mode]);
		for (var i = 0; i < _modes.length; ++i) {
			_modes[i].css("display", i != mode ? "none" : "inline-block");
		}
		_activeMode = mode;
	    _updateFcHeader();

	}

	function _updateFcHeader() {
	    var header = document.querySelector('.fc-header');

	    if (!header || window.innerWidth > 1200) return;

	    setTimeout(function () {
	        var left = header.querySelector('.fc-header-left');
	        var center = header.querySelector('.fc-header-center');
	        var right = header.querySelector('.fc-header-right');
	        var diff = header.clientWidth - left.clientWidth - right.clientWidth;
	        center.style.width = diff + "px";
	    },100);
	}

	function _setCurrentView(mode) {
		_updateViewSelector(mode);
		if (_activeButtonName && _activeButtonName.length > 0) {
			_this.clickButton(_activeButtonName, mode);
		}
	}

	function _renderViewSelectors(elem) {
		elem.find(".fc-header-right").append(
				/*'<span class="fc-view-selector">' +
					'<span class="icon">&nbsp;</span>' +
					'<span class="label">' + htmlEscape(options.modes.calendarViewLabel) + '</span>' +
					'<span class="fc-dropdown">&nbsp;</span>' +
				'</span>' + */
				'<span class="fc-calendar-buttons"/>' +
				'<span class="fc-list-buttons"/>');
		_modes[0] = elem.find(".fc-calendar-buttons")
				.append(_renderButton.call(_this, "agendaDay"))
				.append(_renderButton.call(_this, "agendaWeek"))
				.append(_renderButton.call(_this, "month"))
                .append(_renderButton.call(_this, "list"))
                .append(_renderButton.call(_this, "todo"));
		_modes[1] = elem.find(".fc-list-buttons")
				.append(_renderButton.call(_this, "listDay"))
				.append(_renderButton.call(_this, "listWeek"))
				.append(_renderButton.call(_this, "listMonth"))
				.append(_renderButton.call(_this, "list"));
		_labels[0]  = options.modes.calendarViewLabel;
		_labels[1]  = options.modes.listViewLabel;
		_classes[0] = "calendar";
		_classes[1] = "list";
		_switchTable[0] = {
		    listDay:    "agendaDay",
		    todoList:   "todo",
			listWeek:   "agendaWeek",
			listMonth:  "month",
			list:       "month",
			day:        "agendaDay"
		};
		_switchTable[1] = {
		    agendaDay:  "listDay",
		    todo:       "todoList",
			agendaWeek: "listWeek",
			month:      "listMonth",
			day:        "listDay"
		};
		_nameToMode = {
			agendaDay:  0,
			agendaWeek: 0,
			month:      0,
		    todo:       0,
			listDay:    1,
			listWeek:   1,
			listMonth:  1,
			list:       0
		};

		_viewSelectorLabel = elem.find(".fc-view-selector .label");
		_viewSelectorIcon = elem.find(".fc-view-selector .icon");

		elem.find(".fc-view-selector .label, .fc-view-selector .fc-dropdown").click(
			function (event) {
				fcMenus.hideMenus(fcMenus.modeMenu);
				fcMenus.modeMenu.popupMenu("open", _viewSelectorLabel);
				event.stopPropagation();
			});

		if (!fcMenus.modeMenu || fcMenus.modeMenu.length < 1) {
			fcMenus.modeMenu = $('<div id="fc_mode_menu"/>');
		} else {
			fcMenus.modeMenu.popupMenu("close");
			fcMenus.modeMenu.popupMenu("destroy");
		}
		fcMenus.modeMenu.popupMenu({
			anchor: "left,bottom",
			direction: "right,down",
			arrow: "up",
			showArrow: false,
			closeTimeout: -1,
			cssClassName: "asc-popupmenu",
			items: [
				{
					label: _labels[0],
					click: function(event, data) {_setCurrentView.call(_this, 0);}
				},
				{
					label: _labels[1],
					click: function(event, data) {_setCurrentView.call(_this, 1);}
				}
			]
		});

		_setCurrentView.call(_this, 0);
	}



	this.render = function() {
		tm = options.theme ? 'ui' : 'fc';
		var sections = options.header;
		if (sections) {
			element = $('<div class="fc-header-outer"/>')
					.append(
						$('<div class="fc-header"/>')
							.append(_renderSection.call(this, "left"))
							.append(_renderSection.call(this, "center"))
							.append(_renderSection.call(this, "right"))
					);
			// temporary desabled
			//_renderTodoLabel.call(this, element);
			_renderViewSelectors.call(this, element);
			_renderNewSelectorLabel.call(this, $("#calendarSidePanelActions"));
			_renderToday.call(this,element);
			return element;
		}
		return null;
	};


	this.destroy = function() {
		element.remove();
	};

	this.updateTitle = function(newTitle, viewName) {
		var title = element.find('span.fc-header-title').empty();
		if (typeof(newTitle) == "string") {
			title.append($("<h2>" + htmlEscape(newTitle) + "</h2>"));
		} else {
			var nt = $(newTitle).clone(true);
			title.append(nt.children());
		}
		title.removeClass().addClass("fc-header-title");
		var parts = viewName.split(/(?=[A-Z])/);
		var c = parts.pop();
		if (c != undefined) {
			title.addClass(c.toLowerCase());
		}
	};

	this.activateButton = function(buttonName) {
		_activeButtonName = buttonName;
		_updateViewSelector(_nameToMode[buttonName] !== undefined ? _nameToMode[buttonName] : 0);
		element.find('span.fc-button-' + buttonName)
			.addClass(tm + '-state-active');
	};

	this.deactivateButton = function(buttonName) {
		element.find('span.fc-button-' + buttonName)
				.removeClass(tm + '-state-active');
	};

	this.disableButton = function(buttonName) {
		element.find('span.fc-button-' + buttonName)
			.addClass(tm + '-state-disabled');
	};

	this.enableButton = function(buttonName) {
		element.find('span.fc-button-' + buttonName)
			.removeClass(tm + '-state-disabled');
	};

	this.clickButton = function(buttonName, mode) {
		element.find(".fc-button-" +
				_switchTable[mode != undefined ? mode : _activeMode][buttonName]).click();
	};

	this.resize = function() {
		element.find(".fc-header-left")[0].style.width = "";
		element.find(".fc-header-center")[0].style.width = "";
	};

}


function PermissionsList(calendar, container, linkText) {
	var _this = this;

	// Trigger self events:
	//   onChange(permissions)
	//   onResize()
	//
	// Trigger calendar's events:
	//   editPermissions(param)
	//   removePermissions(param)

	var _handlers = {};

	function _trigger(eventName) {
		if (_handlers && $.isFunction(_handlers[eventName])) {
			_handlers[eventName].apply(
					_handlers.context != undefined ? _handlers.context : window,
					Array.prototype.slice.call(arguments, 1));
		}
	}

	this.setEventsHandlers = function(handlers) {
		if (handlers != undefined) {
			$.extend(_handlers, handlers);
		}
	};


	var _userList;
	var _moreText;
	var _moreLink;
	var _shortListLen;

	var _permissions;
	var _type;
	var _objectId;


	(_create());

	function _create() {
		var sl = calendar.options.sharedList;
		container.append(
				'<div class="empty-list">' +
					'<span class="add-icon"/>' +
					'<span class="link">' + htmlEscape(linkText) + '</span>' +
				'</div>' +
				'<div class="users-list">' +
					'<div class="label">' + htmlEscape(sl.title) + '</div>' +
					'<div class="short-list"/>' +
					'<div class="more-users">' +
						'<span class="link">' + htmlEscape(sl.moreLink) + '</span>' +
					'</div>' +
					'<div class="add-users">' +
						'<span class="add-icon"/>' +
						'<span class="link">' + htmlEscape(sl.addLink) + '</span>' +
					'</div>' +
				'</div>');
		_userList = container.find(".users-list .short-list");
		_moreLink = container.find(".more-users .link");
		_moreText = sl.moreLink;
		_shortListLen = sl.shortListLength > 0 ? sl.shortListLength : 5;
		container
				.find(".empty-list .link, .add-users .link, .add-users .add-icon")
				.click(_changePermissions);
	}

	function _changePermissions() {
		calendar.trigger("editPermissions", _this,
				{
					type:       _type,
					objectId:   _objectId,
					permissions: _permissions
				},
				_updatePermissions);
	}

	function _deletePermission() {
		var i = $(this).parent().index();
		calendar.trigger("removePermissions", _this,
				{
					type:        _type,
					objectId:    _objectId,
					userId:      _permissions.users[i].objectId,
					permissions: _permissions
				},
				_updatePermissions);
	}

	function _updatePermissions(response) {
		if (response.result) {
			_trigger.call(_this, "onChange", response);
		}
	}


	function _renderUser(user) {
		var item =
					'<span class="user">' +
						'<span class="icon">&nbsp;</span>' +
						'<span class="name">' + htmlEscape(user.name) + '</span>' +
						'<span class="remove-btn">&nbsp;</span>' +
					'</span> ';
		return item;
	}

	this.render = function(permissions, type, objectId) {
		_permissions = permissions;
		_type = type;
		_objectId = objectId;

		container.empty();
		_create();

		container.removeClass("has-users more-users");
		_userList.find(".user").remove();
		_moreLink.unbind("click");

		if (permissions && permissions.users && permissions.users.length > 0) {
			container.show();
			container.addClass("has-users");
			var list = "";
			var otherList = "";
			for (var i = 0; i < permissions.users.length; ++i) {
				var item = _renderUser.call(_this, permissions.users[i]);
				if (i < _shortListLen) {
					list += item;
				} else {
					otherList += item;
				}
			}
			_userList.append(list);
			_userList.find(".user .remove-btn").click(_deletePermission);
			var moreCount = permissions.users.length - _shortListLen;
			if (moreCount > 0) {
				container.addClass("more-users");
				_moreLink
						.text(_moreText.replace("%d", moreCount))
						.click(
								function(ev) {
									$(this).unbind("click");
									container.removeClass("more-users");
									_userList.append(otherList);
									_userList.find(".user .remove-btn").click(_deletePermission);
									_trigger.call(_this, "onResize");
								});
			}
		}
	};

}


function CategoryDialog(calendar) {
	var _this = this;

	// Trigger dialog's events:
	//   onClose(elem, source, changed)
	//   onDelete(source)

	// Trigger calendar's events:
	//   editPermissions(param)
	//   removePermissions(param)

	var _handlers = {};

	function _trigger(eventName) {
		if (_handlers && $.isFunction(_handlers[eventName])) {
			_handlers[eventName].apply(
					_handlers.context != undefined ? _handlers.context : window,
					Array.prototype.slice.call(arguments, 1));
		}
	}

	this.setEventsHandlers = function(handlers) {
		if (handlers != undefined) {
			$.extend(_handlers, handlers);
		}
	};

	var _dialog;
	
	var _icalStream;
	var ic = calendar.options.icalStream;
	
	var _permissionsList;

	var _anchor;
	var _elem;
	var _source;
	var _permissions;

	var kCreateMode    = 1;
	var kEditMode      = 2;
	var kCreateUrlMode = 3;
	var kEditUrlMode = 4;
	var kCreateUrlWithoutSyncMode = 5;
    var kEditModeFile = 6;

    var configuration = {
        isSyncWithCalendar: 0,
        isNewCalendar: 0,
        isExportLink: 0,
        isExportFile: 0
    };

	var currentMode;

	var kTitle        = 1;
	var kColorBox     = 11;
	var kTextColorBox = 12;
	
	(function _create() {
		_dialog = $(calendar.options.categories.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("fc-shadow")
				.popupFrame({
					anchor: "left,bottom",
					direction: "right,down",
					showArrow: false,
					showModal: true,
					beforeClose: function() {_close.call(_this, false);return false;}
				});
	    _updateConfiguration();
		_dialog.find(".ical-export .ical-link").click(function() {
			_openIcalStream.call(_this, {pageX: "center", pageY: "center"});
		});
		_dialog.find(".export .export-link").click(function () {
            _openExportStream.call(_this, { pageX: "center", pageY: "center" });
		    _dialog.popupFrame('hide');
		});
       
	
		_dialog.find(".buttons .save-btn").click(function() {
		    if (jq(this).hasClass("disable"))
		        return;
		    
		    _close.call(_this, true);
		});
		_dialog.find(".buttons .cancel-btn, .header .close-btn").click(function() {
			_close.call(_this, false);
		});
		_dialog.find(".buttons .delete-btn").click(function() {
			_trigger.call(_this, "onDelete", _source);
			_close.call(_this, false, true);
		});
		//
        _getControl(kTitle).keyup(function (val) {
            fcUtil.validateInput(this, fcUtil.validateNonemptyString);
            var str = jq(this).val();
            if (str.search(ASC.CalendarController.characterRegExp) != -1) {
                jq(this).val(ASC.CalendarController.ReplaceSpecCharacter(str));
                ASC.CalendarController.displayInfoPanel(calendar.options.categories.dialogErrorMassageSpecCharacter.format(ASC.CalendarController.characterString), true);
            }
        });
		_dialog.find(".ical-url-input input").keyup(function() {
			fcUtil.validateInputHttp(this, fcUtil.validateNonemptyString);
		});
		
		_getControl(kColorBox).click(function() {fcColorPicker.open(this, _setColor, fcColors.DefaultPicker);});
		_getControl(kTextColorBox).click(function() {fcColorPicker.open(this, _setTextColor,fcColors.TextPicker);});
		//
		_permissionsList = new PermissionsList(calendar, _dialog.find(".shared-list"),
				calendar.options.sharedList.addLink);
		_permissionsList.setEventsHandlers({
					context:   _this,
					onResize: function() {_dialog.popupFrame("updatePosition", _anchor);},
					onChange: _updatePermissions
				});
		
	}());
	
	(function _createIcal() {
		_icalStream = $(ic.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("add-popup")
				.popupFrame({
					anchor: "right,top",
					direction: "right,down",
					offset: "0,0",
					showArrow: false
				});
		
		_icalStream.find(".buttons .cancel-btn, .header .close-btn").click(function () {
			_closeIcalStream.call(_this, false);
		});
        _icalStream.find((".url-link .control input")).click(function () {
            $(this).select();
        });
        _icalStream.find((".url-link .control .button.copy")).click(function () {
            var control = $($(this)[0].parentNode);
            if (!control.hasClass('disabled')) {
                control.find('input').select();
                try {
                    document.execCommand('copy');
                    ASC.CalendarController.displayInfoPanel(calendar.options.categories.dialogCopyMessage, false);
                } catch (err) { }
            }
        });
        _icalStream.find((".url-link .control .button.try-again")).click(function () {
            getCaldavLink();
        });
	}());

	function _getControl(controlId) {
		switch (controlId) {
			case kTitle:return _dialog.find(".title input");
			case kColorBox:return _dialog.find(".color .inner");
			case kTextColorBox:return _dialog.find(".color .inner-for-text");
		}
		return undefined;
	}

	function _setIconColor(newColor, icon) {
		var c = fcUtil.parseCssColor(newColor);
		var bc = ((Math.round(c.r * 0.9) << 16) | (Math.round(c.g * 0.9) << 8) | Math.round(c.b * 0.9)).toString(16);
		while (bc.length < 6) {bc = "0" + bc;}
		icon.css("background-color", newColor).css("border-color", "#" + bc);
		icon.parent().css("border-color", "#" + bc);
	}

	function _setColor(newColor) {
	    _setIconColor(newColor, _getControl(kColorBox));
		_dialog.find(".title .bullet").css("background", newColor);
	}

	function _setTextColor(newColor) {
		_setIconColor(newColor, _getControl(kTextColorBox));
	}

	function _setMode(mode, isImport) {
		
		currentMode = mode;
		
		switch (mode) {
			case kCreateMode:
			case kCreateUrlMode:
				_dialog.removeClass("edit-mode"); break;
			
			case kEditMode:
				_dialog.addClass("edit-mode"); break;
		}
		if (isImport) {
		    _dialog.addClass("import");
		} else {
		    _dialog.removeClass("import");
		}
	}


	function _updatePermissions(response) {
		if (response.result) {
			_permissions = response.permissions;
			if (response.isShared != undefined) {
				_source.isShared = response.isShared;
			}
			_permissionsList.render(_permissions, kCalendarPermissions, _source.objectId);
			_dialog.popupFrame("updatePosition", _anchor);
		}
	}

	function _updateConfiguration() {
	    var configurationCode = '';
	  
	    _dialog.find(".choose_event_source").removeClass("hidden");
	    _dialog.find(".calendar").removeClass("hidden");
	    
	    for (key in configuration) {
	        configurationCode += configuration[key];
	    }
	    switch (configurationCode) {
	        case "1110":
	            _dialog.find(".title").removeClass("hidden");
	            _dialog.find(".color").removeClass("hidden");
	            _dialog.find(".shared-list").addClass("hidden"); 
	            _dialog.find(".row").addClass("hidden");
	            _dialog.find(".ical").addClass("hidden");
	            _dialog.find(".sync-with-calendar").removeClass("hidden");
	            _dialog.find(".ical-url-input").removeClass("hidden");
	            
	            _dialog.find(".calendar select").val(-1);
	            _dialog.find(".calendar select").prop('disabled', true);
	            _dialog.find(".calendar .bullet").css("color", "transparent");
	            
	            _setMode.call(_this, kCreateUrlMode, true);
	            break;
	        case "0110":
	            _dialog.find(".title").removeClass("hidden");
	            _dialog.find(".color").removeClass("hidden");
	            _dialog.find(".shared-list").removeClass("hidden");
	            _dialog.find(".row").removeClass("hidden");
	            _dialog.find(".sync-with-calendar").removeClass("hidden");
	            _dialog.find(".ical-url-input").removeClass("hidden");
	            _dialog.find(".ical").addClass("hidden");
	            
	            _dialog.find(".calendar select").prop('disabled', false);
	            
	            _setMode.call(_this, kCreateUrlWithoutSyncMode, true);
	            break;
	        case "0010":
	            _dialog.find(".title").addClass("hidden");
	            _dialog.find(".color").addClass("hidden");
	            _dialog.find(".shared-list").addClass("hidden");
	            _dialog.find(".row").addClass("hidden");
	            _dialog.find(".ical").addClass("hidden");
	            _dialog.find(".sync-with-calendar").removeClass("hidden");
	            _dialog.find(".ical-url-input").removeClass("hidden");
	            
	            _dialog.find(".calendar select").prop('disabled', false);

	            _setMode.call(_this, kEditUrlMode, true);
	            break;
	        case "0101":
	            _dialog.find(".title").removeClass("hidden");
	            _dialog.find(".color").removeClass("hidden");
	            _dialog.find(".shared-list").removeClass("hidden");
	            _dialog.find(".row").removeClass("hidden");
	            _dialog.find(".sync-with-calendar").addClass("hidden");
	            _dialog.find(".ical-url-input").addClass("hidden");
	            _dialog.find(".ical").removeClass("hidden");
	            
	            _dialog.find(".calendar select").prop('disabled', false);

	            _setMode.call(_this, kCreateMode, true);
	            break;
	        case "0001":
	            _dialog.find(".title").addClass("hidden");
	            _dialog.find(".color").addClass("hidden");
	            _dialog.find(".shared-list").addClass("hidden");
	            _dialog.find(".row").addClass("hidden");
	            _dialog.find(".sync-with-calendar").addClass("hidden");
	            _dialog.find(".ical-url-input").addClass("hidden");
	            _dialog.find(".ical").removeClass("hidden");
	            
	            _dialog.find(".calendar select").prop('disabled', false);

	            _setMode.call(_this, kEditModeFile, true);
	            break;
	        case "0000":
	            _dialog.find(".title").removeClass("hidden");
	            _dialog.find(".color").removeClass("hidden");
	            _dialog.find(".shared-list").removeClass("hidden");
	            _dialog.find(".row").removeClass("hidden");
	            _dialog.find(".choose_event_source").addClass("hidden");
	            _dialog.find(".ical").addClass("hidden");
	            _dialog.find(".calendar").addClass("hidden");
	            _dialog.find(".sync-with-calendar").addClass("hidden");
	            break;
	        default:
	           
	    }
    }

	function _open(anchor) {
		$(document).bind("keyup", _checkEscKey);
		_dialog.popupFrame("open", anchor);
	    
		_dialog.find('#ical-browse-btn').show();
		_dialog.find(".ical-file-selected").hide();
		_dialog.find(".ical-file-del").hide();
	    
		_dialog.find(".ical-url-input input").val("");

		_dialog.find(".choose_event_source span").removeClass('active');
		_dialog.find("#events_link").addClass('active');
		_dialog.find(".buttons .save-btn").removeClass("disable");

		_dialog.find(".sync-with-calendar input").prop('checked', false);

		_dialog.find(".sync-with-calendar input").click(function() {
		    configuration.isSyncWithCalendar = +(_dialog.find(".sync-with-calendar input").is(":checked"));
		    configuration.isNewCalendar = 1;
		    
		    _updateConfiguration();
		});
		_dialog.find(".choose_event_source span").click(function () {
		    $(".choose_event_source span").removeClass('active');
		    $(this).addClass('active');
		    if ($(this)[0].id == "events_link") {
		        _setMode.call(_this, kCreateUrlMode);
		        configuration.isExportLink = 1;
		        configuration.isExportFile = 0;
		        _dialog.find(".buttons .save-btn").removeClass("disable");
		    } else {
		        _setMode.call(_this, kEditModeFile);
		        configuration.isExportLink = 0;
		        configuration.isExportFile = 1;
		        configuration.isSyncWithCalendar = 0;
                
		        if (!AjaxUploader.isChanged) _dialog.find(".buttons .save-btn").addClass("disable");
		        
		        _dialog.find(".sync-with-calendar input").prop('checked', false);
		    };
		    _updateConfiguration();
		});
	    
		_dialog.find(".calendar select").change(function (ev) {
		    var v = $(this).val();
		    var s = calendar.getEventSources();
		   
		    for (var i = 0; i < s.length; ++i) {
		        if (s[i].objectId != v) {
		            if (v == -1) {
		                _dialog.find(".calendar .bullet").css("background", "transparent");
		                _dialog.find(".title input").focus();
		                
		                configuration.isNewCalendar = 1;
		                var opt = calendar.options;
		                var categories = opt.categories;
		                var newColor = fcUtil.parseCssColor(fcUtil.randomHex(true));
		                var newBg = fcUtil.parseCssColor(fcUtil.randomHex(false));
		                var newBor = fcUtil.changeColorLightness(newBg.r, newBg.g, newBg.b, opt.eventBg2BorderRatio);

		                _elem = undefined;
		                _source = {
		                    title: categories.defaultTitle,
		                    textColor: newColor.origColor,
		                    backgroundColor: newBg.origColor,
		                    borderColor: newBor.color,
		                    isHidden: false,
		                    events: [],
		                    todos: [],
		                    permissions: { users: [] },
		                    defaultAlert: { type: 0 },
		                    timeZone: $.extend({}, opt.defaultTimeZone)
		                };
		                _anchor = anchor;
		            };
		            _updateConfiguration();
		            continue;
		        }
		        configuration.isNewCalendar = 0;
		        _source = calendar.getEventSources()[i];
                _elem = s[1].isTodo === 0 ? $('.categories .content-li')[(i - 1)] : $('.categories .content-li')[(i - 2)];
		        _updateConfiguration();
		        _dialog.find(".calendar .bullet").css("background", s[i].backgroundColor);
                return;
		    }
		});
		// check length
		var titleMaxLen = defaults.eventMaxTitleLength;
		var inputTxt = _dialog.find(".title input");
		if (inputTxt.length > 0)
		{
			inputTxt.keyup(function(){
				if (inputTxt.val().length > titleMaxLen){
					inputTxt.val(inputTxt.val().substr(0, titleMaxLen));
				}
			});
		}
		//

	    inputTxt.focus().select();

		// upload ajax
		AjaxUploader = new AjaxUpload('#ical-browse-btn', {
			action: 'upload.php',
			autoSubmit: false,
			//responseType: "xml",
			onChange: function(file, extension) {
				
				if ( !(extension && ( /^(ics)$/.test(extension) || /^(txt)$/.test(extension) )) ){
					_dialog.find(".ical-file-selected").html(ic.dialog_incorrectFormat).css("color", "#cc3300");
					return;
				} 
				this.isChanged = true;
			    _dialog.find(".buttons .save-btn").removeClass("disable");
				_dialog.find('#ical-browse-btn').hide();
			    _dialog.find(".ical-file-del").show();
				_dialog.find(".ical-file-selected").show().html(file).css("color", "grey");
			},
			onSubmit: function (file, extension) {
				LoadingBanner.displayLoading(); 
			},
			onComplete: function (file, response) {
				LoadingBanner.hideLoading(true);
				calendar.refetchEvents();
			}
		});

	    _dialog.find(".ical-file-del").click(function() {
	        AjaxUploader.isChanged = false;
	        _dialog.find(".buttons .save-btn").addClass("disable");
	        _dialog.find('#ical-browse-btn').show();
	        _dialog.find(".ical-file-del").hide();
	        _dialog.find(".ical-file-selected").hide().html('');
	    });
	}
	
	function _openIcalStream(anchor) {
		$(document).bind("keyup", _checkEscKeyIcalStream);
		
		calendar.trigger("getiCalUrl", _this, _source.objectId, function(response){
			if (response.result) {
				var link = "<a href=" + response.url + " target='_blank'>" + response.url + "</a>";
				_icalStream.find(".saved-url-link").html(link);
			}
		});
		
		_icalStream.width(_dialog.width() + 160);
		_icalStream.popupFrame("open", anchor);
	}

    var timerId;
    function getCaldavLink() {
        clearInterval(timerId);
        var linkContainer = _icalStream.find(".url-link.caldav");
        var helpLink = _icalStream.find(".caldav-help");

        linkContainer.find(".control").removeClass('success').removeClass('failure').addClass('disabled').addClass('processing');
        linkContainer.find(".control input").attr('disabled', 'disabled');

        linkContainer.show();
        helpLink.show();

        var counter = 0, preparingMessage = ic.dialogPreparingMessage, preparingErrorMessage = ic.dialogPreparingErrorMessage;
        timerId = setInterval(function () {
            preparingMessage = preparingMessage + ".";
            if (counter == 4) {
                preparingMessage = ic.dialogPreparingMessage;
                counter = 0;
            }
            linkContainer.find(".control input").val(preparingMessage);
            counter++;
        }, 500);

        calendar.trigger("getCaldavUrl", _this, _source.objectId, function (response) {
            clearInterval(timerId);
            if (response.result) {
                if (response.url != "") {
                    linkContainer.find(".control input").val(response.url);
                    linkContainer.find(".control input").removeAttr("disabled");
                    linkContainer.find(".control").removeClass("disabled").removeClass('processing').addClass('success');
                } else {
                    linkContainer.find(".control input").val(preparingErrorMessage);
                    linkContainer.find(".control").removeClass('processing').addClass('failure');
                }
            }
        });
    }

    function _openExportStream(anchor) {
        $(document).bind("keyup", _checkEscKeyIcalStream);
        
        calendar.trigger("getiCalUrl", _this, _source.objectId, function (response) {
            if (response.result) {
                var linkContainer = _icalStream.find(".url-link.ical");
                linkContainer.show();
                linkContainer.find(".control input").val(response.url);
                getCaldavLink();
            }
        });
        
        _icalStream.width(_dialog.width());
        _icalStream.popupFrame("open", anchor);
    }

    function _close(changed, deleted) {
		fcColorPicker.close();
		if (changed && false == _doDDX.call(_this, true)) {return;}
		$(document).unbind("keyup", _checkEscKey);
		_dialog.popupFrame("close");
		_icalStream.popupFrame("close");


		var elem = _elem;
		var source = _source;
		if (configuration.isNewCalendar == 1 && configuration.isExportLink == 1 && configuration.isSyncWithCalendar == 1) {
			var opt = calendar.options;
			var categories = opt.categories;
			var newColor = fcUtil.parseCssColor(fcUtil.randomHex(true));
			var newBg = fcUtil.parseCssColor(fcUtil.randomHex(false));
			var newBor = fcUtil.changeColorLightness(newBg.r, newBg.g, newBg.b, opt.eventBg2BorderRatio);

			elem = undefined;
			source = {
				title: _source.title,
				textColor: _source.textColor,
				backgroundColor: _source.backgroundColor,
				borderColor: _source.borderColor,
				isHidden: false,
				events: [],
				todos: [],
				permissions: { users: [] },
				defaultAlert: { type: 0 },
				timeZone: $.extend({}, opt.defaultTimeZone),
				iCalUrl: _source.iCalUrl
			};
		}

        _trigger.call(
            _this,
            "onClose",
            elem,
            source,
            changed,
            deleted);
	}
	
	function _closeIcalStream() {
	    $(document).unbind("keyup", _checkEscKeyIcalStream);
	    _icalStream.popupFrame("close");
	    if (_dialog.popupFrame('isVisible')) _dialog.popupFrame('show');
	}

	function _checkEscKey(ev) {
		if (ev.which == 27) {
			_close.call(_this, false);
		}
	}
	
	function _checkEscKeyIcalStream(ev) {
		if (ev.which == 27) {
			_closeIcalStream.call(_this);
		}
	}

	function _doDDX(saveData) {
		var opt = calendar.options,
				dlg = {
					title:     _getControl(kTitle),
					bgColor:   _getControl(kColorBox),
					textColor: _getControl(kTextColorBox),
					alert:     _dialog.find(".alert select"),
					timezone:  _dialog.find(".timezone select"),
					iCalUrl:  _dialog.find(".ical-url-input input"),
					calendar: _dialog.find(".calendar select"),
					calendar_b: _dialog.find(".calendar .bullet")
				},
				i;

		if (saveData) {     // ------------- SAVE data -------------
		   
		    if (currentMode == kEditModeFile) { return true; }
		    
		    if (false == fcUtil.validateInput(dlg.title, fcUtil.validateNonemptyString)) { return false; }
		    
		    if (currentMode == kCreateUrlMode || currentMode == kEditUrlMode || currentMode == kCreateUrlWithoutSyncMode) {
				if (false == fcUtil.validateInputHttp(dlg.iCalUrl, fcUtil.validateNonemptyString)) {return false;}
		    }
		    
		    // iCal url
		    if (currentMode == kCreateUrlMode || currentMode == kEditUrlMode || currentMode == kCreateUrlWithoutSyncMode) {
		        _source.iCalUrl = dlg.iCalUrl.val();
		    }
		    
		    if (currentMode == kCreateUrlWithoutSyncMode) {
		        _source.withoutSync = true;
		    }
		    if (currentMode == kEditUrlMode) { return true; }
		    
			_source.title = $.trim(dlg.title.val());
			_source.title = _source.title.substr(0, Math.min(
					calendar.options.eventMaxTitleLength, _source.title.length));

			var newBg = fcUtil.parseCssColor(dlg.bgColor.css("background-color"));
			var newBor;
			if (newBg) {
				newBor = fcUtil.changeColorLightness(newBg.r, newBg.g, newBg.b, calendar.options.eventBg2BorderRatio);
				_source.backgroundColor = newBg.origColor;
				_source.borderColor = newBor.color;
			}
			_source.textColor = dlg.textColor.css("background-color");

			_source.defaultAlert.type = parseInt(dlg.alert.val(), 10);

			//if (_source.canEditTimeZone) 
			{
				_source.timeZone.id = dlg.timezone.val();
				for (i = 0; i < opt.timeZones.length; ++i) {
					if (opt.timeZones[i].id == _source.timeZone.id) {
						_source.timeZone.name = opt.timeZones[i].name;
						_source.timeZone.delta = opt.timeZones[i].offset - _source.timeZone.offset;
						_source.timeZone.offset = opt.timeZones[i].offset;
						break;
					}
				}
			}

			_source.permissions = _permissions;
			
		} else {            // ------------- LOAD data -------------

			dlg.title.val(_source.title);
			dlg.title.css("color", "").css("border-color", "");

			// to round all float numbers to 2nd digit after point
			var rgb = fcUtil.parseCssColor(_source.backgroundColor);
			_setColor.call(_this, rgb.origColor);
			rgb = fcUtil.parseCssColor(_source.textColor);
			_setTextColor.call(_this, rgb.origColor);

			dlg.alert.val(_source.defaultAlert.type);

			//if (_source.canEditTimeZone) 
			{
				var options = '';
				var tz, tzT;
				for (i = 0; i < opt.timeZones.length; ++i) {
					tz = opt.timeZones[i];
					tzT = htmlEscape(tz.name);
					options += '<option value="' + htmlEscape(tz.id) + '" ' +
									'title="' + tzT + '">' + tzT + '</option>';
				}
				dlg.timezone.html(options);
				dlg.timezone.val(_source.timeZone.id);
				_dialog.find(".timezone").removeClass("hidden");
			} /*else {
				_dialog.find(".timezone").addClass("hidden");
			}*/

			_permissions = _source.permissions;
			_permissionsList.render(_permissions, kCalendarPermissions, _source.objectId);

			var options = '<option value="-1" title="' + htmlEscape(calendar.options.newLabel) + '" >&nbsp;&nbsp;&nbsp;&nbsp;' + htmlEscape(calendar.options.newLabel) + '</option><option disabled="disabled"></option>';
			var calT;
			var sources = calendar.getEventSources();
			for (i = 0; i < sources.length; ++i) {
			    if ((sources[i].objectId != undefined) &&
						(sources[i].isEditable || !sources[i].isSubscription) && sources[i].isTodo != 1) {
			        calT = htmlEscape(sources[i].title);
			        options += '<option value="' + htmlEscape(sources[i].objectId) + '" ' +
							'title="' + calT + '">' +
							'&nbsp;&nbsp;&nbsp;&nbsp;' +  // for select elem padding does not work in safari
							calT + '</option>';
			    }
			}
			dlg.calendar.removeAttr("disabled");
			
			dlg.calendar.html(options);
			dlg.calendar_b.css("background", "transparent");

			var calCount = 0;
			$.each(calendar.getEventSources(), function(i,src) {
			    if (src.objectId != undefined && !src.isSubscription && src.isTodo != 1) {++calCount;}
			});

			if (calCount > 1 && !jq("#asc_event .event-editor .editor").is(":visible")) {
				_dialog.find(".buttons").removeClass("read-only");
			} else {
				_dialog.find(".buttons").addClass("read-only");
			}
		}
		return true;
	}
	function _getDefaultSource() {
	    var sources = calendar.getEventSources();
	    var s1;
	    for (var i = 0; i < sources.length; ++i) {
	        if (fcUtil.objectIsValid(sources[i]) && (
			    fcUtil.objectIsEditable(sources[i]) || !sources[i].isSubscription)) {
	            if (s1 == undefined) { s1 = sources[i]; }
	            if (!sources[i].isHidden) { return sources[i]; }
	        }
	    }
	    return s1;
	}


	this.edit = function(elem, anchor) {
		configuration.isExportFile = 0;
		configuration.isExportLink = 0;
		configuration.isNewCalendar = 0;
		configuration.isSyncWithCalendar = 0;
		_updateConfiguration();

		if (elem != _elem) {
			_close.call(_this, false);
			_elem = elem;
			_source = calendar.getEventSources()[$(_elem).data("sourceIndex")];
		}
		_anchor = anchor;
		_doDDX.call(_this);
		_setMode.call(_this, kEditMode);
		
		_dialog.find(".choose_event_source").addClass("hidden");
		_dialog.find(".sync-with-calendar").addClass("hidden");
		_dialog.find(".calendar").addClass("hidden");

		_dialog.find(".ical").addClass("hidden");
		_dialog.find(".export").removeClass("hidden");
		_dialog.find(".ical-import").removeClass("hidden");
		
		_dialog.find(".title").removeClass("hidden");
		_dialog.find(".row").removeClass("hidden");
		_dialog.find(".shared-list").removeClass("hidden");
		_dialog.find(".export").removeClass("hidden");
		_dialog.find(".ical-url-input").addClass("hidden");
		
		_open.call(_this, anchor);
	};

	this.addNew = function (anchor) {

	    configuration.isExportFile = 0;
	    configuration.isExportLink = 0;
	    configuration.isNewCalendar = 0;
	    configuration.isSyncWithCalendar = 0;
	    _updateConfiguration();

		var opt = calendar.options;
		var categories = opt.categories;
		var newColor = fcUtil.parseCssColor(fcUtil.randomHex(true));
		var newBg = fcUtil.parseCssColor(fcUtil.randomHex(false));
		var newBor = fcUtil.changeColorLightness(newBg.r, newBg.g, newBg.b, opt.eventBg2BorderRatio);

		_elem = undefined;
		_source = {
			title: categories.defaultTitle,
			textColor: newColor.origColor,
			backgroundColor: newBg.origColor,
			borderColor: newBor.color,
			isHidden: false,
			events: [],
			todos: [],
			permissions: {users:[]},
			defaultAlert: {type:0},
			timeZone: $.extend( {}, opt.defaultTimeZone )
		};
		_anchor = anchor;
		_doDDX.call(_this);
		_setMode.call(_this, kCreateMode);
		
		_dialog.find(".export").addClass("hidden");

		/*_dialog.find(".choose_event_source").addClass("hidden");
		_dialog.find(".ical").addClass("hidden");
		_dialog.find(".calendar").addClass("hidden");
		_dialog.find(".sync-with-calendar").addClass("hidden");*/

		//_dialog.find(".ical-import").removeClass("hidden");
		
		_dialog.find(".row").removeClass("hidden");
		_dialog.find(".shared-list").removeClass("hidden");
		_dialog.find(".ical-url-input").addClass("hidden");
		
		_open.call(_this, anchor);
	};
	
	this.addiCalCalendar = function (anchor) {

	    configuration.isExportLink = 1;
	    configuration.isExportFile = 0;
	    configuration.isNewCalendar = 1;
	    configuration.isSyncWithCalendar = 0;
	    _updateConfiguration();

		var opt = calendar.options;
		var categories = opt.categories;
		var newColor = fcUtil.parseCssColor(fcUtil.randomHex(true));
		var newBg = fcUtil.parseCssColor(fcUtil.randomHex(false));
		var newBor = fcUtil.changeColorLightness(newBg.r, newBg.g, newBg.b, opt.eventBg2BorderRatio);

		_elem = undefined;
		_source = {
			title: categories.defaultTitle,
			textColor: newColor.origColor,
			backgroundColor: newBg.origColor,
			borderColor: newBor.color,
			isHidden: false,
			events: [],
			todos: [],
			permissions: {users:[]},
			defaultAlert: {type:0},
			timeZone: $.extend( {}, opt.defaultTimeZone )
		};
		_anchor = anchor;
		if (configuration.isSyncWithCalendar == 0) {
		    _setMode.call(_this, kCreateUrlWithoutSyncMode, true);
		} else {
		    _setMode.call(_this, kCreateUrlMode, true);
		}

		_doDDX.call(_this);
		
		_dialog.find(".export").addClass("hidden");
		
		_open.call(_this, anchor);
	};

	this.close = function(changed) {
		_close.call(_this, changed);
	};

}


function SubscriptionDialog(calendar) {
	var _this = this;

	// Trigger dialog's events:
	//   onClose(elem, source, changed)
	//   onUnsubscribe(source)

	var _handlers = {};

	function _trigger(eventName) {
		if (_handlers && $.isFunction(_handlers[eventName])) {
			_handlers[eventName].apply(
					_handlers.context != undefined ? _handlers.context : window,
					Array.prototype.slice.call(arguments, 1));
		}
	}

	this.setEventsHandlers = function(handlers) {
		if (handlers != undefined) {
			$.extend(_handlers, handlers);
		}
	};


	var _dialog;
	var _permissionsList;
	
	var _icalStream;
	var ic = calendar.options.icalStream;

	var _elem;
	var _source;
	var _anchor;
	var _permissions;

	var kTitle        = 1;
	var kColorBox     = 11;
	var kTextColorBox = 12;

	(function _create() {
		_dialog = $(calendar.options.categories.subscriptionsDialog)
				.addClass("asc-dialog")
				.addClass("fc-shadow")
				.popupFrame({
					anchor: "left,bottom",
					direction: "right,down",
					showArrow: false,
					showModal: true,
					beforeClose: function() {_close.call(_this, false);return false;}
				});
		
		_dialog.find(".ical-export .ical-link").click(function() {
		    _openIcalStream.call(_this, { pageX: "center", pageY: "center" });
		    _dialog.popupFrame('hide');
		});
				
		_dialog.find(".buttons .save-btn").click(function() {
		    if (jq(this).hasClass("disable"))
		        return;
		    
		    _close.call(_this, true);
		});
		_dialog.find(".buttons .cancel-btn, .header .close-btn").click(function() {
			_close.call(_this, false);
		});
		_dialog.find(".buttons .unsubs-btn").click(function() {
			_trigger.call(_this, "onUnsubscribe", _source);
			_close.call(_this, false);
		});
		_dialog.find(".buttons .delete-btn").click(function() {
			_trigger.call(_this, "onDelete", _source);
			_close.call(_this, false, true);
		});
		//
		_getControl(kTitle).keyup(function() {fcUtil.validateInput(this, fcUtil.validateNonemptyString);});
		_getControl(kColorBox).click(function() {fcColorPicker.open(this, _setColor,fcColors.DefaultPicker);});
		_getControl(kTextColorBox).click(function() {fcColorPicker.open(this, _setTextColor,fcColors.TextPicker);});
		//
		_permissionsList = new PermissionsList(calendar, _dialog.find(".shared-list"),
				calendar.options.sharedList.addLink);
		_permissionsList.setEventsHandlers({
					context:   _this,
					onResize: function() {_dialog.popupFrame("updatePosition", _anchor);},
					onChange: _updatePermissions
				});
	}());
	
	(function _createIcal() {
		_icalStream = $(ic.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("add-popup")
				.popupFrame({
					anchor: "right,top",
					direction: "right,down",
					offset: "0,0",
					showArrow: false
				});
		
		_icalStream.find(".buttons .cancel-btn, .header .close-btn").click(function () {
		    _closeIcalStream.call(_this, false);
		    _icalStream.popupFrame("close");
		    if (_dialog.popupFrame('isVisible')) _dialog.popupFrame('show');
		});
	    

		_icalStream.find((".url-link .control input")).click(function () {
		    $(this).select();
		});
		_icalStream.find((".url-link .control .button.copy")).click(function () {
		    var control = $($(this)[0].parentNode);
		    control.find('input').select();
		    try {
		        document.execCommand('copy');
                ASC.CalendarController.displayInfoPanel(calendar.options.categories.dialogCopyMessage, false);
		    } catch (err) { }
		});
		
	}());

	function _getControl(controlId) {
		switch (controlId) {
			case kTitle:return _dialog.find(".title input");
			case kColorBox:return _dialog.find(".color .inner");
			case kTextColorBox:return _dialog.find(".color .inner-for-text");
		}
		return undefined;
	}

	function _setIconColor(newColor, icon) {
		var c = fcUtil.parseCssColor(newColor);
		var bc = ((Math.round(c.r * 0.9) << 16) | (Math.round(c.g * 0.9) << 8) | Math.round(c.b * 0.9)).toString(16);
		while (bc.length < 6) {bc = "0" + bc;}
		icon.css("background-color", newColor).css("border-color", "#" + bc);
		icon.parent().css("border-color", "#" + bc);
	}

	function _setColor(newColor) {
	    _setIconColor(newColor, _getControl(kColorBox));
		_dialog.find(".title .bullet").css("background", newColor);
	}

	function _setTextColor(newColor) {
		_setIconColor(newColor, _getControl(kTextColorBox));
	}


	function _updatePermissions(response) {
		if (response.result) {
			_permissions = response.permissions;
			if (response.isShared != undefined) {
				_source.isShared = response.isShared;
			}
			_permissionsList.render(_permissions, kCalendarPermissions, _source.objectId);
			_dialog.popupFrame("updatePosition", _anchor);
		}
	}


	function _open(anchor) {
		$(document).bind("keyup", _checkEscKey);
		
		// check length
		var titleMaxLen = defaults.eventMaxTitleLength;
		var inputTxt = _dialog.find(".title input");
		if (inputTxt.length > 0)
		{
			inputTxt.keyup(function(){
				if (inputTxt.val().length > titleMaxLen){
					inputTxt.val(inputTxt.val().substr(0, titleMaxLen));
				}
			});
		}
		//
		
		if (_source.isiCalStream) {
			_dialog.find(".ical").addClass("hidden");
			_dialog.find(".buttons").find(".delete-btn").removeClass("hidden");
			
			if ((_source.iCalUrl != undefined) && (_source.iCalUrl != "")) {
				_dialog.find(".ical-saved-url").removeClass("hidden");
				
				var link = "<a href=" + _source.iCalUrl + " target='_blank'>" + _source.iCalUrl + "</a>";
				_dialog.find(".saved-url-link").html(link);
			}
		}
		else {
			_dialog.find(".ical").removeClass("hidden");
			_dialog.find(".export").removeClass("hidden");
			
			_dialog.find(".ical-saved-url").addClass("hidden");
			_dialog.find(".buttons").find(".delete-btn").addClass("hidden");
			_dialog.find(".saved-url-link").html("");
		}
		
		if (_source.isEditable && !_source.isSubscription) {
			_dialog.find(".ical-import").removeClass("hidden");
		}
		else {
			_dialog.find(".ical-import").addClass("hidden");
		}
		_dialog.popupFrame("open", anchor);
		
		_dialog.find(".ical-file-selected").html(ic.dialogButton_fileNotSelected);
		
		// upload ajax
		AjaxUploader = new AjaxUpload('#ical-browse-btn-subs', {
			action: 'upload.php',
			autoSubmit: false,
			//responseType: "xml",
			onChange: function(file, extension) {
				
				if ( !(extension && ( /^(ics)$/.test(extension) || /^(txt)$/.test(extension) )) ){
					_dialog.find(".ical-file-selected").html(ic.dialog_incorrectFormat).css("color", "#cc3300");
					return;
				}
				
				this.isChanged = true; 
				_dialog.find(".ical-file-selected").html(ic.dialogButton_fileSelected).css("color", "grey");
				},
			onSubmit: function(file, extension) {
				LoadingBanner.displayLoading(); 
				},
			onComplete: function(file, response) { 
				LoadingBanner.hideLoading();
				calendar.refetchEvents();
				}
			});
	}
	var timerId;
	function getCaldavLink() {
	    clearInterval(timerId);
	    var linkContainer = _icalStream.find(".url-link.caldav");
	    linkContainer.find(".control").removeClass('success').removeClass('failure').addClass('disabled').addClass('processing');
	    linkContainer.find(".control input").attr('disabled', 'disabled');

	    linkContainer.show();

	    var counter = 0, preparingMessage = ic.dialogPreparingMessage, preparingErrorMessage = ic.dialogPreparingErrorMessage;
	    timerId = setInterval(function () {
	        preparingMessage = preparingMessage + ".";
	        if (counter == 4) {
	            preparingMessage = ic.dialogPreparingMessage;
	            counter = 0;
	        }
	        linkContainer.find(".control input").val(preparingMessage);
	        counter++;
	    }, 500);

	    calendar.trigger("getCaldavUrl", _this, _source.objectId, function (response) {
	        clearInterval(timerId);
	        if (response.result) {
	            if (response.url != "") {
	                linkContainer.find(".control input").val(response.url);
	                linkContainer.find(".control input").removeAttr("disabled");
	                linkContainer.find(".control").removeClass("disabled").removeClass('processing').addClass('success');
	            } else {
	                linkContainer.find(".control input").val(preparingErrorMessage);
	                linkContainer.find(".control").removeClass('processing').addClass('failure');
	            }
	        }
	    });
	}
	function _openIcalStream(anchor) {
		$(document).bind("keyup", _checkEscKeyIcalStream);

		calendar.trigger("getiCalUrl", _this, _source.objectId, function (response) {
		    if (response.result) {
		        var linkContainer = _icalStream.find(".url-link.ical");
		        linkContainer.show();
		        linkContainer.find(".control input").val(response.url);
		        getCaldavLink();
		    }
		});
		
		_icalStream.width(_dialog.width());
		_icalStream.popupFrame("open", anchor);
	}

	function _close(changed, deleted) {
		fcColorPicker.close();
		if (changed && false == _doDDX.call(_this, true)) {return;}
		$(document).unbind("keyup", _checkEscKey);
		_dialog.popupFrame("close");
		_icalStream.popupFrame("close");
		_trigger.call(_this, "onClose", _elem, _source, changed, deleted);
	}
	
	function _closeIcalStream() {
		$(document).unbind("keyup", _checkEscKeyIcalStream);
		_icalStream.popupFrame("close");
	}

	function _checkEscKey(ev) {
		if (ev.which == 27) {
			_close.call(_this, false);
		}
	}
	
	function _checkEscKeyIcalStream(ev) {
		if (ev.which == 27) {
			_closeIcalStream.call(_this);
		}
	}

	function _doDDX(saveData) {
		var opt = calendar.options,
				dlg = {
					title:                  _getControl(kTitle),
					bgColor:                _getControl(kColorBox),
					textColor:              _getControl(kTextColorBox),
					alert:                  _dialog.find(".alert select"),
					timezone:               _dialog.find(".timezone select"),
					owner:                  _dialog.find(".owner .name")
				},
				i;
		var isEditable = _source.isEditable;
		var canChangeAlert = _source.canAlertModify === undefined || _source.canAlertModify;
		var canChangeTimezone = _source.canEditTimeZone;

		if (saveData) {     // ------------- SAVE data -------------

			if (false == fcUtil.validateInput(dlg.title, fcUtil.validateNonemptyString)) {return false;}
			_source.title = $.trim(dlg.title.val());
			_source.title = _source.title.substr(0,
					Math.min(calendar.options.eventMaxTitleLength, _source.title.length));

			var newBg = fcUtil.parseCssColor(dlg.bgColor.css("background-color"));
			var newBor;
			if (newBg) {
				newBor = fcUtil.changeColorLightness(newBg.r, newBg.g, newBg.b, calendar.options.eventBg2BorderRatio);
				_source.backgroundColor = newBg.origColor;
				_source.borderColor = newBor.color;
			}
			_source.textColor = dlg.textColor.css("background-color");

			if (canChangeAlert) {
				_source.defaultAlert.type = parseInt(dlg.alert.val(), 10);
			}

			if (canChangeTimezone) {
				_source.timeZone.id = dlg.timezone.val();
				for (i = 0; i < opt.timeZones.length; ++i) {
					if (opt.timeZones[i].id == _source.timeZone.id) {
						_source.timeZone.name = opt.timeZones[i].name;
						_source.timeZone.delta = opt.timeZones[i].offset - _source.timeZone.offset;
						_source.timeZone.offset = opt.timeZones[i].offset;
						break;
					}
				}
			}

			if (isEditable) {
				_source.permissions = _permissions;
			}

		} else {            // ------------- LOAD data -------------

			dlg.title.val(_source.title);
			dlg.title.css("color", "").css("border-color", "");

			// to round all float numbers to 2nd digit after point
			var rgb = fcUtil.parseCssColor(_source.backgroundColor);
			_setColor.call(_this, rgb.origColor);
			rgb = fcUtil.parseCssColor(_source.textColor);
			_setTextColor.call(_this, rgb.origColor);

			if (canChangeAlert && !_source.isiCalStream) {
				dlg.alert.val(_source.defaultAlert.type);
				_dialog.find(".alert").removeClass("hidden");
			} 
			else {
				dlg.alert.val(kAlertNever);
				_dialog.find(".alert").addClass("hidden");
			}

			if (canChangeTimezone && !_source.isiCalStream) {
				var options = '';
				var tz, tzT;
				for (i = 0; i < opt.timeZones.length; ++i) {
					tz = opt.timeZones[i];
					tzT = htmlEscape(tz.name);
					options += '<option value="' + htmlEscape(tz.id) + '" ' +
									'title="' + tzT + '">' + tzT + '</option>';
				}
				dlg.timezone.html(options);
				dlg.timezone.val(_source.timeZone.id);
				_dialog.find(".timezone").removeClass("hidden");
				_dialog.find(".timezone-read-only").addClass("hidden");
			} 
			else {
				_dialog.find(".timezone").addClass("hidden");
				_dialog.find(".timezone-read-only").removeClass("hidden");
				_dialog.find(".timezone-desc").html(htmlEscape(_source.timeZone.name));
			}

			if (_source.objectId !== "shared_events" && _source.owner && _source.owner.name && _source.owner.name.length > 0) {
				dlg.owner.html(htmlEscape(_source.owner.name));
				_dialog.find(".owner").removeClass("hidden");
			} else {
				dlg.owner.html("");
				_dialog.find(".owner").addClass("hidden");
			}

			_permissions = _source.permissions || {};
			_permissions.users = _permissions.users || [];
			if (isEditable) {
				_permissionsList.render(_permissions, kCalendarPermissions, _source.objectId);
			} else {
				_dialog.find(".shared-list").removeClass("has-users").empty();
				var list = "";
				for (var i = 0; i < _permissions.users.length; i++) {
					if (i > 0) {list += ", ";}
					list += _permissions.users[i].name;
				}
				if (list.length > 0) {
                    _dialog.find(".shared-list").show();
					_dialog.find(".shared-list").addClass("has-users").append(
							'<div class="users-list">' +
								'<div class="label">' + htmlEscape(calendar.options.sharedList.title) + '</div>' +
								'<div class="short-list">' + htmlEscape(list) + '</div>' +
							'</div>');
				} else {
				    _dialog.find(".shared-list").hide();
				}
			}

		}
		return true;
	}


	this.edit = function(elem, anchor) {
		if (elem != _elem) {
			_close.call(_this, false);
			_elem = elem;
			_source = calendar.getEventSources()[$(_elem).data("sourceIndex")];
		}
		_anchor = anchor;
		_doDDX.call(_this);
		_open.call(_this, anchor);
	};

	this.close = function(changed) {
		_close.call(_this, changed);
	};

}


function ManageSubscriptionsDialog(calendar) {
	var _this = this;

	// Triggers dialog's events:
	//   onClose(changed)

	// Triggers calendar's events:
	//   loadSubscriptions(callback)
	//   manageSubscriptions(param, callback)

	var _handlers = {};

	function _trigger(eventName) {
		if (_handlers && $.isFunction(_handlers[eventName])) {
			_handlers[eventName].apply(
					_handlers.context != undefined ? _handlers.context : window,
					Array.prototype.slice.call(arguments, 1));
		}
	}

	this.setEventsHandlers = function(handlers) {
		if (handlers != undefined) {
			$.extend(_handlers, handlers);
		}
	};


	var _dialog;
	var _anchor;
	var _subscriptions;

	(function _create() {
		_dialog = $(calendar.options.categories.subscriptionsManageDialog)
				.addClass("asc-dialog")
				.addClass("fc-shadow")
				.popupFrame({
					anchor: "left,bottom",
					direction: "right,down",
					showArrow: false,
					showModal: true,
					beforeClose: function() {_close.call(_this, false);return false;}
				});
		_dialog.find("#fc_subscr_save").click(function() {
			_close.call(_this, true);
		});
		_dialog.find("#fc_subscr_cancel, .header .close-btn").click(function() {
			_close.call(_this, false);
		});
		//
		var qtext = calendar.options.categories.subscriptionsManageDialog_qsearchText;
		_dialog.find(".qsearch input")
				.focus(function() {
					var q = $(this);
					if (q.val().toLowerCase() == qtext.toLowerCase()) {q.val("");}
				})
				.blur(function() {
					var q = $(this);
					if (q.val() == "") {q.val(qtext);}
				})
				.keyup(function() {
					var qval = $(this).val().toLowerCase();
					if (qval.length > 2) {
						_dialog.find("ul.groups li li")
								.filter(function() {return $(this).text().toLowerCase().indexOf(qval) == -1;})
								.hide();
						_dialog.find("ul.groups li li")
								.filter(function() {return $(this).text().toLowerCase().indexOf(qval) != -1;})
								.show();
					} else {
						_dialog.find(".groups li").show();
					}
					_updateScrollArea();
				});
		_dialog.find(".qsearch .clean-btn").click(function() {
			_cleanQSearch();
			_dialog.find(".groups li").show();
		});
	}());

	function _cleanQSearch() {
		_dialog.find(".qsearch input")
				.val(calendar.options.categories.subscriptionsManageDialog_qsearchText);
	}

	function _updateScrollArea() {
		_dialog.find(".groups .scroll-area").data("jsp").reinitialise();
	}

	function _close(changed) {
		$(document).unbind("keyup", _checkEscKey);
		_dialog.popupFrame("close");
		if (changed) {_doDDX.call(_this, true);}
		_trigger.call(_this, "onClose", changed);
	}

	function _checkEscKey(ev) {
		if (ev.which == 27) {
			_close.call(_this, false);
		}
	}

	function _doDDX(saveData) {
		var dlg = {
			list: _dialog.find("div.groups")
		};

		if (saveData) {     // ------------- SAVE data -------------

			var param = [];

			_dialog.find("ul.groups li li input").each(function() {
				var cb = $(this);
				param.push({
					action:   cb.is(":checked") ? kSubscriptionAddAction : kSubscriptionRemoveAction,
					objectId: _subscriptions[parseInt(cb.val(), 10)].objectId,
					isNew:    false
				});
			});

			//debugOutput("debug", "manageSubscriptions: %o", param);
			calendar.trigger("manageSubscriptions", _this, param, function(response) {
				//debugOutput("debug", "manageSubscriptions -> callback: response: %o", response);
				if (!response.result) {return;}
				calendar.refetchEvents();
			});

		} else {            // ------------- LOAD data -------------

			_cleanQSearch();

			dlg.list.empty();
			dlg.list.append('<div class="scroll-area"><ul class="groups"/></div>');

			var sList = {};
			for (var i = 0; i < _subscriptions.length; ++i) {
				var group = _subscriptions[i].group != undefined && _subscriptions[i].group != null ?
						_subscriptions[i].group : "Unknown";
				if (!$.isArray(sList[group])) {sList[group] = [];}
				sList[group].push({subscription: _subscriptions[i], index: i});
			}

			var groupList = dlg.list.find("ul.groups");
			var groupItem, sublist;
			for (group in sList) if (sList.hasOwnProperty(group)) {
				groupItem = $('<li><span class="group-bullet"/><span>' + group + '</span></li>');
				sublist = $('<ul/>');
				sList[group]
					.sort(function(l,r) {
							return l.subscription.title.toLowerCase() < r.subscription.title.toLowerCase() ? -1 : 1;
					})
					.sort(function(l,r) {
						return l.subscription.isNew ? -1 : (r.subscription.isNew ? 1 : -1);
					});
				for (i = 0; i < sList[group].length; ++i) {
					var subscription = sList[group][i].subscription;
					$('<li><label><input type="checkbox" name="checkedSubscriptions"' +
							' value="' + sList[group][i].index + '"'
							+ (subscription.isSubscribed ? ' checked="checked"' : '') + '/> '
							+ htmlEscape(subscription.title) + '</label></li>')
						.addClass(subscription.isNew ? "new-item" : "")
						.appendTo(sublist);
				}
				if (sublist.length > 0) {groupItem.append(sublist);}
				groupList.append(groupItem);
			}

			groupList.find(".group-bullet").click(function() {
				var b = $(this);
				if (b.hasClass("folded")) {
					b.removeClass("folded");
					b.parent().children("ul").slideDown(_updateScrollArea);
				} else {
					b.addClass("folded");
					b.parent().children("ul").slideUp(_updateScrollArea);
				}
			});

			//_dialog.find(".groups .scroll-area").jScrollPane();

		}
	}


	this.open = function(anchor) {
		_anchor = anchor;
		calendar.trigger("loadSubscriptions", _this,
				function(response) {
					if (!response.result || !$.isArray(response.subscriptions)) {return;}
						_subscriptions = response.subscriptions;
						_dialog.popupFrame("open", _anchor);
						_doDDX.call(_this);
						$(document).bind("keyup", _checkEscKey);
						_dialog.popupFrame("updatePosition", _anchor);
				});
	};

	this.close = function(changed) {
		_close.call(_this, changed);
	};

}


function CategoriesList(calendar) {
	var _this = this;

	var _content;
	var _list;

	var _categoryDialog;
	var _subscriptionDialog;
	var _manageSubscriptionsDialog;

	var _datepicker;
	var _dpVisibleDate;
	var _dpCommonVisibleDate = new Date();
	var isOpenCommonDatePicker = false;
	var _dpickerIsVisible = true;
	var _dpIgnoreUpdate = false;
	var _dpSettingDate = false;
	var _dpYearMenuCaller;
	var _dpPrevHeight = 0;

	var _clickStart;
	var _clickCount;

	var kWholeList         = 0;
	var kCategoriesOnly    = 1;
	var kSubscriptionsOnly = 2;


	var formatDate = calendar.formatDate;
	var formatDates = calendar.formatDates;


	function _changeTime(d, offset) {
		return new Date( d.getTime() + offset * 60000 );
	}

	function _updateTimeZone(events, offset) {
		for (var i = 0; i < events.length; ++i) {
			if (events[i].allDay === undefined || !events[i].allDay) {
				events[i].start = _changeTime(events[i].start, offset);
				if (events[i].end instanceof Date) {
					events[i].end = _changeTime(events[i].end, offset);
				}
			}
		}
	}

	// Categories

	function _addNewCategory() {
		_categoryDialog.addNew({pageX:"center",pageY:"center"});
	}

	function _editCategory(categoryElem) {
	    ASC.CalendarController.CancelEditDialog();
		_categoryDialog.edit(categoryElem, {pageX:"center",pageY:"center"});
	}

    function _deleteCategory(source) {
        calendar.trigger("editCalendar", _this,
            $.extend({ action: kCalendarDeleteAction }, source),
            function(response) {
                if (!response.result) {
                    return;
                }
                calendar.removeEventSource(source);
                calendar.rerenderEvents();
                _rerenderList.call(_this);

                if (jq("#asc_event").is(":visible")) {
                    jq("#asc_event").find(".editor .calendar select option[value=" + source.objectId + "]").remove();
                    jq("#asc_event").find(".editor .calendar select").change();
                }

            });
    }

    function _updateCategory(elem, source, changed, deleted) {
		if (changed) {
			if (elem) {
				// Change existing category
				calendar.trigger("editCalendar", _this,
						$.extend({action: kCalendarChangeAction}, source),
						function(response) {
							if (!response.result) {return;}

							_syncCategory(source, response);
							_updateListItem.call(_this, elem);
							_ellipsisLongItem.call(elem);
							if (source.timeZone !== undefined) {
								_updateTimeZone(source.events, source.timeZone.delta);
							}
							
							if (AjaxUploader.isChanged != undefined) {
								AjaxUploader._settings.action = response.importUrl;
								AjaxUploader.submit();
							}
							calendar.addEventSource(response.source);
							_rerenderList.call(_this, kSubscriptionsOnly, true);
							calendar.refetchEvents();

						});
			} else {
				// Add new category
			    calendar.trigger("editCalendar", _this,
			        $.extend({ action: kCalendarAddAction }, source),
			        function(response) {
			            if (!response.result) {
			                return;
			            }

			            if (AjaxUploader.isChanged != undefined) {
			                AjaxUploader._settings.action = response.importUrl;
			                AjaxUploader.submit();
			            }

			            calendar.addEventSource(response.source);
			            _rerenderList.call(_this, kCategoriesOnly, true);
			            _rerenderList.call(_this, kSubscriptionsOnly, true);
			            calendar.refetchEvents();

			            if (jq("#asc_event").is(":visible")) {
			                jq("#asc_event")
			                    .find(".editor .calendar select")
			                    .append(jq("<option></option>")
			                        .attr("value", response.source.objectId)
			                        .attr("title", response.source.title)
			                        .html("&nbsp;&nbsp;&nbsp;&nbsp;" + htmlEscape(response.source.title)));
			            }

			        });
			}
		}
		else if (!deleted) {
			calendar.trigger("editCalendar", _this,
						$.extend({action: kCalendarCancelAction}, source),
						function(response) {
							if (!response.result) {return;}
						});
		}
	}

	function _syncCategory(source, response){
		if (response.source.objectId === source.objectId){
			source.isShared = response.source.isShared;
			// ...
		}
	}


	// Subscriptions

	function _editSubscription(elem) {
		_subscriptionDialog.edit(elem, {pageX:"center",pageY:"center"});
	}

	function _updateSubscription(elem, source, changed, deleted) {
		if (changed) {
			if (elem) {
				calendar.trigger("editCalendar", _this,
						$.extend({action: kCalendarChangeAction}, source),
						function(response) {
							if (!response.result) {return;}
							_updateListItem.call(_this, elem);
							_ellipsisLongItem.call(elem);
							if (source.timeZone !== undefined) {
								_updateTimeZone(source.events, source.timeZone.delta);
							}
							
							if (AjaxUploader.isChanged != undefined) {
								AjaxUploader._settings.action = response.importUrl;
								AjaxUploader.submit();
							}
							else {
								calendar.refetchEvents();
							}
						});
			}
		}
		else if (!deleted) {
			calendar.trigger("editCalendar", _this,
						$.extend({action: kCalendarCancelAction}, source),
						function(response) {
							if (!response.result) {return;}
							calendar.refetchEvents();
						});
		}
	}

	function _removeSubscription(source) {
		calendar.trigger("manageSubscriptions", _this,
				[{
					action:   kSubscriptionRemoveAction,
					objectId: source.objectId,
					isNew:    false
				}],
				function(response){
					if (response.result) {calendar.removeEventSource(source);}
				});
	}

	function _manageSubscriptions() {
		_manageSubscriptionsDialog.open({pageX:"center",pageY:"center"});
	}


	// Render functions

	function _renderListItem(index, item) {
		return $(
				'<div class="content-li">' +
					fcUtil.makeBullet(!item.isHidden, item.backgroundColor,
					                  calendar.options.categories.inactiveColor,
					                  item.isSubscription ? false : item.isShared) +
					'<div class="label" style="'+ (item.isHidden ? ("color:" + calendar.options.categories.inactiveColor) : "") +'">' +
						htmlEscape(item.title ? item.title : 'Unknown') + '</div>' +
					'<div class="edit-icon" title="' + htmlEscape(calendar.options.categories.dialogHeader_edit) + '"/>' +
				'</div>')
				.data("sourceIndex", index);
	}

	function _ellipsisLongItem() {
        var li = $(this);
        var label = li.find(".label");
        label.attr("title", label.text());

        //TODO: remove this function! use css!
        return;
        label.css("right", "")
            .removeClass("show-tooltip")
            .unbind("mouseenter");
		var dots = li.find(".dots");
		if (label.position().left + label.width() >= li.width() - 3/*paddind*/) {
			if (dots.length < 1) {dots = $('<div class="dots">&#8230;</div>').appendTo(li);}
			label
					.css("right", (li.width() - dots.position().left) + "px")
					.addClass("show-tooltip")
					.mouseenter(
							function() {
								var id = "tt_" + (new Date()).getTime();
								var hideTT = function(){
									$("#" + id).remove();};
								var label = $(this);
								$('<div class="fc-label-tooltip" id="' + id + '">' + htmlEscape(label.text()) + '</div>')
										.appendTo("body")
										.offset(label.offset())
										.mouseleave(function() {setTimeout(hideTT, 0);});
								setTimeout(hideTT, 2000);
							});
		} else {
			if (dots.length > 0) {dots.remove();}
		}
	}

	function _updateListItem(item) {
		var elem = $(item);
		var source = calendar.getEventSources()[elem.data("sourceIndex")];
		fcUtil.updateBullet(
				elem.find(".bullet"),
				!source.isHidden,
				source.backgroundColor,
				calendar.options.categories.inactiveColor,
				source.isSubscription ? false : source.isShared);
		elem.find(".label").text(source.title);
	}

	function _toggleListItem(item) {
		var elem = $(item);
		var source = calendar.getEventSources()[elem.data("sourceIndex")];
		var hidden = source.isHidden;
		source.isHidden = !hidden;
		calendar.trigger("editCalendar", _this,
				$.extend({action: kCalendarHideAction}, source),
				function(response) {
					if (!response.result) {source.isHidden = hidden;return;}
					//calendar.refetchEvents();
					_updateListItem.call(_this, elem);
					calendar.rerenderEvents();
				});
	}

	function _renderCategories(list) {
	    var sources = calendar.getEventSources();
	    
	    //list.find(".categories").removeClass('hidden');
	    list.find(".my_calendars").removeClass('active');
	    
	    

		var categ = list.find(".categories");
		categ.empty();
		
			for (var i = 0; i < sources.length; ++i) {
				var cal = sources[i];

				if (cal.isTodo == 1) continue;

				if (!cal.title || cal.title.length < 1 || cal.isSubscription) { continue; }
				cal.isHidden = cal.isHidden == true ? true : false; // convert to boolean

				var li = _renderListItem.call(_this, i, cal);
				li.find(".bullet, .label").click(function () {
					_toggleListItem.call(_this, $(this).parent().get(0));
				});
				li.find(".edit-icon").click(function () {
					_editCategory.call(_this, $(this).parent().get(0));
				});
				li.appendTo(categ);
			}
		

		
	}

	function _renderSubscriptions(list) {
		var sources = calendar.getEventSources();
        if (!list.find(".subscr").length) {
            return;
        }
	    
        //list.find(".subscr").removeClass('hidden');
        list.find(".other_calendars").removeClass('active');
	    
		
		var subscr = list.find(".subscr");
		subscr.empty();
		
			for (var i = 0; i < sources.length; ++i) {
				var sub = sources[i];
				if (!sub.title || sub.title.length < 1 || !sub.isSubscription) { continue; }
				sub.isHidden = sub.isHidden == true ? true : false; // convert to boolean

				var li = _renderListItem.call(_this, i, sub);
				li.find(".bullet, .label").click(function () {
					_toggleListItem.call(_this, $(this).parent().get(0));
				});
				li.find(".edit-icon").click(function () {
					_editSubscription.call(_this, $(this).parent().get(0));
				});
				li.appendTo(subscr);
			}
		
		
	}

	function _renderList() {
		var list = $("div.fc-catlist .content");
		if (list.length < 1) {
			list = $(
				'<div class="content">' +
					'<div class="content-h first my_calendars">' +
						'<span class="main-label">' + htmlEscape(calendar.options.categories.title) + '</span>' +
						//<!--'<span class="add-label" title="' + htmlEscape(calendar.options.categories.addNewCategoryLabel) + '"/>' + -->
					'</div>' +
					'<div class="categories"/>' +
                    (calendar.options.isPersonal ? "" :
					'<div class="content-h other_calendars">' +
						'<span class="main-label">' + htmlEscape(calendar.options.categories.subscriptionsTitle) + '</span>' +
						'<span class="manage-label" title="' + htmlEscape(calendar.options.categories.subscriptionsManageLabel) + '"/>' +
					'</div>' +
					'<div class="subscr"/>' +
				'</div>'));
			//list.find(".add-label").click(function() {_addNewCategory.call(_this);});
			list.find(".manage-label").click(function(event) {
			    event.preventDefault();
			    _manageSubscriptions.call(_this);
			    
			    list.find(".content-h.other_calendars,.content-h.my_calendars").removeClass('active');
			    list.find(".subscr,.categories").removeClass('hidden');
			    _resizeList(true);
			    
			    return false;
			});
			//list.find(".categories, .subscr").jScrollPane();

			list.find(".content-h.my_calendars").click(function () {
			    $(this).toggleClass('active');
				list.find(".categories").toggleClass('hidden');
				_resizeList(true);
			});
			list.find(".content-h.other_calendars").click(function () {
			    $(this).toggleClass('active');
			    var categoriesHeight = list.find(".categories").height();
				list.find(".subscr").toggleClass('hidden');
				_resizeList(true, categoriesHeight);
			});
		}
		_renderCategories.call(_this, list);
		_renderSubscriptions.call(_this, list);
		return list;
	}

	function _resizeList(scrollToEnd, categHeight) {
	    if (_list.length < 1) {return;}

		var categ = _list.find(".categories");
		var subscr = _list.find(".subscr");

	    var isCategoriesHidden = categ.hasClass('hidden'),
	        isSubscrHidden = subscr.hasClass('hidden');
	    


		_list.find(".content-li").each(_ellipsisLongItem);

		_list.css("visibility", "hidden");
		_list.removeClass("fixed");

		// find lists
		
		var categItems = categ.find(".content-li");
		
		var subscrItems = subscr.find(".content-li");

		// restore heights of lists
		var cih = categItems.eq(0).length ? categItems.eq(0).outerHeight(true) : 22;
		var categH = categItems.length * cih;
		var minCategH = categItems.length > 1 ? 2 * cih : cih;
		var sih = subscrItems.eq(0).length ? subscrItems.eq(0).outerHeight(true) : 22;
		var subscrH = subscrItems.length * sih;
		var minSubscrH = subscrItems.length > 1 ? 2 * sih : sih;

		categ.height(categH);
		subscr.height(subscrH);

		// make datepicker sticky
		var pickerDiv = $('#calendarSidePanelCalendar').find(".fc-catlist-picker").removeClass("fixed");
		var makeSticky =
				pickerDiv.position().top + pickerDiv.outerHeight(true) > _content.height();
		if (makeSticky) {
			pickerDiv.addClass("fixed");
			_list.addClass("fixed");
			_list.css("bottom", pickerDiv.outerHeight(true) + "px");
		}

		// calc new heights
		var listH = _list.height();
		var otherH = (_list.find(".date-box").length ? _list.find(".date-box").outerHeight(true) : 0) +
				(_list.find(".content-h").length ? _list.find(".content-h").outerHeight(true) * 2 : 0);
		var scrollH = listH - otherH;
		var categSpace = categ.outerHeight(true) - categ.height();
		var subscrSpace = subscr.outerHeight(true) - subscr.height();
		var newCategH = Math.max(minCategH, Math.round(scrollH * categH / (categH + subscrH)) || 0);
		var newSubscrH = Math.max(minSubscrH, Math.round(scrollH * subscrH / (categH + subscrH)) || 0);
		var delta = newCategH + newSubscrH - scrollH;
		if (delta > 0) {
			if (newCategH > newSubscrH) {newCategH = newCategH - delta;}
			else                        {newSubscrH = newSubscrH - delta;}
		}
		newCategH = isSubscrHidden ? categItems.length * (cih + 1) : newCategH;
		if (isSubscrHidden && categHeight) {
		    var resultCategH = categHeight ? categHeight : newCategH - categSpace;
		    categ.css("height", resultCategH + "px");
		} else {
			if ((newCategH + _list.find(".content-h").outerHeight(true))> _list.height()) {
				newCategH = _list.height() - subscr.outerHeight(true) - _list.find(".content-h").outerHeight(true);
			}
		    categ.css("height", (newCategH - categSpace) + "px");
		}
	   
		subscr.css("height", (newSubscrH - subscrSpace) + "px");

		//var categJSP = categ.data("jsp");
		//categJSP.reinitialise();
		//if (subscr.length) subscr.data("jsp").reinitialise();

		//if (scrollToEnd) {
		//	categJSP.scrollToBottom();
		//}

		_list.css("visibility", "visible");
	    
		if (isCategoriesHidden) {
		    categ.addClass('hidden');
		    _list.find(".my_calendars").addClass('active');
		}
		if (isSubscrHidden) {
		    subscr.addClass('hidden');
		    _list.find(".other_calendars").addClass('active');
		}
	}

	function _rerenderList(flag, scrollToEnd) {
		if (flag == undefined || flag == kWholeList || flag == kCategoriesOnly) {
			_renderCategories.call(_this, _list);
		}
		if (flag == undefined || flag == kWholeList || flag == kSubscriptionsOnly) {
			_renderSubscriptions.call(_this, _list);
		}
		_resizeList.call(_this, scrollToEnd);
	}


	function _renderDatepicker() {
		var result = $(
				'<div class="fc-catlist-picker">' +
					'<div>' +
						'<div id="fc_datepicker" class="asc-datepicker"/>' +
						'<div class="hide">' +
							'<span>' +
								htmlEscape(calendar.options.categories.datepickerHideLabel) +
							'</span>' +
						'</div>' +
					'</div>' +
				'</div>');
		result.find(".hide span").click(function() {_showDatepicker.call(_this, !_dpickerIsVisible);});

		_datepicker = result.find("#fc_datepicker").datepicker({
			firstDay: calendar.options.firstDay,
			onChangeMonthYear: function(year, month, inst) {
				if (_dpSettingDate == true) {return;}
				_dpVisibleDate = new Date(year, month - 1, 1);
				setTimeout(function() {_updateDatepickerCells(_dpVisibleDate);}, 0);
			},
			onSelect: function(dateText, inst) {

			    var showDay = false;

			    if (jq("#asc_event .event-editor .editor").is(":visible")) {
			        if (confirm(ASC.Resources.Master.ResourceJS.WarningMessageBeforeUnload)) {
			            window.toastr.remove();
			            jq("#asc_event").hide();
			            jq("#asc_calendar").show();
			            calendar.updateSize();
			            showDay = true;
			        }
			    } else {
			        window.toastr.remove();
			        jq("#asc_event").hide();
			        jq("#asc_calendar").show();
			        calendar.updateSize();
			        showDay = true;
			    }

			    if (showDay) {
			        _dpIgnoreUpdate = true;
			        _dpVisibleDate = _datepicker.datepicker("getDate");
			        calendar.gotoDate(_dpVisibleDate);
			        calendar.changeViewAndMode("day");
			        _dpIgnoreUpdate = false;
			        //
			        setTimeout(_updateDatepickerCells, 0);
			    }
			}
		});

        function initMonthMenu(directionUp) {
            fcMenus.dpMonthMenu = $("#fc_datepicker_mmenu").length ? $("#fc_datepicker_mmenu") : $("<div id='fc_datepicker_mmenu'/>");
            if (isOpenCommonDatePicker) {
                fcMenus.dpMonthMenu.css('z-index', 2001);
            }

			fcMenus.dpMonthMenu.popupMenu({
				anchor: directionUp ? "left,top" : "right,bottom",
				direction: directionUp ? "right,up" : "left,down",
				arrow: directionUp ? "down" : "up",
				arrowPosition: "50%",
				showArrow: false,
				cssClassName: "asc-popupmenu",
				items: calendar.options.monthNames,
                itemClick: function (event, data) {
                    _dpCommonVisibleDate = isOpenCommonDatePicker ? $('#fc_common_dp .asc-datepicker').datepicker("getDate") !== null ? $('#fc_common_dp .asc-datepicker').datepicker("getDate") : _dpCommonVisibleDate : _dpCommonVisibleDate;
                    var delta = isOpenCommonDatePicker ? data.itemIndex - _dpCommonVisibleDate.getMonth() : data.itemIndex - _dpVisibleDate.getMonth();
					adjustDatepickerDate(delta, "M");
				}
			});
		}

        function initYearMenu(y, directionUp) {
            if (isOpenCommonDatePicker) {
                fcMenus.dpYearMenu.css('z-index', 2001);
            }
			fcMenus.dpYearMenu.popupMenu({
				anchor: directionUp ? "left,top" : "right,bottom",
				direction: directionUp ? "right,up" : "left,down",
				arrow: directionUp ? "down" : "up",
				arrowPosition: "50%",
				showArrow: false,
				cssClassName: "asc-popupmenu",
                items: [
                    (y + 3).toString(),
                    (y + 2).toString(),
                    (y + 1).toString(),
                    "divider",
                    (y - 1).toString(),
                    (y - 2).toString(),
                    (y - 3).toString()
				],
                itemClick: function (event, data) {
                    _dpCommonVisibleDate = isOpenCommonDatePicker ? $('#fc_common_dp .asc-datepicker').datepicker("getDate") !== null ? $('#fc_common_dp .asc-datepicker').datepicker("getDate") : _dpCommonVisibleDate : _dpCommonVisibleDate;
                    var delta = isOpenCommonDatePicker ? parseInt(data.item, 10) - _dpCommonVisibleDate.getFullYear()  : parseInt(data.item, 10) - y;
					adjustDatepickerDate(delta, "Y");
				}
			});
		}

        function adjustDatepickerDate(delta, period) {
            if (delta != 0) {
                if (isOpenCommonDatePicker) {
                    if (period === "M") {
                        _dpCommonVisibleDate = addMonths(_dpCommonVisibleDate, delta);
                    } else if (period === "Y") {
                        _dpCommonVisibleDate = addYears(_dpCommonVisibleDate, delta);
                    } else {
                        return;
                    }
                    $('#fc_common_dp .asc-datepicker').datepicker("setDate", _dpCommonVisibleDate);
                } else {
                    if (period === "M") {
                        _dpVisibleDate = addMonths(_dpVisibleDate, delta);
                    } else if (period === "Y") {
                        _dpVisibleDate = addYears(_dpVisibleDate, delta);
                    } else {
                        return;
                    }
                    _dpSettingDate = true;
                    $.datepicker._adjustDate("#fc_datepicker", delta, period);
                    _dpSettingDate = false;
                    _updateDatepickerCells.call(_this, _dpVisibleDate);
                }
			}
		}

		initMonthMenu(true);

        $(document).on("click", "#fc_datepicker .ui-datepicker-title , #fc_common_dp .ui-datepicker-title", function(e) {
            var directionUp = $(e.target).offset().top > fcMenus.dpMonthMenu.outerHeight(true) + 10;

            isOpenCommonDatePicker = $("div").is("#fc_common_dp") && $("#fc_common_dp").is(':visible');

            if (e.target.className == "ui-datepicker-month") {
				initMonthMenu(directionUp);
				fcMenus.hideMenus(fcMenus.dpMonthMenu);
				fcMenus.dpMonthMenu.popupMenu("open", e.target);
				return;
			}
			if (e.target.className == "ui-datepicker-year") {
				if (!_dpYearMenuCaller || _dpYearMenuCaller != e.target) {
                    _dpYearMenuCaller = e.target;
                    _dpCommonVisibleDate = isOpenCommonDatePicker ? $('#fc_common_dp .asc-datepicker').datepicker("getDate") !== null ? $('#fc_common_dp .asc-datepicker').datepicker("getDate") : _dpCommonVisibleDate : _dpCommonVisibleDate;
					var y = isOpenCommonDatePicker ? _dpCommonVisibleDate.getFullYear() : _dpVisibleDate.getFullYear();
					if (!fcMenus.dpYearMenu || fcMenus.dpYearMenu.length < 1) {
						fcMenus.dpYearMenu = $("#fc_datepicker_ymenu").length ? $("#fc_datepicker_ymenu") : $("<div id='fc_datepicker_ymenu'/>");
					} else {
						fcMenus.dpYearMenu.popupMenu("close");
						fcMenus.dpYearMenu.popupMenu("destroy");
					}
					initYearMenu(y, directionUp);
				}
				fcMenus.hideMenus(fcMenus.dpYearMenu);
				fcMenus.dpYearMenu.popupMenu("open", e.target);
				return;
			}
		});
		return result;
	}

	function _showDatepicker(show) {
		_showVersion.call(_this);

		$.cookie('fc_show_minicalendar', !show ? "0" : "1", {expires: 365});

		var pickerDiv = $("#calendarSidePanelCalendar .fc-catlist-picker");
		var label = pickerDiv.find(".hide span");
		if (show == false) {
			if (_dpickerIsVisible) {
				_datepicker.hide();
				label.text(calendar.options.categories.datepickerShowLabel);
				_dpickerIsVisible = false;
			}
		} else {
			if (!_dpickerIsVisible) {
				_datepicker.show();
				label.text(calendar.options.categories.datepickerHideLabel);
				_dpickerIsVisible = true;
			}
		}

		var pickerH = $("#calendarSidePanelCalendar .fc-catlist-picker").outerHeight(true);
		_list.css("bottom", pickerH + "px");
		_resizeList.call(_this);
	}

	function _showVersion() {
		if (_clickStart === undefined) {_clickStart = (new Date()).getTime();}
		_clickCount = _clickCount ? _clickCount + 1 : 1;
		if (_clickCount >= 6) {
			if ((new Date()).getTime() - _clickStart <= 5000) {
				var id = "ver_" + (new Date()).getTime();
				$('<div class="fc-label-tooltip" style="padding:2em;" id="' + id + '">' +
						htmlEscape('FullCalendar v' + $.fullCalendar.version) + '</div>')
						.appendTo("body")
						.offset(calendar.getView().getViewRect());
				setTimeout(function() {$("#" + id).remove();}, 3000);
			}
			_clickStart = undefined;
			_clickCount = 0;
		}
	}

	function _updateDatepickerCells(startDate) {
		_datepicker.find(".ui-datepicker-prev .ui-icon")
				.removeClass("ui-icon-circle-triangle-w")
				.addClass("ui-icon-carat-1-w");
		_datepicker.find(".ui-datepicker-next .ui-icon")
				.removeClass("ui-icon-circle-triangle-e")
				.addClass("ui-icon-carat-1-e");
		// find visible date range
		var date = startDate instanceof Date ? startDate : calendar.getDate();
		var visStart = new Date(date.getFullYear(), date.getMonth(), 1);
		var days = visStart.getDay() - calendar.options.firstDay;
		addDays(visStart, -(days >= 0 ? days : days + 7));
		// get all events
		var events = calendar.clientEvents();
		
		var sd = new Date(visStart.getFullYear(), visStart.getMonth() - 1, 1);
		var ed = new Date(visStart.getFullYear(), visStart.getMonth() + 2, 1);
		
		//if (!events.length) {
			calendar.trigger("getMonthEvents", _this,
					$.extend({startDate: sd, endDate: ed}),
					function(response) {
						if (response.result) {
							var daysArr = response.days;
							
							// mark days with events
							_datepicker.find(".ui-datepicker-calendar tbody td").each(function(i, _cell) {
								var cell = $(_cell);
								
								for (var j = 0; j < daysArr.length; ++j) {
									
									var eventDate = clearTime(new Date(daysArr[j].getFullYear(), daysArr[j].getMonth(), daysArr[j].getDate() + days)).toString();
									var cellDate = clearTime(new Date(visStart.getFullYear(), visStart.getMonth(), visStart.getDate() + i + days)).toString();
									
									if (eventDate === cellDate) {
										cell.addClass("has-events");
										return;
									}
								}
							});
						}
					}
				);
			//}
		
		// mark days with events
		_datepicker.find(".ui-datepicker-calendar tbody td").each(function(i, _cell) {
			var cell = $(_cell);
			var date = addDays(cloneDate(visStart), i);
			for (var j = 0; j < events.length; ++j) {
				var ev = events[j];
				var start = clearTime(cloneDate(ev.start));
				var end = clearTime(cloneDate(ev.end || ev.start));
				if (start <= date && date <= end && (!ev.source || !ev.source.isHidden)) {
					//cell.addClass("has-events");
					return;
				}
			}
		});
	}

	function _updateDatepickerSize() {
		var newH = _content.find(".fc-catlist-picker").outerHeight(true);
		if (newH != _dpPrevHeight) {
			_resizeList.call(_this);
			_dpPrevHeight = newH;
		}
	}
	
	


	// Public Interface

	this.render = function() {
		_list = _renderList.call(_this);
		_content = $('<div class="fc-catlist asc-dialog"><div class="fc-modal"/></div>')
				.append(_list);
	    
		$('#calendarSidePanelCalendar').append(_renderDatepicker.call(_this));

		_categoryDialog = new CategoryDialog(calendar);
		_categoryDialog.setEventsHandlers({
			context:    _this,
			onClose:    _updateCategory,
			onDelete:   _deleteCategory
		});

		_subscriptionDialog = new SubscriptionDialog(calendar);
		_subscriptionDialog.setEventsHandlers({
			context:          _this,
			onClose:          _updateSubscription,
			onUnsubscribe:    _removeSubscription,
			onDelete:         _deleteCategory
		});

		_manageSubscriptionsDialog = new ManageSubscriptionsDialog(calendar);

		return _content;
	};

	this.rerenderList = function() {
		//if (!_content.is(":visible")) {return;}
		_rerenderList.call(_this);
	};

	this.resize = function(newHeight) {
		//if (!_content.is(":visible")) {return;}
		_content.css("height", newHeight + "px");
		_resizeList.call(_this);
	};

	this.updateDatepicker = function(newDate) {
		//if (!_content.is(":visible")) {return;}
		if (_datepicker.length < 1 || _dpIgnoreUpdate) {return;}

		_dpSettingDate = true;
		_dpVisibleDate = newDate;
		_datepicker.datepicker("setDate", newDate);
		_dpSettingDate = false;

		_updateDatepickerCells.call(_this);
	};

	this.updateDatepickerSize = function() {
		//if (!_content.is(":visible")) {return;}
		_updateDatepickerSize.call(_this);
	};

	this.updateDatepickerCells = function() {
		//if (!_content.is(":visible")) {return;}
		_updateDatepickerCells.call(_this);
	};

	this.showMiniCalendar = function(show) {
		//if (!_content.is(":visible")) {return;}
		_showDatepicker.call(_this, show);
	};
	
	this.addNewCalendar = function(anchor) {
		_categoryDialog.addNew(anchor);
	}

	this.addiCalCalendar = function(anchor) {
		_categoryDialog.addiCalCalendar(anchor);
	}
}


function TodoList(calendar) {
	var _this = this;

	var _list;
    var _listStates = {};
	var _editor;
	var _todo_viewer;
    var _anchor;
    var _curTodoElem;
    var _curTodo;
	var _sortType = 0;
	var _sortLabel;
	var _uiBlocker;
	var _date = null;
	var _deleteDialog;
	var _icalStream;
    var _minTime = -62135596800000;
    var ic = calendar.options.icalStream;

    function _parseDateTime(inputD, result) {
	    var dateStr = inputD.val();
	    var dateStrIsEmpty = dateStr.search(/\S/) < 0;
	    var date, time, r;
	    if (!dateStrIsEmpty) {
	        date = fcUtil.validateDateString(dateStr);
	        r = (date === null) ? 0 : 1;
	    } else {
	        r = -1;
	        date = null;
	        time = null;
	    }
	    result.date = { isEmpty: dateStrIsEmpty, isValid: date !== null, value: date };
	    return r;
	}
    
	function _doDDX(save, isViewer) {
		var todo = {
			title:       _editor.find("#fc_todo_title"),
			start_d:     _editor.find("#fc_todo_start_date"),
			start_t:     _editor.find("#fc_todo_start_time"),
			completed:   _editor.find("#fc_todo_completed"),
			priority:    _editor.find("#fc_todo_priority"),
			cal:         _editor.find("#fc_todo_cal"),
			description: _editor.find("#fc_todo_description"),
			ok:          _editor.find("#fc_todo_ok")
		};
	    var viewTodo = {
	        title: _todo_viewer.find(".title")[0],
	        start_d: _todo_viewer.find(".date-time .date")[0],
	        description: _todo_viewer.find(".description .text")[0],
	        mark_btn: _todo_viewer.find(".buttons .mark-btn")[0]
	    };
		var elem = $(_curTodoElem);
		var sources = calendar.getEventSources();
		var src = sources[elem.data("sourceIndex")];
		var newSource;
		var curTodo = src.todos[elem.data("todoId")];

		if (save) {    // ------------- SAVE data -------------

		    curTodo.title = $.trim(todo.title.val());
		   
		    if (false == fcUtil.validateInput(todo.title, fcUtil.validateNonemptyString)) { return false; }

			curTodo.completed = todo.completed.is(":checked");
			curTodo.description = $.trim(todo.description.val());
			curTodo.priority = todo.priority.val();
		    curTodo.completed = todo.completed == true ? true : false;

		    var date = {};
		    var validateDateResult = _validateDateFields(date);
		    
		    if (!validateDateResult && !date.data.date.isEmpty) { return false; }

		    curTodo.start = parseDate(date.data.date.value + "T23:59:59");

			var cal = todo.cal.val();
			if (cal != src.title) {
				for (var i = 0; i < sources.length; ++i) {
					if (sources[i].title != cal) {continue;}
					newSource = sources[i];
					newSource.todos = newSource.todos || [];
					newSource.todos.push(curTodo);
					src.todos =
							$.grep(src.todos, function(a){return a != curTodo;});
					break;
				}
			}
			_updateTodo(curTodo);
			_curTodoElem = undefined;
			_renderList.call(_this);
			_closeEditor.call(_this);

		} else {       // ------------- LOAD data -------------

			todo.title.val(curTodo.title.trim());
			todo.title.css("color", "").css("border-color", "");
			todo.start_d.css("color", "").css("border-color", "");
			todo.start_t.css("color", "").css("border-color", "");

			_editor.find(".header .title").text(curTodo.objectId ? window.g_fcOptions.todoEditor.dialogHeader_edit : window.g_fcOptions.todoEditor.dialogHeader_add);

			if (curTodo.completed == true) {
				todo.completed.prop("checked", true);
			} else {
				todo.completed.removeAttr("checked");
			}

		    var minDate = new Date(1, 0, 1);
		    if ((curTodo.start instanceof Date) && !(curTodo.start.getFullYear() <= minDate.getFullYear())) {
			    todo.start_d.val(formatDate(curTodo.start, calendar.options.eventEditor.dateFormat));
			    todo.start_t.val(formatDate(curTodo.start, calendar.options.eventEditor.timeFormat));
			} else {
		        todo.start_d.val(_date != null ? (formatDate(_date, calendar.options.eventEditor.dateFormat)) : "");
		        todo.start_t.val(_date != null ? "00:00" : "");
		        _date = null;
		    }

			todo.priority.val(curTodo.priority != undefined ? curTodo.priority : "2");

			var options = "";
			for (i = 0; i < sources.length; ++i) {
				var e = sources[i];
				options += "<option>" + htmlEscape(e.title) + "</option>";
			}
			todo.cal.html(options);
			todo.cal.val(src.title);

			todo.description.val(curTodo.description != undefined ? curTodo.description : "");
		    
			if (isViewer != undefined) {
			    
			    viewTodo.mark_btn.innerText = curTodo.completed ? calendar.options.todoViewer.dialogButton_mark_off : calendar.options.todoViewer.dialogButton_mark_on;
			        
			    viewTodo.title.innerText = curTodo.title;
			    viewTodo.description.innerText = curTodo.description != undefined ? curTodo.description : "";
			    if ((curTodo.start instanceof Date) && !(minDate.getTime() == curTodo.start.getTime())) {
			        viewTodo.start_d.innerText = formatDate(curTodo.start, calendar.options.eventEditor.dateFormat);
			    } else {
			        viewTodo.start_d.innerText = _date != null ? (formatDate(_date, calendar.options.eventEditor.dateFormat)) : "";
			        _date = null;
			    }
			}
		    _curTodo = curTodo;
		}
	}
	(function _createIcal() {
	    _icalStream = $(ic.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("add-popup")
				.popupFrame({
				    anchor: "right,top",
				    direction: "right,down",
				    offset: "0,0",
				    showArrow: false
				});

	    _icalStream.find(".buttons .cancel-btn, .header .close-btn").click(function () {
	        _closeTodoExportStream.call(_this);
	    });
	    _icalStream.find(".ical-description span")[0].innerHTML = ic.dialogTodoDescription;
	    
	    _icalStream.find((".url-link .control input")).click(function () {
	        $(this).select();
	    });
	    _icalStream.find((".url-link .control .button.copy")).click(function () {
	        var control = $($(this)[0].parentNode);
	        control.find('input').select();
	        try {
                document.execCommand('copy');
                ASC.CalendarController.displayInfoPanel(calendar.options.categories.dialogCopyMessage, false);
	        } catch (err) { }
	    });

	}());
    

	function _updateTodo(todo, resolve) {
	    var action = kTodoAddAction;
	    if (todo.objectId) {
	        action = kTodoChangeAction;
	    }
	    var isExistTodo = false;
	    calendar.trigger("editTodo", _this,
                $.extend({ action: action },todo),
                function (response) {
                    if (response.result) {
                        var sources = calendar.getEventSources();
                        var cache = calendar.getCache();
                        for (var i = 0; i < sources.length; ++i) {
                            var source = sources[i];
                            if (response.todo.length > 0) {
                                if (source.todos && source.objectId == response.todo[0].sourceId) {
                                      
                                    response.todo[0].completed = new Date(response.todo[0].completed).getTime() == _minTime ? false : true;
                                    response.todo[0].start = ASC.Api.TypeConverter.ServerTimeToClient(response.todo[0].start);
                                    response.todo[0].source = source;
                                    
                                    for (var k = 0; k < cache.length; k++) {
                                        if (cache[k].objectId == response.todo[0].objectId) {

                                            calendar.fetchEvents(calendar.getView().visStart, calendar.getView().visEnd, resolve);
                                            isExistTodo = true;
                                        }
                                    }
                                    if (!isExistTodo) {
                                        source.todos = source.todos.concat(response.todo[0]);
                                    }
                                    
                                }
                            }
                        }
                        if (!isExistTodo && response.todo[0]) {

                            calendar.fetchEvents(calendar.getView().visStart, calendar.getView().visEnd, resolve);
                        }
                    }

                });
    }
	function _openTodoContainer(_this) {
	    var $container = $(($(_this)[0].parentNode));
	    var date = $container.data('date') == null ? new Date(1, 0, 1, 23, 59, 59).getTime() : $container.data('date');
	    _listStates[date] = !_listStates[date];
	    $container.toggleClass('close');
	}
	function _adjustPopupPosition() {
	    var vr = calendar.getView().getViewRect();                               // current view's rect
	    var ar = fcUtil.getElementRect(_anchor);                                 // anchor element's rect
	    var pw = _todo_viewer.outerWidth(true);// + _settings.outerWidth(true) + 30;     // popup's width
	    var ph = _todo_viewer.outerHeight(true);                                      // popip's height

	    // adjust popup's ahchor, direction & arrow
	    if (ar.right + pw <= (vr.right - 250) || ar.left - pw < vr.left) {
	        _todo_viewer.popupFrame("option", "anchor", "right,top");
	        _todo_viewer.popupFrame("option", "direction", "right,down");
	        _todo_viewer.popupFrame("option", "arrow", "left");
	        _todo_viewer.popupFrame("option", "offset", "-4px,0");
	        _todo_viewer.popupFrame("updatePosition", _anchor);
	        pw = _todo_viewer.outerWidth(true);// + _settings.outerWidth(true) + 30;
	        var offs = ar.right + pw - vr.right;
	        offs = offs < 0 ? -4 : -offs;
	        _todo_viewer.popupFrame("option", "offset", offs + "px,0");
	    } else {
	        _todo_viewer.popupFrame("option", "anchor", "left,top");
	        _todo_viewer.popupFrame("option", "direction", "left,down");
	        _todo_viewer.popupFrame("option", "arrow", "right");
	        _todo_viewer.popupFrame("option", "offset", "2px,0");
	    }

	    _todo_viewer.popupFrame("updatePosition", _anchor);

	    // adjust popup's top & arrow position
	    var skipArrowPos = false;
	    if (ar.top < vr.top || ar.bottom > vr.bottom) {
	       // calendar.getView().resetScroll(_eventObj.start.getHours());
	        ar = fcUtil.getElementRect(_anchor);
	        if (ar.top < vr.top) {
	            skipArrowPos = true;
	            var m = _todo_viewer.popupFrame("option", "offset").match(/^([+-]?\d+(\.\d+)?)(px)?,([+-]?\d+(\.\d+)?)(px)?/i);
	            var newOffs = m[1] + (m[3] ? m[3] : "") + "," +
						(vr.top - ar.top + parseInt(m[4], 10)) + (m[6] ? m[6] : "");
	            _todo_viewer.popupFrame("option", "offset", newOffs);
	        }
	    }
	    var pt = (Math.max(ar.top, vr.top) + Math.min(ar.bottom, vr.bottom) - ph) * 0.5;
	    var ap = 50;
	    if (!skipArrowPos) {
	        if (pt < vr.top) {
	            ap = Math.round((ph * 0.5 - vr.top + pt) * 100 / ph);
	        } else if (pt + ph > vr.bottom) {
	            ap = Math.round((ph * 0.5 + pt + ph - vr.bottom) * 100 / ph);
	        }
	    }
	    _todo_viewer.popupFrame("option", "arrowPosition", ap + "%");
	}
	function _openViewer(todoElem, elem) {
	    _list.addClass("modal");
	    _uiBlocker.show();
	    _todo_viewer.popupFrame("option", "showArrow", true);
	    _anchor = elem;
	    _adjustPopupPosition.call(_this);
	    _todo_viewer.popupFrame("close");
	    _todo_viewer.popupFrame("open", elem);
	    _uiBlocker.addClass("fc-modal-transparent");
	    if (todoElem != _curTodoElem) {
	        _editor.popupFrame("close");
	        _curTodoElem = todoElem;
	        _doDDX.call(_this, false, true);
	    }
	}

	function _openEditor(todoElem) {
		if (todoElem != _curTodoElem) {
			_editor.popupFrame("close");
			_curTodoElem = todoElem;
			_doDDX.call(_this);
		}
		_list.addClass("modal");
		_uiBlocker.show();
		_editor.popupFrame("open", { pageX: "center", pageY: "center" }, todoElem);
		_editor.find("#fc_todo_title").focus();
	}

	function _updateTodoList() {
	    
        var sources = calendar.getEventSources();
        for (var i = 0; i < sources.length; ++i) {
            var source = sources[i];
            if (source.todos && source.todos.length > 0) {
                source.todos = source.todos.filter(function (todo) {
                    return !!todo.objectId;
                });
            }
        }
        _renderList.call(_this);
	    
    }

	function _closeDeleteDialog() {
	    _deleteDialog.popupFrame("close");
	    _uiBlocker.hide();
	    _curTodoElem = null;
	}

	function _closeEditor() {
		_editor.popupFrame("close");
		_uiBlocker.hide();
		_list.removeClass("modal");

		_updateTodoList();
		calendar.openEventWin = null;
	}
	function _closeViewer() {
	    _todo_viewer.popupFrame("close");
	    _uiBlocker.hide();
	    _uiBlocker.removeClass("fc-modal-transparent");
	    _list.removeClass("modal");
	    calendar.openEventWin = null;
	}

	function _compileTodos(_sources) {
	    var todos = [];
	    var todosObj = {};
	    var sources = _sources ? _sources : calendar.getEventSources();
		for (var i = 0; i < sources.length; ++i) {
		    var source = sources[i];
			if (source.todos && source.todos.length > 0) {
				for (var j = 0; j < source.todos.length; ++j) {
					source.todos[j].source = source;
					source.todos[j].sourceIndex = i;
					source.todos[j].id = j;

				    todosObj[source.todos[j].objectId] = source.todos[j];
				}
				
			}
		}
	    
		for (var k in todosObj) {
		    todos.push(todosObj[k]);
		}
		return todos;
	}
    
	function _openDelDialog(todoElem) {
	    
	    _list.addClass("modal");
	    _uiBlocker.show();
	    _curTodoElem = todoElem;
	    _deleteDialog.popupFrame("open", { pageX: "center", pageY: "center" });

	}

	var _formatDate = function (d, fmt, monthnames, daynames) {
	    var
          c = '',
          r = [],
          escape = false,
          hours = d.getHours(),
          isam = hours < 12,
          day = '',
	      dateName = '';
	    monthnames = monthnames || ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
	    daynames = daynames || ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

	    if (fmt.search(/%p|%P/) !== -1) {
	        if (hours > 12) {
	            hours = hours - 12;
	        } else if (hours == 0) {
	            hours = 12;
	        }
	    }
	    if (window.moment) {
	        day = window.moment(d).calendar(null, {
	            lastWeek: 'dddd DD.MM.YYYY',
	            sameElse: 'dddd DD.MM.YYYY',
	            nextWeek: 'dddd DD.MM.YYYY'
	        }).split(' ')[0];
	        dateName = window.moment(d).calendar(null, {
	            sameDay: 'D MMMM',
	            nextDay: 'D MMMM',
	            nextWeek: 'D MMMM',
	            lastDay: 'D MMMM',
	            lastWeek: 'D MMMM',
	            sameElse: 'D MMMM'
	        }).split(' ')[1];
	    } else {
	        day = daynames[d.getDay()];
	    }
	    for (var i = 0, n = fmt.length; i < n; ++i) {
	        c = fmt.charAt(i);
	        if (escape) {
	            switch (c) {
	                case 'h': c = '' + hours; break;
	                case 'H': c = leftPad(hours); break;
	                case 'M': c = leftPad(d.getMinutes()); break;
	                case 'S': c = leftPad(d.getSeconds()); break;
	                case 'd': c = '' + d.getDate(); break;
	                case 'm': c = '' + (d.getMonth() + 1); break;
	                case 'y': c = '' + d.getFullYear(); break;
	                case 'b': c = '' + window.moment ? dateName : monthnames[d.getMonth()]; break;
	                case 'p': c = (isam) ? ('' + 'am') : ('' + 'pm'); break;
	                case 'P': c = (isam) ? ('' + 'AM') : ('' + 'PM'); break;
	                case 'D': c = '' + day; break;
	            }
	            r.push(c);
	            escape = false;
	        } else {
	            if (c == '%') {
	                escape = true;
	            } else {
	                r.push(c);
	            }
	        }
	    }
	    return r.join('');
	};
	var getDisplayDate = function (date) {
	    var displaydate = _formatDate(date, '%d %b, %D', ASC.Resources.Master.MonthNamesFull, ASC.Resources.Master.DayNamesFull);
	    return displaydate !== '' ? displaydate : date.toLocaleTimeString();
	};
	var leftPad = function (n) {
	    n = '' + n;
	    return n.length === 1 ? '0' + n : n;
	};

	var resolveNewTodoItemList = function (resolve) {
	    var containerDate = resolve.containerDate;
	    newTodoItemList(containerDate);
    };
    var newTodoItemList = function (date) {
        var _date = Date.parse(date) != 0 ? date : null;
        var id = _addNewTodo.call(_this, _date);
        if (id) {
            _curTodoElem = undefined;
            _renderList.call(_this);
	                    
            var newElem = _findTodoElement.call(_this, id.sourceIndex, id.todoId);
            newElem.find(".label").val('');
            newElem.find(".label").click();
        }
    }
	var changeTodoTitle = function () {
	    
	    var elem = $($(this).parent());
	    var sources = calendar.getEventSources();
	    var src = sources[elem.data("sourceIndex")];
	    var curTodo = src.todos[elem.data("todoId")];

	    var $lbl = $(this), text = $lbl.text(),
	    $txt = $('<input type="text" class="editable-label-text" maxlength="150" value="' + text + '" />');

	    var container = $($(elem).parent()[0]);
	    var containerDate = container.data("date") != null ? new Date(container.data("date")) : null;
	    
	    elem.addClass('edit');

        $lbl.replaceWith($txt);
        $txt.focus();

	    $txt.blur(function () {
	        var newText = $(this).val();
	        if (false != fcUtil.validateInput($(this), fcUtil.validateNonemptyString)) {
	            $lbl.text(newText);
	            curTodo.title = newText;
	            _updateTodo(curTodo);
	            elem.removeClass('edit');
	            $txt.replaceWith($lbl);
	            $lbl.click(changeTodoTitle);
	            _updateTodoList();
	        } else {
	            if (curTodo.objectId == undefined) {
	                calendar.cleanEmptyEventSources();
	                elem.detach();
	            }
	        }
          
        })
        .keydown(function (evt) {
            if (evt.keyCode == 13) {
                var newText = $(this).val();
                if (false != fcUtil.validateInput($(this), fcUtil.validateNonemptyString)) {
                    $lbl.text(newText);
                    curTodo.title = newText;

                    _updateTodo(curTodo, { resolve: true, containerDate: containerDate });

                    $lbl.click(changeTodoTitle);
                    $txt.replaceWith($lbl);
                    elem.removeClass('edit');
                    _curTodoElem = undefined;
                }
                else {
                    if (curTodo.objectId == undefined) {
                        calendar.cleanEmptyEventSources();
                        $txt.blur();
                    }
                }
            }
        });
    }

	function unique(arr) {
	    var obj = {};
	    var result = [];

	    for (var i = 0; i < arr.length; i++) {
	        var str = arr[i].objectId;
	        obj[str] = arr[i]; 
	    }
	    for (var j in obj) {
	        result.push(obj[j]);
	    }

	    return result;
	}

	function _renderList(resolveTodoList) {
		var items = _list.find(".content .items");
		items.empty();
		var todos = _compileTodos.call(_this);
		var sortTodos = todos.sort(function (a, b) {
		    return a.start - b.start;
		});
		var minDate = new Date(1, 0, 2, 23, 59, 59);

	    var now = new Date();
	    var today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59).valueOf();
	   
	    var lastTodoDate;
	    var container = null;
	    var counter = 0;

	    for (var j = 0; j < sortTodos.length; j++) {
	        var todo = sortTodos[j];

	        var todoDate = todo.start ? new Date(todo.start.getFullYear(), todo.start.getMonth(), todo.start.getDate(), 23,59,59).valueOf() : minDate.valueOf();

	        var containerClass = "";
	        var containerTitle = "";
	        
	        var day = todo.start ? getDisplayDate(todo.start).split(' ') : '';

	        counter++;
	        if (counter == sortTodos.length) {
	            if (container != null) container.appendTo(items);
	        }
	        if (todo.completed && calendar.hideCompletedTodos) {
	            continue;
	        }
	        
	        var li = $(
                    '<div class="content-li">' +
                        '<label><input type="checkbox"' + (todo.completed ? 'checked="checked"' : '') + ' class="bullet"/><span></span></label>' +
                        '<span class="label">' +
                            htmlEscape(todo.title ? todo.title : 'Unknown') + '</span> ' +
                         '<span class="description">' +
                            htmlEscape(todo.description ? todo.description : '') + '</span>' +
                        '<div class="edit-todo-button" title="' + htmlEscape(calendar.options.todoEditor.dialogHeader_edit) + '">' + calendar.options.todoList.editIcon + '</div>' +
                        '<div class="del-todo-button" title="' + htmlEscape(calendar.options.deleteTodoDialog.dialogHeader) + '">' + calendar.options.todoList.deleteIcon + '</div>' +
                    '</div>');


	        li.find(".bullet").change(function () {
	            _completeTodo.call(_this, $($(this).parent()).parent());
	        });
	        li.find(".label").click(changeTodoTitle);
	        
	        li.find(".edit-todo-button").click(function() {
	            _openEditor.call(_this, $(this).parent());
	        });
	        li.find(".del-todo-button").click(function () {
	            _openDelDialog.call(_this, $(this).parent());
	        });
	        
	        li.find(".description").click(function () {
                _openEditor.call(_this, $(this).parent());
	        });
	        if (todo.completed) {
	            li.addClass("completed");
	        }
	        li.data({ "sourceIndex": todo.sourceIndex, "todoId": todo.id });

	        if (lastTodoDate == todoDate) {
	            li.appendTo(container);
	        } else {
	            if (todoDate <= minDate.valueOf()) {
	                containerClass = "no_due_date";
	                containerTitle = htmlEscape(calendar.options.todoList.noDueDate);
	            } else if ((todoDate < today - 86400000) || (todoDate < today)) {
	                if (container != null && container.hasClass('overdue')) {
	                    li.appendTo(container);
	                    continue;
	                } else {
	                    containerClass = "overdue";
	                    containerTitle = htmlEscape(calendar.options.todoList.overdue);
	                }
	               
	            } else if (todoDate == today) {
	                containerClass = "today";
	                containerTitle = day.length > 0 ? day[day.length - 1] : '';
	            } else if (86400000 + today == todoDate) {
	                containerClass = "tomorrow";
	                containerTitle = day.length > 0 ? day[day.length - 1] : '';
	            } else {
	                containerClass = "future";
	                containerTitle = getDisplayDate(todo.start);
	            }

                if (container == null) {
                    container = $('<div class="todo-container ' + containerClass + '"><span class="title">' + containerTitle + '</span><span class="add-todo"></span></div>');
                    container.data({ "date": containerClass == "no_due_date" ? 0 : containerClass == "overdue" ? -1 : todoDate });
                    container.appendTo(items);
                } else {
                    container.appendTo(items);
                    container = $('<div class="todo-container ' + containerClass + '"><span class="title">' + containerTitle + '</span><span class="add-todo"></span></div>');
                    container.data({ "date": containerClass == "no_due_date" ? 0 : containerClass == "overdue" ? -1 : todoDate });
                }

                if (containerClass == "no_due_date" && _listStates['0'] != undefined) {
                    container.addClass(_listStates['0'] ? 'close' : '');
                } else if (containerClass == "overdue" && _listStates['-1'] != undefined) {
                    container.addClass(_listStates['-1'] ? 'close' : '');
                } else if (_listStates[todoDate] != undefined) {
                    container.addClass(_listStates[todoDate] ? 'close' : '');
                }
                _listStates[todoDate] = container.hasClass('close');
                container.find(".title").click(function () {
                    _openTodoContainer(this);
                });

                container.find(".add-todo").click(function () {
                    var containerDate = $($(this).parent()[0]).data("date");

                    _date = containerDate != null && containerDate != 0 && containerDate != -1 ? new Date(containerDate) : null;
                    var id = _addNewTodo.call(_this, _date);
                    if (id) {
                        _curTodoElem = undefined;
                        _renderList.call(_this);

                        var todoContainers = _list.find(".todo-container");
                        for (var i = 0; i < todoContainers.length; i++) {
                            if ($(todoContainers[i]).data("date") == containerDate) {
                                if ($(todoContainers[i]).hasClass("close")) _openTodoContainer($(todoContainers[i]).find(".title"));
                            }
                        }
                        var newElem = _findTodoElement.call(_this, id.sourceIndex, id.todoId);
                        newElem.find(".label").val('');
                        newElem.find(".label").click();
                    }
	            });

	            li.appendTo(container);
	        }
	        lastTodoDate = todoDate;
	        if (counter == sortTodos.length) {
	            container.appendTo(items);
	        }
	    }
	    if (resolveTodoList != undefined && typeof resolveTodoList == "object" && resolveTodoList.resolve) {
	        resolveNewTodoItemList(resolveTodoList);
	    } 
	}

	function _renderMenu() {
		if (!fcMenus.todoMenu || fcMenus.todoMenu.length < 1) {
		    //fcMenus.todoMenu = $("<div id='fc_todo_menu'/>");
		    fcMenus.todoMenu = $(calendar.options.todoList.menuTemplate); 
		} else {
			fcMenus.todoMenu.popupMenu("close");
			fcMenus.todoMenu.popupMenu("destroy");
		}
		fcMenus.todoMenu.popupMenu({
		    anchor: "left,bottom",
		    direction: "right,down",
			arrow: "up",
			showArrow: false,
			cssClassName: "asc-popupmenu",
		    closeTimeout: -1
		});
	    
		fcMenus.todoMenu.find('#todo-in-cal-check').prop('checked', localStorageManager.getItem("showTodosInCalendar"));
		fcMenus.todoMenu.find('#todo-in-cal-check').change(function () {
		    _hideTodosInCalendar.call(_this); 
		});
	    
		fcMenus.todoMenu.find('#del-mark-td-check').prop('checked', localStorageManager.getItem("hideCompletedTodos"));
		fcMenus.todoMenu.find('#del-mark-td-check').change(function () {
		    _hideCompletedTodos.call(_this);
		});
		fcMenus.todoMenu.find('#sync-lnk').click(function () {
		    _openTodoExportStream.call(_this, { pageX: "center", pageY: "center" });
		});
		
	}

	function _getTodoCalendar() {
        var sources = calendar.getEventSources();
        for (var i = 0; i < sources.length; i++) {
            if (sources[i].isTodo == 1) {
                return sources[i];
            }
        }
        return null;
    }

	function _closeTodoExportStream() {
	    _icalStream.popupFrame("close");
	    _uiBlocker.hide();
	}

    var timerId;

    function updateTodoExportStream() {
        var todoCalendar = _getTodoCalendar();

        var linkContainer = _icalStream.find(".url-link.caldav");
        linkContainer.show();
        linkContainer.find(".control").removeClass('success').removeClass('failure').addClass('disabled').addClass('processing');
        linkContainer.find(".control input").attr('disabled', 'disabled');
            
        var counter = 0, preparingMessage = ic.dialogPreparingMessage;
        timerId = setInterval(function() {
            preparingMessage = preparingMessage + ".";
            if (counter == 4) {
                preparingMessage = ic.dialogPreparingMessage;
                counter = 0;
            }
            linkContainer.find(".control input").val(preparingMessage);
            counter++;
        }, 500);

        calendar.trigger("getCaldavUrl", _this, todoCalendar != null ? todoCalendar.objectId : 'todo_calendar', function (response) {
            clearInterval(timerId);
            if (response.result) {
                var preparingErrorMessage = ic.dialogPreparingErrorMessage;
                if (response.url != "" && linkContainer) {
                    linkContainer.find(".control input").val(response.url);
                    linkContainer.find(".control input").removeAttr("disabled");
                    linkContainer.find(".control").removeClass("disabled").removeClass('processing').addClass('success');
                } else {
                    linkContainer.find(".control input").val(preparingErrorMessage);
                    linkContainer.find(".control").removeClass('processing').addClass('failure');
                }
            }
        });

    }

    function _openTodoExportStream(anchor) {

        _icalStream.find((".url-link .control .button.try-again")).click(function () {
            clearInterval(timerId);
            updateTodoExportStream();
        });

        updateTodoExportStream();
        _uiBlocker.show();
        _icalStream.width(372);
        _icalStream.popupFrame("open", anchor);

    }

	function _renderSortMenu() {
		if (!fcMenus.sortMenu || fcMenus.sortMenu.length < 1) {
			fcMenus.sortMenu = $("<div id='fc_todo_sort_menu'/>");
		} else {
			fcMenus.sortMenu.popupMenu("close");
			fcMenus.sortMenu.popupMenu("destroy");
		}
		fcMenus.sortMenu.popupMenu({
			anchor: "right,top",
			direction: "left,up",
			arrow: "down",
			cssClassName: "asc-popupmenu",
			items: [
				{
					label: calendar.options.todoList.sortByCalendarLabel,
					click: function(event, data) {
						_sortType = 0;
						_sortLabel.text(calendar.options.todoList.sortByCalendarLabel);
						_renderList.call(_this);
					}
				},
				{
					label: calendar.options.todoList.sortByPriorityLabel,
					click: function(event, data) {
						_sortType = 1;
						_sortLabel.text(calendar.options.todoList.sortByPriorityLabel);
						_renderList.call(_this);
					}
				},
				{
					label: calendar.options.todoList.sortAlphabeticallyLabel,
					click: function(event, data) {
						_sortType = 2;
						_sortLabel.text(calendar.options.todoList.sortAlphabeticallyLabel);
						_renderList.call(_this);
					}
				}
			]
		});
	}
	function _validateDateFields(result) {
	    var dlg = {
	        date: _editor.find(".date")
	    };

	    var frDate = {}, fr = _parseDateTime(dlg.date, frDate);
	    frDate.dateTime = fr == 1 ? parseDate(frDate.date.value + "T23:59:59") : null;

	    var frc, r;
	    if (fr == 1) {
	        r = true;
	        frc = "";
	    } else {
	        r = false;
	        frc = frDate.date.isValid ? "" : "#cc3300";
	    }
	    dlg.date.css("color", "").css("border-color", frc);

	    if (result != undefined) {
	        result.data = frDate;
	    }
	    return r;
	}
	function _renderTodoEditor() {
		
	    _editor = $(calendar.options.todoEditor.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("fc-shadow")
				.popupFrame({
					anchor: "left,bottom",
					direction: "right,down",
					showArrow: false,
					showModal: true,
				});
	    _todo_viewer = $(calendar.options.todoViewer.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("fc-shadow")
				.popupFrame({
				    anchor: "right,top",
				    direction: "right,down",
				    offset: "-2px,0",
				    arrow: "left",
				    arrowPosition: "50%",
				    showArrow: false
				});
	    _deleteDialog = $(calendar.options.deleteTodoDialog.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("fc-shadow")
				.popupFrame({
				    anchor: "left,bottom",
				    direction: "right,down",
				    showArrow: false,
				    showModal: true,
				});
	    
	    var date = _editor.find(".date");
	    

	    function loadDate(input, dp, defDate) {
	        var d = parseISO8601(input.val());
	        dp.datepicker("setDate", (d instanceof Date) ? d : defDate);
	    }
	    function saveDate(input, dp) {
	        input.val(formatDate(
					dp.datepicker("getDate"),
					calendar.options.eventEditor.dateFormat));
	        input.change();
	    }
	    _editor.find(".cal-icon").click(function () {
	        fcDatepicker.open(calendar, this,
					function (dp) { loadDate(date, dp, null); },
					function (elem, dp) {
					    this.close();
					    saveDate(date, dp);
					});
	    });
	    
	    function getCaret(el) {
	        if (el.selectionStart) {
	            return el.selectionStart;
	        } else if (document.selection) {
	            el.focus();
 
	            var r = document.selection.createRange();
	            if (r == null) {
	                return 0;
	            }
	            var re = el.createTextRange(),
                        rc = re.duplicate();
	            re.moveToBookmark(r.getBookmark());
	            rc.setEndPoint('EndToStart', re);
 
	            return rc.text.length;
	        }
	        return 0;
	    }
	    _editor.keypress(function (e) {
	       if ((event.keyCode == 10 || event.keyCode == 13) && event.ctrlKey) {
	            var $fcTodoDescription = _editor.find('#fc_todo_description');
	            if($fcTodoDescription.is(":focus"))
	            {
	                var caret = getCaret(document.getElementById('fc_todo_description'));
	                var str = $fcTodoDescription.val();
	                var fersPat = str.substr(0, caret);
	                var secondPat = str.substr(caret);
	                $fcTodoDescription.val(fersPat + '\n' + secondPat);
	                document.getElementById('fc_todo_description').setSelectionRange(caret + 1, caret + 1);
	            }
	       }else if(e.which == 13) {
	           _doDDX.call(_this, true);
	       }
	    });
	    _editor.find(".time").mask("00:00");
	    _editor.find(".time, .date")
				.bind("keyup change", function(result) {
					if (!!$(this).val()) _validateDateFields(result);
					else $(this).css("border-color", "");
				});

	    _editor.find("#fc_todo_title").keyup(function () { fcUtil.validateInput(this, fcUtil.validateNonemptyString); });

		_editor.find("#fc_todo_ok").click(function() {
			_doDDX.call(_this, true);
		});
		_editor.find(".close-btn").click(function () {
		    _closeEditor.call(_this);
		});
		_editor.find("#fc_todo_cancel").click(function() {
			_closeEditor.call(_this);
		});
	    

		_deleteDialog.find(".save-btn").click(function () {
		    _deleteTodo.call(_this, _curTodoElem);
		});
		_deleteDialog.find(".close-btn").click(function () {
		    _closeDeleteDialog.call(_this);
		});
		_deleteDialog.find(".cancel-btn").click(function () {
		    _closeDeleteDialog.call(_this);
		});
	    
		_todo_viewer.find(".mark-btn").click(function () {
		    _completeTodo.call(_this, _curTodoElem);
		    _closeViewer.call(_this);
		});
		_todo_viewer.find(".edit-btn").click(function () {
		    _closeViewer.call(_this);
		    _openEditor.call(_this, _curTodoElem);
		});
		_todo_viewer.find(".delete-btn").click(function () {
		    _closeViewer.call(_this);
		    _openDelDialog.call(_this, _curTodoElem);
		});
				
	}

	function _addNewTodo(todaDate) {
		var sources = calendar.getEventSources();
		if (sources.length < 1) {return null;}
		var todo = {
			title: " ",
			completed: false,
			start: todaDate ? todaDate : null
		};
		sources[0].todos.push(todo);
		return {sourceIndex: 0, todoId: sources[0].todos.length - 1};
	}

	function _findTodoElement(sourceIndex, todoId) {
		var e = _list.find(".content .items .content-li").filter(function() {
					var li = $(this);
					return li.data("sourceIndex") == sourceIndex && li.data("todoId") == todoId;
				});
		return e.length > 0 ? e : null;
	}

	function _deleteCompletedTodos() {
		var sources = calendar.getEventSources();
		for (var i = 0; i < sources.length; ++i) {
			var src = sources[i];
			if (!src.todos || src.todos.length < 1) {continue;}
			for (var j = 0; j < src.todos.length; ++j) {
				if (src.todos[j].completed) {
					src.todos.splice(j, 1);
				}
			}
		}
		_renderList.call(_this);
	}

	function _hideTodosInCalendar() {
	    calendar.showTodosInCalendar = !calendar.showTodosInCalendar;
	    localStorageManager.setItem("showTodosInCalendar", calendar.showTodosInCalendar);
	    calendar.fetchEvents(calendar.getView().visStart, calendar.getView().visEnd);
	}
	function _hideCompletedTodos() {
	    calendar.hideCompletedTodos = !calendar.hideCompletedTodos;
        localStorageManager.setItem("hideCompletedTodos", calendar.hideCompletedTodos);
	    
	    _renderList.call(_this);
	    calendar.fetchEvents(calendar.getView().visStart, calendar.getView().visEnd);
	    
	}

	function _completeTodo(todoElem) {
		var elem = $(todoElem);
		var source = calendar.getEventSources()[elem.data("sourceIndex")];
		var todo = source.todos[elem.data("todoId")];
		todo.completed = !todo.completed;

		var _elem = $(todoElem);
		var sources = calendar.getEventSources();
		var src = sources[_elem.data("sourceIndex")];
		
		var curTodo = src.todos[elem.data("todoId")];
		_updateTodo(curTodo);
		_curTodoElem = undefined;
		if (todo.completed) _elem.addClass("completed");
		else _elem.removeClass("completed");
		//_renderList.call(_this);
	}

	function _deleteTodo(todoElem) {
	    var elem = $(todoElem);
	    var sources = calendar.getEventSources();
	    var todo = sources[elem.data("sourceIndex")].todos[elem.data("todoId")];
	    
	    calendar.trigger("editTodo", _this,
                 $.extend(
                         { action: kTodoDeleteAction },
                         todo),
                 function (response) {
                     if (response.result) {
                         
                         var cache = calendar.getCache();
                         for (var i = 0; i < sources.length; ++i) {
                             if (sources[i].todos && sources[i].todos.length > 0) {
                                 sources[i].todos = sources[i].todos.filter(function (_todo) {
                                     return _todo.objectId != todo.objectId;
                                 });
                             }
                         }
                         for (var j = 0; j < cache.length; ++j) {
                             if (cache[j].objectId == todo.objectId) {
                                 cache.splice(j, 1);
                                 break;
                             }
                         }
                         calendar.reportEvents(cache);
                         _renderList.call(_this);
                         _closeDeleteDialog.call(_this);
                     }

                 });
    }

	this.render = function() {
		var result = $(
				"<div>" +
					"<div class='fc-todo-list'>" +
						"<div class='content'>" +
							"<div class='content-h'>" +
								"<span class='label'>" + htmlEscape(calendar.options.todoList.title) + "</span>" +
								//"<span class='fc-dropdown'>&nbsp;</span>" +
								"<span class='fc-settings' title='" + htmlEscape(calendar.options.categories.subscriptionsManageLabel) + "'>" + calendar.options.todoList.settingsIcon + "</span>" +
                                "<div class='close-btn' title='" + htmlEscape(calendar.options.categories.dialogButton_cancel) + "'>&times;</div>" +
							"</div>" +
							"<div class='items'/>" +
				            "<span class='add-btn'>" +
				                htmlEscape(calendar.options.todoList.addTodoLabel) +
				            "<span class='add-todo'></span>" +
							"</span>" +
						/*	"<div class='sort-label'>" +
								"<span class='label'>" +
									htmlEscape(calendar.options.todoList.sortByCalendarLabel) + "</span>" +
								"<span class='fc-dropdown'>&nbsp;</span>" +
							"</div>" +*/
						"</div>" +
						"<div class='fc-modal'/>" +
					"</div>" +
				"</div>"
				);

		_list = result.find(".fc-todo-list");
		_sortLabel = result.find(".sort-label .label");

		result.find(".add-btn").click(function() {
		    _this.addNewTodo();
		});

		result.find(".content-h .close-btn").click(function () {
		    
		    var fc_container = $('#fc_container');
		    fc_container.toggleClass('open-todo-list');
		    fc_container.find('.fc-button-todo').toggleClass('fc-state-active');
		   
		});

		result.find(".content-h .label, .content-h .fc-settings").click(function() {
			fcMenus.hideMenus(fcMenus.todoMenu);
			fcMenus.todoMenu.popupMenu("open", $(this).parent().find(".label"));
		});
		result.find(".sort-label .label, .sort-label .fc-dropdown").click(function() {
			fcMenus.hideMenus(fcMenus.sortMenu);
			fcMenus.sortMenu.popupMenu("open", $(this).parent().find(".label"));
		});
		_uiBlocker = result.find(".fc-modal").click(function () {
            _closeEditor.call(_this);
            _closeDeleteDialog.call(_this);
            _closeTodoExportStream.call(_this);
            _closeViewer.call(_this);
		});

		_renderList.call(this);
		_renderMenu.call(this);
		_renderSortMenu.call(this);
		_renderTodoEditor.call(this);

		return result.children();
	};

	this.createTodo = function (todo) {
	    _updateTodo(todo);
	    _curTodoElem = undefined;
	    _renderList.call(_this);
	    _closeEditor.call(_this);
	};
    
	this.openTodoEditor = function (todo, elem) {
	    var todos = $('.fc-todo-list .content-li');
	    for (var i = 0; i < todos.length; i++) {
	        if ($(todos[i]).data("todoId") == todo.id) {
			    _openViewer.call(_this, todos[i], elem);
			}
		}
		
	};
    this.updateTodo = function(todo) {
        _updateTodo(todo);
    };

    this.getTodoElem = function() {
        return _curTodo;
    };
	

    this.rerenderList = function (resolveTodoList) {
        _renderList.call(this, resolveTodoList); 
	};

	this.resize = function(newHeight) {
		_list.css("height", newHeight + "px");
	};

	this.addNewTodo = function() {
		var id = _addNewTodo.call(_this);
		if (id) {
			_curTodoElem = undefined;
			_renderList.call(_this);
			var newElem = _findTodoElement.call(_this, id.sourceIndex, id.todoId);
			if (newElem) {
				_openEditor.call(_this, newElem[0]);
			}
		}
	};

	this.show = function() {
		_list.parent().removeClass("hidden");
		_list.show();
		calendar.updateSize();
	};

	this.hide = function() {
		_list.hide();
		_list.parent().addClass("hidden");
		calendar.updateSize();
	};

}


function EventEditor(calendar, uiBlocker) {
	var _this = this;
	
	// repeat settings options
	var rs = calendar.options.repeatSettings;
	var ds = calendar.options.deleteSettings;
	var cp = calendar.options.confirmPopup;

	var _modes = {
	    view:                       _viewMode,
	    todo:                       _todoMode,
	    edit:                       _editMode,
		addDialog:					_addDialogMode,
		addPopup:					_addPopupMode,
		addPopupDelSettings:		_addPopupDelSettings
	};
	
	var dwm = {
		day:     0,
		week:    1,
		month:   2,
		year:    3
	};

    var deleteMode = {
        single: 0,
        allFollowing: 1,
        allSeries: 2
    };
	
    var confirmSettings = {
        viewMode: {
            none: 0,
            addEvent: 1,
            updateEvent: 2,
            updateGuests: 3,
            deleteEvent: 4
        },
        notificationMode: {
            nobody: 0,
            partially: 1,
            everybody: 2
        },
        notificationType: {
            request: 1,
            update: 2,
            cancel: 4
        },
        notificationUsers: {
            newGuests: [],
            removedGuests: [],
            updatedGuests: []
        },
        selectedViewMode: 0,
        selectedNotificationMode: 0,
        selectedDeleteMode: 0
    };

	var _dialog;

	var alertType = kAlertDefault;								// number
    var repeatRule = ASC.Api.iCal.RecurrenceRule.EveryDay;	// standart or custom object rules
	var dwm_current = dwm.day;
	var dayRuleObject = undefined;
	
	var _settings;
	var _delSettings;
	var _confirmPopup;
	var _dialogMode;
	var _permissionsList;

	var _anchor;
	var _eventObj;
	var _todoObj;
	var _canEdit;
	var _canDelete;
	var _canChangeSource;
	var _canUnsubscribe;

	var formatDate = calendar.formatDate;
	var formatDates = calendar.formatDates;

    var _editModes = {
        event: 0,
        todo: 1
    };
    var _editMode = _editModes.event;

	(function _create() {
		_dialog = $(calendar.options.eventEditor.dialogTemplate)
				.addClass("asc-dialog")
				.addClass("fc-shadow")
				.popupFrame({
					anchor: "right,top",
					direction: "right,down",
					offset: "-2px,0",
					arrow: "left",
					arrowPosition: "50%",
					showArrow: false
				});
		
		_dialog.find(".buttons .edit-btn").click(function() {
			//if (_canEdit) {
			//	_resetMode.call(_this);
			//	_dialogMode = false;
			//	_dialog.addClass("edit-popup");
			//	_dialog.popupFrame("updatePosition", _anchor);
				
			//	_enableRepeatSettings.call(_this);
			//	_setRepeatSettingsHeight.call(_this);
		    //}
		    _close.call(_this, false);
		    calendar.showEventPageViewer(_canEdit, _anchor, _eventObj);
		});

		function updateMode(currentBtn) {

		    _dialog.find(".buttonGroup span.active").removeClass('active');
		    currentBtn.addClass('active');
		    
			var mode;
			var s = calendar.getEventSources();
		    if (currentBtn.hasClass('event')) {
		        _editMode = _editModes.event;
				mode = 'edit';
				var calendarId = _dialog.find(".editor .calendar select").val();
				for (var i = 0; i < s.length; ++i) {
					if (s[i].objectId == calendarId) {
						_anchor.find(".fc-event-skin, .fc-event-skin-day")
							.css("border-color", s[i].backgroundColor)
							.css("background-color", s[i].backgroundColor)
							.css("color", s[i].textColor);
						$(_anchor.find(".fc-event-skin, .fc-event-skin-day")).parent()
							.css("border-color", s[i].backgroundColor)
							.css("background-color", s[i].backgroundColor)
							.css("color", s[i].textColor);
					}
				}
		    } else {
		        _editMode = _editModes.todo;
				mode = 'todo';
				for (var i = 0; i < s.length; ++i) {
					if (s[i].isTodo == 1) {
						_anchor.find(".fc-event-skin, .fc-event-skin-day")
							.css("border-color", s[i].backgroundColor)
							.css("background-color", s[i].backgroundColor)
							.css("color", s[i].textColor);
						$(_anchor.find(".fc-event-skin, .fc-event-skin-day")).parent()
							.css("border-color", s[i].backgroundColor)
							.css("background-color", s[i].backgroundColor)
							.css("color", s[i].textColor);
                    }
				}
		    }
		    _modes[mode].call(_this);
	    }

		_dialog.find(".buttonGroup span").click(function () {
			updateMode($(this));
		});
		_dialog.find(".buttonGroup span").on('touchstart', function (e) {
		    
		    updateMode($(this));
		    
		    e.preventDefault();
		    
		    _dialog.find('.title input').click().focus();
		});
		_dialog.find(".buttons .save-btn").click(function() {
		    if (jq(this).hasClass("disable"))
		        return;
		    
		    if (_editMode == _editModes.event) {
		        var hasSettings = !_settings.hasClass("hidden");
		        if (hasSettings) {
		            if (!_validateDateFieldsSettings.call(_this)) {
		                return;
		            }
		            _closeSettings.call(_this, hasSettings);
		        }
		    }
		    _close.call(_this, true);
		   
		});
		_dialog.find(".buttons .close-btn").click(function() {
		    _close.call(_this, false);
		    calendar.showEventPageViewer(_canEdit, _anchor, _eventObj);
		});
		_dialog.find(".buttons .delete-btn").click(function() {
			if (_canDelete) {
			    _openDelSettings.call(_this, "addPopupDelSettings", _eventObj.repeatRule.Freq == ASC.Api.iCal.Frequency.Never);
			}
		});
		_dialog.find(".buttons .unsubs-btn").click(function() {
			if (_canUnsubscribe) {
			    _unsubscribeEvent.call(_this);
			}
		});
	    
		_dialog.find(".buttons .view-details").click(function() {
		    _close.call(_this, false);
		    _doDDX.call(_this, true, true);
		    calendar.showEventPageViewer(_canEdit, _anchor, _eventObj);
		});
		
		_renderRepeatAlertList.call(_this);
		
		//
		_permissionsList = new PermissionsList(calendar, _dialog.find(".editor .shared-list"),
				calendar.options.sharedList.addLink);
		_permissionsList.setEventsHandlers({
					context:   _this,
					onResize: _resizePopup,
					onChange: _updatePermissions
				});
	    //
	    
		_dialog.find(".viewer .reply-buttons .accepted").click(function() {
		    if(!jq(this).hasClass("active"))
		        _eventReply(true);
		});
		_dialog.find(".viewer .reply-buttons .tentative").click(function() {
		    if(!jq(this).hasClass("active"))
		        _eventReply();
		});
		_dialog.find(".viewer .reply-buttons .declined").click(function() {
		    if(!jq(this).hasClass("active"))
		        _eventReply(false);
		});

		_dialog.find(".editor .title input").keyup(function() {fcUtil.validateInput(this, fcUtil.validateNonemptyString);});
		_dialog.find(".editor .all-day input").click(_handleAllDayClick);
		
		_dialog.find(".editor .all-day .label").css("cursor", "pointer").click(function() {
			_dialog.find(".editor .all-day .cb").trigger("click");
			_handleAllDayClick.call(_this);
		});
		//
		function loadDate(input, dp, defDate) {
			var d = parseISO8601(input.val());
			dp.datepicker("setDate", (d instanceof Date) ? d : defDate);
		}
		function saveDate(input, inputT, dp) {
			input.val(formatDate(
					dp.datepicker("getDate"),
					calendar.options.eventEditor.dateFormat));
			if (!inputT.is(":disabled") && $.trim(inputT.val()).length < 1) {
				inputT.val("00:00");
			}
			input.change();
		}
		var fromD = _dialog.find(".editor .from-date");
		var fromT = _dialog.find(".editor .from-time");
		
		var toD   = _dialog.find(".editor .to-date");
		var toT   = _dialog.find(".editor .to-time");
	    
		var todoD = _dialog.find(".editor .todo_editor .date");
		var todoT = _dialog.find(".editor .todo_editor .time");
	    
		_dialog.find(".editor .todo_editor .cal-icon").click(function () {
		    fcDatepicker.open(calendar, this,
					function (dp) { loadDate(todoD, dp, _eventObj.start); },
					function (elem, dp) {
					    this.close();
					    saveDate(todoD, todoT, dp);

					});
		});
	    
		
		_dialog.find(".editor .from.cal-icon").click(function() {
			fcDatepicker.open(calendar, this,
					function(dp) {loadDate(fromD, dp, _eventObj.start);},
					function(elem, dp) {
						this.close();
						saveDate(fromD, fromT, dp);
						
						var fromD_settings = _settings.find(".from-date");
						var fromT_settings = _settings.find(".from-time");
						saveDate(fromD_settings, fromT_settings, dp);
					});
		});
		_dialog.find(".editor .to.cal-icon").click(function() {
			fcDatepicker.open(calendar, this,
					function(dp) {loadDate(toD, dp, _eventObj.end||_eventObj.start);},
					function(elem, dp) {
						this.close();
						saveDate(toD, toT, dp);
					});
		});
		//
		_dialog.find(".editor .from-time, .editor .to-time").mask("00:00");
		_dialog
			.find(".editor .from-date, .editor .from-time, .editor .to-date, .editor .to-time")
			.bind("keyup change", function (result) {
				var r = _validateDateFields(result)
				if (r && !($(result.currentTarget).hasClass('from-time') || $(result.currentTarget).hasClass('to-time'))) {
					updateEditorView();
				}
			});
	    //
	    
		_dialog.find(".editor .todo_editor .time").mask("00:00");
		_dialog
				.find(".editor .todo_editor .date, .editor .todo_editor .time")
				.bind("keyup change", _validateTodoDateFields);
	    //
		_dialog.find(".editor .calendar select").change(function (ev) {
			var v = $(this).val();
			var s = calendar.getEventSources();
			for (var i = 0; i < s.length; ++i) {
				if (s[i].objectId != v) { continue; }
				if (s[i].isTodo == 1) { continue; }
				_dialog.find(".editor .calendar .bullet").css("background", s[i].backgroundColor);

				if (!_anchor.length) return;

				if (_anchor.is(".fc-event-skin-day")) {
					_anchor
						.css("border-color", s[i].backgroundColor)
						.css("background-color", s[i].backgroundColor)
						.css("color", s[i].textColor);
					_anchor.find(".fc-event-skin, .fc-event-skin-day")
						.css("border-color", s[i].backgroundColor)
						.css("background-color", s[i].backgroundColor)
						.css("color", s[i].textColor);
				} else {
					_anchor.find(".bullet").css("color", s[i].backgroundColor);
				}

				return;
			}
		});
		//
		if (uiBlocker && uiBlocker.length > 0) {
		    uiBlocker.click(function() {
		        if(_dialog.is(":visible")) {
		            _close.call(_this, false);
		            _closeSettings.call(_this, false);
		        }
		    });
		}
	}());

	function updateEditorView(isTodo) {
		var frDate = {}, fr = _parseDateTime(_dialog.find(".editor .from-date"), _dialog.find(".editor .from-time"), frDate);
		var toDate = {}, to = _parseDateTime(_dialog.find(".editor .to-date"), _dialog.find(".editor .to-time"), toDate);
		var start = fr == 1 ? parseDate(frDate.date.value + "T" + frDate.time.value) : null;
		var end = to == 1 ? parseDate(toDate.date.value + "T" + toDate.time.value) : null;

		if (!start || !end) {
			return;
		}

		_close.call(_this, false);

		var allDay = _dialog.find(".editor .all-day input").is(":checked");

		_eventObj.title = _dialog.find('.title input').val();

		_eventObj.start = start;
		_eventObj._start = start;
		_eventObj.end = isTodo ? start : end;
		_eventObj._end =  isTodo ? start : end;

		_eventObj.allDay = !isTodo ? allDay : true;
		_eventObj.location = _dialog.find(".editor .location input").val();

		var s = calendar.getEventSources();
		if (_dialog.find(".editor .calendar select").val() == null && !isTodo) {
			_eventObj.afretResizeSource = s[2];
			_eventObj.textColor = s[2].textColor;
			_eventObj.backgroundColor = s[2].backgroundColor;
			_eventObj.borderColor = s[2].borderColor;
		} else {
			for (var i = 0; i < s.length; ++i) {
				if (s[i].objectId == _dialog.find(".editor .calendar select").val() && !isTodo) {
					_eventObj.afretResizeSource = s[i];
					_eventObj.textColor = s[i].textColor;
					_eventObj.backgroundColor = s[i].backgroundColor;
					_eventObj.borderColor = s[i].borderColor;
				} else if (isTodo && s[i].isTodo == 1) {
					_eventObj.afretResizeSource = s[i];
					_eventObj.textColor = s[i].textColor;
					_eventObj.backgroundColor = s[i].backgroundColor;
					_eventObj.borderColor = s[i].borderColor;
				}
			}
        }
		

		calendar.renderEvent(_eventObj);

		var eventElement = calendar.getView().getEventElement(_eventObj);

		if (!eventElement) {
			return;
		}

		_open.call(_this, "addPopup", eventElement, _eventObj);
	}

	function _showDaySections(){
		_settings.find(".fc-days-week").addClass("hidden");
		_settings.find(".fc-month-radio").addClass("hidden");
	}
		
	function _showWeekSections(){
		_settings.find(".fc-month-radio").addClass("hidden");
		_settings.find(".fc-days-week").removeClass("hidden");
	}
		
	function _showMonthSections(){
		_settings.find(".fc-days-week").addClass("hidden");
		_settings.find(".fc-month-radio").removeClass("hidden");
	}
	
	function _showEndSectionsNever(){
		_settings.find(".fc-repeat-cycles").addClass("hidden");
		_settings.find(".fc-end-date").addClass("hidden");
	}
	
	function _showEndSectionsCycles(){
		_settings.find(".fc-end-date").addClass("hidden");
		_settings.find(".fc-repeat-cycles").removeClass("hidden");
		_validateDateFieldsSettings.call(_this);
	}
	
	function _showEndSectionsDate(){
		_settings.find(".fc-repeat-cycles").addClass("hidden");
		_settings.find(".fc-end-date").removeClass("hidden");
		_validateDateFieldsSettings.call(_this);
	}
	
	function _getEndDate(mode) {
		var startDate = parseISO8601(_settings.find(".from-date").val());
		var interval = parseInt(_settings.find(".fc-interval-selector").find("option:selected").text(), 10);
		
		switch (mode) {
			case dwm.day: 
				return calendar.formatDate(new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate() + interval + 1, 0, 0, 0), rs.dateFormat);
			case dwm.week: 
				return calendar.formatDate(new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate() + interval*7 + 1, 0, 0, 0), rs.dateFormat);
			case dwm.month: 
				return calendar.formatDate(new Date(startDate.getFullYear(), startDate.getMonth() + interval, startDate.getDate() + 1, 0, 0, 0), rs.dateFormat);
			case dwm.year: 
				return calendar.formatDate(new Date(startDate.getFullYear() + interval, startDate.getMonth(), startDate.getDate() + 1, 0, 0, 0), rs.dateFormat);
			}
	}
	
	// create settings dialog
	(function _createSettings() {
		_settings = _dialog.find(".repeat-settings");
		
		_settings.find(".buttons .save-btn").click(function() {
		    if (jq(this).hasClass("disable"))
		        return;
		    
		    _closeSettings.call(_this, true);
		});
		_settings.find(".buttons .cancel-btn, .buttons .close-btn, .header .close-btn").click(function() {
			_closeSettings.call(_this, false);
		});
		
		// day/week/month selector
		var _DWMSelectorLabel = _settings.find(".fc-dwm-selector");
		
		_settings.find(".fc-dwm-selector").click(
			function (event) {
				
				if ($(this).find(".fc-selector-link").hasClass("not-active")) {
					return false;
				}
				
				fcMenus.hideMenus(fcMenus.modeMenuDWM);
				fcMenus.modeMenuDWM.popupMenu("open", _DWMSelectorLabel);
				event.stopPropagation();
			});
			
			if (!fcMenus.modeMenuDWM || fcMenus.modeMenuDWM.length < 1) {
				fcMenus.modeMenuDWM = $('<div id="fc_mode_menu_dwm"/>');
			} else {
				fcMenus.modeMenuDWM.popupMenu("close");
				fcMenus.modeMenuDWM.popupMenu("destroy");
			}
			fcMenus.modeMenuDWM.popupMenu({
				anchor: "left,bottom",
				direction: "right,down",
				arrow: "up",
				showArrow: false,
				closeTimeout: -1,
				cssClassName: "asc-popupmenu",
				items: [
					{
						label: rs.dialogRepeatOn_days,
						click: function() {
							_DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_days);
							_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_day);
							dwm_current = dwm.day;
							_showDaySections.call(_this);
							_settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
							}
					},
					{
						label: calendar.options.repeatSettings.dialogRepeatOn_weeks,
						click: function() {
							_DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_weeks);
							_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_week);
							dwm_current = dwm.week;
							_showWeekSections.call(_this);
							_settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
							}
					},
					{
						label: calendar.options.repeatSettings.dialogRepeatOn_months,
						click: function() {
							_DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_months);
							_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_month);
							dwm_current = dwm.month;
							_showMonthSections.call(_this);
							_settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
							}
					},
					{
						label: calendar.options.repeatSettings.dialogRepeatOn_years,
						click: function() {
							_DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_years);
							_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_year);
							dwm_current = dwm.year;
							_showDaySections.call(_this);
							_settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
							}
					}
				]
			});
			
		// end of repeat selector
		var _endRepeatSelectorLabel = _settings.find(".fc-endrepeat-selector");
		
		_settings.find(".fc-endrepeat-selector").click(
			function (event) {
				
				if ($(this).find(".fc-selector-link").hasClass("not-active")) {
					return false;
				}
				
				fcMenus.hideMenus(fcMenus.modeMenuEndRepeat);
				fcMenus.modeMenuEndRepeat.popupMenu("open", _endRepeatSelectorLabel);
				event.stopPropagation();
			});
			
			if (!fcMenus.modeMenuEndRepeat || fcMenus.modeMenuEndRepeat.length < 1) {
				fcMenus.modeMenuEndRepeat = $('<div id="fc_mode_menu_end_repeat"/>');
			} else {
				fcMenus.modeMenuEndRepeat.popupMenu("close");
				fcMenus.modeMenuEndRepeat.popupMenu("destroy");
			}
			fcMenus.modeMenuEndRepeat.popupMenu({
				anchor: "left,bottom",
				direction: "right,down",
				arrow: "up",
				showArrow: false,
				closeTimeout: -1,
				cssClassName: "asc-popupmenu",
				items: [
					{
						label: calendar.options.repeatSettings.dialogOptionNever,
						click: function() {
							_endRepeatSelectorLabel.find(".fc-selector-link").text(rs.dialogOptionNever);
							_showEndSectionsNever.call(_this);
							}
					},
					{
						label: calendar.options.repeatSettings.dialogOptionCount,
						click: function() {
							_endRepeatSelectorLabel.find(".fc-selector-link").text(rs.dialogOptionCount);
							_settings.find(".fc-cycle-times").val(3);
							_showEndSectionsCycles.call(_this);
							}
					},
					{
						label: calendar.options.repeatSettings.dialogOptionDate,
						click: function() {
							_endRepeatSelectorLabel.find(".fc-selector-link").text(rs.dialogOptionDate);
							_settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
							_showEndSectionsDate.call(_this);
							}
					}
				]
			});
		
		//
		function loadDate(input, dp, defDate) {
			var d = parseISO8601(input.val());
			dp.datepicker("setDate", (d instanceof Date) ? d : defDate);
		}
		function saveDate(input, inputT, dp) {
			input.val(formatDate(
					dp.datepicker("getDate"),
					rs.dateFormat));
			if (!inputT.is(":disabled") && $.trim(inputT.val()).length < 1) {
				inputT.val("00:00");
			}
			input.change();
		}
		
		var fromD = _settings.find(".from-date");
		var fromT = _settings.find(".from-time");
		var toD = _settings.find(".to-date");
		var toT = _settings.find(".to-time");
		
		_settings.find(".from.cal-icon").click(function() {
			
			if (_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").hasClass("not-active")) {
				return false;
			}
			
			fcDatepicker.open(calendar, this,
					function(dp) {loadDate(fromD, dp, _eventObj.start);},
					function(elem, dp) {
						this.close();
						saveDate(fromD, fromT, dp);
						
						var fromD_parent = _dialog.find(".from-date");
						var fromT_parent = _dialog.find(".from-time");
						saveDate(fromD_parent, fromT_parent, dp);
					});
		});
		
		_settings.find(".to.cal-icon").click(function() {
			
			if (_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").hasClass("not-active")) {
				return false;
			}
			
			fcDatepicker.open(calendar, this,
					function(dp) {loadDate(toD, dp, _eventObj.end||_eventObj.start);},
					function(elem, dp) {this.close();saveDate(toD, toT, dp);});
		});
		
		//
		_settings
				.find(".from-date, .to-date, .fc-cycle-times")
				.bind("keyup change", _validateDateFieldsSettings);
		//
		_settings.find(".calendar select").change(function (ev) {
			var v = $(this).val();
			var s = calendar.getEventSources();
			for (var i = 0; i < s.length; ++i) {
			    if (s[i].objectId != v) { continue; }
			    _settings.find(".calendar .bullet").css("color", s[i].backgroundColor);
				return;
			}
		});
		
	}());
	
	// create settings dialog
	(function _createDelSettings() {
		_delSettings = $(ds.dialogTemplate)
				.addClass("asc-dialog")
				.popupFrame({
					anchor: "right,top",
					direction: "right,down",
					offset: "0,0",
					showArrow: false
				});
				
		// radio
		function _setCheckedAttrValue(element, checked) {
			if ((element != undefined) && (element.length != 0)) {
                element.prop("checked", checked);
			}
		}
		
		_delSettings.find(".delete-selector .delete-this-label").click(function() {
			_setCheckedAttrValue.call(_this, _delSettings.find(".delete-selector .delete-this"), true);
		});
		
		_delSettings.find(".delete-selector .delete-following-label").click(function() {
			_setCheckedAttrValue.call(_this, _delSettings.find(".delete-selector .delete-following"), true);
		});
		
		_delSettings.find(".delete-selector .delete-all-label").click(function() {
			_setCheckedAttrValue.call(_this, _delSettings.find(".delete-selector .delete-all"), true);
		});
		
		_delSettings.find(".buttons .save-btn").click(function() {
		    if (jq(this).hasClass("disable"))
		        return;
		    
		    var delType = deleteMode.single;

		    if(!_delSettings.hasClass("single")) {
		        if (_delSettings.find(".delete-following").is(":checked")) {
				    delType = deleteMode.allFollowing;
			    }
			    else if (_delSettings.find(".delete-all").is(":checked")) {
				    delType = deleteMode.allSeries;
			    }
		    }
		    
			_closeDelSettings.call(_this, true);

			if (_getConfirmViewMode.call(_this)) {
			    confirmSettings.selectedDeleteMode = delType;
			    _openConfirmPopup.call(_this);
			} else {
			    _deleteEvent.call(_this, delType, _eventObj._start);
			    _close.call(_this, false, true);
			}

		});
		_delSettings.find(".buttons .cancel-btn, .buttons .close-btn, .header .close-btn").click(function() {
			_closeDelSettings.call(_this, false);
		});
		
	}());

    // create confirm dialog
	(function _createConfirmPopup() {
	    _confirmPopup = $(cp.dialogTemplate)
				.addClass("asc-dialog")
				.popupFrame({
				    anchor: "right,top",
				    direction: "right,down",
				    offset: "0,0",
				    showArrow: false
				});

	    _confirmPopup.find(".buttons .send-btn, .buttons .send-everyone-btn").click(function() {
	        _sendGuestsNotification.call(_this, confirmSettings.notificationMode.everybody);
	    });

	    _confirmPopup.find(".buttons .send-customs-btn").click(function() {
	        _sendGuestsNotification.call(_this, confirmSettings.notificationMode.partially);
	    });

	    _confirmPopup.find(".buttons .dont-send-btn").click(function() {
	        _sendGuestsNotification.call(_this, confirmSettings.notificationMode.nobody);
	    });
	    _confirmPopup.find(".header .close-btn").click(function() {
	        _closeConfirmPopup.call(_this, false);
	    });

	}());


	function _resizePopup() {
		if (!_dialogMode) {_adjustPopupPosition.call(_this);}
		_dialog.popupFrame("updatePosition", _anchor);
	}

	function _adjustPopupPosition() {
		var vr = calendar.getView().getViewRect();                               // current view's rect
		var ar = fcUtil.getElementRect(_anchor);                                 // anchor element's rect
		var pw = _dialog.outerWidth(true);// + _settings.outerWidth(true) + 30;     // popup's width
		var ph = _dialog.outerHeight(true);                                      // popip's height

		// adjust popup's ahchor, direction & arrow
		if (ar.right + pw <= (vr.right - _settings.outerWidth(true)) || ar.left - pw < vr.left) {
			_dialog.popupFrame("option", "anchor", "right,top");
			_dialog.popupFrame("option", "direction", "right,down");
			_dialog.popupFrame("option", "arrow", "left");
			_dialog.popupFrame("option", "offset", "-4px,0");
			_dialog.popupFrame("updatePosition", _anchor);
			pw = _dialog.outerWidth(true);// + _settings.outerWidth(true) + 30;
			var offs = ar.right + pw - vr.right;
			offs = offs < 0 ? -4 : -offs;
			_dialog.popupFrame("option", "offset", offs + "px,0");
		} else {
			_dialog.popupFrame("option", "anchor", "left,top");
			_dialog.popupFrame("option", "direction", "left,down");
			_dialog.popupFrame("option", "arrow", "right");
			_dialog.popupFrame("option", "offset", "2px,0");
		}

		_dialog.popupFrame("updatePosition", _anchor);

		// adjust popup's top & arrow position
		var skipArrowPos = false;
		if (ar.top < vr.top || ar.bottom > vr.bottom) {
			calendar.getView().resetScroll(_eventObj.start.getHours());
			ar = fcUtil.getElementRect(_anchor);
			if (ar.top < vr.top) {
				skipArrowPos = true;
				var m = _dialog.popupFrame("option", "offset").match(/^([+-]?\d+(\.\d+)?)(px)?,([+-]?\d+(\.\d+)?)(px)?/i);
				var newOffs = m[1] + (m[3] ? m[3] : "") + "," +
						(vr.top - ar.top + parseInt(m[4], 10)) + (m[6] ? m[6] : "");
				_dialog.popupFrame("option", "offset", newOffs);
			}
		}
		var pt = (Math.max(ar.top, vr.top) + Math.min(ar.bottom, vr.bottom) - ph) * 0.5;
		var ap = 50;
		if (!skipArrowPos) {
			if (pt < vr.top) {
				ap = Math.round((ph * 0.5 - vr.top + pt) * 100 / ph);
			} else if (pt + ph > vr.bottom) {
				ap = Math.round((ph * 0.5 + pt + ph - vr.bottom) * 100 / ph);
			}
		}
		_dialog.popupFrame("option", "arrowPosition", ap + "%");
	}

	function _resetMode() {
	    _dialog.removeClass("add-dialog add-popup edit-popup todo-popup");
		_dialogMode = undefined;
	}

	function _viewMode(elem, eventObj) {
		_resetMode.call(_this);
		_dialogMode = false;
		_dialog.popupFrame("option", "showArrow", true);
		_adjustPopupPosition.call(_this);
		_dialog.popupFrame("open", elem);
		uiBlocker.addClass("fc-modal-transparent");
	}
	
	function _editMode() {
		_resetMode.call(_this);
		updateEditorView(false);
	    _dialog.addClass("edit-popup");
	    _dialog.find('.title input').focus();
	}

	function _todoMode() {
		_resetMode.call(_this);
		updateEditorView(true);
	    _dialog.addClass("edit-popup todo-popup");
	    _dialog.find('.title input').focus();
	}

    function _getAlertLabel(type) {
		if (type != undefined) {
			switch (type) {
				case kAlertDefault: 		return calendar.options.eventEditor.dialogAlertOption_default;
				case kAlertNever:			return calendar.options.eventEditor.dialogAlertOption_never;
				case 1: 					return calendar.options.eventEditor.dialogAlertOption_5minutes;
				case 2: 					return calendar.options.eventEditor.dialogAlertOption_15minutes;
				case 3: 					return calendar.options.eventEditor.dialogAlertOption_30minutes;
				case 4: 					return calendar.options.eventEditor.dialogAlertOption_hour;
				case 5: 					return calendar.options.eventEditor.dialogAlertOption_2hours;
				case 6: 					return calendar.options.eventEditor.dialogAlertOption_day;
				default: 					return "Unknown";
			}
		}
	}
	
	function _getRepeatLabel(rule) {
		if (rule != undefined) {
			if (rule.Equals(ASC.Api.iCal.RecurrenceRule.Never)) {
				return calendar.options.eventEditor.dialogRepeatOption_never;
			}
			else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryDay)) {
				return calendar.options.eventEditor.dialogRepeatOption_day;
			}
			else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryWeek)) {
				return calendar.options.eventEditor.dialogRepeatOption_week;
			}
			else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryMonth)) {
				return calendar.options.eventEditor.dialogRepeatOption_month;
			}
			else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryYear)) {
				return calendar.options.eventEditor.dialogRepeatOption_year;
			}
			else {
				return calendar.options.eventEditor.dialogRepeatOption_custom;
			}
		}
	}
	
	function _disableRepeatSettings() {
		_settings.find(".fc-interval-selector").attr("disabled", "disabled");
		_settings.find("input").each(function(){
			el = $(this);
			el.attr("disabled", "disabled");
		});
		
		_settings.find(".fc-dwm-selector").find(".fc-selector-link").addClass("not-active");
		_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").addClass("not-active");
	}
	
	function _enableRepeatSettings() {
		_settings.find(".fc-interval-selector").removeAttr("disabled");
		_settings.find("input").each(function(){
			el = $(this);
			el.removeAttr("disabled");
		});
		
		_settings.find(".fc-dwm-selector").find(".fc-selector-link").removeClass("not-active");
		_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").removeClass("not-active");
	}
	
	function _setRepeatBackground(mode) {
		if (!mode) {		// old style
			_dialog.find(".repeat-alert").find(".right").css("background-color", "transparent");
		}
		else {				// new style
			_dialog.find(".repeat-alert").find(".right").css("background-color", "#f5f5f5");
		}
	}
	
	function _renderRepeatAlertList() {
		// repeat list
		var _repeatSelectorLabel = _dialog.find(".fc-view-repeat");
		
		_dialog.find(".fc-view-repeat").click(
			function (event) {
				fcMenus.hideMenus(fcMenus.modeMenuRepeat);
				fcMenus.modeMenuRepeat.popupMenu("open", _repeatSelectorLabel);
				event.stopPropagation();
			});
			
			if (!fcMenus.modeMenuRepeat || fcMenus.modeMenuRepeat.length < 1) {
				fcMenus.modeMenuRepeat = $('<div id="fc_mode_menu_repeat"/>');
			} else {
				fcMenus.modeMenuRepeat.popupMenu("close");
				fcMenus.modeMenuRepeat.popupMenu("destroy");
			}
			fcMenus.modeMenuRepeat.popupMenu({
				anchor: "left,bottom",
				direction: "right,down",
				arrow: "up",
				showArrow: false,
				closeTimeout: -1,
				cssClassName: "asc-popupmenu",
				items: [
					{
						label: calendar.options.eventEditor.dialogRepeatOption_never,
						click: function() {
							repeatRule = ASC.Api.iCal.RecurrenceRule.Never;
							_repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
							_closeSettings.call(_this, false);
							_dialog.find(".repeat-settings").addClass("hidden");
							_setRepeatBackground.call(_this, 0);
							_adjustPopupPosition.call(_this);
						}
					},
					{
						label: calendar.options.eventEditor.dialogRepeatOption_day,
						click: function() {
							repeatRule = ASC.Api.iCal.RecurrenceRule.EveryDay;
							_repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
							_closeSettings.call(_this, false);
							_dialog.find(".repeat-settings").addClass("hidden");
							_setRepeatBackground.call(_this, 0);
							_adjustPopupPosition.call(_this);
						}
					},
					{
						label: calendar.options.eventEditor.dialogRepeatOption_week,
						click: function() {
							repeatRule = ASC.Api.iCal.RecurrenceRule.EveryWeek ;
							_repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
							_closeSettings.call(_this, false);
							_dialog.find(".repeat-settings").addClass("hidden");
							_setRepeatBackground.call(_this, 0);
							_adjustPopupPosition.call(_this);
						}
					},
					{
						label: calendar.options.eventEditor.dialogRepeatOption_month,
						click: function() {
							repeatRule = ASC.Api.iCal.RecurrenceRule.EveryMonth;
							_repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
							_closeSettings.call(_this, false);
							_dialog.find(".repeat-settings").addClass("hidden");
							_setRepeatBackground.call(_this, 0);
							_adjustPopupPosition.call(_this);
						}
					},
					{
						label: calendar.options.eventEditor.dialogRepeatOption_year,
						click: function() {
							repeatRule = ASC.Api.iCal.RecurrenceRule.EveryYear;
							_repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
							_closeSettings.call(_this, false);
							_dialog.find(".repeat-settings").addClass("hidden");
							_setRepeatBackground.call(_this, 0);
							_adjustPopupPosition.call(_this);
						}
					},
					{
						label: calendar.options.eventEditor.dialogRepeatOption_custom,
						click: function() {
							_repeatSelectorLabel.find(".fc-selector-link").text(calendar.options.eventEditor.dialogRepeatOption_custom);
							_openSettings.call(_this);
							_dialog.find(".repeat-settings").removeClass("hidden");
							
							_enableRepeatSettings.call(_this);
							_setRepeatBackground.call(_this, 1);
							_adjustPopupPosition.call(_this);
							_setRepeatSettingsHeight.call(_this);
						}
					}
				]
			});
		
		// alert list  
		var _alertSelectorLabel = _dialog.find(".fc-view-alert");
		
		_dialog.find(".fc-view-alert").click(
			function (event) {
				fcMenus.hideMenus(fcMenus.modeMenuAlert);
				fcMenus.modeMenuAlert.popupMenu("open", _alertSelectorLabel);
				event.stopPropagation();
			});

			if (!fcMenus.modeMenuAlert || fcMenus.modeMenuAlert.length < 1) {
				fcMenus.modeMenuAlert = $('<div id="fc_mode_menu_alert"/>');
			} else {
				fcMenus.modeMenuAlert.popupMenu("close");
				fcMenus.modeMenuAlert.popupMenu("destroy");
			}
			fcMenus.modeMenuAlert.popupMenu({
				anchor: "left,bottom",
				direction: "right,down",
				arrow: "up",
				showArrow: false,
				closeTimeout: -1,
				cssClassName: "asc-popupmenu",
				
				items: [
					{
						label: calendar.options.eventEditor.dialogAlertOption_default,
						click: function() {
							alertType = kAlertDefault;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					},
					{
						label: calendar.options.eventEditor.dialogAlertOption_never,
						click: function() {
							alertType = kAlertNever;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					},
					{
						label: calendar.options.eventEditor.dialogAlertOption_5minutes,
						click: function() {
							alertType = 1;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					},
					{
						label: calendar.options.eventEditor.dialogAlertOption_15minutes,
						click: function() {
							alertType = 2;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					},
					{
						label: calendar.options.eventEditor.dialogAlertOption_30minutes,
						click: function() {
							alertType = 3;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					},
					{
						label: calendar.options.eventEditor.dialogAlertOption_hour,
						click: function() {
							alertType = 4;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					},
					{
						label: calendar.options.eventEditor.dialogAlertOption_2hours,
						click: function() {
							alertType = 5;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					},
					{
						label: calendar.options.eventEditor.dialogAlertOption_day,
						click: function() {
							alertType = 6;
							_alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
						}
					}
				]
			});
	}

	function _addDialogMode(elem, eventObj) {
		_anchor = {pageX:"center",pageY:"center"};
		_resetMode.call(_this);
		_dialogMode = true;
		_dialog.addClass("add-dialog");
		_dialog.popupFrame("option", "showArrow", false);
		_dialog.popupFrame("open", _anchor);
		uiBlocker.removeClass("fc-modal-transparent");
	}

	function _addPopupMode(elem, eventObj) {
		_resetMode.call(_this);
		_dialogMode = false;
		_dialog.addClass("add-popup");
		_dialog.popupFrame("option", "showArrow", true);
		_adjustPopupPosition.call(_this);
		_dialog.popupFrame("open", elem);
		uiBlocker.addClass("fc-modal-transparent");
	}
	
	function _addPopupDelSettings() {
		_anchor = {pageX:"center",pageY:"center"};
		_delSettings.popupFrame("open", _anchor);
		_delSettings.addClass("add-popup");
		_delSettings.addClass("fc-shadow");
		uiBlocker.removeClass("fc-modal-transparent");
	}

	function _renderPermissions() {
		_eventObj.permissions = _eventObj.permissions || {};
		_eventObj.permissions.users = _eventObj.permissions.users || [];

		var list = "";
		for (var i = 0; i < _eventObj.permissions.users.length; i++) {
			if (i > 0) {list += ", ";}
			list += _eventObj.permissions.users[i].name;
		}

	    if (calendar.options.isPersonal) {
	        _dialog.find(".shared-list").remove();
	    } else {
	        _dialog.find(".viewer .shared-list .users-list").html(htmlEscape(list));

	        if (list.length > 0) {
	            _dialog.find(".viewer .shared-list").addClass("has-users");
	        } else {
	            _dialog.find(".viewer .shared-list").removeClass("has-users");
	        }
	    }

		_permissionsList.render(_eventObj.permissions, kEventPermissions, _eventObj.objectId);
	}

	function _updatePermissions(response) {
		if (response.result) {
			_eventObj.permissions = response.permissions;
			if (response.isShared != undefined) {
				_eventObj.isShared = response.isShared;
			}
			_renderPermissions.call(_this);
			_resizePopup();
			_setRepeatSettingsHeight.call(_this);
		}
	}


	function _open(mode, elem, eventObj) {
		_dialog.popupFrame("close");
		uiBlocker.hide();
		
		_dialog.find(".repeat-settings").addClass("hidden");
		_setRepeatBackground.call(_this, 0);
		
		// check length
		var titleMaxLen = defaults.eventMaxTitleLength;
		var inputTxt = _dialog.find(".editor .title input, .editor .location input");
		if (inputTxt.length > 0)
		{
			inputTxt.keyup(function(){
				if (inputTxt.val().length > titleMaxLen){
					inputTxt.val(inputTxt.val().substr(0, titleMaxLen));
				}
			});
		}
		//

		_eventObj = eventObj;
		_eventObj.sourceId = _eventObj.sourceId || (_eventObj.source ? _eventObj.source.objectId : undefined);
		
		repeatRule = _eventObj.repeatRule;

		_canChangeSource = _eventObj.source == undefined ||
				_eventObj.source && !_eventObj.source.isSubscription;
		_canDelete = fcUtil.objectIsEditable(_eventObj) ||
				fcUtil.objectIsEditable(_eventObj.source) ||
				_eventObj.source && !_eventObj.source.isSubscription;
		_canEdit = _eventObj.source == undefined || _canDelete;

		_canUnsubscribe = _eventObj && _eventObj.canUnsubscribe &&
				_eventObj.source && _eventObj.source.isSubscription;

		if (_canEdit) {
			_dialog.find(".buttons").addClass("editable");
		} else {
			_dialog.find(".buttons").removeClass("editable");
		}
		if (_canDelete) {
			_dialog.find(".buttons").addClass("erasable");
		} else {
			_dialog.find(".buttons").removeClass("erasable");
		}
		if (_canEdit || _canDelete) {
			_dialog.find(".buttons").removeClass("readonly");
		} else {
			_dialog.find(".buttons").addClass("readonly");
		}
		if (_canUnsubscribe) {
			_dialog.find(".buttons").addClass("shared");
		} else {
			_dialog.find(".buttons").removeClass("shared");
		}
		if (eventObj.allDay && (eventObj.start == eventObj.end || eventObj.end == null)) {
			_dialog.find(".viewer .date-time .right").hide();
		} else {
			_dialog.find(".viewer .date-time .right").show();
		}

		_doDDX.call(_this);
		
		_anchor = elem;
		_modes[mode].call(_this, elem, eventObj);
		_resizePopup();
	    _dialog.find(".editor .title input").focus().select();

		_setRepeatSettingsHeight.call(_this);
		
		$(document).bind("keyup", _checkEscKey);

		if (_dialog.popupFrame("isVisible")) {
			uiBlocker.show();
		} else {
			uiBlocker.hide();
		}
	}
	
	function _setRepeatSettingsHeight() {
		_settings.height("auto");
		_settings.height( _dialog.find(".end-point").offset().top - _dialog.find(".start-point").offset().top - 
																	(_dialog.hasClass("add-dialog") ? _dialog.find(".header").outerHeight() : 0) );
	}

	// repeat interval
	function _setRepeatInterval(selectedItem, count) {
		if (selectedItem <= count) {
			var intervals = "";
			for (var i = 1; i < count; i++) {
				intervals += "<option" + ((selectedItem == i) ? " selected" : "") + " value='" + i + "'>" + i + "</option>";
			}
			
			var html = $(intervals);
			_settings.find(".fc-interval-selector").html(html);
			
			_settings.find(".fc-interval-selector").change(function() {
				_settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
			});
		}
	}
	
	// repeat days of week
	function _setSelectedDays(indexArr) {
		var daysSection = "";

	    var dayNamesInCurCulture;
	    var beforeFirstDay = [];
	    var afterFirstDay = [];

	    for (var i = 0; i < rs.dayNamesShort.length; i++) {
	        var item = { index: i, name: rs.dayNamesShort[i] };
	        if(i < g_fcOptions.firstDay){
	            beforeFirstDay.push(item);
	        } else {
	            afterFirstDay.push(item);
	        }
	    }
	    dayNamesInCurCulture = afterFirstDay.concat(beforeFirstDay);

	    for (var i = 0; i < dayNamesInCurCulture.length; i++) {
			var isSelected = false;
			for (var j = 0; j < indexArr.length; j++) {
				if (dayNamesInCurCulture[i].index == indexArr[j]) {
					isSelected = true;
					break;
				}
			}
			
			daysSection += 	"<div class='checkbox-day'>" +
								"<input class='repeat-day-" + dayNamesInCurCulture[i].index + "' type='checkbox' " + ((isSelected == true) ? "checked" : "") + ">" +
								"<div>" + htmlEscape(dayNamesInCurCulture[i].name) + "</div>" +
							"</div>";
		}
		daysSection += "<div class='clear'></div>";
		var html = $(daysSection);
		_settings.find(".fc-days-week").html(html);
	}
	function _getSelectedDays() {
		indexArr = new Array();
		if (_settings.find(".fc-days-week.hidden").length == 0) {
			for (var i = 0; i < rs.dayNamesShort.length; i++) {
				var checkedClass = ".repeat-day-" + i;
				var checkedItem = _settings.find(checkedClass).is(":checked");
				if (checkedItem == true) {
					indexArr.push(i);
				}
			}
		}
		return indexArr;
	}
	
	function _getRepeatDayByIndex(index) {
		switch (index) {
			case 0: return ASC.Api.iCal.DayOfWeek.Sunday;
			case 1: return ASC.Api.iCal.DayOfWeek.Monday;
			case 2: return ASC.Api.iCal.DayOfWeek.Tuesday;
			case 3: return ASC.Api.iCal.DayOfWeek.Wednesday;
			case 4: return ASC.Api.iCal.DayOfWeek.Thursday;
			case 5: return ASC.Api.iCal.DayOfWeek.Friday;
			case 6: return ASC.Api.iCal.DayOfWeek.Saturday;
		}
	}
	
	function _openSettings()
	{
		var fromD = _dialog.find(".editor .from-date");
		_settings.find(".from-date").val(fromD.val());
		_validateDateFieldsSettings.call(_this);
		
		var date = parseISO8601(fromD.val());
		var endDate = undefined;
		
		var maxDayCount = 32 - new Date(date.getFullYear(), date.getMonth(), 32).getDate();
		var dayOfWeek = date.getDay();
		var dayOfMonth = date.getDate();
		
		var indexDay = Math.floor((dayOfMonth - 1) / 7);
		var maxIndexDay = indexDay + Math.floor((maxDayCount - dayOfMonth) / 7);
		
		var dayName = calendar.options.repeatSettings.dayNames[dayOfWeek];
		var dayAlias = "";
		
		switch (indexDay) {
			case 0:
			case 1:
			case 2:
			case 4: dayAlias = rs.dayAliasNames[indexDay]; break;
			case 3: (indexDay != maxIndexDay) ? dayAlias = rs.dayAliasNames[indexDay] : dayAlias = rs.dayAliasNames[indexDay + 1]; break;
		}
		
		var html = $("<div>" + 
						"<div style='margin-bottom: 0.5em;'>" +
						"<input class='only-day' type='radio' name='day-radio' value='" + dayOfMonth + "' />&nbsp;" + 
							"<span class='only-day-label'>" + rs.dialogEachLabel + " " + dayOfMonth + " " + rs.dialogIntervalOption_day + "</span></div>" +
					 	"<input class='each-day' type='radio' name='day-radio' value='" + dayName + "'/>&nbsp;" + 
					 		"<span class='each-day-label'>" + rs.dialogAliasLabel + " " + dayAlias + " " + dayName + "</span>" +
					 "</div>");
					 
		_settings.find(".fc-month-radio").html(html);
		_settings.find(".only-day").attr({checked: "checked"});
		
		_settings.find(".only-day-label").click(function() {
			_settings.find(".only-day").trigger("click");
		});
		
		_settings.find(".each-day-label").click(function() {
			_settings.find(".each-day").trigger("click");
		});
		
		dayRuleObject = undefined;
		_settings.find(".each-day").click(function () {
			dayRuleObject = _getRepeatDayByIndex.call(_this, dayOfWeek);
			var dayRuleIndex = 0;
			
			switch (indexDay) {
				case 0:
				case 1:
				case 2: dayRuleIndex  = indexDay + 1; break;
				case 3: dayRuleIndex  = -2; break;
				case 4: dayRuleIndex  = -1; break;
			}
			if (indexDay == maxIndexDay) {
				dayRuleIndex = -1;
			}
			
			dayRuleObject.Order = dayRuleIndex;
		});
		
		_settings.find(".only-day").click(function () {
			dayRuleObject = undefined;
		});
		
		_setRepeatInterval.call(this, repeatRule.Interval, 31);
		_settings.find(".fc-cycle-times").val((repeatRule.Count > 0) ? repeatRule.Count : 3);
		
		var dayIndexArr = new Array();
		for (var i = 0; i < repeatRule.ByDay.length; i++) {
			dayIndexArr.push(rs.dayIndexResponse[repeatRule.ByDay[i].Id]);
		}
		
		_setSelectedDays.call(this, dayIndexArr.length ? dayIndexArr : [dayOfWeek]);
		
		// set default view
		if ((repeatRule.Freq == ASC.Api.iCal.Frequency.Never) || (repeatRule.Freq == ASC.Api.iCal.Frequency.Daily)) {
			_showDaySections.call(_this);
			dwm_current = dwm.day;
			_settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_days);
			_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_day);
		}
		else if (repeatRule.Freq == ASC.Api.iCal.Frequency.Weekly) {
			_showWeekSections.call(_this);
			dwm_current = dwm.week;
			_settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_weeks);
			_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_week);
		}
		else if (repeatRule.Freq == ASC.Api.iCal.Frequency.Monthly) {
			_showMonthSections.call(_this);
			dwm_current = dwm.month;
			_settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_months);
			_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_month);
			
			if ((repeatRule.ByDay.length == 1) && (repeatRule.ByDay[0].Order != 0)) {
				_settings.find(".only-day").attr({checked: ""});
				_settings.find(".each-day").attr({checked: "checked"}).click();
			}
			else {
				_settings.find(".each-day").attr({checked: ""});
				_settings.find(".only-day").attr({checked: "checked"});
			}
		} else if (repeatRule.Freq == ASC.Api.iCal.Frequency.Yearly) {
			_showDaySections.call(_this);
			dwm_current = dwm.year;
			_settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_years);
			_settings.find(".fc-interval-label").text(rs.dialogIntervalOption_year);
		}
		
		_settings.find(".to-date").val(repeatRule.Until ? calendar.formatDate(repeatRule.Until, rs.dateFormat) : 
																	_getEndDate.call(_this, dwm_current));
		
		// end repeat
		if (repeatRule.Until) {
			_showEndSectionsDate.call(_this);
			_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").text(rs.dialogOptionDate);
		}
		else if (repeatRule.Count > 0) {
			_showEndSectionsCycles.call(_this);
			_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").text(rs.dialogOptionCount);
		}
		else {
			_showEndSectionsNever.call(_this);
			_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").text(rs.dialogOptionNever);
		}
	}
	
	function _openDelSettings(mode, single)
	{
	    _dialog.popupFrame("close");
	    $(document).unbind("keyup", _checkEscKey);

	    if (single)
	        _delSettings.addClass("single");
	    else
	        _delSettings.removeClass("single");

	    _delSettings.popupFrame("close");
		_delSettings.find("input[type=radio]:first").prop("checked", true);
		uiBlocker.hide();
		
		_modes[mode].call(_this);
		
		$(document).bind("keyup", _checkEscKeyDelSettings);

		if (_delSettings.popupFrame("isVisible")) {
			uiBlocker.show();
		} else {
			uiBlocker.hide();
		}
	}

	function _close(changed, deleted) {
	    calendar.openEventWin = null;
	    if (changed) {
	        if (_editMode == _editModes.event) {
	            if (!_canEdit || false == _doDDX.call(_this, true)) {
	                return;
	            }
	            _updateEvent.call(_this);
	        } else {
	            if (false == _doDDX.call(_this, true)) {
	                return;
	            }
	            _createTodo.call(_this);
	        }
	        return;
	    }
	    if (_eventObj.source == undefined && _eventObj._id != undefined) {
	        calendar.removeEvents(_eventObj._id);
	    }

	    if ((_eventObj.source != undefined) && !changed && !deleted)
	        _updateEvent.call(_this, true);
	    $(document).unbind("keyup", _checkEscKey);
	    _closeDialog.call(_this);
	    
	}
	
	function _closeSettings(changed) {
		if (changed && _canEdit) {
			_prepareRepeatRule.call(_this);
		}
	}
	
	function _closeDelSettings(changed) {
		if (changed) {
			if (!_canEdit) {return;}
			_closeDialogDelSettings.call(_this);
			return;
		}
		
		$(document).unbind("keyup", _checkEscKeyDelSettings);
		_closeDialogDelSettings.call(_this);
	}

	function _checkEscKey(ev) {
		if (ev.which == 27) {
			_close.call(_this, false);
		}
	}
	
	function _checkEscKeyDelSettings(ev) {
		if (ev.which == 27) {
			_closeDelSettings.call(_this, false);
		}
	}

	function _closeDialog() {
		fcDatepicker.close();
		_dialog.popupFrame("close");
		uiBlocker.hide();
	}
    
	function _disableDialogBtns(disable) {
	    if (disable){
	        _dialog.find(".buttons .save-btn").addClass("disable");
	    } else {
	        _dialog.find(".buttons .save-btn").removeClass("disable");
	    }
	}
	
	function _closeDialogDelSettings() {
	    _delSettings.popupFrame("close");
	    uiBlocker.hide();
	}


	function _getConfirmViewMode() {

	    confirmSettings.notificationUsers.newGuests = [];
	    confirmSettings.notificationUsers.updatedGuests = [];
	    confirmSettings.notificationUsers.removedGuests = [];
	    confirmSettings.selectedViewMode = confirmSettings.viewMode.none;
	    confirmSettings.selectedNotificationMode = confirmSettings.notificationMode.nobody;

	    if(_eventObj.status == 2 || (_eventObj.source && _eventObj.source.isSubscription))
	        return confirmSettings.selectedViewMode;

	    var isOrganizer = false;
	    var organizerEmail = _eventObj.organizer ? _eventObj.organizer[3].replace(new RegExp("mailto:", "ig"), "").toLowerCase() : "";

	    jq.each(ASC.Mail.Accounts, function(index, account) {
	        if (account.enabled && organizerEmail == account.email.toLowerCase()) {
	            isOrganizer = true;
	            return false;
	        }
	        return true;
	    });

	    if(!isOrganizer)
	        return confirmSettings.selectedViewMode;

	    var guests = [];
	    jq.each(_eventObj.attendees || [], function(index, attendeeObj) {
	        var attendeeEmail = attendeeObj[3].replace(new RegExp("mailto:", "ig"), "");
	        if (attendeeEmail.toLowerCase() != organizerEmail)
	            guests.push(attendeeEmail);
	    });

	    if (guests.length) {
	        confirmSettings.selectedViewMode = confirmSettings.viewMode.deleteEvent;
	        confirmSettings.notificationUsers.removedGuests = guests;
	        confirmSettings.notificationUsers.updatedGuests = guests;
	    }
	    
	    return confirmSettings.selectedViewMode;
	}

	function _openConfirmPopup()
	{
	    switch (confirmSettings.selectedViewMode) {
	        case confirmSettings.viewMode.deleteEvent:
	            _confirmPopup.find(".title").text(calendar.options.confirmPopup.dialogDeleteEventHeader);
	            _confirmPopup.find(".body").text(calendar.options.confirmPopup.dialogDeleteEventBody);
	            _confirmPopup.find(".send-btn").show();
	            _confirmPopup.find(".send-customs-btn, .send-everyone-btn").hide();
	            break;
	        default:
	            break;
	    }

	    _dialog.popupFrame("close");
	    $(document).unbind("keyup", _checkEscKey);

	    _delSettings.popupFrame("close");
	    $(document).unbind("keyup", _checkEscKeyDelSettings);

	    _confirmPopup.popupFrame("close");

	    _confirmPopup.popupFrame("open", { pageX: "center", pageY: "center" });
	    _confirmPopup.css("position","fixed");
	    uiBlocker.removeClass("fc-modal-transparent");

	    if (_confirmPopup.popupFrame("isVisible")) {
	        uiBlocker.show();
	    } else {
	        uiBlocker.hide();
	    }
	}

	function _closeConfirmPopup() {
	    _confirmPopup.popupFrame("close");
	    uiBlocker.hide();
	}

	function _sendGuestsNotification(mode) {
	    confirmSettings.selectedNotificationMode = mode;
	    _deleteEvent.call(_this, confirmSettings.selectedDeleteMode, _eventObj._start);
	    _close.call(_this, false, true);
	    _closeConfirmPopup.call(_this);
	}

	function _sendNotification(sourceId, uniqueId, type, callback) {
	    var attendeesEmails = [];
	    var method = null;

	    switch (type) {
	        case confirmSettings.notificationType.cancel:
	            switch (confirmSettings.selectedNotificationMode) {
	                case confirmSettings.notificationMode.everybody:
	                case confirmSettings.notificationMode.partially:
	                    attendeesEmails = confirmSettings.notificationUsers.removedGuests;
	                    method = ASC.Mail.Utility.SendCalendarCancel;
	                    break;
	                default:
	                    break;
	            }
	            break;
	        case confirmSettings.notificationType.update:
	            switch (confirmSettings.selectedNotificationMode) {
	                case confirmSettings.notificationMode.everybody:
	                case confirmSettings.notificationMode.partially:
	                    attendeesEmails = confirmSettings.notificationUsers.updatedGuests;
	                    method = ASC.Mail.Utility.SendCalendarUpdate;
	                    break;
	                default:
	                    break;
	            }
	            break;
	        default:
	            break;
	    }

	    if (attendeesEmails.length && method) {
	        ASC.CalendarController.Busy = true;
	        window.LoadingBanner.displayLoading();
	        
	        method.call(this, sourceId, uniqueId, attendeesEmails)
                .done(function() {
                    //toastr.success(calendar.options.confirmPopup.dialogSuccessToastText);
                    console.log(calendar.options.confirmPopup.dialogSuccessToastText, arguments);
                    if (callback)
                        callback();
                })
                .fail(function() {
                    toastr.error(calendar.options.confirmPopup.dialogErrorToastText);
                    console.error(calendar.options.confirmPopup.dialogErrorToastText, arguments);
                })
	            .always(function () {
	                ASC.CalendarController.Busy = false;
	                window.LoadingBanner.hideLoading();
	            });
	    } else {
	        if (callback)
	            callback();
	    }
	}


	function _parseDateTime(inputD, inputT, result) {
		var dateStr = inputD.val();
		var timeStr = inputT.val();
		var dateStrIsEmpty = dateStr.search(/\S/) < 0;
		var timeStrIsEmpty = timeStr.search(/\S/) < 0;
		var date, time, r;
		if (!dateStrIsEmpty || !timeStrIsEmpty) {
			date = fcUtil.validateDateString(dateStr);
			time = fcUtil.validateTimeString(timeStr);
			r = (date === null || !timeStrIsEmpty && time === null) ? 0 : 1;
		} else {
			r = -1;
			date = null;
			time = null;
		}
		result.date = {isEmpty: dateStrIsEmpty, isValid: date !== null, value: date};
		result.time = {isEmpty: timeStrIsEmpty, isValid: time !== null, value: time};
		return r;
	}
	function _validateTodoDateFields(result) {
	    var dlg = {
	        date: _dialog.find(".editor .todo_editor .date"),
	        time: _dialog.find(".editor .todo_editor .time"),
	    };
	    var todoDate = {}, fr = _parseDateTime(dlg.date, dlg.time, todoDate);
	    
	    todoDate.dateTime = fr == 1 ? parseDate(todoDate.date.value + "T23:59:59") : null;

	    var frc, r;
	    
	    if (fr == 1) {
	        r = true;
	        frc = "";
	    } else {
	        r = false;
            frc = todoDate.date.isValid ? "" : dlg.date.val() === "" ? "" : "#cc3300";
	    }
	    dlg.date.css("color", "").css("border-color", frc);
	 
	    if (result != undefined) {
	        result.todoDate = todoDate;
	    }

	    return r;
	}
	var changeTimeFrom = null;
    
	function _validateDateFields(result) {
		var allday = _dialog.find(".editor .all-day input").is(":checked");
		var dlg = {
			from:      _dialog.find(".editor .from-date"),
			from_t:    _dialog.find(".editor .from-time"),
			to:        _dialog.find(".editor .to-date"),
			to_t:      _dialog.find(".editor .to-time")
		};
		var frDate = {}, fr = _parseDateTime(dlg.from, dlg.from_t, frDate);
		var toDate = {}, to = _parseDateTime(dlg.to, dlg.to_t, toDate);
		frDate.dateTime = fr == 1 ? parseDate(frDate.date.value + "T" + frDate.time.value) : null;
		toDate.dateTime = to == 1 ? parseDate(toDate.date.value + "T" + toDate.time.value) : null;

		var frc, frtc, toc, totc, r, delta;
		if (!allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime > 0) ||
			allday && fr == 1 && to == -1 ||
			allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime >= 0)) {
			r = true;
			frc = frtc = toc = totc = "";
		} else {
			r = false;
			frc  = frDate.date.isValid ? "" : "#cc3300";
			frtc = frDate.time.isValid ? "" : "#cc3300";
			toc  = toDate.date.isValid && delta ? "" : "#cc3300";
			totc = toDate.time.isValid && delta ? "" : "#cc3300";
		}
		dlg.from.css("color", "").css("border-color", frc);
		dlg.from_t.css("color", "").css("border-color", frtc);
		dlg.to.css("color", "").css("border-color", toc);
		dlg.to_t.css("color", "").css("border-color", totc);

		if (result) {
			if ($(result.currentTarget).hasClass('from-time') || $(result.currentTarget).hasClass('from-date')) {
				var oldTime = new Date(Date.parse(_eventObj._start ? _eventObj._start : _eventObj.start));
				var newTime = new Date(Date.parse(frDate.dateTime));

				if (changeTimeFrom != null) {
					oldTime = changeTimeFrom;
				}

				var diff = newTime.getTime() - oldTime.getTime();
				if (diff != NaN && diff != 0) {

					var date = new Date();
					date.setTime(Date.parse(toDate.dateTime) + diff);

					if (date != 'Invalid Date') {
						toDate.dateTime.setTime(Date.parse(toDate.dateTime) + diff);

						changeTimeFrom = newTime;

						if ($(result.currentTarget).hasClass('from-time')) {
							var time =
								(toDate.dateTime.getHours() < 10 ? '0' + toDate.dateTime.getHours() : toDate.dateTime.getHours())
								+ ":" +
								(toDate.dateTime.getMinutes() < 10 ? '0' + toDate.dateTime.getMinutes() : toDate.dateTime.getMinutes());
							var newDate = date.getFullYear() + '-'
								+ ((date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + '-'
								+ (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
							toDate.date.value = newDate;
							toDate.time.value = time;

							dlg.to[0].value = newDate;
							dlg.to_t[0].value = time;

						} else if ($(result.currentTarget).hasClass('from-date')) {

							var newDate = date.getFullYear() + '-'
								+ ((date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + '-'
								+ (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());

							toDate.date.value = newDate;
							dlg.to[0].value = newDate;
						}
						r = _validateDateFields.call(_this);
					}
				}
            }
        }
		

		if (result != undefined) {
			result.fromDate = frDate;
			result.toDate   = toDate;
		}
		
		return r;
	}
	
	function _validateDateFieldsSettings(result) {
		
		var r = true;
		var allday = _dialog.find(".editor .all-day input").is(":checked");
		var dlg = {
			from:              _settings.find(".from-date"),
			from_t:            _settings.find(".from-time"),
			to:                _settings.find(".to-date"),
			to_t:              _settings.find(".to-time"),
			cycles:            _settings.find(".fc-cycle-times")
		};
		
		if (!_settings.find(".fc-end-date").hasClass("hidden")) {
			
			var frDate = {}, fr = _parseDateTime(dlg.from, dlg.from_t, frDate);
			var toDate = {}, to = _parseDateTime(dlg.to, dlg.to_t, toDate);
			frDate.dateTime = fr == 1 ? parseDate(frDate.date.value + "T" + frDate.time.value) : null;
			toDate.dateTime = to == 1 ? parseDate(toDate.date.value + "T" + toDate.time.value) : null;
	
			var frc, frtc, toc, totc, delta;
			if (!allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime > 0) ||
			    allday && fr == 1 && to == -1 ||
			    allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime >= 0)) {
				r = true;
				frc = frtc = toc = totc = "";
			} else {
				r = false;
				frc  = frDate.date.isValid ? "" : "#cc3300";
				frtc = frDate.time.isValid ? "" : "#cc3300";
				toc  = toDate.date.isValid && delta ? "" : "#cc3300";
				totc = toDate.time.isValid && delta ? "" : "#cc3300";
			}
			dlg.from.css("color", "").css("border-color", frc);
			dlg.from_t.css("color", "").css("border-color", frtc);
			dlg.to.css("color", "").css("border-color", toc);
			dlg.to_t.css("color", "").css("border-color", totc);
			if (result != undefined) {
				result.fromDate = frDate;
				result.toDate   = toDate;
			}
		}
		
		if (!_settings.find(".fc-repeat-cycles").hasClass("hidden")) {
			var cb = "";
			r = true;
			var isNum = dlg.cycles.val().match('^[0-9]+$');
			if ( (dlg.cycles.find(".hidden").length == 0) && !isNum ) { 
				r = false;
				cb  = !r || (r && (dlg.cycles.val() < 0)) ? "#cc3300" : "";
			}
			dlg.cycles.css("color", "").css("border-color", cb);
		}
		
		return r;
	}

	function _handleAllDayClick() {
		changeTimeFrom = null;
		var allday = _dialog.find(".editor .all-day input").is(":checked");
		var dlg = {
				from:  _dialog.find(".editor .from-date"),
				from_t:  _dialog.find(".editor .from-time"),
				to:      _dialog.find(".editor .to-date"),
				to_t:    _dialog.find(".editor .to-time")
		};
		if (allday) {
			//dlg.to.val("");
			dlg.from_t.val("").attr("disabled", "disabled");
			dlg.to_t.val("").attr("disabled", "disabled");
		} else {
			var defaultEndDate = new Date(_eventObj.start.getFullYear(), _eventObj.start.getMonth(), _eventObj.start.getDate(), _eventObj.start.getHours(), _eventObj.start.getMinutes() + 30);
			
			if(!dlg.from.val())
			    dlg.from.val(formatDate(_eventObj.start, calendar.options.eventEditor.dateFormat));

			dlg.from_t
					.val(formatDate(_eventObj.start, calendar.options.eventEditor.timeFormat))
					.removeAttr("disabled");
			dlg.to_t
					.val(_eventObj.end instanceof Date ?
							formatDate(_eventObj.end, calendar.options.eventEditor.timeFormat) : formatDate(defaultEndDate, calendar.options.eventEditor.timeFormat))
					.removeAttr("disabled");
		    
			if(!dlg.to.val())
                dlg.to.val(_eventObj.end instanceof Date ?
					formatDate(_eventObj.end, calendar.options.eventEditor.dateFormat) : formatDate(defaultEndDate, calendar.options.eventEditor.dateFormat));
		}
		_validateDateFields();
	}

	function _prepareRepeatRule() {
		if (repeatRule) {
			repeatRule = undefined;
		}
		
		// get all values		
		var dlg = {
			from:        _settings.find(".from-date"),
			to:          _settings.find(".to-date"),
			interval:    _settings.find(".fc-interval-selector"),
			cycles:      _settings.find(".fc-cycle-times")
		};
		
		repeatRule = ASC.Api.iCal.RecurrenceRule.EveryDay;
		switch (dwm_current) {
			case dwm.day: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=DAILY"); break;
			case dwm.week: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=WEEKLY"); break;
			case dwm.month: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=MONTHLY"); break;
			case dwm.year: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=YEARLY"); break;
		}
		
		repeatRule.Interval = dlg.interval.find("option:selected").text();
		repeatRule.Count = _settings.find(".fc-repeat-cycles.hidden").length ? repeatRule.Count : dlg.cycles.val();
		
		var dayIndexArr = _getSelectedDays.call(_this);
		for (var i = 0; i < dayIndexArr.length; i++) {
			repeatRule.ByDay.push(_getRepeatDayByIndex.call(this, dayIndexArr[i]));
		}
		
		if ((_settings.find(".fc-month-radio.hidden").length == 0) && (dayRuleObject != undefined)) {
			repeatRule.ByDay.push(dayRuleObject);
		}
		
		if (_settings.find(".fc-end-date.hidden").length == 0) {
			var dates = {};
			if (!_validateDateFieldsSettings(dates)) {return false;}
			repeatRule.Until = dates.toDate.dateTime;
		}
		
		_eventObj.repeatRule = repeatRule;
		
		return (repeatRule != undefined);
	}

	function _doDDX(saveData,toViewDetails) {
		var sources = calendar.getEventSources();
		var sourceIsValid = fcUtil.objectIsValid(_eventObj.source);
		var canChangeAlert = sourceIsValid && (
				_eventObj.source.canAlertModify != undefined && _eventObj.source.canAlertModify ||
				_eventObj.source.canAlertModify == undefined) ||
				!sourceIsValid;

		var dlg = {
			viewer: {
			    title:       _dialog.find(".viewer .title"),
			    location:    _dialog.find(".viewer .location"),
			    attendees:   _dialog.find(".viewer .attendees"),
			    replybuttons:_dialog.find(".viewer .reply-buttons"),
				owner:       _dialog.find(".viewer .owner .name"),
				allday:      _dialog.find(".viewer .all-day"),
				from:        _dialog.find(".viewer .from-date"),
				from_t:      _dialog.find(".viewer .from-time"),
				to:          _dialog.find(".viewer .to-date"),
				to_t:        _dialog.find(".viewer .to-time"),
				repeat:      _dialog.find(".viewer .repeat"),
				alert:       _dialog.find(".viewer .alert"),
				calendar:    _dialog.find(".viewer .calendar .name"),
				calendar_b:  _dialog.find(".viewer .calendar .bullet"),
				description: _dialog.find(".viewer .description .text"),
				status:      _dialog.find(".viewer .status")
			},
			editor: {
			    title:       _dialog.find(".editor .title input"),
			    location:    _dialog.find(".editor .location input"),
			    attendees:   _dialog.find(".editor .attendees input"),
				allday:      _dialog.find(".editor .all-day input"),
				from:        _dialog.find(".editor .from-date"),
				from_t:      _dialog.find(".editor .from-time"),
				to:          _dialog.find(".editor .to-date"),
				to_t:        _dialog.find(".editor .to-time"),
				repeat:      _dialog.find(".editor .fc-view-repeat .fc-selector-link"),
				alert:       _dialog.find(".editor .fc-view-alert .fc-selector-link"),
				calendar:    _dialog.find(".editor .calendar select"),
				calendar_b:  _dialog.find(".editor .calendar .bullet"),
				description: _dialog.find(".editor .description textarea"),
				status:      _dialog.find(".editor .status")
			},
		    todo: {
		        title: _dialog.find(".editor .title input"),
		        date: _dialog.find(".editor .todo_editor .date"),
		        time: _dialog.find(".editor .todo_editor .time"),
		        description: _dialog.find(".editor .todo_editor .description textarea"),
		    },
			infoText:    _dialog.find(".info-text")
		};
		var i;

		if (saveData) {			// ------------- SAVE data -------------

			if (!_canEdit) {return false;}

			if (_editMode == _editModes.event) {

				if (false == fcUtil.validateInput(dlg.editor.title, fcUtil.validateNonemptyString) && !toViewDetails) {
                    return false;
                }
                _eventObj.title = $.trim(dlg.editor.title.val());
                _eventObj.title = _eventObj.title.substr(0,
                    Math.min(calendar.options.eventMaxTitleLength, _eventObj.title.length));

                _eventObj.location = $.trim(dlg.editor.location.val());

                _eventObj.allDay = dlg.editor.allday.is(":checked");

                var dates = {};
                if (!_validateDateFields(dates)) {
                    return false;
                }
                _eventObj.start = dates.fromDate.dateTime;
                _eventObj.end = dates.toDate.dateTime;

                if (canChangeAlert) {
                    //_eventObj.repeat.type = parseInt(dlg.editor.repeat.val(), 10);
                    //_eventObj.alert.type = parseInt(dlg.editor.alert.val(), 10);

                    _eventObj.repeatRule = repeatRule;
                    _eventObj.alert.type = alertType;
                }

                _eventObj.newSourceId = dlg.editor.calendar.val();

                _eventObj.status = $.trim(dlg.editor.status.val());

                _eventObj.attendees = [];

                if (!_eventObj.organizer && ASC.Mail.DefaultAccount) {
                    var organizerObj = new ICAL.Property("organizer");
                    organizerObj.setParameter("cn", ASC.Mail.DefaultAccount.name);
                    organizerObj.setValue("mailto:" + ASC.Mail.DefaultAccount.email);
                    _eventObj.organizer = organizerObj.jCal;
                }

                var src;
                $.each(sources, function() {
                    if (this.objectId == _eventObj.newSourceId) {
                        src = this;
                        return false;
                    }
                    return true;
                });
                if (src) {
                    _eventObj.newTimeZone = $.extend({}, src.timeZone);
                }

                var description = $.trim(dlg.editor.description.val());
                /*if (description.length > 0)*/
                {
                    _eventObj.description = description;
                }

                delete _eventObj.textColor;
                delete _eventObj.backgroundColor;
                delete _eventObj.borderColor;
                calendar.normalizeEvent(_eventObj);
            } else {
                _todoObj = {
                    title: calendar.options.todoList.newTodoTitle,
                    completed: false,
                    start: null
                };
                if (false == fcUtil.validateInput(dlg.todo.title, fcUtil.validateNonemptyString)) {
                    return false;
                }
                _todoObj.title = $.trim(dlg.editor.title.val());
                _todoObj.title = _todoObj.title.substr(0,
                    Math.min(calendar.options.eventMaxTitleLength, _todoObj.title.length));
                
                var dates = {};
                if (!_validateTodoDateFields(dates) && !dates.todoDate.date.isEmpty ) {
                    return false;
                }
                _todoObj.start = dates.todoDate.dateTime;
                
                _todoObj.description = $.trim(dlg.todo.description.val());
                
            }
			
		} else {					// ------------- LOAD data -------------
			
			//tite
		    dlg.editor.title.css("color", "").css("border-color", "").val(_eventObj.title);
			dlg.viewer.title.text(_eventObj.title);

			//infotext
			if (_eventObj.status == 2) {
			    dlg.infoText.show();
			} else {
			    dlg.infoText.hide();
			}

            //location
			dlg.editor.location.val(_eventObj.location || "");
			dlg.viewer.location.text(_eventObj.location || "");

			if (_eventObj.location)
			    dlg.viewer.location.show();
			else {
			    dlg.viewer.location.hide();
			}

		    //attendees
			if(_eventObj.attendees && _eventObj.attendees.length) {
			    var statuses = {
			        needsAction: "NEEDS-ACTION", needsActionCount: 0,
			        accepted: "ACCEPTED", acceptedCount: 0,
			        declined: "DECLINED", declinedCount: 0,
			        tentative: "TENTATIVE", tentativeCount: 0
			    };
			    
			    var showReplyButtons = false;

			    jq(_eventObj.attendees).each(function (index, attendee) {
			        
			        var attendeeEmail = attendee[3].replace(new RegExp("mailto:", "ig"), "");
			        var attendeePartstat = attendee[1].partstat.toUpperCase();

			        if (!showReplyButtons) {
			            jq(ASC.Mail.Accounts).each(function(j, account) {
			                if (account.enabled && attendeeEmail.toLowerCase() == account.email.toLowerCase()) {
			                    showReplyButtons = true;
			                    dlg.viewer.replybuttons.find(".reply-button").removeClass("active");
			                    dlg.viewer.replybuttons.find(".reply-button." + attendeePartstat.toLowerCase()).addClass("active");
			                    return false;
			                }
			                return true;
			            });
			        }

			        switch (attendeePartstat) {
			            case statuses.accepted:
			                statuses.acceptedCount++;
			                break;
			            case statuses.declined:
			                statuses.declinedCount++;
			                break;
			            case statuses.tentative:
			                statuses.tentativeCount++;
			                break;
			            case statuses.needsAction:
			                statuses.needsActionCount++;
			                break;
			            default:
			                break;
			        }
			        
			    });

			    dlg.viewer.attendees.find(".guests-count").text(_eventObj.attendees.length);
			    dlg.viewer.attendees.find(".accepted-count").text(statuses.acceptedCount);
			    dlg.viewer.attendees.find(".declined-count").text(statuses.declinedCount);
			    dlg.viewer.attendees.show();

			    if (_canEdit && showReplyButtons && _eventObj.status != 2 && !_eventObj.source.isSubscription)
			        dlg.viewer.replybuttons.show();
			    else
			        dlg.viewer.replybuttons.hide();

			} else {
			    dlg.viewer.replybuttons.hide();
			    dlg.viewer.attendees.hide();
			}

			var organizerName = _eventObj.organizer && _eventObj.organizer.length > 1 ? _eventObj.organizer[1].cn : "";
			organizerName = organizerName ? organizerName : _eventObj.owner && _eventObj.owner.name ? _eventObj.owner.name : "";

			if (organizerName) {
			    dlg.viewer.owner.html(htmlEscape(organizerName));
				_dialog.find(".viewer .owner").removeClass("hidden");
			} else {
				dlg.viewer.owner.html("");
				_dialog.find(".viewer .owner").addClass("hidden");
			}

            //all day
			if (_eventObj.allDay == true) {
				dlg.editor.allday.prop("checked", true);
				dlg.viewer.allday.addClass("yes");
			} else {
				dlg.editor.allday.prop("checked", false);
				dlg.viewer.allday.removeClass("yes");
			}

            //editor from
			dlg.editor.from.css("color", "").css("border-color", "");
			dlg.editor.from_t.css("color", "").css("border-color", "");

			dlg.todo.date.css("color", "").css("border-color", "");
			dlg.todo.time.css("color", "").css("border-color", "");
			dlg.todo.date.val(formatDate(_eventObj.start, calendar.options.eventEditor.dateFormat));
			dlg.todo.time.val('00:00');
		    
			if (_eventObj.start instanceof Date) {
				dlg.editor.from.val(formatDate(_eventObj.start, calendar.options.eventEditor.dateFormat));
				if (_eventObj.allDay == false) {
					dlg.editor.from_t.val(formatDate(_eventObj.start, calendar.options.eventEditor.timeFormat));
				} else {
					dlg.editor.from_t.val("");
				}
			} else {
				dlg.editor.from.val("");
				dlg.editor.from_t.val("");
			}

            //editor to
			dlg.editor.to.css("color", "").css("border-color", "");
			dlg.editor.to_t.css("color", "").css("border-color", "");
		    
			if (_eventObj.end instanceof Date) {
				dlg.editor.to.val(formatDate(_eventObj.end, calendar.options.eventEditor.dateFormat));
				if (_eventObj.allDay == false) {
					dlg.editor.to_t.val(formatDate(_eventObj.end, calendar.options.eventEditor.timeFormat));
				} else {
					dlg.editor.to_t.val("");
				}
			} else {
			    if (_eventObj.allDay && _eventObj.start instanceof Date) {
			        dlg.editor.to.val(formatDate(_eventObj.start, calendar.options.eventEditor.dateFormat));
			    } else {
			        dlg.editor.to.val("");
			        dlg.editor.to_t.val("");
			    }
			}
		    
            //viewer from
			dlg.viewer.from.text(dlg.editor.from.val());
			
			if( (_eventObj.start instanceof Date && !_eventObj.allDay) || (_eventObj.start instanceof Date && _eventObj.allDay && _eventObj.isSegmEvent) ){
				dlg.viewer.from_t.text(formatDate(_eventObj.start, calendar.options.axisFormat));
			} else {
				dlg.viewer.from_t.text("");
			}
			
		    //viewer to
			dlg.viewer.to.text(dlg.editor.to.val());

			if ((_eventObj.end instanceof Date && !_eventObj.allDay) || (_eventObj.end instanceof Date && _eventObj.allDay && _eventObj.isSegmEvent)) {
				dlg.viewer.to_t.text(formatDate(_eventObj.end, calendar.options.axisFormat));
			} else {
				dlg.viewer.to_t.text("");
			}

			var defaultSource = _getDefaultSource();
			var afretResizeSourceIsValid = fcUtil.objectIsValid(_eventObj.afretResizeSource);
			var calSource = sourceIsValid ? _eventObj.source : afretResizeSourceIsValid ? _eventObj.afretResizeSource : defaultSource;

			dlg.editor.repeat.text(function() {
				if (!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.Never) && 
					!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryDay) &&
					!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryWeek) &&
					!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryMonth) &&
					!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryYear)) {
						_openSettings.call(_this);
						_settings.removeClass("hidden");
						
						_disableRepeatSettings.call(_this);
						_setRepeatBackground.call(_this, 1);
					}
				
				return _getRepeatLabel.call(_this, _eventObj.repeatRule);
			});
			dlg.editor.alert.text(sourceIsValid ? _getAlertLabel.call(_this, _eventObj.alert.type) : _getAlertLabel.call(_this, kAlertDefault));

			if (canChangeAlert) {
				_dialog.find(".viewer .repeat-alert").removeClass("hidden");
				_dialog.find(".editor .repeat-alert").removeClass("hidden");
				
				//_dialog.find(".viewer .fc-dropdown").removeClass("hidden");
				//_dialog.find(".editor .fc-dropdown").removeClass("hidden");
			} else {
				dlg.editor.repeat.text(ASC.Api.iCal.RecurrenceRule.Never);
				dlg.editor.alert.text(kAlertNever);
				_dialog.find(".viewer .repeat-alert").addClass("hidden");
				_dialog.find(".editor .repeat-alert").addClass("hidden");
				
				//_dialog.find(".viewer .fc-dropdown").removeClass("hidden");
				//_dialog.find(".editor .fc-dropdown").removeClass("hidden");
			}
			dlg.viewer.repeat.text(dlg.editor.repeat.text());
			dlg.viewer.alert.text(dlg.editor.alert.text());

			var options = '';
			var calT;
			var calVal;
			var calColor;
			if (_canChangeSource) {
				for (i = 0; i < sources.length; ++i) {
					if ((sources[i].objectId != undefined) &&
							(sources[i].isEditable || !sources[i].isSubscription) && sources[i].isTodo != 1) {
						calT = htmlEscape(sources[i].title);
						options += '<option value="' + htmlEscape(sources[i].objectId) + '" ' +
								'title="' + calT + '">' +
								'&nbsp;&nbsp;&nbsp;&nbsp;' +  // for select elem padding does not work in safari
								calT + '</option>';
					}
				}
				calVal = calSource.objectId;
				calColor = calSource.backgroundColor;
				dlg.editor.calendar.removeAttr("disabled");
			} else {
				calVal = sourceIsValid ?
						_eventObj.source.objectId : -1;
				calColor = sourceIsValid ?
						_eventObj.source.backgroundColor : calendar.options.eventBackgroundColor;
				calT = htmlEscape(sourceIsValid ? _eventObj.source.title : "");
				options = '<option value="' + htmlEscape(calVal) + '" title="' + calT + '">' +
						'&nbsp;&nbsp;&nbsp;&nbsp;' +      // for select elem padding does not work in safari
						calT + '</option>';
				dlg.editor.calendar.attr("disabled", "disabled");
			}

			dlg.editor.calendar.html(options);
			dlg.editor.calendar.val(calVal);
			dlg.viewer.calendar.text(sourceIsValid ?
					_eventObj.source.title :
					dlg.editor.calendar.find("option:selected").text());

			calColor = htmlEscape(calColor);
			dlg.editor.calendar_b.css("background", calColor);
			dlg.viewer.calendar_b.css("background", calColor);

			dlg.editor.status.val(_eventObj.status);
			dlg.viewer.status.text(dlg.editor.status.find("option:selected").text());

			dlg.editor.description.val(_eventObj.description != undefined ? _eventObj.description : "");
			setTimeout(function() {     // jScrollPane must be init for visible element
				dlg.viewer.description.empty();
				dlg.viewer.description.append(
						'<div><div class="inner">' + htmlEscape(dlg.editor.description.val()) + '</div></div>');
				var inner = dlg.viewer.description.find(".inner");
				inner.css("width", inner.width() + "px");
				dlg.viewer.description.children("div").jScrollPane();
				inner.css("width", "");
				
				//hide description field title in Birthday event
				if (_eventObj.sourceId == "users_birthdays") {
					dlg.viewer.description.prev().hide();
				} else {
					dlg.viewer.description.prev().show();
				}
				
				_resizePopup();
			}, 0);

			_renderPermissions.call(_this);
			_handleAllDayClick.call(_this);
			changeTimeFrom = null;
		}
		return true;
	}


	function _getDefaultSource() {
		var sources = calendar.getEventSources();
		var s1;
		for (var i = 0; i < sources.length; ++i) {
			if (fcUtil.objectIsValid(sources[i]) && (
			    fcUtil.objectIsEditable(sources[i]) || !sources[i].isSubscription) && sources[i].isTodo != 1) {
				if (s1 == undefined) {s1 = sources[i];}
				if (!sources[i].isHidden) {return sources[i];}
			}
		}
		return s1;
	}

	function _createEvent(startDate, endDate, allDay) {
		var evt = {
			title:           "",
			description:     "",
			allDay:          allDay,
			start:           startDate,
			end:             endDate,
			repeatRule:      ASC.Api.iCal.RecurrenceRule.Never,
			alert:           {type:kAlertDefault},
			isShared:        false,
			permissions:     {users:[]},
			attendees:       []
		};
	    

		if (ASC.Mail.DefaultAccount) {
		    var organizerObj = new ICAL.Property("organizer");
		    organizerObj.setParameter("cn", ASC.Mail.DefaultAccount.name);
		    organizerObj.setValue("mailto:" + ASC.Mail.DefaultAccount.email);
		    evt.organizer = organizerObj.jCal;
		}

	    return evt;
	}

	function _deleteEvent(deleteType, eventDate) {
		if (!_canDelete ||
		    !fcUtil.objectIsValid(_eventObj) ||
		    !fcUtil.objectIsValid(_eventObj.source)) {return;}

		if (_eventObj.sourceId && _eventObj.uniqueId && (_eventObj.repeatRule.Freq == ASC.Api.iCal.Frequency.Never || confirmSettings.selectedDeleteMode == deleteMode.allSeries))
	        _sendNotification(_eventObj.sourceId, _eventObj.uniqueId, confirmSettings.notificationType.cancel, deleteEvt);
	    else
	        deleteEvt();

	    function deleteEvt() {
	        var id = _eventObj._id;
	        calendar.trigger("editEvent", _this,
	            $.extend(
	                { action: kEventDeleteAction, sourceId: _eventObj.source.objectId, type: deleteType, date: eventDate },
	                _eventObj),
	            function(response) {
	                if (!response.result) {
	                    return;
	                }
	                calendar.removeEvents(id);

	                //
	                if (response.event != undefined) {
	                    if (!response.event.length) {
	                        if (_eventObj.repeatRule.Freq != ASC.Api.iCal.Frequency.Never && confirmSettings.selectedDeleteMode != deleteMode.allSeries) {
	                            _sendNotification(_eventObj.sourceId, _eventObj.uniqueId, confirmSettings.notificationType.cancel, function() {
	                                ASC.CalendarController.RemoveEvent(id, deleteMode.allSeries, eventDate);
	                            });
	                        }
	                        return;
	                    }
	                    //
	                    var sources = calendar.getEventSources();
	                    var j = 0;
	                    while (j < response.event.length) {
	                        _setEventSource(response.event[j], sources);
	                        j++;
	                    }
	                    calendar.addEvents(response.event);

	                    if(_eventObj.repeatRule.Freq != ASC.Api.iCal.Frequency.Never && confirmSettings.selectedDeleteMode != deleteMode.allSeries)
	                        _sendNotification(_eventObj.sourceId, _eventObj.uniqueId, confirmSettings.notificationType.update);
	                }
	            });
	    }
	}

	function _unsubscribeEvent() {
		if (!_canUnsubscribe ||
		    !fcUtil.objectIsValid(_eventObj) ||
		    !fcUtil.objectIsValid(_eventObj.source)) {return;}
		//
		var id = _eventObj._id;
		calendar.trigger("editEvent", _this,
				$.extend(
						{action: kEventUnsubscribeAction, sourceId: _eventObj.source.objectId},
						_eventObj),
				function(response) {
					if (!response.result) {return;}
					calendar.removeEvents(id);
				    _close.call(_this, false);
				});
	}

	function _setEventSource(event, sources) {
		if (event.sourceId == undefined) {
			event.sourceId = event.newSourceId;
		}
		if (!event.source && event.sourceId != undefined) {
			for (var i = 0; i < sources.length; ++i) {
				if (sources[i].objectId != undefined &&
						sources[i].objectId == event.sourceId) {
					event.source = sources[i];
					break;
				}
			}
		}
	}
	function _createTodo() {
	    calendar.todolist.createTodo(_todoObj);
	    _dialog.popupFrame("close");
	    uiBlocker.hide();
	}
	function _updateEvent(isCancel) {
		if (!_canEdit) {return;}
		
		if(isCancel)
		{
			calendar.trigger("editEvent", _this, $.extend( {action: kEventCancelAction, sourceId: _eventObj.source.objectId}, _eventObj), function(response){} );
			return;
		}

		if (_eventObj.source) {
		    _disableDialogBtns(true);
		    // update event
		    calendar.trigger("editEvent", _this,
					$.extend(
							{action: kEventChangeAction, sourceId: _eventObj.source.objectId},
							_eventObj),
					function(response) {
					    _disableDialogBtns(false);
					    if (!response.result) {return;}
						_closeDialog.call(_this);
						if (response.event.length < 1) {return;}
						//
						var sources = calendar.getEventSources();
						if (response.event[0])
							calendar.removeEvents(response.event[0].objectId);
						for (var j = 0; j < response.event.length; ++j) {
							_setEventSource(response.event[j], sources);
						}
						calendar.addEvents(response.event);
					});
		} else {
		    _disableDialogBtns(true);
		    var id = _eventObj._id;
			// create new event
			calendar.trigger("editEvent", _this,
					$.extend({action: kEventAddAction}, _eventObj),
					function(response) {
					    _disableDialogBtns(false);
					    if (!response.result) {return;}
						_closeDialog.call(_this);
						calendar.removeEvents(id);
						if (response.event.length < 1) {return;}
						//
						var sources = calendar.getEventSources();
						if (response.event[0])
							calendar.removeEvents(response.event[0].objectId);
						for (var j = 0; j < response.event.length; ++j) {
							_setEventSource(response.event[j], sources);
						}
						calendar.addEvents(response.event);
					});
		}
	}

    function _eventReply(decision) {

        if (!_eventObj.attendees || !_eventObj.attendees.length) return;

        var partstat = typeof decision === "boolean" ? decision ? "ACCEPTED" : "DECLINED" : "TENTATIVE";

        var replyEmail = null;

        jq(_eventObj.attendees).each(function(i, attendee) {

            var attendeeEmail = attendee[3].replace(new RegExp("mailto:", "ig"), "");
            var attendeePartstat = attendee[1].partstat.toUpperCase();

            jq(ASC.Mail.Accounts).each(function(j, account) {
                if (account.enabled && attendeeEmail.toLowerCase() == account.email.toLowerCase() && attendeePartstat != partstat) {
                    replyEmail = attendeeEmail;
                    return false;
                }
                return true;
            });

            return replyEmail == null;
        });

        if (_eventObj.sourceId && _eventObj.uniqueId && replyEmail) {
            _doReply(_eventObj.sourceId, _eventObj.uniqueId, replyEmail, partstat);
        }
    }

    function _doReply(calendarId, eventUid, attendeeEmail, partstat) {
        _dialog.find(".viewer .reply-button").removeClass("active");

        ASC.CalendarController.Busy = true;
        window.LoadingBanner.displayLoading();

        ASC.Mail.Utility.SendCalendarReply(calendarId, eventUid, attendeeEmail, partstat)
            .done(function () {
                _doReplyCallback(attendeeEmail, partstat);
            })
            .fail(function () {
                toastr.error(calendar.options.confirmPopup.dialogErrorToastText);
                console.error(calendar.options.confirmPopup.dialogErrorToastText, arguments);
            })
            .always(function () {
                ASC.CalendarController.Busy = false;
                window.LoadingBanner.hideLoading();
            });
    }
    
    function _doReplyCallback(attendeeEmail, partstat) {
        _dialog.find(".viewer .reply-buttons ." + partstat.toLowerCase()).addClass("active");
        
        jq(_eventObj.attendees).each(function (index, item) {
            var itemEmail = item[3].replace(new RegExp("mailto:", "ig"), "");
            if (itemEmail.toLowerCase() == attendeeEmail.toLowerCase()) {
                item[1].partstat = partstat;
                item[1].rsvp = "FALSE";
                return false;
            }
            return true;
        });
        
        var statuses = {
            n: "NEEDS-ACTION", nc: 0,
            a: "ACCEPTED", ac: 0,
            d: "DECLINED", dc: 0,
            t: "TENTATIVE", tc: 0
        };

        jq(_eventObj.attendees).each(function (index, attendee) {
			        
            var attendeePartstat = attendee[1].partstat.toUpperCase();
			        
            switch (attendeePartstat) {
                case statuses.a:
                    statuses.ac++;
                    break;
                case statuses.d:
                    statuses.dc++;
                    break;
                case statuses.t:
                    statuses.tc++;
                    break;
                case statuses.n:
                    statuses.nc++;
                    break;
                default:
                    break;
            }
			        
        });

        _dialog.find(".attendees .guests-count").text(_eventObj.attendees.length);
        _dialog.find(".attendees .accepted-count").text(statuses.ac);
        _dialog.find(".attendees .declined-count").text(statuses.dc);

    }

    // Public interface

    this.openEvent = function (elem, event) {
        calendar.openEventWin = { objectId: event.objectId, isTodo: event.isTodo };
	    if (ASC.CalendarController.Busy) {
	        console.log("ASC.CalendarController.Busy");
	        return false;
	    }

	    ASC.CalendarController.CancelEditDialog();

		if (event && !isNaN(event.objectId) && event.uniqueId && !event.isTodo) {
	        Teamlab.getCalendarEventById({},
                event.objectId,
                {
                    success: function(p, eventInfo) {
                        if (eventInfo.eventUid === event.uniqueId && eventInfo.mergedIcs) {
                            console.info(eventInfo);

                            var evt = parseIcs(eventInfo.mergedIcs);

                            event = jq.extend(event, evt || {});

                            _open.call(_this, "view", elem, event);
                        }
                    },
                    error: function(p, e) {
                        console.error(e);
                    },
                    max_request_attempts: 1
                });
		} if (event.isTodo) {
			calendar.todolist.openTodoEditor(event, elem);
		} else {
	        _open.call(_this, "view", elem, event);
	    }
	};

	this.addEvent = function(startDate, endDate, allDay , isAfterResize) {
	    if (ASC.CalendarController.Busy) {
	        console.log("ASC.CalendarController.Busy");
	        return false;
	    }

	    calendar.openEventWin = { objectId: null, isTodo: false };
	    
	    ASC.CalendarController.CancelEditDialog();

	    // Protect from addind event in nonexistent category
		var defaultSource = _getDefaultSource();
		if (defaultSource == undefined) return false;

		_dialog.find(".buttonGroup span.active").removeClass('active');
		_dialog.find(".buttonGroup span.event").addClass('active');
	    _editMode = _editModes.event;

		var ev;
		if (startDate != undefined) {
		    ev = _createEvent(startDate, endDate, allDay);
		    if (isAfterResize && _eventObj) {
		        ev.alert = _eventObj.alert;
		        ev.allDay = _eventObj.allDay;
		        ev.location = _eventObj.location;
		        ev.start = _eventObj.start;
		        ev.end = _eventObj.end;
		        ev.title = _eventObj.title; 
		        
		        var s = calendar.getEventSources();
		        for (var i = 0; i < s.length; ++i) {
		            if (_eventObj.newSourceId != undefined && _eventObj.newSourceId == s[i].objectId) {
		                ev.afretResizeSource = s[i];
		            }
		        }

		        ev.textColor = defaultSource.textColor;
		        ev.backgroundColor = defaultSource.backgroundColor;
		        ev.borderColor = defaultSource.borderColor;
		    } else {
		        // add event via clicking calendar cell
		        
		        ev.textColor = defaultSource.textColor;
		        ev.backgroundColor = defaultSource.backgroundColor;
		        ev.borderColor = defaultSource.borderColor;
		    }
			
		    calendar.renderEvent(ev);
			_open.call(_this, "addPopup", calendar.getView().getEventElement(ev), ev);
		} else {
			// add event via header menu
			ev = _createEvent(
					new Date(),
					addMinutes(new Date(), calendar.options.defaultEventMinutes),
					false);
			_open.call(_this, "addDialog", undefined, ev);
		}
	};

	this.isVisible = function() {
		return _dialog.popupFrame("isVisible");
	};
    
	this.closePopupEvent = function (isResize) {
	    if (isResize) {
	        _doDDX.call(_this, true);
	        calendar.openEventWin = { objectId: null, isTodo: false};
	    }
	    if (this.isVisible() && !_dialogMode) {
	        _close.call(_this, false);
	    }
	};

    this.getEventObj = function() {
        return _eventObj;
    };
    
}


function EventPage(calendar) {
    var _this = this;
	
    var rs = calendar.options.repeatSettings;
    var ds = calendar.options.deleteSettings;
    var cp = calendar.options.confirmPopup;

    var dwm = {
        day:     0,
        week:    1,
        month:   2,
        year:    3
    };

    var deleteMode = {
        single: 0,
        allFollowing: 1,
        allSeries: 2
    };

    var confirmSettings = {
        viewMode: {
            none: 0,
            addEvent: 1,
            updateEvent: 2,
            updateGuests: 3,
            deleteEvent: 4
        },
        notificationMode: {
            nobody: 0,
            partially: 1,
            everybody: 2
        },
        notificationType: {
            request: 1,
            update: 2,
            cancel: 4
        },
        notificationUsers: {
            newGuests: [],
            removedGuests: [],
            updatedGuests: []
        },
        selectedViewMode: 0,
        selectedNotificationMode: 0,
        selectedDeleteMode: 0,
    };

    var replyDecisionSettings = {
        sendReply: true,
        email: null,
        decision: null
    };
	
    var _dialog;
    var _settings;
    var _delSettings;
    var _confirmPopup;
    var uiBlocker;
    var alertType = kAlertDefault;
    var repeatRule = ASC.Api.iCal.RecurrenceRule.EveryDay;
    var dwm_current = dwm.day;
    var dayRuleObject = undefined;
	

    var _eventObj;
    var _canEdit;
    var _canDelete;
    var _canChangeSource;
    var _canUnsubscribe;

    var formatDate = calendar.formatDate;
    var formatDates = calendar.formatDates;


    (function _createPage() {
        _dialog = jq("#asc_event").empty();
        
        jq("#eventPageTemplate").tmpl({ maxlength: defaults.eventMaxTitleLength }).appendTo(_dialog);

        var selector = jq("#asc_event .editor .owner select");
        jq.each(ASC.Mail.Accounts, function (index, item) {
            var name = item.name ? Encoder.htmlEncode(item.name) : Teamlab.profile.displayName;
            var option = jq("<option/>").attr("value", item.email).attr("data-name", Encoder.htmlDecode(name)).html("{0} &lt;{1}&gt;".format(name, item.email));
            selector.append(option);
        });

        selector.tlcombobox({ align: "left" });

        uiBlocker = _dialog.find(".fc-modal");

        _dialog.find(".buttons .save-btn").click(function() {
            if (jq(this).hasClass("disable"))
                return;
		    
            var hasSettings = !_settings.hasClass("hidden");
            if (hasSettings) {
                if (!_validateDateFieldsSettings.call(_this)) {
                    return;
                }
                _closeSettings.call(_this, hasSettings);
            }
            var oldEventObj = Object.assign({}, _eventObj),
                compareResult = {},
                sentInvitations = _dialog.find(".editor .sent-invitations input").is(":checked"),
                confirmViewMode = _getConfirmViewMode.call(_this);
            
            if (sentInvitations) {
                if (oldEventObj.sourceId != undefined) { //it's not new event

                    var validData = _doDDX.call(_this, true);
                    if (!validData) return;

                    var newEventObj = Object.assign({}, _eventObj);
                    _eventObj = Object.assign({}, oldEventObj);

                    compareResult = deepEventsCompare(oldEventObj, newEventObj);

                    if (!compareResult.isCompare) {
                        if (compareResult.differentsList.length == 1 && compareResult.differentsList.indexOf("attendees") != -1) {
                            if (confirmViewMode) {
                                _openConfirmPopup.call(_this);
                            } else {
                                _close.call(_this, true);
                            }
                        } else if (compareResult.differentsList.length >= 1) {
                            if (confirmViewMode) {
                                _sendGuestsNotification.call(_this, confirmSettings.notificationMode.everybody);
                            } else {
                                _close.call(_this, true);
                            }
                        }
                    } else {
                        _close.call(_this, true);
                    }
                } else {
                    if (confirmViewMode) {
                        _sendGuestsNotification.call(_this, confirmSettings.notificationMode.everybody);
                    } else {
                        _close.call(_this, true);
                    }
                }
            } else {
                _close.call(_this, true);
            }
        });
       
        function deepEventsCompare () {
            var i, l, leftChain, rightChain;

            var result = {
                isCompare: true,
                differentsList: []
            };

            function compare2Objects (x, y, notPush) {
                var p;

                if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
                    return result;
                }

                if (x === y) {
                    return result;
                }

                if ((typeof x === 'function' && typeof y === 'function') ||
                   (x instanceof Date && y instanceof Date) ||
                   (x instanceof RegExp && y instanceof RegExp) ||
                   (x instanceof String && y instanceof String) ||
                   (x instanceof Number && y instanceof Number)) {
                    return x.toString() === y.toString();
                }

                if (!(x instanceof Object && y instanceof Object)) {
                    result.isCompare = false;
                    return result;
                }

                if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
                    result.isCompare = false;
                    return result;
                }

                if (x.constructor !== y.constructor) {
                    result.isCompare = false;
                    return result;
                }

                if (x.prototype !== y.prototype) {
                    result.isCompare = false;
                    return result;
                }

                if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
                    result.isCompare = false;
                    return result;
                }
                

                for (p in y) {
                    if (y.hasOwnProperty(p) !== x.hasOwnProperty(p) && (p != "newSourceId" && p != "newTimeZone")) {
                        result.isCompare = false;
                        if(!notPush) result.differentsList.push(p);
                    }
                    else if (typeof y[p] !== typeof x[p] && (p != "newSourceId" && p != "newTimeZone")) {
                        result.isCompare = false;
                        if(!notPush) result.differentsList.push(p);
                    }
                }

                for (p in x) {
                    if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
                        result.isCompare = false;
                        if(!notPush) result.differentsList.push(p);
                    }
                    else if (typeof y[p] !== typeof x[p]) {
                        result.isCompare = false;
                        if(!notPush) result.differentsList.push(p);
                    }
                    if (x[p] == null && y[p] != null) {
                        result.differentsList.push(p);
                    } else {
                        switch (typeof (x[p])) {
                            case 'object':
                            case 'function':

                                leftChain.push(x);
                                rightChain.push(y);

                                if (p == "attendees") {
                                    var t = Object.assign({}, result);
                                    result = { isCompare: true, differentsList: [] };
                                    var tmpResult = compare2Objects(x[p], y[p], true);
                                
                                    if (!tmpResult.isCompare) {
                                        result.isCompare = false;
                                        result.differentsList.push(p);
                                    }
                                    result.isCompare = !result.isCompare ? result.isCompare : t.isCompare;
                                    result.differentsList = result.differentsList.concat(t.differentsList);
                                    tmpResult = t = null;

                                }else if (!compare2Objects (x[p], y[p])) {
                                    result.isCompare = false;
                                    if(!notPush) result.differentsList.push(p);
                                }

                                leftChain.pop();
                                rightChain.pop();
                                break;

                            default:
                                if (p == "sourceId") {
                                    if(x[p] !== y["sourceId"] || x[p] !== y["newSourceId"]){
                                        result.isCompare = false;
                                        if(!notPush) result.differentsList.push(p);
                                    }
                                }else if (x[p] !== y[p]) {
                                    result.isCompare = false;
                                    if(!notPush) result.differentsList.push(p);
                                }
                                break;
                        }
                    }
                    
                }
               
                return result;
            }

            if (arguments.length < 1) {
                return result; 
            }

            for (i = 1, l = arguments.length; i < l; i++) {

                leftChain = [];
                rightChain = [];

                compare2Objects(arguments[0], arguments[i]);

            }

            return result;
        }
       
        _dialog.find(".event-header .header-back-link, .buttons .cancel-btn, .buttons .close-btn").click(function() {
            _close.call(_this, false);
        });
        
        _dialog.find(".buttons .delete-btn").click(function() {
            if (_canDelete) {
                _openDelSettings.call(_this, _eventObj.repeatRule.Freq == ASC.Api.iCal.Frequency.Never);
            }
        });
        
        _dialog.find(".buttons .unsubs-btn").click(function() {
            if (_canUnsubscribe) {
                _unsubscribeEvent.call(_this);
            }
        });

        _renderRepeatAlertList.call(_this);
		
        _dialog.find(".editor .title input").keyup(function() {
            fcUtil.validateInput(this, fcUtil.validateNonemptyString);
        });
        
        _dialog.find(".editor .attendees input.textEdit").AttendeesSelector("init", {
            isInPopup: false,
            items: [],
            container: _dialog.find(".editor .attendees .attendees-user-list"),
            organizer: _dialog.find(".editor .owner select"),
        });

        _dialog.find(".editor .addUserLink").ShareUsersSelector("init", {
            permissions: { data: { actions: [], items: [] }, users: []},
            container:  _dialog.find(".editor .shared-user-list")
        });

        _dialog.find(".editor .owner select").on("change", function() {
            var email = jq(this).val();
            var attendeeSelector = _dialog.find(".editor .attendees input.textEdit");
            var attendees = attendeeSelector.AttendeesSelector("get");
            var redraw = false;

            jq.each(attendees, function(index, item) {
                if(Boolean(item[1]["x-organizer"])){
                    item[3] = "mailto:" + email;
                    redraw = true;
                }
            });

            if (redraw) attendeeSelector.AttendeesSelector("set", attendees);
        });

        _dialog.find(".editor .all-day input").click(_handleAllDayClick);
		
        _dialog.find(".editor .all-day .label").css("cursor", "pointer").click(function() {
            _dialog.find(".editor .all-day .cb").trigger("click");
            _handleAllDayClick.call(_this);
        });

        function loadDate(input, dp, defDate) {
            var d = parseISO8601(input.val());
            dp.datepicker("setDate", (d instanceof Date) ? d : defDate);
        }
        
        function saveDate(input, inputT, dp) {
            input.val(formatDate(
					dp.datepicker("getDate"),
					calendar.options.eventEditor.dateFormat));
            if (!inputT.is(":disabled") && $.trim(inputT.val()).length < 1) {
                inputT.val("00:00");
            }
            input.change();
        }
        
        var fromD = _dialog.find(".editor .from-to .from-date");
        var fromT = _dialog.find(".editor .from-to .from-time");
		
        var toD   = _dialog.find(".editor .from-to .to-date");
        var toT   = _dialog.find(".editor .from-to .to-time");
		
        _dialog.find(".editor .from-to .from.cal-icon").click(function() {
            fcDatepicker.open(calendar, this,
					function(dp) {loadDate(fromD, dp, _eventObj.start);},
					function(elem, dp) {
					    this.close();
					    saveDate(fromD, fromT, dp);
						
					    var fromD_settings = _settings.find(".from-date");
					    var fromT_settings = _settings.find(".from-time");
					    saveDate(fromD_settings, fromT_settings, dp);
					});
        });
        
        _dialog.find(".editor .from-to .to.cal-icon").click(function() {
            fcDatepicker.open(calendar, this,
					function(dp) {loadDate(toD, dp, _eventObj.end||_eventObj.start);},
					function(elem, dp) {
					    this.close();
					    saveDate(toD, toT, dp);
					});
        });

        _dialog.find(".editor .from-to .from-time, .editor .from-to .to-time").mask("00:00");
        
        _dialog.find(".editor .from-to .from-date, .editor .from-to .from-time, .editor .from-to .to-date, .editor .from-to .to-time")
            .bind("keyup change", _validateDateFields);

        _dialog.find(".editor .calendar select").change(function (ev) {
            var v = $(this).val();
            var s = calendar.getEventSources();
            for (var i = 0; i < s.length; ++i) {
                if (s[i].objectId != v || s[i].isTodo == 1) { continue; }
                _dialog.find(".editor .calendar .bullet").css("background", s[i].backgroundColor);
                
                if (s[i].isSubscription) {
                    _dialog.find(".editor .attendees").hide();
                } else {
                    if (!_dialog.find(".editor .attendees .input-container").hasClass("display-none") ||
                        !_dialog.find(".editor .attendees .attendees-user-list").hasClass("display-none") ||
                        !_dialog.find(".editor .attendees .attendees-noaccount").hasClass("display-none")) {
                        _dialog.find(".editor .attendees").show();
                    } else {
                        _dialog.find(".editor .attendees").hide();
                    }
                }

                return;
            }
        });
        
        jq("#attendeesHelpSwitcher").on("click", function () {
            jq(this).helper({ BlockHelperID: 'attendeesHelpInfo' });
        });
        
        if (window.onbeforeunload == null) {
                window.onbeforeunload = function () {
                    if(jq("#asc_event .event-editor .editor").is(":visible")) {
                        return ASC.Resources.Master.ResourceJS.WarningMessageBeforeUnload;
                    }
                };
            }
    }());
	
    (function _createSettings() {
        _settings = _dialog.find(".repeat-settings");

        // day/week/month selector
        var _DWMSelectorLabel = _settings.find(".fc-dwm-selector");
		
        _settings.find(".fc-dwm-selector").click(
			function (event) {
			    
			    if ($(this).find(".fc-selector-link").hasClass("not-active")) {
			        return;
			    }
				
			    fcMenus.hideMenus(fcMenus.modeMenuDWMEventPage);
			    fcMenus.modeMenuDWMEventPage.popupMenu("open", _DWMSelectorLabel);
			    event.stopPropagation();
			});
			
        if (!fcMenus.modeMenuDWMEventPage || fcMenus.modeMenuDWMEventPage.length < 1) {
            fcMenus.modeMenuDWMEventPage = $('<div id="fc_mode_menu_dwm_eventpage"/>');
        } else {
            fcMenus.modeMenuDWMEventPage.popupMenu("close");
            fcMenus.modeMenuDWMEventPage.popupMenu("destroy");
        }
        
        fcMenus.modeMenuDWMEventPage.popupMenu({
            anchor: "left,bottom",
            direction: "right,down",
            arrow: "up",
            showArrow: false,
            closeTimeout: -1,
            cssClassName: "asc-popupmenu",
            items: [
                {
                    label: rs.dialogRepeatOn_days,
                    click: function() {
                        _DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_days);
                        _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_day);
                        dwm_current = dwm.day;
                        _showDaySections.call(_this);
                        _settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
                    }
                },
                {
                    label: calendar.options.repeatSettings.dialogRepeatOn_weeks,
                    click: function() {
                        _DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_weeks);
                        _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_week);
                        dwm_current = dwm.week;
                        _showWeekSections.call(_this);
                        _settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
                    }
                },
                {
                    label: calendar.options.repeatSettings.dialogRepeatOn_months,
                    click: function() {
                        _DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_months);
                        _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_month);
                        dwm_current = dwm.month;
                        _showMonthSections.call(_this);
                        _settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
                    }
                },
                {
                    label: calendar.options.repeatSettings.dialogRepeatOn_years,
                    click: function() {
                        _DWMSelectorLabel.find(".fc-selector-link").text(rs.dialogRepeatOn_years);
                        _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_year);
                        dwm_current = dwm.year;
                        _showDaySections.call(_this);
                        _settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
                    }
                }
            ]
        });
			
        // end of repeat selector
        var _endRepeatSelectorLabel = _settings.find(".fc-endrepeat-selector");
		
        _settings.find(".fc-endrepeat-selector").click(
			function (event) {
				
			    if ($(this).find(".fc-selector-link").hasClass("not-active")) {
			        return false;
			    }
				
			    fcMenus.hideMenus(fcMenus.modeMenuEndRepeatEventPage);
			    fcMenus.modeMenuEndRepeatEventPage.popupMenu("open", _endRepeatSelectorLabel);
			    event.stopPropagation();
			});
			
        if (!fcMenus.modeMenuEndRepeatEventPage || fcMenus.modeMenuEndRepeatEventPage.length < 1) {
            fcMenus.modeMenuEndRepeatEventPage = $('<div id="fc_mode_menu_end_reapeat_eventpage"/>');
        } else {
            fcMenus.modeMenuEndRepeatEventPage.popupMenu("close");
            fcMenus.modeMenuEndRepeatEventPage.popupMenu("destroy");
        }
        fcMenus.modeMenuEndRepeatEventPage.popupMenu({
            anchor: "left,bottom",
            direction: "right,down",
            arrow: "up",
            showArrow: false,
            closeTimeout: -1,
            cssClassName: "asc-popupmenu",
            items: [
                {
                    label: calendar.options.repeatSettings.dialogOptionNever,
                    click: function() {
                        _endRepeatSelectorLabel.find(".fc-selector-link").text(rs.dialogOptionNever);
                        _showEndSectionsNever.call(_this);
                    }
                },
                {
                    label: calendar.options.repeatSettings.dialogOptionCount,
                    click: function() {
                        _endRepeatSelectorLabel.find(".fc-selector-link").text(rs.dialogOptionCount);
                        _settings.find(".fc-cycle-times").val(3);
                        _showEndSectionsCycles.call(_this);
                    }
                },
                {
                    label: calendar.options.repeatSettings.dialogOptionDate,
                    click: function() {
                        _endRepeatSelectorLabel.find(".fc-selector-link").text(rs.dialogOptionDate);
                        _settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
                        _showEndSectionsDate.call(_this);
                    }
                }
            ]
        });
		
        //
        function loadDate(input, dp, defDate) {
            var d = parseISO8601(input.val());
            dp.datepicker("setDate", (d instanceof Date) ? d : defDate);
        }
        function saveDate(input, inputT, dp) {
            input.val(formatDate(
					dp.datepicker("getDate"),
					rs.dateFormat));
            if (!inputT.is(":disabled") && $.trim(inputT.val()).length < 1) {
                inputT.val("00:00");
            }
            input.change();
        }
		
        var fromD = _settings.find(".from-date");
        var fromT = _settings.find(".from-time");
        var toD = _settings.find(".to-date");
        var toT = _settings.find(".to-time");
		
        _settings.find(".from.cal-icon").click(function() {
			
            if (_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").hasClass("not-active")) {
                return false;
            }
			
            fcDatepicker.open(calendar, this,
					function(dp) {loadDate(fromD, dp, _eventObj.start);},
					function(elem, dp) {
					    this.close();
					    saveDate(fromD, fromT, dp);
						
					    var fromD_parent = _dialog.find(".from-date");
					    var fromT_parent = _dialog.find(".from-time");
					    saveDate(fromD_parent, fromT_parent, dp);
					});
        });
		
        _settings.find(".to.cal-icon").click(function() {
			
            if (_settings.find(".fc-endrepeat-selector").find(".fc-selector-link").hasClass("not-active")) {
                return false;
            }
			
            fcDatepicker.open(calendar, this,
					function(dp) {loadDate(toD, dp, _eventObj.end||_eventObj.start);},
					function(elem, dp) {this.close();saveDate(toD, toT, dp);});
        });
		
        //
        _settings
				.find(".from-date, .to-date, .fc-cycle-times")
				.bind("keyup change", _validateDateFieldsSettings);
        //
        _settings.find(".calendar select").change(function (ev) {
            var v = $(this).val();
            var s = calendar.getEventSources();
            for (var i = 0; i < s.length; ++i) {
                if (s[i].objectId != v || s[i].isTodo == 1) { continue; }
                _settings.find(".calendar .bullet").css("color", s[i].backgroundColor);
                return;
            }
        });
		
    }());
	
    (function _createDelSettings() {
        _delSettings = $(ds.dialogTemplate)
				.addClass("asc-dialog")
				.popupFrame({
				    anchor: "right,top",
				    direction: "right,down",
				    offset: "0,0",
				    showArrow: false
				});
				
        function setCheckedAttrValue(element, checked) {
            if ((element != undefined) && (element.length != 0)) {
                element.prop("checked", checked);
            }
        }
		
        _delSettings.find(".delete-selector .delete-this-label").click(function() {
            setCheckedAttrValue.call(_this, _delSettings.find(".delete-selector .delete-this"), true);
        });
		
        _delSettings.find(".delete-selector .delete-following-label").click(function() {
            setCheckedAttrValue.call(_this, _delSettings.find(".delete-selector .delete-following"), true);
        });
		
        _delSettings.find(".delete-selector .delete-all-label").click(function() {
            setCheckedAttrValue.call(_this, _delSettings.find(".delete-selector .delete-all"), true);
        });
		
        _delSettings.find(".buttons .save-btn").click(function() {
            if (jq(this).hasClass("disable"))
                return;
		    
            var delType = deleteMode.single;

            if (!_delSettings.hasClass("single")) {
                if (_delSettings.find(".delete-following").is(":checked")) {
                    delType = deleteMode.allFollowing;
                } else if (_delSettings.find(".delete-all").is(":checked")) {
                    delType = deleteMode.allSeries;
                }
            }
            
            _closeDelSettings.call(_this, true);

            if (_getConfirmViewMode.call(_this, true)) {
                confirmSettings.selectedDeleteMode = delType;
                _openConfirmPopup.call(_this);
            } else {
                _deleteEvent.call(_this, delType, _eventObj._start);
                _close.call(_this, false, true);
            }
        });
        
        _delSettings.find(".buttons .cancel-btn, .buttons .close-btn, .header .close-btn").click(function() {
            _closeDelSettings.call(_this, false);
        });

    }());

    (function _createConfirmPopup() {
        _confirmPopup = $(cp.dialogTemplate)
				.addClass("asc-dialog")
				.popupFrame({
				    anchor: "right,top",
				    direction: "right,down",
				    offset: "0,0",
				    showArrow: false
				});

        _confirmPopup.find(".buttons .send-btn, .buttons .send-everyone-btn").click(function() {
            _sendGuestsNotification.call(_this, confirmSettings.notificationMode.everybody);
        });

        _confirmPopup.find(".buttons .send-customs-btn").click(function() {
            _sendGuestsNotification.call(_this, confirmSettings.notificationMode.partially);
        });

        _confirmPopup.find(".buttons .dont-send-btn").click(function() {
            _sendGuestsNotification.call(_this, confirmSettings.notificationMode.nobody);
        });
        
        _confirmPopup.find(".header .close-btn").click(function() {
            _closeConfirmPopup.call(_this, false);
        });

        
    }());


    function _showDaySections(){
        _settings.find(".fc-days-week").addClass("hidden").parent().addClass("hidden");
        _settings.find(".fc-month-radio").addClass("hidden").parent().addClass("hidden");
    }
		
    function _showWeekSections(){
        _settings.find(".fc-month-radio").addClass("hidden").parent().addClass("hidden");
        _settings.find(".fc-days-week").removeClass("hidden").parent().removeClass("hidden");
    }
		
    function _showMonthSections(){
        _settings.find(".fc-days-week").addClass("hidden").parent().addClass("hidden");
        _settings.find(".fc-month-radio").removeClass("hidden").parent().removeClass("hidden");
    }
	
    function _showEndSectionsNever(){
        _settings.find(".fc-repeat-cycles").addClass("hidden");
        _settings.find(".fc-end-date").addClass("hidden");
    }
	
    function _showEndSectionsCycles(){
        _settings.find(".fc-end-date").addClass("hidden");
        _settings.find(".fc-repeat-cycles").removeClass("hidden");
        _validateDateFieldsSettings.call(_this);
    }
	
    function _showEndSectionsDate(){
        _settings.find(".fc-repeat-cycles").addClass("hidden");
        _settings.find(".fc-end-date").removeClass("hidden");
        _validateDateFieldsSettings.call(_this);
    }
	
    function _getEndDate(mode) {
        var startDate = parseISO8601(_settings.find(".from-date").val());
        var interval = parseInt(_settings.find(".fc-interval-selector").find("option:selected").text(), 10);
		
        switch (mode) {
            case dwm.day: 
                return calendar.formatDate(new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate() + interval + 1, 0, 0, 0), rs.dateFormat);
            case dwm.week: 
                return calendar.formatDate(new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate() + interval*7 + 1, 0, 0, 0), rs.dateFormat);
            case dwm.month: 
                return calendar.formatDate(new Date(startDate.getFullYear(), startDate.getMonth() + interval, startDate.getDate() + 1, 0, 0, 0), rs.dateFormat);
            case dwm.year: 
                return calendar.formatDate(new Date(startDate.getFullYear() + interval, startDate.getMonth(), startDate.getDate() + 1, 0, 0, 0), rs.dateFormat);
        }
    }

	
    function _getAlertLabel(type) {
        if (type != undefined) {
            switch (type) {
                case kAlertDefault: 		return calendar.options.eventEditor.dialogAlertOption_default;
                case kAlertNever:			return calendar.options.eventEditor.dialogAlertOption_never;
                case 1: 					return calendar.options.eventEditor.dialogAlertOption_5minutes;
                case 2: 					return calendar.options.eventEditor.dialogAlertOption_15minutes;
                case 3: 					return calendar.options.eventEditor.dialogAlertOption_30minutes;
                case 4: 					return calendar.options.eventEditor.dialogAlertOption_hour;
                case 5: 					return calendar.options.eventEditor.dialogAlertOption_2hours;
                case 6: 					return calendar.options.eventEditor.dialogAlertOption_day;
                default: 					return "Unknown";
            }
        }
    }
	
    function _getRepeatLabel(rule) {
        if (rule != undefined) {
            if (rule.Equals(ASC.Api.iCal.RecurrenceRule.Never)) {
                return calendar.options.eventEditor.dialogRepeatOption_never;
            }
            else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryDay)) {
                return calendar.options.eventEditor.dialogRepeatOption_day;
            }
            else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryWeek)) {
                return calendar.options.eventEditor.dialogRepeatOption_week;
            }
            else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryMonth)) {
                return calendar.options.eventEditor.dialogRepeatOption_month;
            }
            else if (rule.Equals(ASC.Api.iCal.RecurrenceRule.EveryYear)) {
                return calendar.options.eventEditor.dialogRepeatOption_year;
            }
            else {
                return calendar.options.eventEditor.dialogRepeatOption_custom;
            }
        }
    }
	
    function _disableRepeatSettings() {
        _settings.find(".fc-interval-selector").attr("disabled", "disabled");
        _settings.find("input").attr("disabled", "disabled");
        _settings.find(".fc-dwm-selector").find(".fc-selector-link").addClass("not-active");
        _settings.find(".fc-endrepeat-selector").find(".fc-selector-link").addClass("not-active");
    }
	
    function _enableRepeatSettings() {
        _settings.find(".fc-interval-selector").removeAttr("disabled");
        _settings.find("input").removeAttr("disabled");
        _settings.find(".fc-dwm-selector").find(".fc-selector-link").removeClass("not-active");
        _settings.find(".fc-endrepeat-selector").find(".fc-selector-link").removeClass("not-active");
    }
	
    function _renderRepeatAlertList() {
        // repeat list
        var _repeatSelectorLabel = _dialog.find(".fc-view-repeat");
		
        _dialog.find(".fc-view-repeat").click(
			function (event) {
			    fcMenus.hideMenus(fcMenus.modeMenuRepeatEventPage);
			    fcMenus.modeMenuRepeatEventPage.popupMenu("open", _repeatSelectorLabel);
			    event.stopPropagation();
			});
			
        if (!fcMenus.modeMenuRepeatEventPage || fcMenus.modeMenuRepeatEventPage.length < 1) {
            fcMenus.modeMenuRepeatEventPage = $('<div id="fc_mode_menu_repeat_eventpage"/>');
        } else {
            fcMenus.modeMenuRepeatEventPage.popupMenu("close");
            fcMenus.modeMenuRepeatEventPage.popupMenu("destroy");
        }
        fcMenus.modeMenuRepeatEventPage.popupMenu({
            anchor: "left,bottom",
            direction: "right,down",
            arrow: "up",
            showArrow: false,
            closeTimeout: -1,
            cssClassName: "asc-popupmenu",
            items: [
                {
                    label: calendar.options.eventEditor.dialogRepeatOption_never,
                    click: function() {
                        repeatRule = ASC.Api.iCal.RecurrenceRule.Never;
                        _repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
                        _closeSettings.call(_this, false);
                        _dialog.find(".repeat-settings").addClass("hidden");
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogRepeatOption_day,
                    click: function() {
                        repeatRule = ASC.Api.iCal.RecurrenceRule.EveryDay;
                        _repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
                        _closeSettings.call(_this, false);
                        _dialog.find(".repeat-settings").addClass("hidden");
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogRepeatOption_week,
                    click: function() {
                        repeatRule = ASC.Api.iCal.RecurrenceRule.EveryWeek ;
                        _repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
                        _closeSettings.call(_this, false);
                        _dialog.find(".repeat-settings").addClass("hidden");
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogRepeatOption_month,
                    click: function() {
                        repeatRule = ASC.Api.iCal.RecurrenceRule.EveryMonth;
                        _repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
                        _closeSettings.call(_this, false);
                        _dialog.find(".repeat-settings").addClass("hidden");
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogRepeatOption_year,
                    click: function() {
                        repeatRule = ASC.Api.iCal.RecurrenceRule.EveryYear;
                        _repeatSelectorLabel.find(".fc-selector-link").text(_getRepeatLabel.call(_this, repeatRule));
                        _closeSettings.call(_this, false);
                        _dialog.find(".repeat-settings").addClass("hidden");
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogRepeatOption_custom,
                    click: function() {
                        _repeatSelectorLabel.find(".fc-selector-link").text(calendar.options.eventEditor.dialogRepeatOption_custom);
                        _openSettings.call(_this);
                        _dialog.find(".repeat-settings").removeClass("hidden");
                    }
                }
            ]
        });
		
        // alert list  
        var _alertSelectorLabel = _dialog.find(".fc-view-alert");
		
        _dialog.find(".fc-view-alert").click(
			function (event) {
			    fcMenus.hideMenus(fcMenus.modeMenuAlertEventPage);
			    fcMenus.modeMenuAlertEventPage.popupMenu("open", _alertSelectorLabel);
			    event.stopPropagation();
			});

        if (!fcMenus.modeMenuAlertEventPage || fcMenus.modeMenuAlertEventPage.length < 1) {
            fcMenus.modeMenuAlertEventPage = $('<div id="fc_mode_menu_alert_eventpage"/>');
        } else {
            fcMenus.modeMenuAlertEventPage.popupMenu("close");
            fcMenus.modeMenuAlertEventPage.popupMenu("destroy");
        }
        fcMenus.modeMenuAlertEventPage.popupMenu({
            anchor: "left,bottom",
            direction: "right,down",
            arrow: "up",
            showArrow: false,
            closeTimeout: -1,
            cssClassName: "asc-popupmenu",
				
            items: [
                {
                    label: calendar.options.eventEditor.dialogAlertOption_default,
                    click: function() {
                        alertType = kAlertDefault;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogAlertOption_never,
                    click: function() {
                        alertType = kAlertNever;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogAlertOption_5minutes,
                    click: function() {
                        alertType = 1;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogAlertOption_15minutes,
                    click: function() {
                        alertType = 2;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogAlertOption_30minutes,
                    click: function() {
                        alertType = 3;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogAlertOption_hour,
                    click: function() {
                        alertType = 4;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogAlertOption_2hours,
                    click: function() {
                        alertType = 5;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                },
                {
                    label: calendar.options.eventEditor.dialogAlertOption_day,
                    click: function() {
                        alertType = 6;
                        _alertSelectorLabel.find(".fc-selector-link").text(_getAlertLabel.call(_this, alertType));
                    }
                }
            ]
        });
    }


    function _open(mode, elem, eventObj) {
        calendar.trigger("getPermissions", _this,
            {
                type: kEventPermissions,
                objectId: eventObj.objectId,
                permissions: eventObj.permissions
            },
            function(res) {
                if (res.result) {
                    eventObj.permissions = res.permissions;
                    if (res.isShared != undefined) {
                        eventObj.isShared = res.isShared;
                    }
                }
                _openPage(mode, elem, eventObj);
            }
        );
    }

    function _openPage(mode, elem, eventObj) {

        _dialog.find(".repeat-settings").addClass("hidden");

        // check length
        var titleMaxLen = defaults.eventMaxTitleLength;
        var inputTxt = _dialog.find(".editor .title input, .editor .location input");
        if (inputTxt.length > 0)
        {
            inputTxt.keyup(function(){
                if (inputTxt.val().length > titleMaxLen){
                    inputTxt.val(inputTxt.val().substr(0, titleMaxLen));
                }
            });
        }
        //

        _eventObj = eventObj;
        _eventObj.sourceId = _eventObj.sourceId || (_eventObj.source ? _eventObj.source.objectId : undefined);

        repeatRule = _eventObj.repeatRule;
        alertType = _eventObj.alert.type;

        _canChangeSource = _eventObj.source == undefined ||
				_eventObj.source && !_eventObj.source.isSubscription;
        _canDelete = fcUtil.objectIsEditable(_eventObj) ||
				fcUtil.objectIsEditable(_eventObj.source) ||
				_eventObj.source && !_eventObj.source.isSubscription;
        _canEdit = _eventObj.source == undefined || _canDelete;

        _canUnsubscribe = _eventObj && _eventObj.canUnsubscribe &&
				_eventObj.source && _eventObj.source.isSubscription;

        if (_canEdit) {
            _dialog.find(".buttons").addClass("editable");
        } else {
            _dialog.find(".buttons").removeClass("editable");
        }
        if (_canDelete) {
            _dialog.find(".buttons").addClass("erasable");
        } else {
            _dialog.find(".buttons").removeClass("erasable");
        }
        if (_canEdit || _canDelete) {
            _dialog.find(".buttons").removeClass("readonly");
        } else {
            _dialog.find(".buttons").addClass("readonly");
        }
        if (_canUnsubscribe) {
            _dialog.find(".buttons").addClass("shared");
        } else {
            _dialog.find(".buttons").removeClass("shared");
        }

        _doDDX.call(_this);

        _dialog.find(".viewer .repeat-settings").remove();

        if (mode == "edit") {
            _dialog.find(".event-header span").text(_eventObj.objectId ? window.g_fcOptions.eventEditor.dialogHeader_editEvent : window.g_fcOptions.eventEditor.dialogHeader_createEvent);
            _dialog.find(".event-editor").addClass("edit-popup");
            _enableRepeatSettings.call(_this);
        } else {
            _dialog.find(".event-header span").text(window.g_fcOptions.eventEditor.dialogHeader_viewEvent);
            _dialog.find(".event-editor").removeClass("edit-popup");
            _disableRepeatSettings.call(_this);
            _dialog.find(".editor .repeat-settings").clone().insertAfter(_dialog.find(".viewer .repeat-alert"));
        }

        jq("#asc_calendar").hide();
        jq("#asc_event").show();

        _dialog.find(".editor .title input").focus().select();
    }


    // repeat interval
    function _setRepeatInterval(selectedItem, count) {
        if (selectedItem <= count) {
            var intervals = "";
            for (var i = 1; i < count; i++) {
                intervals += "<option" + ((selectedItem == i) ? " selected" : "") + " value='" + i + "'>" + i + "</option>";
            }
			
            var html = $(intervals);
            _settings.find(".fc-interval-selector").html(html);
			
            _settings.find(".fc-interval-selector").change(function() {
                _settings.find(".to-date").val(_getEndDate.call(_this, dwm_current));
            });
        }
    }
	
    // repeat days of week
    function _setSelectedDays(indexArr) {
        var daysSection = "";

        var dayNamesInCurCulture;
        var beforeFirstDay = [];
        var afterFirstDay = [];

        for (var i = 0; i < rs.dayNamesShort.length; i++) {
            var item = { index: i, name: rs.dayNamesShort[i] };
            if(i < g_fcOptions.firstDay){
                beforeFirstDay.push(item);
            } else {
                afterFirstDay.push(item);
            }
        }
        dayNamesInCurCulture = afterFirstDay.concat(beforeFirstDay);

        for (var i = 0; i < dayNamesInCurCulture.length; i++) {
            var isSelected = false;
            for (var j = 0; j < indexArr.length; j++) {
                if (dayNamesInCurCulture[i].index == indexArr[j]) {
                    isSelected = true;
                    break;
                }
            }
			
            daysSection += 	"<div class='checkbox-day'>" +
								"<input class='repeat-day-" + dayNamesInCurCulture[i].index + "' type='checkbox' " + ((isSelected == true) ? "checked" : "") + ">" +
								"<div>" + htmlEscape(dayNamesInCurCulture[i].name) + "</div>" +
							"</div>";
        }
        daysSection += "<div class='clear'></div>";
        var html = $(daysSection);
        _settings.find(".fc-days-week").html(html);
    }
    
    function _getSelectedDays() {
        indexArr = new Array();
        if (_settings.find(".fc-days-week.hidden").length == 0) {
            for (var i = 0; i < rs.dayNamesShort.length; i++) {
                var checkedClass = ".repeat-day-" + i;
                var checkedItem = _settings.find(checkedClass).is(":checked");
                if (checkedItem == true) {
                    indexArr.push(i);
                }
            }
        }
        return indexArr;
    }
	
    function _getRepeatDayByIndex(index) {
        switch (index) {
            case 0: return ASC.Api.iCal.DayOfWeek.Sunday;
            case 1: return ASC.Api.iCal.DayOfWeek.Monday;
            case 2: return ASC.Api.iCal.DayOfWeek.Tuesday;
            case 3: return ASC.Api.iCal.DayOfWeek.Wednesday;
            case 4: return ASC.Api.iCal.DayOfWeek.Thursday;
            case 5: return ASC.Api.iCal.DayOfWeek.Friday;
            case 6: return ASC.Api.iCal.DayOfWeek.Saturday;
        }
    }
	
    function _openSettings()
    {
        var fromD = _dialog.find(".editor .from-date");
        _settings.find(".from-date").val(fromD.val());
        _validateDateFieldsSettings.call(_this);
		
        var date = parseISO8601(fromD.val());
        var endDate = undefined;
		
        var maxDayCount = 32 - new Date(date.getFullYear(), date.getMonth(), 32).getDate();
        var dayOfWeek = date.getDay();
        var dayOfMonth = date.getDate();
		
        var indexDay = Math.floor((dayOfMonth - 1) / 7);
        var maxIndexDay = indexDay + Math.floor((maxDayCount - dayOfMonth) / 7);
		
        var dayName = calendar.options.repeatSettings.dayNames[dayOfWeek];
        var dayAlias = "";
		
        switch (indexDay) {
            case 0:
            case 1:
            case 2:
            case 4: dayAlias = rs.dayAliasNames[indexDay]; break;
            case 3: (indexDay != maxIndexDay) ? dayAlias = rs.dayAliasNames[indexDay] : dayAlias = rs.dayAliasNames[indexDay + 1]; break;
        }
		
        var html = $("<div>" + 
						"<div style='margin-bottom: 0.5em;'>" +
						"<input class='only-day' type='radio' name='day-radio' value='" + dayOfMonth + "' />&nbsp;" + 
							"<span class='only-day-label'>" + rs.dialogEachLabel + " " + dayOfMonth + " " + rs.dialogIntervalOption_day + "</span></div>" +
					 	"<input class='each-day' type='radio' name='day-radio' value='" + dayName + "'/>&nbsp;" + 
					 		"<span class='each-day-label'>" + rs.dialogAliasLabel + " " + dayAlias + " " + dayName + "</span>" +
					 "</div>");
					 
        _settings.find(".fc-month-radio").html(html);
        _settings.find(".only-day").attr({checked: "checked"});
		
        _settings.find(".only-day-label").click(function() {
            _settings.find(".only-day").trigger("click");
        });
		
        _settings.find(".each-day-label").click(function() {
            _settings.find(".each-day").trigger("click");
        });
		
        dayRuleObject = undefined;
        _settings.find(".each-day").click(function () {
            dayRuleObject = _getRepeatDayByIndex.call(_this, dayOfWeek);
            var dayRuleIndex = 0;
			
            switch (indexDay) {
                case 0:
                case 1:
                case 2: dayRuleIndex  = indexDay + 1; break;
                case 3: dayRuleIndex  = -2; break;
                case 4: dayRuleIndex  = -1; break;
            }
            if (indexDay == maxIndexDay) {
                dayRuleIndex = -1;
            }
			
            dayRuleObject.Order = dayRuleIndex;
        });
		
        _settings.find(".only-day").click(function () {
            dayRuleObject = undefined;
        });
		
        _setRepeatInterval.call(this, repeatRule.Interval, 31);
        _settings.find(".fc-cycle-times").val((repeatRule.Count > 0) ? repeatRule.Count : 3);
		
        var dayIndexArr = new Array();
        for (var i = 0; i < repeatRule.ByDay.length; i++) {
            dayIndexArr.push(rs.dayIndexResponse[repeatRule.ByDay[i].Id]);
        }
		
        _setSelectedDays.call(this, dayIndexArr.length ? dayIndexArr : [dayOfWeek]);
		
        // set default view
        if ((repeatRule.Freq == ASC.Api.iCal.Frequency.Never) || (repeatRule.Freq == ASC.Api.iCal.Frequency.Daily)) {
            _showDaySections.call(_this);
            dwm_current = dwm.day;
            _settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_days);
            _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_day);
        }
        else if (repeatRule.Freq == ASC.Api.iCal.Frequency.Weekly) {
            _showWeekSections.call(_this);
            dwm_current = dwm.week;
            _settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_weeks);
            _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_week);
        }
        else if (repeatRule.Freq == ASC.Api.iCal.Frequency.Monthly) {
            _showMonthSections.call(_this);
            dwm_current = dwm.month;
            _settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_months);
            _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_month);
			
            if ((repeatRule.ByDay.length == 1) && (repeatRule.ByDay[0].Order != 0)) {
                _settings.find(".only-day").attr({checked: ""});
                _settings.find(".each-day").attr({checked: "checked"}).click();
            }
            else {
                _settings.find(".each-day").attr({checked: ""});
                _settings.find(".only-day").attr({checked: "checked"});
            }
        } else if (repeatRule.Freq == ASC.Api.iCal.Frequency.Yearly) {
            _showDaySections.call(_this);
            dwm_current = dwm.year;
            _settings.find(".fc-dwm-selector").find(".fc-selector-link").text(rs.dialogRepeatOn_years);
            _settings.find(".fc-interval-label").text(rs.dialogIntervalOption_year);
        }
		
        _settings.find(".to-date").val(repeatRule.Until ? calendar.formatDate(repeatRule.Until, rs.dateFormat) : 
																	_getEndDate.call(_this, dwm_current));
		
        // end repeat
        if (repeatRule.Until) {
            _showEndSectionsDate.call(_this);
            _settings.find(".fc-endrepeat-selector").find(".fc-selector-link").text(rs.dialogOptionDate);
        }
        else if (repeatRule.Count > 0) {
            _showEndSectionsCycles.call(_this);
            _settings.find(".fc-endrepeat-selector").find(".fc-selector-link").text(rs.dialogOptionCount);
        }
        else {
            _showEndSectionsNever.call(_this);
            _settings.find(".fc-endrepeat-selector").find(".fc-selector-link").text(rs.dialogOptionNever);
        }
    }
	
    function _openDelSettings(single)
    {
        _delSettings.popupFrame("close");

        if (single)
            _delSettings.addClass("single");
        else
            _delSettings.removeClass("single");

        _delSettings.find("input[type=radio]:first").prop("checked", true);

        uiBlocker.hide();
		
        _delSettings.popupFrame("open", { pageX: "center", pageY: "center" });
        _delSettings.addClass("add-popup");
        _delSettings.addClass("fc-shadow");
        _delSettings.css("position","fixed");
		
        $(document).bind("keyup", _checkEscKeyDelSettings);

        if (_delSettings.popupFrame("isVisible")) {
            uiBlocker.show();
        } else {
            uiBlocker.hide();
        }
    }

    function _close(changed, deleted) {
        if (changed) {
            if (!_canEdit || false == _doDDX.call(_this, true)) {return;}
            _updateEvent.call(_this);
            return;
        }
        if (_eventObj.source == undefined && _eventObj._id != undefined) {
            calendar.removeEvents(_eventObj._id);
        }
		
        if ((_eventObj.source != undefined) && !changed && !deleted)
            _updateEvent.call(_this, true);

        _closeDialog.call(_this);
    }
	
    function _closeSettings(changed) {
        if (changed && _canEdit) {
            _prepareRepeatRule.call(_this);
        }
    }
	
    function _closeDelSettings(changed) {
        if (changed) {
            if (!_canEdit) {return;}
            _closeDialogDelSettings.call(_this);
            return;
        }
		
        $(document).unbind("keyup", _checkEscKeyDelSettings);
        
        _closeDialogDelSettings.call(_this);
    }

    function _checkEscKeyDelSettings(ev) {
        if (ev.which == 27) {
            _closeDelSettings.call(_this, false);
        }
    }


    function _getConfirmViewMode(checkDelete) {
        
        confirmSettings.notificationUsers.newGuests = [];
        confirmSettings.notificationUsers.updatedGuests = [];
        confirmSettings.notificationUsers.removedGuests = [];
        confirmSettings.selectedViewMode = confirmSettings.viewMode.none;
        confirmSettings.selectedNotificationMode = confirmSettings.notificationMode.nobody;

        if(_eventObj.status == 2 || (_eventObj.source && _eventObj.source.isSubscription))
            return confirmSettings.selectedViewMode;

        var oldEvent = jq.extend({}, _eventObj);

        if (!checkDelete) {
            var validData = _doDDX.call(_this, true);
            if (!validData)
                return confirmSettings.selectedViewMode;
        }

        var isOrganizer = false;
        var organizerEmail = _eventObj.organizer ? _eventObj.organizer[3].replace(new RegExp("mailto:", "ig"), "").toLowerCase() : "";

        jq.each(ASC.Mail.Accounts, function(index, account) {
            if (account.enabled && organizerEmail == account.email.toLowerCase()) {
                isOrganizer = true;
                return false;
            }
            return true;
        });

        if(!isOrganizer)
            return confirmSettings.selectedViewMode;

        if (checkDelete) {
            var removedGuests = [];
            jq.each(_eventObj.attendees || [], function(index, attendeeObj) {
                var attendeeEmail = attendeeObj[3].replace(new RegExp("mailto:", "ig"), "");
                if (attendeeEmail.toLowerCase() != organizerEmail)
                    removedGuests.push(attendeeEmail);
            });

            if (removedGuests.length) {
                confirmSettings.selectedViewMode = confirmSettings.viewMode.deleteEvent;
                confirmSettings.notificationUsers.removedGuests = removedGuests;
            }

            return confirmSettings.selectedViewMode;
        }

        var oldAttendees = [];
        jq.each(oldEvent.attendees || [], function(index, attendeeObj) {
            var attendeeEmail = attendeeObj[3].replace(new RegExp("mailto:", "ig"), "");
            if (attendeeEmail.toLowerCase() != organizerEmail)
                oldAttendees.push(attendeeEmail);
        });

        var newAttendees = [];
        jq.each(_eventObj.attendees || [], function(index, attendeeObj) {
            var attendeeEmail = attendeeObj[3].replace(new RegExp("mailto:", "ig"), "");
            if (attendeeEmail.toLowerCase() != organizerEmail)
                newAttendees.push(attendeeEmail);
        });

        if (oldAttendees.length == 0 && newAttendees.length == 0)
            return confirmSettings.selectedViewMode;

        if (!oldEvent.objectId) {
            if (newAttendees.length) {
                confirmSettings.selectedViewMode = confirmSettings.viewMode.addEvent;
                confirmSettings.notificationUsers.newGuests = newAttendees;
            }

            return confirmSettings.selectedViewMode;
        }

        var oldOrganizerEmail = oldEvent.organizer ? oldEvent.organizer[3].replace(new RegExp("mailto:", "ig"), "").toLowerCase() : "";
        var organizerChanged = oldOrganizerEmail && oldOrganizerEmail != organizerEmail;

        var oldStartData = oldEvent.start ? oldEvent.start.getTime() : null;
        var newStartData = _eventObj.start ? _eventObj.start.getTime() : null;
        var oldEndData = oldEvent.end ? oldEvent.end.getTime() : null;
        var newEndData = _eventObj.end ? _eventObj.end.getTime() : null;

        if (organizerChanged ||
            oldEvent.title != _eventObj.title ||
            oldEvent.location != _eventObj.location ||
            oldEvent.description != _eventObj.description ||
            oldStartData != newStartData ||
            oldEndData != newEndData ||
            oldEvent.allDay != _eventObj.allDay ||
            oldEvent.sourceId != _eventObj.newSourceId ||
            oldEvent.repeatRule.ToiCalString() != _eventObj.repeatRule.ToiCalString())
            confirmSettings.selectedViewMode  = confirmSettings.viewMode.updateEvent;

        jq.each(newAttendees, function (index, newAttendee) {
            if (jq.inArray(newAttendee, oldAttendees) < 0)
                confirmSettings.notificationUsers.newGuests.push(newAttendee);
            else
                confirmSettings.notificationUsers.updatedGuests.push(newAttendee);
        });
        
        confirmSettings.notificationUsers.removedGuests = jq.grep(oldAttendees, function (oldAttendee) {
            return jq.inArray(oldAttendee, newAttendees) < 0;
        });

        if (confirmSettings.notificationUsers.newGuests.length || confirmSettings.notificationUsers.removedGuests.length)
            confirmSettings.selectedViewMode  = confirmSettings.viewMode.updateGuests;

        return confirmSettings.selectedViewMode;
    }

    function _openConfirmPopup()
    {
        switch (confirmSettings.selectedViewMode) {
            case confirmSettings.viewMode.addEvent:
                _confirmPopup.find(".title").text(calendar.options.confirmPopup.dialogAddEventHeader);
                _confirmPopup.find(".body").text(calendar.options.confirmPopup.dialogAddEventBody);
                _confirmPopup.find(".send-btn").show();
                _confirmPopup.find(".send-customs-btn, .send-everyone-btn").hide();
                break;
            case confirmSettings.viewMode.updateEvent:
                _confirmPopup.find(".title").text(calendar.options.confirmPopup.dialogUpdateEventHeader);
                _confirmPopup.find(".body").text(calendar.options.confirmPopup.dialogUpdateEventBody);
                _confirmPopup.find(".send-btn").show();
                _confirmPopup.find(".send-customs-btn, .send-everyone-btn").hide();
                break;
            case confirmSettings.viewMode.updateGuests:
                _confirmPopup.find(".title").text(calendar.options.confirmPopup.dialogUpdateEventHeader);
                _confirmPopup.find(".body").text(calendar.options.confirmPopup.dialogUpdateGuestsBody);
                _confirmPopup.find(".send-btn").hide();
                _confirmPopup.find(".dont-send-btn").hide();
                _confirmPopup.find(".send-customs-btn, .send-everyone-btn").show();
                break;
            case confirmSettings.viewMode.deleteEvent:
                _confirmPopup.find(".title").text(calendar.options.confirmPopup.dialogDeleteEventHeader);
                _confirmPopup.find(".body").text(calendar.options.confirmPopup.dialogDeleteEventBody);
                _confirmPopup.find(".send-btn").show();
                _confirmPopup.find(".send-customs-btn, .send-everyone-btn").hide();
                break;
            default:
                break;
        }

        _delSettings.popupFrame("close");
        $(document).unbind("keyup", _checkEscKeyDelSettings);
        
        _confirmPopup.popupFrame("close");
        uiBlocker.hide();
		
        _confirmPopup.popupFrame("open", { pageX: "center", pageY: "center" });
        _confirmPopup.css("position","fixed");

        if (_confirmPopup.popupFrame("isVisible")) {
            uiBlocker.show();
        } else {
            uiBlocker.hide();
        }
    }

    function _closeConfirmPopup() {
        _confirmPopup.popupFrame("close");
        uiBlocker.hide();
    }

    function _sendGuestsNotification(mode) {
        confirmSettings.selectedNotificationMode = mode;
        if (confirmSettings.selectedViewMode == confirmSettings.viewMode.deleteEvent) {
            _deleteEvent.call(_this, confirmSettings.selectedDeleteMode, _eventObj._start);
            _close.call(_this, false, true);
        } else {
            _close.call(_this, true);
        }
        _closeConfirmPopup.call(_this);
    }

    function _sendNotification(sourceId, uniqueId, type, callback) {
        var attendeesEmails = [];
        var method = null;

        switch (type) {
        case confirmSettings.notificationType.request:
            switch (confirmSettings.selectedNotificationMode) {
            case confirmSettings.notificationMode.everybody:
            case confirmSettings.notificationMode.partially:
                attendeesEmails = confirmSettings.notificationUsers.newGuests;
                method = ASC.Mail.Utility.SendCalendarRequest;
                break;
            default:
                break;
            }
            break;
        case confirmSettings.notificationType.update:
            switch (confirmSettings.selectedNotificationMode) {
            case confirmSettings.notificationMode.everybody:
                attendeesEmails = confirmSettings.notificationUsers.updatedGuests;
                method = ASC.Mail.Utility.SendCalendarUpdate;
                break;
            default:
                break;
            }
            break;
        case confirmSettings.notificationType.cancel:
            switch (confirmSettings.selectedNotificationMode) {
            case confirmSettings.notificationMode.everybody:
            case confirmSettings.notificationMode.partially:
                attendeesEmails = confirmSettings.notificationUsers.removedGuests;
                method = ASC.Mail.Utility.SendCalendarCancel;
                break;
            default:
                break;
            }
            break;
        default:
            break;
        }

        if (attendeesEmails.length && method) {
            ASC.CalendarController.Busy = true;
            window.LoadingBanner.displayLoading();
            
            method.call(this, sourceId, uniqueId, attendeesEmails)
                .done(function() {
                    //toastr.success(calendar.options.confirmPopup.dialogSuccessToastText);
                    console.log(calendar.options.confirmPopup.dialogSuccessToastText, arguments);
                    if (callback)
                        callback();
                })
                .fail(function() {
                    toastr.error(calendar.options.confirmPopup.dialogErrorToastText);
                    console.error(calendar.options.confirmPopup.dialogErrorToastText, arguments);
                })
                .always(function () {
                    ASC.CalendarController.Busy = false;
                    window.LoadingBanner.hideLoading();
                });
        } else {
            if(callback)
                callback();
        }
    }

    function _sendReply(calendarId, eventUid) {
        if (!replyDecisionSettings.sendReply || !replyDecisionSettings.email || !replyDecisionSettings.decision)
            return;

        ASC.CalendarController.Busy = true;
        window.LoadingBanner.displayLoading();
        
        ASC.Mail.Utility.SendCalendarReply(calendarId, eventUid, replyDecisionSettings.email, replyDecisionSettings.decision)
            .done(function () {
                console.log(calendar.options.confirmPopup.dialogSuccessToastText, arguments);
            })
            .fail(function () {
                toastr.error(calendar.options.confirmPopup.dialogErrorToastText);
                console.error(calendar.options.confirmPopup.dialogErrorToastText, arguments);
            })
            .always(function () {
                ASC.CalendarController.Busy = false;
                window.LoadingBanner.hideLoading();
            });
    }


    function _closeDialog() {
        window.toastr.remove();
        jq("#asc_event").hide();
        jq("#asc_calendar").show();
        calendar.updateSize();
        uiBlocker.hide();
    }
    
    function _disableDialogBtns(disable) {
        if (disable){
            _dialog.find(".buttons .save-btn").addClass("disable");
        } else {
            _dialog.find(".buttons .save-btn").removeClass("disable");
        }
    }
	
    function _closeDialogDelSettings() {
        _delSettings.popupFrame("close");
        uiBlocker.hide();
    }

    function _parseDateTime(inputD, inputT, result) {
        var dateStr = inputD.val();
        var timeStr = inputT.val();
        var dateStrIsEmpty = dateStr.search(/\S/) < 0;
        var timeStrIsEmpty = timeStr.search(/\S/) < 0;
        var date, time, r;
        if (!dateStrIsEmpty || !timeStrIsEmpty) {
            date = fcUtil.validateDateString(dateStr);
            time = fcUtil.validateTimeString(timeStr);
            r = (date === null || !timeStrIsEmpty && time === null) ? 0 : 1;
        } else {
            r = -1;
            date = null;
            time = null;
        }
        result.date = {isEmpty: dateStrIsEmpty, isValid: date !== null, value: date};
        result.time = {isEmpty: timeStrIsEmpty, isValid: time !== null, value: time};
        return r;
    }

    var changeTimeFrom = null;
    
    function _validateDateFields(result) {
        var allday = _dialog.find(".editor .all-day input").is(":checked");
        var dlg = {
            from:      _dialog.find(".editor .from-date"),
            from_t:    _dialog.find(".editor .from-time"),
            to:        _dialog.find(".editor .to-date"),
            to_t:      _dialog.find(".editor .to-time")
        };
        var frDate = {}, fr = _parseDateTime(dlg.from, dlg.from_t, frDate);
        var toDate = {}, to = _parseDateTime(dlg.to, dlg.to_t, toDate);
        frDate.dateTime = fr == 1 ? parseDate(frDate.date.value + "T" + frDate.time.value) : null;
        toDate.dateTime = to == 1 ? parseDate(toDate.date.value + "T" + toDate.time.value) : null;

        var frc, frtc, toc, totc, r, delta;
        if (!allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime > 0) ||
			allday && fr == 1 && to == -1 ||
			allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime >= 0)) {
            r = true;
            frc = frtc = toc = totc = "";
        } else {
            r = false;
            frc  = frDate.date.isValid ? "" : "#cc3300";
            frtc = frDate.time.isValid ? "" : "#cc3300";
            toc  = toDate.date.isValid && delta ? "" : "#cc3300";
            totc = toDate.time.isValid && delta ? "" : "#cc3300";
        }
        dlg.from.css("color", "").css("border-color", frc);
        dlg.from_t.css("color", "").css("border-color", frtc);
        dlg.to.css("color", "").css("border-color", toc);
        dlg.to_t.css("color", "").css("border-color", totc);

        if ($(this).hasClass('from-time') || $(this).hasClass('from-date')) {

            var oldTime = new Date(Date.parse(_eventObj._start ? _eventObj._start : _eventObj.start));
            var newTime = new Date(Date.parse(frDate.dateTime));
            
            if (changeTimeFrom != null) {
                oldTime = changeTimeFrom;
            }
            
            var diff = newTime.getTime() - oldTime.getTime();
            if (diff != NaN && diff != 0) {

                var date = new Date();
                date.setTime(Date.parse(toDate.dateTime) + diff);

                if (date != 'Invalid Date') {
                    toDate.dateTime.setTime(Date.parse(toDate.dateTime) + diff);

                    changeTimeFrom = newTime;

                    if ($(this).hasClass('from-time')) {
                        var time =
                            (toDate.dateTime.getHours() < 10 ? '0' + toDate.dateTime.getHours() : toDate.dateTime.getHours())
                            + ":" +
                            (toDate.dateTime.getMinutes() < 10 ? '0' + toDate.dateTime.getMinutes() : toDate.dateTime.getMinutes());

                        toDate.time.value = time;
                        $('input.to-time').val(time);
                        
                    } else if ($(this).hasClass('from-date')) {
                        
                        var newDate = date.getFullYear() + '-'
                           + ((date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)) + '-'
                           + (date.getDate() < 10 ? '0' + date.getDate() : date.getDate());
                       
                        toDate.date.value = newDate;
                        $('input.to-date')[0].value = newDate;
                    }
                    _validateDateFields.call(_this);
                }
            }
        }

        if (result != undefined) {
            result.fromDate = frDate;
            result.toDate   = toDate;
        }
		
        return r;
    }
	
    function _validateDateFieldsSettings(result) {
		
        var r = true;
        var allday = _dialog.find(".editor .all-day input").is(":checked");
        var dlg = {
            from:              _settings.find(".from-date"),
            from_t:            _settings.find(".from-time"),
            to:                _settings.find(".to-date"),
            to_t:              _settings.find(".to-time"),
            cycles:            _settings.find(".fc-cycle-times")
        };
		
        if (!_settings.find(".fc-end-date").hasClass("hidden")) {
			
            var frDate = {}, fr = _parseDateTime(dlg.from, dlg.from_t, frDate);
            var toDate = {}, to = _parseDateTime(dlg.to, dlg.to_t, toDate);
            frDate.dateTime = fr == 1 ? parseDate(frDate.date.value + "T" + frDate.time.value) : null;
            toDate.dateTime = to == 1 ? parseDate(toDate.date.value + "T" + toDate.time.value) : null;
	
            var frc, frtc, toc, totc, delta;
            if (!allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime > 0) ||
			    allday && fr == 1 && to == -1 ||
			    allday && fr == 1 && to == 1 && (delta = toDate.dateTime - frDate.dateTime >= 0)) {
                r = true;
                frc = frtc = toc = totc = "";
            } else {
                r = false;
                frc  = frDate.date.isValid ? "" : "#cc3300";
                frtc = frDate.time.isValid ? "" : "#cc3300";
                toc  = toDate.date.isValid && delta ? "" : "#cc3300";
                totc = toDate.time.isValid && delta ? "" : "#cc3300";
            }
            dlg.from.css("color", "").css("border-color", frc);
            dlg.from_t.css("color", "").css("border-color", frtc);
            dlg.to.css("color", "").css("border-color", toc);
            dlg.to_t.css("color", "").css("border-color", totc);
            if (result != undefined) {
                result.fromDate = frDate;
                result.toDate   = toDate;
            }
        }
		
        if (!_settings.find(".fc-repeat-cycles").hasClass("hidden")) {
            var cb = "";
            r = true;
            var isNum = dlg.cycles.val().match('^[0-9]+$');
            if ( (dlg.cycles.find(".hidden").length == 0) && !isNum ) { 
                r = false;
                cb  = !r || (r && (dlg.cycles.val() < 0)) ? "#cc3300" : "";
            }
            dlg.cycles.css("color", "").css("border-color", cb);
        }
		
        return r;
    }

    function _handleAllDayClick() {
        var allday = _dialog.find(".editor .all-day input").is(":checked");
        var dlg = {
            from:  _dialog.find(".editor .from-date"),
            from_t:  _dialog.find(".editor .from-time"),
            to:      _dialog.find(".editor .to-date"),
            to_t:    _dialog.find(".editor .to-time")
        };
        if (allday) {
            //dlg.to.val("");
            dlg.from_t.val("").attr("disabled", "disabled");
            dlg.to_t.val("").attr("disabled", "disabled");
        } else {
            var defaultEndDate = new Date(_eventObj.start.getFullYear(), _eventObj.start.getMonth(), _eventObj.start.getDate(), _eventObj.start.getHours(), _eventObj.start.getMinutes() + 30);
			
            if(!dlg.from.val())
                dlg.from.val(formatDate(_eventObj.start, calendar.options.eventEditor.dateFormat));
            
            dlg.from_t
					.val(formatDate(_eventObj.start, calendar.options.eventEditor.timeFormat))
					.removeAttr("disabled");
            if (_eventObj.end == _eventObj.start) {
                _eventObj.end = new Date(_eventObj.end.getFullYear(), _eventObj.end.getMonth(), _eventObj.end.getDate(), _eventObj.end.getHours(), _eventObj.end.getMinutes() + 30);
            }
            dlg.to_t
					.val(_eventObj.end instanceof Date ?
							formatDate(_eventObj.end, calendar.options.eventEditor.timeFormat) : formatDate(defaultEndDate, calendar.options.eventEditor.timeFormat))
					.removeAttr("disabled");
            
            if(!dlg.to.val())
                dlg.to.val(_eventObj.end instanceof Date ?
					formatDate(_eventObj.end, calendar.options.eventEditor.dateFormat) : formatDate(defaultEndDate, calendar.options.eventEditor.dateFormat));
        }
        _validateDateFields();
    }

    function _prepareRepeatRule() {
        if (repeatRule) {
            repeatRule = undefined;
        }
		
        // get all values		
        var dlg = {
            from:        _settings.find(".from-date"),
            to:          _settings.find(".to-date"),
            interval:    _settings.find(".fc-interval-selector"),
            cycles:      _settings.find(".fc-cycle-times")
        };
		
        repeatRule = ASC.Api.iCal.RecurrenceRule.EveryDay;
        switch (dwm_current) {
            case dwm.day: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=DAILY"); break;
            case dwm.week: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=WEEKLY"); break;
            case dwm.month: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=MONTHLY"); break;
            case dwm.year: repeatRule = ASC.Api.iCal.ParseRRuleFromString("FREQ=YEARLY"); break;
        }
		
        repeatRule.Interval = dlg.interval.find("option:selected").text();
        repeatRule.Count = _settings.find(".fc-repeat-cycles.hidden").length ? repeatRule.Count : dlg.cycles.val();
		
        var dayIndexArr = _getSelectedDays.call(_this);
        for (var i = 0; i < dayIndexArr.length; i++) {
            repeatRule.ByDay.push(_getRepeatDayByIndex.call(this, dayIndexArr[i]));
        }
		
        if ((_settings.find(".fc-month-radio.hidden").length == 0) && (dayRuleObject != undefined)) {
            repeatRule.ByDay.push(dayRuleObject);
        }
		
        if (_settings.find(".fc-end-date.hidden").length == 0) {
            var dates = {};
            if (!_validateDateFieldsSettings(dates)) {return false;}
            repeatRule.Until = dates.toDate.dateTime;
        }
		
        return (repeatRule != undefined);
    }

    function _doDDX(saveData) {
        var sources = calendar.getEventSources();
        var sourceIsValid = fcUtil.objectIsValid(_eventObj.source);
        var canChangeAlert = sourceIsValid && (
				_eventObj.source.canAlertModify != undefined && _eventObj.source.canAlertModify ||
				_eventObj.source.canAlertModify == undefined) ||
				!sourceIsValid;

        var dlg = {
            viewer: {
                title:       _dialog.find(".viewer .title .text"),
                location:    _dialog.find(".viewer .location .text"),
                attendees:   _dialog.find(".viewer .attendees-user-list"),
                owner:       _dialog.find(".viewer .owner .name"),
                allday:      _dialog.find(".viewer .all-day"),
                from:        _dialog.find(".viewer .from-date"),
                from_t:      _dialog.find(".viewer .from-time"),
                to:          _dialog.find(".viewer .to-date"),
                to_t:        _dialog.find(".viewer .to-time"),
                repeat:      _dialog.find(".viewer .repeat"),
                alert:       _dialog.find(".viewer .alert"),
                calendar:    _dialog.find(".viewer .calendar .name"),
                calendar_b:  _dialog.find(".viewer .calendar .bullet"),
                users:       _dialog.find(".viewer .shared-user-list"),
                description: _dialog.find(".viewer .description .text")
            },
            editor: {
                replybuttons:_dialog.find(".reply-buttons"),
                title:       _dialog.find(".editor .title input"),
                location:    _dialog.find(".editor .location input"),
                owner:       _dialog.find(".editor .owner .name"),
                ownerSelector: _dialog.find(".editor .owner select"),
                attendees:   _dialog.find(".editor .attendees input"),
                attendeesInputBtn:   _dialog.find(".editor .attendees .btn-container .button"),
                attendeesInputContainer:   _dialog.find(".editor .attendees .input-container"),
                attendeesList:_dialog.find(".editor .attendees .attendees-user-list"),
                attendeesNoAccount:_dialog.find(".editor .attendees .attendees-noaccount"),
                attendeesHelpSwitcher: _dialog.find("#attendeesHelpSwitcher"),
                allday:      _dialog.find(".editor .all-day input"),
                from:        _dialog.find(".editor .from-date"),
                from_t:      _dialog.find(".editor .from-time"),
                to:          _dialog.find(".editor .to-date"),
                to_t:        _dialog.find(".editor .to-time"),
                repeat:      _dialog.find(".editor .fc-view-repeat .fc-selector-link"),
                alert:       _dialog.find(".editor .fc-view-alert .fc-selector-link"),
                calendar:    _dialog.find(".editor .calendar select"),
                calendar_b:  _dialog.find(".editor .calendar .bullet"),
                users:       _dialog.find(".editor .addUserLink"),
                usersList:   _dialog.find(".editor .shared-user-list"),
                description: _dialog.find(".editor .description textarea"),
                
                sent_invitations: _dialog.find(".editor .sent-invitations input")
            },
            infoText:    _dialog.find(".info-text")
        };

        if (saveData) {
            return _doDDXSaveData.call(_this, dlg, sources, sourceIsValid, canChangeAlert);
        } else { 
            return _doDDXLoadData.call(_this, dlg, sources, sourceIsValid, canChangeAlert);
        }
        
    }

    function _doDDXSaveData(dlg, sources, sourceIsValid, canChangeAlert) {

        if (!_canEdit) {return false;}

        if (false == fcUtil.validateInput(dlg.editor.title, fcUtil.validateNonemptyString)) {return false;}

        var dates = {};

        if (!_validateDateFields(dates)) {return false;}

        _eventObj.title = $.trim(dlg.editor.title.val());
        _eventObj.title = _eventObj.title.substr(0, Math.min(calendar.options.eventMaxTitleLength, _eventObj.title.length));
        _eventObj.location = $.trim(dlg.editor.location.val());
        _eventObj.description = $.trim(dlg.editor.description.val());
        _eventObj.allDay = dlg.editor.allday.is(":checked");
        _eventObj.start = dates.fromDate.dateTime;
        _eventObj.end   = dates.toDate.dateTime;

        if (canChangeAlert) {
            _eventObj.repeatRule = repeatRule;
            _eventObj.alert.type = alertType;
        }

        _eventObj.newSourceId = dlg.editor.calendar.val();
        
        if (!_eventObj.sourceId && _getDefaultSource(_eventObj.newSourceId).isSubscription) {
            _eventObj.attendees = [];
        } else {
            dlg.editor.attendeesInputBtn.click(); //add guests for users who are too lazy to click on the button
            _eventObj.attendees =  dlg.editor.attendees.AttendeesSelector("get");
        }
        
        var replyDecision = null;
        var replyEmail = null;
        var selectedReplyDecision = dlg.editor.replybuttons.find(".reply-radio:checked").attr("data-value");
        
        jq(_eventObj.attendees).each(function(i, attendee) {

            var attendeeEmail = attendee[3].replace(new RegExp("mailto:", "ig"), "");
            var attendeePartstat = attendee[1].partstat.toUpperCase();
            var nextStep = true;

            jq(ASC.Mail.Accounts).each(function(j, account) {
                if (account.enabled && attendeeEmail.toLowerCase() == account.email.toLowerCase()) {
                    nextStep = false;
                    if (selectedReplyDecision && selectedReplyDecision != attendeePartstat) {
                        replyEmail = account.email;
                        replyDecision = selectedReplyDecision;
                    }
                    return nextStep;
                }
                return nextStep;
            });

            return nextStep;
        });

        if (replyDecisionSettings.sendReply && replyEmail && replyDecision) {
            replyDecisionSettings.email = replyEmail;
            replyDecisionSettings.decision = replyDecision;
        } else {
            replyDecisionSettings.email = null;
            replyDecisionSettings.decision = null;
            replyDecisionSettings.sendReply = false;
        }

        _eventObj.permissions = dlg.editor.users.ShareUsersSelector("get");

        var organizerObj = new ICAL.Property("organizer");
        var selectedAccountObj = dlg.editor.ownerSelector.find("option:selected");
        var selectedAccount = selectedAccountObj.length ? { email: selectedAccountObj.attr("value"), name: Encoder.htmlDecode(selectedAccountObj.attr("data-name")) } : ASC.Mail.DefaultAccount;

        if (!_eventObj.sourceId) {
            if (selectedAccount) {
                organizerObj.setParameter("cn", selectedAccount.name);
                organizerObj.setValue("mailto:" + selectedAccount.email);
                _eventObj.organizer = organizerObj.jCal;
            }
        } else {
            var isOrganizer = false;
            if (_eventObj.organizer && _eventObj.organizer[3]) {
                var organizerEmail = _eventObj.organizer[3].replace(new RegExp("mailto:", "ig"), "").toLowerCase();
                jq(ASC.Mail.Accounts).each(function(index, account) {
                    if (organizerEmail == account.email.toLowerCase()) {
                        isOrganizer = true;
                        return false;
                    }
                    return true;
                });
            }
            if (isOrganizer && selectedAccount) {
                organizerObj.setParameter("cn", selectedAccount.name);
                organizerObj.setValue("mailto:" + selectedAccount.email);
                _eventObj.organizer = organizerObj.jCal;
            }
        }

        var src;
            
        $.each(sources, function() {
            if (this.objectId == _eventObj.newSourceId) {
                src = this;
                return false;
            }
            return true;
        });
            
        if (src) {
            _eventObj.newTimeZone = $.extend({}, src.timeZone);
        }

        delete _eventObj.textColor;
        delete _eventObj.backgroundColor;
        delete _eventObj.borderColor;
            
        calendar.normalizeEvent(_eventObj);

        return true;
    }

    function _doDDXLoadData(dlg, sources, sourceIsValid, canChangeAlert) {

        dlg.editor.title.css("color", "").css("border-color", "");
        dlg.editor.title.val(_eventObj.title || "");
        dlg.viewer.title.text(_eventObj.title || "");
        dlg.editor.attendeesInputContainer.find('input')[0].value = "";

        dlg.editor.sent_invitations.prop("checked", true);

        if (_eventObj.status == 2) {
            dlg.infoText.show();
        } else {
            dlg.infoText.hide();
        }

        dlg.editor.location.val(_eventObj.location || "");
        dlg.viewer.location.text(_eventObj.location || "");

        if (!_eventObj.location) {
            dlg.viewer.location.parent().hide();
        } else {
            dlg.viewer.location.parent().show();
        }

        var organizerName = _eventObj.organizer && _eventObj.organizer.length > 1 ? _eventObj.organizer[1].cn : "";
        organizerName = organizerName ? organizerName : _eventObj.owner ? _eventObj.owner.name : "";
            
        if (organizerName) {
            dlg.editor.owner.html(htmlEscape(organizerName));
            dlg.viewer.owner.html(htmlEscape(organizerName));
            _dialog.find(".owner").show();
        } else {
            dlg.editor.owner.html("");
            dlg.viewer.owner.html("");
            _dialog.find(".owner").hide();
        }

        var isNewEvent = !_eventObj.sourceId;
        var hasAccounts = ASC.Mail.Accounts.length > 0;
        
        var isOrganizer = false;
        var canEditOrganizer = false;
        var canEditAttendees = false;
        var showNoAccountsLink = false;

        if (isNewEvent) {
            isOrganizer = true;
            if (hasAccounts) {
                canEditOrganizer = true;
                canEditAttendees = true;
                dlg.editor.ownerSelector.val(ASC.Mail.DefaultAccount.email).change();
            } else {
                showNoAccountsLink = true;
            }
        } else {
            if (_eventObj.organizer && _eventObj.organizer[3]) {
                var organizerEmail = _eventObj.organizer[3].replace(new RegExp("mailto:", "ig"), "").toLowerCase();
                jq(ASC.Mail.Accounts).each(function(index, account) {
                    if (organizerEmail == account.email.toLowerCase()) {
                        isOrganizer = true;
                        dlg.editor.ownerSelector.val(account.email).change();
                        return false;
                    }
                    return true;
                });
            } else if (_eventObj.owner && _eventObj.owner.objectId === Teamlab.profile.id) {
                isOrganizer = true;
            }
            
            if (hasAccounts) {
                canEditOrganizer = isOrganizer;
                canEditAttendees = isOrganizer;
            } else {
                showNoAccountsLink = isOrganizer;
            }
        }

        if (canEditOrganizer) {
            dlg.editor.ownerSelector.parents(".selector").show();
            dlg.editor.owner.hide();
        } else {
            dlg.editor.ownerSelector.parents(".selector").hide();
            dlg.editor.owner.show();
        }

        var attendees = _eventObj.attendees || [];

        if (_canEdit && attendees.length) {
            var text;

            if (_eventObj.source.isSubscription)
                text = calendar.options.confirmPopup.editorInfoTextSubscription;
            else if(!isOrganizer)
                text = calendar.options.confirmPopup.editorInfoText;
            
            if(text)
                window.toastr.warning(text, "", { "closeButton": false, "timeOut": "0", "extendedTimeOut": "0" });
        }

        if (ASC.Mail.Enabled && showNoAccountsLink) {
            dlg.editor.attendeesNoAccount.removeClass("display-none");
        } else {
            dlg.editor.attendeesNoAccount.addClass("display-none");
        }

        if (canEditAttendees) {
            dlg.editor.attendeesHelpSwitcher.show();
        } else {
            dlg.editor.attendeesHelpSwitcher.hide();
        }

        dlg.editor.attendees.AttendeesSelector("set", attendees, canEditAttendees);
        
        if (_eventObj.attendees && _eventObj.attendees.length) {
                
            dlg.viewer.attendees.empty().parent().show();
            
            var replyDecision = null;

            jq.each(_eventObj.attendees, function (index, item) {
                
                var attendeeEmail = item[3].replace(new RegExp("mailto:", "ig"), "");
                var attendeePartstat = item[1].partstat.toUpperCase();
                var attendeeRole = item[1].role;
                var attendeeCommonName = item[1].cn;
			    
                var attendeeData = { canEdit: false, status: attendeePartstat, email: attendeeEmail, name: attendeeCommonName || "", role: attendeeRole };
                jq("#attendeeTemplate").tmpl(attendeeData).appendTo(dlg.viewer.attendees);

                if (!replyDecision) {
                    jq(ASC.Mail.Accounts).each(function(j, account) {
                        if (attendeeEmail.toLowerCase() == account.email.toLowerCase()) {
                            replyDecision = attendeePartstat.toLowerCase();
                            return false;
                        }
                        return true;
                    });
                }
                
            });

            if(dlg.editor.attendeesList.hasClass("scrollable"))
                dlg.viewer.attendees.addClass("scrollable");
            else
                dlg.viewer.attendees.removeClass("scrollable");

            dlg.editor.replybuttons.hide().find(".reply-radio").removeAttr("checked");
            
            if (_canEdit && replyDecision && _eventObj.status != 2 && !_eventObj.source.isSubscription) {
                dlg.editor.replybuttons.find(".reply-radio." + replyDecision).prop("checked", true);
                dlg.editor.replybuttons.show();
                replyDecisionSettings.sendReply = true;
            }

        } else {
            dlg.viewer.attendees.empty().parent().hide();
            dlg.editor.replybuttons.hide().find(".reply-radio").removeAttr("checked");
            replyDecisionSettings.sendReply = false;
        }

        dlg.editor.users.ShareUsersSelector("set", _eventObj.permissions, true);
            
        if (_eventObj.permissions && _eventObj.permissions.users && _eventObj.permissions.users.length) {
            var data = jq.extend(true, {}, _eventObj.permissions.data);

            jq(data.items).each(function(index, item) {
                item.canEdit = false;
            });

            dlg.viewer.users.empty().parent().show();
            jq("#sharingUserTemplate").tmpl(data).appendTo(dlg.viewer.users);

            if(dlg.editor.usersList.hasClass("scrollable"))
                dlg.viewer.users.addClass("scrollable");
            else
                dlg.viewer.users.removeClass("scrollable");

        } else {
            dlg.viewer.users.empty().parent().hide();
        }

        if (_eventObj.allDay == true) {
            dlg.editor.allday.prop("checked", true);
            dlg.viewer.allday.addClass("yes");
        } else {
            dlg.editor.allday.prop("checked", false);
            dlg.viewer.allday.removeClass("yes");
        }

        dlg.editor.from.css("color", "").css("border-color", "");
        dlg.editor.from_t.css("color", "").css("border-color", "");
            
        if (_eventObj.start instanceof Date) {
            dlg.editor.from.val(formatDate(_eventObj.start, calendar.options.eventEditor.dateFormat));
            dlg.editor.from_t.val(_eventObj.allDay ? "" : formatDate(_eventObj.start, calendar.options.eventEditor.timeFormat));
        } else {
            dlg.editor.from.val("");
            dlg.editor.from_t.val("");
        }
            
        dlg.viewer.from.text(dlg.editor.from.val());
        dlg.viewer.from_t.text(dlg.editor.from_t.val());

        dlg.editor.to.css("color", "").css("border-color", "");
        dlg.editor.to_t.css("color", "").css("border-color", "");
            
        if (_eventObj.end instanceof Date) {
            dlg.editor.to.val(formatDate(_eventObj.end, calendar.options.eventEditor.dateFormat));
            dlg.editor.to_t.val(_eventObj.allDay ? "" : formatDate(_eventObj.end, calendar.options.eventEditor.timeFormat));
        } else {
            if (_eventObj.allDay && _eventObj.start instanceof Date) {
                dlg.editor.to.val(formatDate(_eventObj.start, calendar.options.eventEditor.dateFormat));
            } else {
                dlg.editor.to.val("");
                dlg.editor.to_t.val("");
            }
        }
            
        dlg.viewer.to.text(dlg.editor.to.val());
        dlg.viewer.to_t.text(dlg.editor.to_t.val());
			

        if (_eventObj.start instanceof Date) {
            dlg.viewer.from_t.text(_eventObj.allDay ? "" : formatDate(_eventObj.start, calendar.options.axisFormat));
        } else {
            dlg.viewer.from_t.text("");
        }
			
        if (_eventObj.end instanceof Date) {
            dlg.viewer.to_t.text(_eventObj.allDay ? "" : formatDate(_eventObj.end, calendar.options.axisFormat));
        } else {
            dlg.viewer.to_t.text("");
        }

        if (!dlg.viewer.to.text())
            dlg.viewer.to.parent(".wrapper").hide();
        else
            dlg.viewer.to.parent(".wrapper").show();

        var defaultSource = _getDefaultSource(isNewEvent ? _eventObj.newSourceId : null);
        var calSource = sourceIsValid ? _eventObj.source : defaultSource;

        if (isOrganizer && calSource.isSubscription) {
            _dialog.find(".editor .attendees").hide();
        } else {
            if (!dlg.editor.attendeesInputContainer.hasClass("display-none") ||
                !dlg.editor.attendeesList.hasClass("display-none") ||
                !dlg.editor.attendeesNoAccount.hasClass("display-none")) {
                _dialog.find(".editor .attendees").show();
            } else {
                _dialog.find(".editor .attendees").hide();
            }
        }

        dlg.editor.repeat.text(function() {
            if (!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.Never) && 
				!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryDay) &&
				!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryWeek) &&
				!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryMonth) &&
				!_eventObj.repeatRule.Equals(ASC.Api.iCal.RecurrenceRule.EveryYear)) {
                _openSettings.call(_this);
                _settings.removeClass("hidden");
            }
				
            return _getRepeatLabel.call(_this, _eventObj.repeatRule);
        });
            
        dlg.editor.alert.text(sourceIsValid ? _getAlertLabel.call(_this, _eventObj.alert.type) : _getAlertLabel.call(_this, kAlertDefault));

        if (canChangeAlert) {
            _dialog.find(".repeat-alert").show();
        } else {
            dlg.editor.repeat.text(ASC.Api.iCal.RecurrenceRule.Never);
            dlg.editor.alert.text(kAlertNever);
            _dialog.find(".repeat-alert").hide();
        }
            
        dlg.viewer.repeat.text(dlg.editor.repeat.text());
        dlg.viewer.alert.text(dlg.editor.alert.text());

        var options = '';
        var calT;
        var calVal;
        var calColor;
        if (_canChangeSource) {
            for (var i = 0; i < sources.length; ++i) {
                if (sources[i].isTodo == 1) continue;

                if ((sources[i].objectId != undefined) && (sources[i].isEditable || !sources[i].isSubscription)) {
                    calT = htmlEscape(sources[i].title);
                    options += '<option value="' + htmlEscape(sources[i].objectId) + '" ' +
							'title="' + calT + '">' +
							'&nbsp;&nbsp;&nbsp;&nbsp;' +  // for select elem padding does not work in safari
							calT + '</option>';
                }
            }
            calVal = calSource.objectId;
            calColor = calSource.backgroundColor;
            dlg.editor.calendar.removeAttr("disabled");
        } else {
            calVal = sourceIsValid ?
					_eventObj.source.objectId : -1;
            calColor = sourceIsValid ?
					_eventObj.source.backgroundColor : calendar.options.eventBackgroundColor;
            calT = htmlEscape(sourceIsValid ? _eventObj.source.title : "");
            options = '<option value="' + htmlEscape(calVal) + '" title="' + calT + '">' +
					'&nbsp;&nbsp;&nbsp;&nbsp;' +      // for select elem padding does not work in safari
					calT + '</option>';
			dlg.editor.calendar.attr("disabled", "disabled");

			var wrapper = $(dlg.viewer.calendar[0].parentElement)
			if (wrapper) {
				var halfwidth = $(wrapper)[0].parentElement;
				if (halfwidth) {
					$(halfwidth).addClass("readonly")
				}
			}

        }

        dlg.editor.calendar.html(options);
        dlg.editor.calendar.val(calVal);
        dlg.viewer.calendar.text(sourceIsValid ?_eventObj.source.title : dlg.editor.calendar.find("option:selected").text());

        calColor = htmlEscape(calColor);
        dlg.editor.calendar_b.css("background", calColor);
        dlg.viewer.calendar_b.css("background", calColor);

        dlg.editor.description.val(_eventObj.description || "");
        dlg.viewer.description.text(_eventObj.description || "");

        if (_eventObj.sourceId == "users_birthdays" || !_eventObj.description) {
            dlg.viewer.description.parent().hide();
        } else {
            dlg.viewer.description.parent().show();
        }

        _handleAllDayClick.call(_this);
       
        return true;
    }



    function _getDefaultSource(objectId) {
        var sources = calendar.getEventSources();
        var validSources = [];

        for (var i = 0; i < sources.length; ++i) {
            if (fcUtil.objectIsValid(sources[i]) && (fcUtil.objectIsEditable(sources[i]) || !sources[i].isSubscription) && sources[i].isTodo != 1) {
                validSources.push(sources[i]);
            }
        }

        for (var j = 0; j < validSources.length; ++j) {
            if (objectId) {
                if (validSources[j].objectId == objectId)
                    return validSources[j];
            } else {
                if (!validSources[j].isHidden)
                    return validSources[j];
            }
        }

        return validSources.length ? validSources[0] : null;
    }

    function _createEvent(startDate, endDate, allDay) {
        changeTimeFrom = null;
        var evt = {
            title:           "",
            description:     "",
            allDay:          allDay,
            start:           startDate,
            end:             endDate,
            repeatRule:      ASC.Api.iCal.RecurrenceRule.Never,
            alert:           {type:kAlertDefault},
            isShared:        false,
            permissions:     {users:[]},
            attendees:       []
        };
        
        if (ASC.Mail.DefaultAccount) {
            var organizerObj = new ICAL.Property("organizer");
            organizerObj.setParameter("cn", ASC.Mail.DefaultAccount.name);
            organizerObj.setValue("mailto:" + ASC.Mail.DefaultAccount.email);
            evt.organizer = organizerObj.jCal;
        }

        return evt;
    }

    function _deleteEvent(deleteType, eventDate) {
        if (!_canDelete ||
		    !fcUtil.objectIsValid(_eventObj) ||
		    !fcUtil.objectIsValid(_eventObj.source)) {return;}

        if (_eventObj.sourceId && _eventObj.uniqueId && (_eventObj.repeatRule.Freq == ASC.Api.iCal.Frequency.Never || confirmSettings.selectedDeleteMode == deleteMode.allSeries))
            _sendNotification(_eventObj.sourceId, _eventObj.uniqueId, confirmSettings.notificationType.cancel, deleteEvt);
        else
            deleteEvt();

        function deleteEvt() {
            var id = _eventObj._id;
            calendar.trigger("editEvent", _this,
                $.extend(
                    { action: kEventDeleteAction, sourceId: _eventObj.source.objectId, type: deleteType, date: eventDate },
                    _eventObj),
                function(response) {
                    if (!response.result) {
                        return;
                    }
                    calendar.removeEvents(id);

                    //
                    if (response.event != undefined) {
                        if (!response.event.length) {
                            if (_eventObj.repeatRule.Freq != ASC.Api.iCal.Frequency.Never && confirmSettings.selectedDeleteMode != deleteMode.allSeries) {
                                _sendNotification(_eventObj.sourceId, _eventObj.uniqueId, confirmSettings.notificationType.cancel, function() {
                                    ASC.CalendarController.RemoveEvent(id, deleteMode.allSeries, eventDate);
                                });
                            }
                            return;
                        }
                        //
                        var sources = calendar.getEventSources();
                        var j = 0;
                        while (j < response.event.length) {
                            _setEventSource(response.event[j], sources);
                            j++;
                        }
                        calendar.addEvents(response.event);

                        if (_eventObj.repeatRule.Freq != ASC.Api.iCal.Frequency.Never && confirmSettings.selectedDeleteMode != deleteMode.allSeries) {
                            confirmSettings.notificationUsers.updatedGuests = confirmSettings.notificationUsers.removedGuests;
                            _sendNotification(_eventObj.sourceId, _eventObj.uniqueId, confirmSettings.notificationType.update);
                        }
                    }
                });
        }
    }

    function _unsubscribeEvent() {
        if (!_canUnsubscribe ||
		    !fcUtil.objectIsValid(_eventObj) ||
		    !fcUtil.objectIsValid(_eventObj.source)) {return;}
        //
        var id = _eventObj._id;
        calendar.trigger("editEvent", _this,
				$.extend(
						{action: kEventUnsubscribeAction, sourceId: _eventObj.source.objectId},
						_eventObj),
				function(response) {
				    if (!response.result) {return;}
				    _close.call(_this, false);
				    calendar.removeEvents(id);
				});
    }

    function _setEventSource(event, sources) {
        if (event.sourceId == undefined) {
            event.sourceId = event.newSourceId;
        }
        if (!event.source && event.sourceId != undefined) {
            for (var i = 0; i < sources.length; ++i) {
                if (sources[i].objectId != undefined && sources[i].objectId == event.sourceId) {
                    event.source = sources[i];
                    break;
                }
            }
        }
    }

    function _updateEvent(isCancel) {
        if (!_canEdit) {return;}
		
        if(isCancel)
        {
            calendar.trigger("editEvent", _this, $.extend( {action: kEventCancelAction, sourceId: _eventObj.source.objectId}, _eventObj), function(response){} );
            return;
        }

        if (_eventObj.source) {
            _disableDialogBtns(true);

            if (_eventObj.sourceId && _eventObj.uniqueId)
                _sendNotification(_eventObj.sourceId, _eventObj.uniqueId, confirmSettings.notificationType.cancel, editEvt);
            else
                editEvt();

        } else {
            _disableDialogBtns(true);
            var id = _eventObj._id;
            // create new event
            calendar.trigger("editEvent", _this,
					$.extend({action: kEventAddAction}, _eventObj),
					function(response) {
					    _disableDialogBtns(false);
					    if (!response.result) {return;}
					    _closeDialog.call(_this);
					    calendar.removeEvents(id);
					    if (response.event.length < 1) {return;}
					    //
					    var sources = calendar.getEventSources();
					    calendar.removeEvents(response.event[0].objectId);
					    for (var j = 0; j < response.event.length; ++j) {
					        _setEventSource(response.event[j], sources);
					    }
					    calendar.addEvents(response.event);
					    
					    _sendNotification(response.event[0].sourceId, response.event[0].uniqueId, confirmSettings.notificationType.request);
					});
        }
        
        function editEvt() {
            calendar.trigger("editEvent", _this,
                $.extend(
                    { action: kEventChangeAction, sourceId: _eventObj.source.objectId },
                    _eventObj),
                function(response) {
                    _disableDialogBtns(false);
                    if (!response.result) {
                        return;
                    }
                    _closeDialog.call(_this);
                    if (response.event.length < 1) {
                        return;
                    }
                    //
                    var sources = calendar.getEventSources();
                    calendar.removeEvents(response.event[0].objectId);
                    for (var j = 0; j < response.event.length; ++j) {
                        _setEventSource(response.event[j], sources);
                    }
                    calendar.addEvents(response.event);

                    _sendNotification(response.event[0].sourceId, response.event[0].uniqueId, confirmSettings.notificationType.request);
                    _sendNotification(response.event[0].sourceId, response.event[0].uniqueId, confirmSettings.notificationType.update);
                    _sendReply(response.event[0].sourceId, response.event[0].uniqueId);
                });
        }
    }

    // Public interface

    this.openEvent = function (canEdit, elem, event) {
        changeTimeFrom = null;
        _open.call(_this, canEdit ? "edit" : "view", elem, event);
    };

    this.addEvent = function(startDate, endDate, allDay) {
        // Protect from addind event in nonexistent category
        var defaultSource = _getDefaultSource();
        if (defaultSource == undefined) return;

        var ev;
        if (startDate != undefined) {
            // add event via clicking calendar cell
            ev = _createEvent(startDate, endDate, allDay);
            ev.textColor = defaultSource.textColor;
            ev.backgroundColor = defaultSource.backgroundColor;
            ev.borderColor = defaultSource.borderColor;
            calendar.renderEvent(ev);
            _open.call(_this, "edit", calendar.getView().getEventElement(ev), ev);
        } else {
            // add event via header menu
            var curDate = new Date();
            var targetDate = new Date(curDate.getFullYear(), curDate.getMonth(), curDate.getDate());
            ev = _createEvent(targetDate, targetDate, true);
            _open.call(_this, "edit", undefined, ev);
        }
    };

    this.isVisible = function() {
        return _dialog.is(":visible");
    };
}


fc.sourceNormalizers = [];
fc.sourceFetchers = [];

var ajaxDefaults = {
	dataType: 'json',
	cache: false
};

var eventGUID = 1;


function EventManager(options, _sources) {
	var t = this;


	if (localStorageManager.getItem("showTodosInCalendar") == undefined) {
	    localStorageManager.setItem("showTodosInCalendar", true);
	}

	// exports
	t.isFetchNeeded = isFetchNeeded;
	t.fetchEvents = fetchEvents;
	t.addEvents = addEvents;
	t.addEventSource = addEventSource;
	t.removeEventSource = removeEventSource;
	t.getEventSources = getEventSources;
	t.cleanEmptyEventSources = cleanEmptyEventSources;
	t.updateEvent = updateEvent;
	t.renderEvent = renderEvent;
	t.removeEvents = removeEvents;
	t.clientEvents = clientEvents;
	t.normalizeEvent = normalizeEvent;
    t.getCache = getCache;
    t.showTodosInCalendar = localStorageManager.getItem("showTodosInCalendar");
    t.hideCompletedTodos = localStorageManager.getItem("hideCompletedTodos");


	// imports
	var trigger = t.trigger;
	var getView = t.getView;
	var reportEvents = t.reportEvents;


	// locals
	var stickySource = { events: [], todos: [] };
	var sources = [ stickySource ];
	var rangeStart, rangeEnd;
	var currentFetchID = 0;
	var pendingSourceCnt = 0;
	var loadingLevel = 0;
	var cache = [];



	/* Fetching
	-----------------------------------------------------------------------------*/


	function isFetchNeeded(start, end) {
		return !rangeStart || start < rangeStart || end > rangeEnd;
	}

	function fetchEvents(start, end, resolve) {
		rangeStart = function(d) {
			var d1 = cloneDate(d, true);
			if (d1.getDate() != 1) {d1.setDate(1);}
			return d1;
		}(start);
		rangeEnd = function(d) {
			var d1 = cloneDate(d, true);
			var m1 = d1.getMonth();
			var y1 = d1.getFullYear();
			m1 = d1.getDate() == 1 ? m1 : (m1 < 11 ? m1 + 1 : (++y1, 0));
			d1.setFullYear(y1, m1, 1);
			return d1;
		}(end);
		cache = [];
		var fetchID = ++currentFetchID;

		trigger("loadEventSources", t, rangeStart, rangeEnd, function(response){
			if (response.result && $.isArray(response.eventSources)) {
				sources.splice(1, sources.length - 1);
				for (var i = 0; i < response.eventSources.length; ++i) {
					_addEventSource(response.eventSources[i]);
				}
				var len = sources.length;
				pendingSourceCnt = len;
				for (i = 0; i < len; ++i) {
					fetchEventSource(sources[i], fetchID);
				}
				t.rerenderCategories(resolve);
			}
		});
	}

	function fetchEventSource(source, fetchID) {
		_fetchEventSource(source, function(response) {
			if (fetchID == currentFetchID) {
				if (response.events) {
				    for (var i = 0; i < response.events.length; i++) {
				        response.events[i].source = source;
				        response.events[i].false = true;
				        normalizeEvent(response.events[i]);
				    }
				    cache = cache.concat(response.events);
				}
				if (response.todos && t.showTodosInCalendar) {
				    var todos = [];
				    for (var j = 0; j < response.todos.length; j++) {
				        if (!t.hideCompletedTodos || (t.hideCompletedTodos && response.todos[j].completed == false)) {
				            response.todos[j].source = source;
				            response.todos[j].isTodo = true;
				            todos.push(response.todos[j]);
				            normalizeEvent(todos[todos.length-1]);
				        } 
				    }
				    if (source.objectId != undefined) cache = cache.concat(todos);

				}
				pendingSourceCnt--;
				if (!pendingSourceCnt) {
					reportEvents(cache);
				}
			}
		});
	}

	function _fetchEventSource(source, callback) {
		var i;
		var fetchers = fc.sourceFetchers;
		var res;
		for (i=0; i<fetchers.length; i++) {
			res = fetchers[i](source, rangeStart, rangeEnd, callback);
			if (res === true) {
				// the fetcher is in charge. made its own async request
				return;
			}
			else if (typeof res == 'object') {
				// the fetcher returned a new source. process it
				_fetchEventSource(res, callback);
				return;
			}
		}
		var events = source.events;
		var todos = source.todos;
		
		if (events) {
			if ($.isFunction(events)) {
				pushLoading();
				events(cloneDate(rangeStart), cloneDate(rangeEnd), function(events) {
				    callback({ result: true, events: events, todos: todos });
					popLoading();
				});
			}
			else if ($.isArray(events)) {
				callback({result:true,events:events, todos: todos});
			}
			else {
			    callback({ result: false, events: [], todos: [] });
			}
		}
		else {
			var url = source.url;
			if (url) {
				var success = source.success;
				var error = source.error;
				var complete = source.complete;
				var data = $.extend({}, source.data || {});
				var startParam = firstDefined(source.startParam, options.startParam);
				var endParam = firstDefined(source.endParam, options.endParam);
				if (startParam) {
					data[startParam] = Math.round(+rangeStart / 1000);
				}
				if (endParam) {
					data[endParam] = Math.round(+rangeEnd / 1000);
				}
				pushLoading();
				$.ajax($.extend({}, ajaxDefaults, source, {
					data: data,
					success: function(events) {
						events = events || [];
						var res = applyAll(success, this, arguments);
						if ($.isArray(res)) {
							events = res;
						}
						callback({result:true,events:events});
					},
					error: function() {
						applyAll(error, this, arguments);
						callback({result:false,events:[]});
					},
					complete: function() {
						applyAll(complete, this, arguments);
						popLoading();
					}
				}));
			}else{
				callback({result:false,events:[]});
			}
		}
	}


	/* Sources
	-----------------------------------------------------------------------------*/

	function addEventSource(source) {
		source = _addEventSource(source);
		if (source) {
			pendingSourceCnt++;
			fetchEventSource(source, currentFetchID); // will eventually call reportEvents
		}
	}

	function _addEventSource(source) {
		if ($.isFunction(source) || $.isArray(source)) {
			source = {events: source};
		}
		else if (typeof source == 'string') {
			source = {url: source};
		}
		if (typeof source == 'object') {
			normalizeSource(source);
			sources.push(source);
			return source;
		}
		return undefined;
	}

	function removeEventSource(source) {
		sources = $.grep(sources, function(src) {
			return !isSourcesEqual(src, source);
		});
		// remove all client events from that source
		cache = $.grep(cache, function(e) {
			return !isSourcesEqual(e.source, source);
		});
		reportEvents(cache);
		t.rerenderCategories();
	}

	function getCache() {
	    return cache;
	}
	function getEventSources() {
		return sources;
	}
	function cleanEmptyEventSources() {
	    for (var i = 0; i < sources.length; i++) {
	        if (sources[i].isTodo != 1) {
	            sources[i].todos = [];
	        }
	    }
	}


	/* Manipulation
	-----------------------------------------------------------------------------*/

	function updateEvent(event) { // update an existing event
		normalizeEvent(event);
		var i, len = cache.length, e,
			defaultEventEnd = getView().defaultEventEnd, // getView???
			startDelta = event.start - event._start,
			endDelta = event.end ?
				(event.end - (event._end || defaultEventEnd(event))) // event._end would be null if event.end
				: 0;                                                 // was null and event was just resized
		for (i=0; i<len; i++) {
			e = cache[i];
			if (e._id == event._id && e != event) {
				e.start = new Date(+e.start + startDelta);
				if (event.end) {
					if (e.end) {
						e.end = new Date(+e.end + endDelta);
					}else{
						e.end = new Date(+defaultEventEnd(e) + endDelta);
					}
				}else{
					e.end = null;
				}
				if (event.title           != undefined) {e.title = event.title;}
				if (event.url             != undefined) {e.url = event.url;}
				if (event.allDay          != undefined) {e.allDay = event.allDay;}
				if (event.className       != undefined) {e.className = event.className;}
				if (event.editable        != undefined) {e.editable = event.editable;}
				if (event.color           != undefined) {e.color = event.color;}
				if (event.backgroundColor != undefined) {e.backgroundColor = event.backgroundColor;}
				if (event.borderColor     != undefined) {e.borderColor = event.borderColor;}
				if (event.textColor       != undefined) {e.textColor = event.textColor;}
				if (event.description     != undefined) {e.description = event.description;}
				if (event.repeat          != undefined) {e.repeat = event.repeat;}
				if (event.alert           != undefined) {e.alert = event.alert;}
				if (event.objectId        != undefined) {e.objectId = event.objectId;}
				if (event.sourceId        != undefined) {e.sourceId = event.sourceId;}
				if (event.source          != undefined) {e.source = event.source;}
				if (event.isShared        != undefined) {e.isShared = event.isShared;}
				if (event.permissions     != undefined) {e.permissions = event.permissions;}
				if (event.owner           != undefined) {e.owner = event.owner;}
				normalizeEvent(e);
			}
		}
		reportEvents(cache);
	}

	function renderEvent(event, stick) {
		normalizeEvent(event);
		if (!event.source) {
			if (stick) {
				stickySource.events.push(event);
				event.source = stickySource;
			}
			cache.push(event);
		}
		reportEvents(cache);
	}

	function addEvents(events) {
		var i=0;
		while(i < events.length) {
			normalizeEvent(events[i]);
			i++;
		}
		cache = cache.concat(events);
		reportEvents(cache);
	}

	function removeEvents(filter) {
		if (!filter) { // remove all
			cache = [];
			// clear all array sources
			for (var i=0; i<sources.length; i++) {
				if ($.isArray(sources[i].events)) {
					sources[i].events = [];
				}
			}
		}else{
			if (!$.isFunction(filter)) { // an event ID
				var id = filter + '';
				filter = function(e) {
					return e._id == id;
				};
			}
			cache = $.grep(cache, filter, true);
			// remove events from array sources
			for (i=0; i<sources.length; i++) {
				if ($.isArray(sources[i].events)) {
					sources[i].events = $.grep(sources[i].events, filter, true);
				}
			}
		}
		reportEvents(cache);
	}

	function clientEvents(filter) {
		if ($.isFunction(filter)) {
			return $.grep(cache, filter);
		}
		else if (filter) { // an event ID
			filter += '';
			return $.grep(cache, function(e) {
				return e._id == filter;
			});
		}
		return cache; // else, return all
	}
	
	/* Loading State
	-----------------------------------------------------------------------------*/

	function pushLoading() {
		if (!loadingLevel++) {
			trigger('loading', null, true);
		}
	}

	function popLoading() {
		if (!--loadingLevel) {
			trigger('loading', null, false);
		}
	}


	/* Event Normalization
	-----------------------------------------------------------------------------*/

	function normalizeEvent(event) {
		var source = event.source || {};
		var ignoreTimezone = firstDefined(source.ignoreTimezone, options.ignoreTimezone);
		event._id = event.objectId !== undefined ?
				event.objectId + '' :
				(event._id !== undefined ?
						event._id :
						(event.id !== undefined ? event.id + '' : '_fc' + eventGUID++));
		if (event.date) {
			if (!event.start) {
				event.start = event.date;
			}
			delete event.date;
		}
		event._start = cloneDate(event.start = parseDate(event.start, ignoreTimezone));
		event.end = parseDate(event.end, ignoreTimezone);
		if (event.end && event.end <= event.start) {
			event.end = null;
		}
		event._end = event.end ? cloneDate(event.end) : null;
		if (event.allDay === undefined) {
		    if (event.isTodo) {
		        event.allDay = true;
		    } else {
		        event.allDay = firstDefined(source.allDayDefault, options.allDayDefault);
		    }
			
		}
		if (event.className) {
			if (typeof event.className == 'string') {
				event.className = event.className.split(/\s+/);
			}
		}else{
			event.className = [];
		}
		// TODO: if there is no start date, return false to indicate an invalid event
	}


	/* Utils
	------------------------------------------------------------------------------*/

	function normalizeSource(source) {
		if (source.backgroundColor && !source.borderColor) {
			var bg = fcUtil.parseCssColor(source.backgroundColor);
			var bor;
			if (bg) {
				bor = fcUtil.changeColorLightness(bg.r, bg.g, bg.b, options.eventBg2BorderRatio);
				source.borderColor = bor.color;
			}
		}

		if (source.className) {
			// TODO: repeat code, same code for event classNames
			if (typeof source.className == 'string') {
				source.className = source.className.split(/\s+/);
			}
		}else{
			source.className = [];
		}
		var normalizers = fc.sourceNormalizers;
		for (var i=0; i<normalizers.length; i++) {
			normalizers[i](source);
		}
	}

	function isSourcesEqual(source1, source2) {
		return source1 && source2 && getSourcePrimitive(source1) == getSourcePrimitive(source2);
	}

	function getSourcePrimitive(source) {
		return ((typeof source == 'object') ? (source.events || source.url) : '') || source;
	}

}



fc.addDays = addDays;
fc.cloneDate = cloneDate;
fc.parseDate = parseDate;
fc.parseISO8601 = parseISO8601;
fc.parseTime = parseTime;
fc.formatDate = formatDate;
fc.formatDates = formatDates;



/* Date Math
-----------------------------------------------------------------------------*/

var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
	DAY_MS = 86400000,
	HOUR_MS = 3600000,
	MINUTE_MS = 60000;


function addYears(d, n, keepTime) {
	d.setFullYear(d.getFullYear() + n);
	if (!keepTime) {
		clearTime(d);
	}
	return d;
}

function addMonths(d, n, keepTime) { // prevents day overflow/underflow
	if (+d) { // prevent infinite looping on invalid dates
		var m = d.getMonth() + n,
			check = cloneDate(d);
		check.setDate(1);
		check.setMonth(m);
		d.setMonth(m);
		if (!keepTime) {
			clearTime(d);
		}
		while (d.getMonth() != check.getMonth()) {
			d.setDate(d.getDate() + (d < check ? 1 : -1));
		}
	}
	return d;
}

function addDays(d, n, keepTime) { // deals with daylight savings
	if (+d) {
		var dd = d.getDate() + n,
			check = cloneDate(d);
		check.setHours(9); // set to middle of day
		check.setDate(dd);
		d.setDate(dd);
		if (!keepTime) {
			clearTime(d);
		}
		fixDate(d, check);
	}
	return d;
}

function fixDate(d, check) { // force d to be on check's YMD, for daylight savings purposes
	if (+d) { // prevent infinite looping on invalid dates
		while (d.getDate() != check.getDate()) {
			d.setTime(+d + (d < check ? 1 : -1) * HOUR_MS);
		}
	}
}

function addMinutes(d, n) {
	d.setMinutes(d.getMinutes() + n);
	return d;
}

function clearTime(d) {
	d.setHours(0, 0, 0, 0);
	return d;
}

function cloneDate(d, dontKeepTime) {
	if (dontKeepTime) {
		return clearTime(new Date(+d));
	}
	return new Date(+d);
}

function zeroDate() { // returns a Date with time 00:00:00 and dateOfMonth=1
	var i=0, d;
	do {
		d = new Date(1970, i++, 1);
	} while (d.getHours()); // != 0
	return d;
}

function skipWeekend(date, inc, excl) {
	inc = inc || 1;
	while (!date.getDay() || (excl && date.getDay()==1 || !excl && date.getDay()==6)) {
		addDays(date, inc);
	}
	return date;
}

function dayDiff(d1, d2) { // d1 - d2
	return Math.round((cloneDate(d1, true) - cloneDate(d2, true)) / DAY_MS);
}

function setYMD(date, y, m, d) {
	if (y !== undefined && y != date.getFullYear()) {
		date.setDate(1);
		date.setMonth(0);
		date.setFullYear(y);
	}
	if (m !== undefined && m != date.getMonth()) {
		date.setDate(1);
		date.setMonth(m);
	}
	if (d !== undefined) {
		date.setDate(d);
	}
}


/* ICS Parsing
-----------------------------------------------------------------------------*/

function parseIcs(icsFormat) {
    if (!icsFormat) return null;

    try {
        var jCalData = window.ICAL.parse(icsFormat);

        var comp = new window.ICAL.Component(jCalData);
        if (comp.name !== "vcalendar")
            return null;

        var vevent = comp.getFirstSubcomponent("vevent");
        if (!vevent)
            return null;

        var event = new window.ICAL.Event(vevent);

        var organizer = vevent.getFirstProperty("organizer");

        var attendees = [];

        jq.each(event.attendees, function(index, attendee) {
            attendees.push(attendee.jCal);
        });

        return {
            location: event.location,
            attendees: attendees,
            organizer: organizer == null ? null : organizer.jCal
        };
    } catch(e) {
        console.error(e);
        return null;
    }
}


/* Date Parsing
-----------------------------------------------------------------------------*/

function parseDate(s, ignoreTimezone) { // ignoreTimezone defaults to true
	if (typeof s == 'object') { // already a Date object
		return s;
	}
	if (typeof s == 'number') { // a UNIX timestamp
		return new Date(s * 1000);
	}
	if (typeof s == 'string') {
		if (s.match(/^\d+(\.\d+)?$/)) { // a UNIX timestamp
			return new Date(parseFloat(s) * 1000);
		}
		if (ignoreTimezone === undefined) {
			ignoreTimezone = true;
		}
		return parseISO8601(s, ignoreTimezone) || (isNaN(Date.parse(s)) ? null : new Date(s));
	}
	// TODO: never return invalid dates (like from new Date(<string>)), return null instead
	return null;
}

function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false
	// derived from http://delete.me.uk/2005/03/iso8601.html
	// TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html
	var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);
	if (!m) {
		return null;
	}
	var date = new Date(m[1], 0, 1, 1); // TODO hack for Russia TZ Daylight Time. remove for chrome 29 ???
	if (ignoreTimezone || !m[14]) {
		var check = new Date(m[1], 0, 1, 9, 0);
		if (m[3]) {
			date.setMonth(m[3] - 1);
			check.setMonth(m[3] - 1);
		}
		if (m[5]) {
			date.setDate(m[5]);
			check.setDate(m[5]);
		}
		fixDate(date, check);
		if (m[7]) {
			date.setHours(m[7]);
		}
		if (m[8]) {
			date.setMinutes(m[8]);
		}
		if (m[10]) {
			date.setSeconds(m[10]);
		}
		if (m[12]) {
			date.setMilliseconds(Number("0." + m[12]) * 1000);
		}
		fixDate(date, check);
	}else{
		date.setUTCFullYear(
			m[1],
			m[3] ? m[3] - 1 : 0,
			m[5] || 1
		);
		date.setUTCHours(
			m[7] || 0,
			m[8] || 0,
			m[10] || 0,
			m[12] ? Number("0." + m[12]) * 1000 : 0
		);
		var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0);
		offset *= m[15] == '-' ? 1 : -1;
		date = new Date(+date + (offset * 60 * 1000));
	}
	return date;
}

function parseTime(s) { // returns minutes since start of day
	if (typeof s == 'number') { // an hour
		return s * 60;
	}
	if (typeof s == 'object') { // a Date object
		return s.getHours() * 60 + s.getMinutes();
	}
	var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/);
	if (m) {
		var h = parseInt(m[1], 10);
		if (m[3]) {
			h %= 12;
			if (m[3].toLowerCase().charAt(0) == 'p') {
				h += 12;
			}
		}
		return h * 60 + (m[2] ? parseInt(m[2], 10) : 0);
	}
	return 0;
}



/* Date Formatting
-----------------------------------------------------------------------------*/
// TODO: use same function formatDate(date, [date2], format, [options])

function formatDate(date, format, options) {
	return formatDates(date, null, format, options);
}

function formatDates(date1, date2, format, options) {
	options = options || defaults;
	var date = date1,
		otherDate = date2,
		i, len = format.length, c,
		i2, formatter,
		res = '', subres;
	for (i=0; i<len; i++) {
		c = format.charAt(i);
		if (c == "'") {
			for (i2=i+1; i2<len; i2++) {
				if (format.charAt(i2) == "'") {
					if (date) {
						if (i2 == i+1) {
							res += "'";
						}else{
							res += format.substring(i+1, i2);
						}
						i = i2;
					}
					break;
				}
			}
		}
		else if (c == '(') {
			for (i2=i+1; i2<len; i2++) {
				if (format.charAt(i2) == ')') {
					subres = formatDate(date, format.substring(i+1, i2), options);
					if (parseInt(subres.replace(/\D/, ''), 10)) {
						res += subres;
					}
					i = i2;
					break;
				}
			}
		}
		else if (c == '[') {
			for (i2=i+1; i2<len; i2++) {
				if (format.charAt(i2) == ']') {
					var subformat = format.substring(i+1, i2);
					subres = formatDate(date, subformat, options);
					if (subres != formatDate(otherDate, subformat, options)) {
						res += subres;
					}
					i = i2;
					break;
				}
			}
		}
		else if (c == '{') {
			date = date2;
			otherDate = date1;
		}
		else if (c == '}') {
			date = date1;
			otherDate = date2;
		}
		else {
			for (i2=len; i2>i; i2--) {
				formatter = dateFormatters[format.substring(i, i2)];
				if (formatter) {
					if (date) {
						res += formatter(date, options);
					}
					i = i2 - 1;
					break;
				}
			}
			if (i2 == i) {
				if (date) {
					res += c;
				}
			}
		}
	}
	return res;
}


var dateFormatters = {
	s  : function(d)  {return d.getSeconds();},
	ss  : function(d)  {return zeroPad(d.getSeconds());},
	m  : function(d)  {return d.getMinutes();},
	mm  : function(d)  {return zeroPad(d.getMinutes());},
	h  : function(d)  {return d.getHours() % 12 || 12;},
	hh  : function(d)  {return zeroPad(d.getHours() % 12 || 12);},
	H  : function(d)  {return d.getHours();},
	HH  : function(d)  {return zeroPad(d.getHours());},
	d  : function(d)  {return d.getDate();},
	dd  : function(d)  {return zeroPad(d.getDate());},
	ddd  : function(d,o)  {return o.dayNamesShort[d.getDay()];},
	dddd: function(d,o)  {return o.dayNames[d.getDay()];},
	M  : function(d)  {return d.getMonth() + 1;},
	MM  : function(d)  {return zeroPad(d.getMonth() + 1);},
	MMM  : function(d,o)  {return o.monthNamesShort[d.getMonth()];},
	MMMM: function(d,o)  {return o.monthNames[d.getMonth()];},
	yy  : function(d)  {return (d.getFullYear()+'').substring(2);},
	yyyy: function(d)  {return d.getFullYear();},
	t  : function(d)  {return d.getHours() < 12 ? 'a' : 'p';},
	tt  : function(d)  {return d.getHours() < 12 ? 'am' : 'pm';},
	T  : function(d)  {return d.getHours() < 12 ? 'A' : 'P';},
	TT  : function(d)  {return d.getHours() < 12 ? 'AM' : 'PM';},
	u  : function(d)  {return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'");},
	S  : function(d)  {
		var date = d.getDate();
		if (date > 10 && date < 20) {
			return 'th';
		}
		return ['st', 'nd', 'rd'][date%10-1] || 'th';
	}
};



fc.applyAll = applyAll;


/* Event Date Math
-----------------------------------------------------------------------------*/

function exclEndDay(event) {
	if (event.end) {
		return _exclEndDay(event.end, event.allDay);
	}else{
		return addDays(cloneDate(event.start), 1);
	}
}

function _exclEndDay(end, allDay) {
	end = cloneDate(end);
	return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end);
}

function segCmp(a, b) {
	return a.event.source === undefined ? -1 : (b.event.source === undefined ? 1 : (
			(b.msLength - a.msLength) * 100 + (a.event.start - b.event.start)));
}

function segsCollide(seg1, seg2) {
	return seg1.end > seg2.start && seg1.start < seg2.end;
}



/* Event Sorting
-----------------------------------------------------------------------------*/

// event rendering utilities
function sliceSegs(events, fixEventEndFunc, start, end) {
	var segs = [],
		i, len=events.length, event,
		eventStart, eventEnd,
		segStart, segEnd,
		isStart, isEnd;
	for (i=0; i<len; i++) {
		event = events[i];
		eventStart = event.start;
		eventEnd = fixEventEndFunc(event);
		if ((!event.source || !event.source.isHidden) && eventEnd > start && eventStart < end && ASC.Api.iCal.RecurrenceRule.isVisibleYearlyEvent(event)) {
			if (eventStart < start) {
				segStart = cloneDate(start);
				isStart = false;
			}else{
				segStart = eventStart;
				isStart = true;
			}
			if (eventEnd > end) {
				segEnd = cloneDate(end);
				isEnd = false;
			}else{
				segEnd = eventEnd;
				isEnd = true;
			}
			segs.push({
				event: event,
				start: segStart,
				end: segEnd,
				isStart: isStart,
				isEnd: isEnd,
				msLength: segEnd - segStart
			});
		}
	}
	return segs.sort(segCmp);
}

// event rendering calculation utilities
function stackSegs(segs) {
	var levels = [],
		i, len = segs.length, seg,
		j, collide, k;
	for (i=0; i<len; i++) {
		seg = segs[i];
		j = 0; // the level index where seg should belong
		while (true) {
			collide = false;
			if (levels[j]) {
				for (k=0; k<levels[j].length; k++) {
					if (segsCollide(levels[j][k], seg)) {
						collide = true;
						break;
					}
				}
			}
			if (collide) {
				j++;
			}else{
				break;
			}
		}
		if (levels[j]) {
			levels[j].push(seg);
		}else{
			levels[j] = [seg];
		}
	}
	return levels;
}



/* Event Element Binding
-----------------------------------------------------------------------------*/

function lazySegBind(container, segs, bindHandlers) {
	container.unbind('mouseover').mouseover(function(ev) {
		var e = ev.target, i, seg;
		while (e && e != this) {
			if (e._fci !== undefined) break;
			e = e.parentNode;
		}
		if ((i = e._fci) !== undefined) {
			e._fci = undefined;
			seg = segs[i];
			bindHandlers(seg.event, seg.element, seg);
			$(ev.target).trigger(ev);
		}
		ev.stopPropagation();
	});
}



/* Element Dimensions
-----------------------------------------------------------------------------*/

function setOuterWidth(element, width, includeMargins) {
	for (var i=0, e; i<element.length; i++) {
		e = $(element[i]);
		e.width(Math.max(0, width - hsides(e, includeMargins)));
	}
}

function setOuterHeight(element, height, includeMargins) {
	for (var i=0, e; i<element.length; i++) {
		e = $(element[i]);
		e.height(Math.max(0, height - vsides(e, includeMargins)));
	}
}

// TODO: curCSS has been deprecated (jQuery 1.4.3 - 10/16/2010)

function hsides(element, includeMargins) {
    var styles = window.getComputedStyle(element[0]);
    return hpadding(styles) + hborders(styles) + (includeMargins ? hmargins(styles) : 0);
}

function hpadding(styles) {
    return (parseFloat(styles.paddingLeft) || 0) + (parseFloat(styles.paddingRight) || 0);
}

function hmargins(styles) {
    return (parseFloat(styles.marginLeft) || 0) + (parseFloat(styles.marginRight) || 0);
}

function hborders(styles) {
    return (parseFloat(styles.borderLeftWidth) || 0) + (parseFloat(styles.borderRightWidth) || 0);
}

function vsides(element, includeMargins) {
    var styles = window.getComputedStyle(element[0]);
    return vpadding(styles) + vborders(styles) + (includeMargins ? vmargins(styles) : 0);
}

function vpadding(styles) {
    return (parseFloat(styles.paddingTop) || 0) + (parseFloat(styles.paddingBottom) || 0);
}

function vmargins(styles) {
    return (parseFloat(styles.marginTop) || 0) + (parseFloat(styles.marginBottom) || 0);
}

function vborders(styles) {
    return (parseFloat(styles.borderTopWidth) || 0) + (parseFloat(styles.borderBottomWidth) || 0);
}

function setMinHeight(element, height, bSetHeight) {
	height = (typeof height == 'number' ? height + 'px' : height);
	element.each(function(i, _element) {
		_element.style.cssText += ';min-height:' + height +
				(bSetHeight ? ';height:' + height: '') +
				';_height:' + height + ';';
	});
}

function setMinWidth(element, width) {
	width = (typeof width == 'number' ? width + 'px' : width);
	element.each(function(i, _element) {
		_element.style.cssText += ';min-width:' + width + ';width:' + width + ';_width:' + width + ';';
	});
}


/* Misc Utils
-----------------------------------------------------------------------------*/


//TODO: arraySlice
//TODO: isFunction, grep ?


function noop() { }

function cmp(a, b) {
	return a - b;
}

function arrayMax(a) {
	return Math.max.apply(Math, a);
}

function zeroPad(n) {
	return (n < 10 ? '0' : '') + n;
}

function smartProperty(obj, name) { // get a camel-cased/namespaced property of an object
	if (obj[name] !== undefined) {
		return obj[name];
	}
	var parts = name.split(/(?=[A-Z])/),
		i=parts.length-1, res;
	for (; i>=0; i--) {
		res = obj[parts[i].toLowerCase()];
		if (res !== undefined) {
			return res;
		}
	}
	return obj[''];
}

function htmlEscape(s) {
	if (typeof s !== "string") {
		return s;
	}
	return s.replace(/&(\s|[^#\w]|\w+(?:[^;\w]|$))/g, '&amp;$1')
		.replace(/</g, '&lt;')
		.replace(/>/g, '&gt;')
		.replace(/'/g, '&#039;')
		.replace(/"/g, '&quot;')
		.replace(/\n/g, '<br/>');
}

function cssKey(_element) {
	return _element.id + '/' + _element.className + '/' + _element.style.cssText.replace(/(^|;)\s*(top|left|width|height)\s*:[^;]*/ig, '');
}

function disableTextSelection(element) {
	element
		.attr('unselectable', 'on')
		.css('MozUserSelect', 'none')
		.bind('selectstart.ui', function() {return false;});
}

/*
function enableTextSelection(element) {
	element
		.attr('unselectable', 'off')
		.css('MozUserSelect', '')
		.unbind('selectstart.ui');
}
*/

function markFirstLast(e) {
	e.children()
		.removeClass('fc-first fc-last')
		.filter(':first-child')
			.addClass('fc-first')
		.end()
		.filter(':last-child')
			.addClass('fc-last');
}

function setDayID(cell, date) {
	cell.className = cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]);
	// TODO: make a way that doesn't rely on order of classes
}

function getSkinCss(event, opt, curView) {
	var source = event.source || {};
	var eventColor = event.color;
	var sourceColor = source.color;
	var optionColor = opt('eventColor');
	var isShort = curView === 'month' && !event.allDay &&
			(!(event.end instanceof Date) ||
			event.end.getFullYear() == event.start.getFullYear() &&
			event.end.getMonth() == event.start.getMonth() &&
			((event.end.getDate() == event.start.getDate()) || (event.end.getDate() - event.start.getDate() == 1 && event.end.getHours() == 0 && event.end.getMinutes() == 0)));

	var backgroundColor = isShort ? 'transparent' : (
		event.backgroundColor ||
		eventColor ||
		source.backgroundColor ||
		sourceColor ||
		opt('eventBackgroundColor') ||
		optionColor);
	var borderColor = isShort ? 'transparent' : (
		event.backgroundColor ||
		eventColor ||
		source.backgroundColor ||
		sourceColor ||
		opt('eventBorderColor') ||
		optionColor);
	var textColor = isShort ? opt('eventTextColor') : (
		event.textColor ||
		source.textColor ||
		opt('eventTextColor'));
	var statements = [];
	if (backgroundColor) {
		statements.push('background-color:' + htmlEscape(backgroundColor));
	}
	if (borderColor) {
		statements.push('border-color:' + htmlEscape(borderColor));
	}
	if (textColor) {
		statements.push('color:' + htmlEscape(textColor));
	}
	return statements.join(';');
}

function applyAll(functions, thisObj, args) {
	if ($.isFunction(functions)) {
		functions = [ functions ];
	}
	if (functions) {
		var i;
		var ret;
		for (i=0; i<functions.length; i++) {
			ret = functions[i].apply(thisObj, args) || ret;
		}
		return ret;
	}
	return false;
}

function firstDefined() {
	for (var i=0; i<arguments.length; i++) {
		if (arguments[i] !== undefined) {
			return arguments[i];
		}
	}
	return false;
}



function TitleRender(calendar) {

	var _renders = {
		month: _renderMonthTitle,
		week:  _renderWeekTitle,
		day:   _renderDayTitle
	};


	var formatDate = calendar.formatDate;
	var formatDates = calendar.formatDates;


	this.render = function(viewName, startDate, endDate) {
		var method = smartProperty(_renders, viewName);
		return method ? method.call(this, startDate, endDate) : $('<span/>');
	};


	function _parseFormatString(fmt) {
		var result = " " + fmt + " ";
		result = result.replace(/([^A-Za-z])(M+)([^A-Za-z])/g, "$1'<span class=\"month\">'$2'</span>'$3");
		result = result.replace(/([^A-Za-z])(y+)([^A-Za-z])/g, "$1'<span class=\"year\">'$2'</span>'$3");
		return result.replace(/^\s+|\s+$/g, "");
	}

	function _renderMonthTitle(startDate, endDate) {
		var fmt = _parseFormatString(calendar.options.titleFormat.month);
		//var m = startDate.getMonth();
		//var prev1 = (m + 12 - 1) % 12;
		//var next1 = (m + 1) % 12;
		var title = $(
				'<span>' +
					//'<span class="link">' +
					//	'<span class="inner left">' +
					//		calendar.options.monthNames[prev1] +
					//	'</span>' +
					//'</span>' +
					'<span class="title-text">' +
						'<span class="h2">' +
							formatDate(startDate, fmt) +
						'</span>' +
					'</span>' +
					//'<span class="link">' +
					//	'<span class="inner right">' +
					//		calendar.options.monthNames[next1] +
					//	'</span>' +
					//'</span>' +
				'</span>');
		fcMenus.buildTitleMenus(calendar, title);
		//title.find(".link .left").click(function() {calendar.prev(-1);});
		//title.find(".link .right").click(function() {calendar.next(+1);});
		return title;
	}

	function _renderWeekTitle(startDate, endDate) {
		var wf = calendar.options.titleFormat.week.replace(/MMMM/g, "MMM");
		var fmt = wf + "[, yyyy]{ '&#8212;' " + wf + ", " + _parseFormatString("yyyy}");
		var tc = formatDates(startDate, endDate, fmt);
		//var fmt2 = wf + "{ '&#8212;' " + wf + "}";
		//var tl = formatDates(addDays(cloneDate(startDate), -7), addDays(cloneDate(endDate), -7), fmt2);
		//var tr = formatDates(addDays(cloneDate(startDate), +7), addDays(cloneDate(endDate), +7), fmt2);
		var title = $(
				'<span>' +
					//'<span class="link">' +
					//	'<span class="inner left">' + tl + '</span>' +
					//'</span>' +
					'<span class="title-text">' +
						'<span class="h2">' + tc + '</span>' +
					'</span>' +
					//'<span class="link">' +
					//	'<span class="inner right">' + tr + '</span>' +
					//'</span>' +
				'</span>');
		fcMenus.buildTitleMenus(calendar, title);
		//title.find(".link .left").click(function() {calendar.prev(-1);});
		//title.find(".link .right").click(function() {calendar.next(+1);});
		return title;
	}

	function _renderDayTitle(startDate, endDate) {
		var tmp = (calendar.options.titleFormat.day.indexOf("ddd") < 0 &&
				calendar.options.titleFormat.day.indexOf("dddd") < 0 ? "dddd, " : "") +
				calendar.options.titleFormat.day
		var fmt = tmp.replace(/dddd/g, "ddd");
		var title = $(
				'<span>' +
					//'<span class="link">' +
					//	'<span class="inner left">' +
					//		formatDate(addDays(cloneDate(startDate), -2), 'd') + '</span>' +
					//'</span>' +
					//'<span class="link">' +
					//	'<span class="inner left">' +
					//		formatDate(addDays(cloneDate(startDate), -1), 'd') + '</span>' +
					//'</span>' +
					'<span class="title-text">' +
						'<span class="h2">' +
							formatDate(startDate, fmt) +
						'</span>' +
					'</span>' +
					//'<span class="link">' +
					//	'<span class="inner right">' +
					//		formatDate(addDays(cloneDate(startDate), +1), 'd') + '</span>' +
					//'</span>' +
					//'<span class="link">' +
					//	'<span class="inner right">' +
					//		formatDate(addDays(cloneDate(startDate), +2), 'd') + '</span>' +
					//'</span>' +
				'</span>');
		//fcMenus.buildTitleMenus(calendar, title);

		//var left = title.find(".link .left");
		//left.eq(0).parent().click(function() {calendar.prev(-2);});
		//left.eq(1).parent().click(function() {calendar.prev(-1);});

		//var right = title.find(".link .right");
		//right.eq(0).parent().click(function() {calendar.next(+1);});
		//right.eq(1).parent().click(function() {calendar.next(+2);});

		title.find(".title-text .h2").click(function() {
			fcDatepicker.open(calendar, this,
					function(dp) {dp.datepicker("setDate", calendar.getDate());},
					function(elem, dp) {this.close();calendar.gotoDate(dp.datepicker("getDate"));});
		});

		return title;
	}

}



fcViews.month = MonthView;

function MonthView(element, calendar) {
	var t = this;


	// exports
	t.render = render;


	// imports
	BasicView.call(t, element, calendar, 'month');
	var opt = t.opt;
	var renderBasic = t.renderBasic;
	var formatDate = calendar.formatDate;



	function render(date, delta) {
		if (delta) {
			addMonths(date, delta);
			date.setDate(1);
		}
		var start = cloneDate(date, true);
		start.setDate(1);
		var end = addMonths(cloneDate(start), 1);
		var visStart = cloneDate(start);
		var visEnd = cloneDate(end);
		var firstDay = opt('firstDay');
		var nwe = opt('weekends') ? 0 : 1;
		if (nwe) {
			skipWeekend(visStart);
			skipWeekend(visEnd, -1, true);
		}
		addDays(visStart, -((visStart.getDay() - Math.max(firstDay, nwe) + 7) % 7));
		addDays(visEnd, (7 - visEnd.getDay() + Math.max(firstDay, nwe)) % 7);
		var rowCnt = Math.round((visEnd - visStart) / (DAY_MS * 7));
		if (opt('weekMode') == 'fixed') {
			addDays(visEnd, (6 - rowCnt) * 7);
			rowCnt = 6;
		}
		var titleRender = new TitleRender(calendar);
		t.title = titleRender.render(t.name, start, end);
		t.start = start;
		t.end = end;
		t.visStart = visStart;
		t.visEnd = visEnd;
		renderBasic(6, rowCnt, nwe ? 5 : 7, true);
	}


	this._afterRenderDaySegs = function(segs) {
		//--diabled big day numbers--
		//t.markEmptyCells(segs);
	};

}



fcViews.basicWeek = BasicWeekView;

function BasicWeekView(element, calendar) {
	var t = this;


	// exports
	t.render = render;


	// imports
	BasicView.call(t, element, calendar, 'basicWeek');
	var opt = t.opt;
	var renderBasic = t.renderBasic;
	var formatDates = calendar.formatDates;



	function render(date, delta) {
		if (delta) {
			addDays(date, delta * 7);
		}
		var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
		var end = addDays(cloneDate(start), 7);
		var visStart = cloneDate(start);
		var visEnd = cloneDate(end);
		var weekends = opt('weekends');
		if (!weekends) {
			skipWeekend(visStart);
			skipWeekend(visEnd, -1, true);
		}
		t.title = formatDates(
			visStart,
			addDays(cloneDate(visEnd), -1),
			opt('titleFormat')
		);
		t.start = start;
		t.end = end;
		t.visStart = visStart;
		t.visEnd = visEnd;
		renderBasic(1, 1, weekends ? 7 : 5, false);
	}


}



fcViews.basicDay = BasicDayView;

//TODO: when calendar's date starts out on a weekend, shouldn't happen

function BasicDayView(element, calendar) {
	var t = this;


	// exports
	t.render = render;


	// imports
	BasicView.call(t, element, calendar, 'basicDay');
	var opt = t.opt;
	var renderBasic = t.renderBasic;
	var formatDate = calendar.formatDate;



	function render(date, delta) {
		if (delta) {
			addDays(date, delta);
			if (!opt('weekends')) {
				skipWeekend(date, delta < 0 ? -1 : 1);
			}
		}
		t.title = formatDate(date, opt('titleFormat'));
		t.start = t.visStart = cloneDate(date, true);
		t.end = t.visEnd = addDays(cloneDate(t.start), 1);
		renderBasic(1, 1, 1, false);
	}


}



function BasicView(element, calendar, viewName) {
	var t = this;


	// exports
	t.renderBasic = renderBasic;
	t.setHeight = setHeight;
	t.setWidth = setWidth;
	t.renderDayOverlay = renderDayOverlay;
	t.defaultSelectionEnd = defaultSelectionEnd;
	t.renderSelection = renderSelection;
	t.clearSelection = clearSelection;
	t.reportDayClick = reportDayClick; // for selection (kinda hacky)
	t.dragStart = dragStart;
	t.dragStop = dragStop;
	t.defaultEventEnd = defaultEventEnd;
	t.getHoverListener = function() {return hoverListener;};
	t.colContentLeft = colContentLeft;
	t.colContentRight = colContentRight;
	t.dayOfWeekCol = dayOfWeekCol;
	t.dateCell = dateCell;
	t.cellDate = cellDate;
	t.cellIsAllDay = function() {return true;};
	t.allDayRow = allDayRow;
	t.allDayBounds = allDayBounds;
	t.getRowCnt = function() {return rowCnt;};
	t.getColCnt = function() {return colCnt;};
	t.getColWidth = function() {return colWidth;};
	t.getDaySegmentContainer = function() {return daySegmentContainer;};
	t.getCellBounds = getCellBounds;
	//--diabled big day numbers--
	//t.markEmptyCells = markEmptyCells;


	// imports
	View.call(t, element, calendar, viewName);
	OverlayManager.call(t);
	SelectionManager.call(t);
	BasicEventRenderer.call(t);
	var opt = t.opt;
	var trigger = t.trigger;
	var clearEvents = t.clearEvents;
	var renderOverlay = t.renderOverlay;
	var clearOverlays = t.clearOverlays;
	var daySelectionMousedown = t.daySelectionMousedown;
	var formatDate = calendar.formatDate;


	// locals

	var head;
	var headCells;
	var body;
	var bodyRows;
	var bodyCells;
	var bodyFirstCells;
	var bodyCellTopInners;
	var daySegmentContainer;

	var viewWidth;
	var viewHeight;
	var colWidth;

	var rowCnt, colCnt;
	var coordinateGrid;
	var hoverListener;
	var colContentPositions;

	var rtl, dis, dit;
	var firstDay;
	var nwe;
	var tm;
	var colFormat;



	/* Rendering
	------------------------------------------------------------*/


	disableTextSelection(element.addClass('fc-grid'));


	function renderBasic(maxr, r, c, showNumbers) {
		rowCnt = r;
		colCnt = c;
		updateOptions();
		var firstTime = !body;
		if (firstTime) {
			buildSkeleton(maxr, showNumbers);
		}else{
			clearEvents();
		}
		updateCells(firstTime);
	}


	function updateOptions() {
		rtl = opt('isRTL');
		if (rtl) {
			dis = -1;
			dit = colCnt - 1;
		}else{
			dis = 1;
			dit = 0;
		}
		firstDay = opt('firstDay');
		nwe = opt('weekends') ? 0 : 1;
		tm = opt('theme') ? 'ui' : 'fc';
		colFormat = opt('columnFormat');
	}


	function buildSkeleton(maxRowCnt, showNumbers) {
		var s;
		var headerClass = tm + "-widget-header";
		var contentClass = tm + "-widget-content";
		var i, j;
		var table;

		s =
			"<table class='fc-border-separate' style='width:100%' cellspacing='0'>" +
			"<thead>" +
			"<tr>";
		for (i=0; i<colCnt; i++) {
			s +=
				"<th class='fc- " + headerClass + "'/>"; // need fc- for setDayID
		}
		s +=
			"</tr>" +
			"</thead>" +
			"<tbody>";
		for (i=0; i<maxRowCnt; i++) {
			s +=
				"<tr class='fc-week" + i + "'>";
			for (j=0; j<colCnt; j++) {
				s +=
					"<td class='fc- " + contentClass + " fc-day" + (i*colCnt+j) + "'>" + // need fc- for setDayID
						"<div>" +
							(showNumbers ?
								"<div class='fc-day-number'/>" :
								''
								) +
							"<div class='fc-day-content'>" +
								"<div style='position:relative;height:100%;'>&nbsp;</div>" +
							"</div>" +
							//--diabled big day numbers--
							//"<div class='fc-day-number-big'/>" +
						"</div>" +
					"</td>";
			}
			s +=
				"</tr>";
		}
		s +=
			"</tbody>" +
			"</table>";
		table = $(s).appendTo(element);

		head = table.find('thead');
		headCells = head.find('th');
		body = table.find('tbody');
		bodyRows = body.find('tr');
		bodyCells = body.find('td');
		bodyFirstCells = bodyCells.filter(':first-child');
		bodyCellTopInners = bodyRows.eq(0).find('div.fc-day-content div');

		markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's
		markFirstLast(bodyRows); // marks first+last td's
		bodyRows.eq(0).addClass('fc-first'); // fc-last is done in updateCells

		dayBind(bodyCells);

		daySegmentContainer =
			$("<div style='position:absolute;z-index:8;top:0;left:0'/>")
				.appendTo(element);
	}


	function updateCells(firstTime) {
		var dowDirty = firstTime || rowCnt == 1; // could the cells' day-of-weeks need updating?
		var month = t.start.getMonth();
		var today = clearTime(new Date());
		var date;
		var todayIndex;
		var topRow;
		var leftCell;

		if (dowDirty) {
			headCells.each(function(i, cell) {
				date = indexDate(i);
				cell.innerHTML = formatDate(date, colFormat);
			    setDayID(cell, date);
			});
		}

		bodyCells.each(function(i, cell) {
			date = indexDate(i);
			if (date.getMonth() == month) {
				cell.classList.remove('fc-other-month');
			} else {
				cell.classList.add('fc-other-month');
			}
			if (+date == +today) {
				cell.classList.add(tm + '-state-highlight', 'fc-today');
				leftCell = cell.previousSibling;
				if (leftCell) {
					leftCell.classList.add("fc-today-left");
				}
				topRow = cell.parentElement.previousSibling;
				if (topRow) {
					topRow.childNodes[cell.cellIndex].classList.add("fc-today-top");
				}
				todayIndex = i;
			} else {
				cell.classList.remove(tm + '-state-highlight', 'fc-today', 'fc-today-left', 'fc-today-top');
			}
			cell.querySelector(".fc-day-number").innerHTML ='<span>' + date.getDate() + '</span>';
			if (dowDirty) {
			    setDayID(cell, date);
			}
		});

		bodyRows.each(function(i, row) {
			if (i < rowCnt) {
				if (i == rowCnt-1) {
					row.classList.add('fc-last');
				}else{
					row.classList.remove('fc-last');
				}
			}else{
				row.style.display = 'none';
			}
		});

		if (todayIndex < 7) {
			bodyCellTopInners = bodyRows.eq(1).find('div.fc-day-content div');
		}

		bodyCells.find(".fc-day-number > span").mousedown(
				function (ev) {
					if (ev.which != 1) {return;}
					var d = calendar.getDate();
					calendar.gotoDate(d.getFullYear(), d.getMonth(), $(this).text());
					calendar.changeView("agendaDay");
				});
	}


	//--diabled big day numbers--
	//function markEmptyCells(segs) {
	//	bodyCells.each(function(i, _cell) {
	//		var cell = $(_cell);
	//		var r = Math.floor(i / colCnt);
	//		var c = i % colCnt;
	//		for (var j = 0; j < segs.length; ++j) {
	//			if (segs[j].row === r &&
	//			    segs[j].startCol <= c && c < segs[j].endCol) {
	//				cell.removeClass("no-events");
	//				return;
	//			}
	//		}
	//		cell.addClass("no-events");
	//	});
	//}


	function setHeight(height) {
		viewHeight = height;

		var sizeManager = ASC.CalendarSizeManager.cache;
		var bodyHeight = viewHeight - sizeManager.fcMonthContentTheadHeight;
		var rowHeight;
		var rowHeightLast;

		if (opt('weekMode') == 'variable') {
			rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6));
		}else{
			rowHeight = Math.floor(bodyHeight / rowCnt);
			rowHeightLast = bodyHeight - rowHeight * (rowCnt-1);
		}

		bodyCells.each(function(i, cell) {
			var h = (Math.floor(i / 7) == rowCnt - 1 ? rowHeightLast : rowHeight) - sizeManager.fcMonthContentCellVSides + 1;
			var innerDiv = cell.querySelector("div");
			innerDiv.style.cssText = ';min-height:' + h + 'px;height:' + h + 'px;';
			var dc = innerDiv.querySelector(".fc-day-content");
			h = h - sizeManager.fcMonthContentCellNumberHeight - sizeManager.fcMonthContentCellNumberVSides;
			dc.style.cssText += ';min-height:' + h + 'px;height:' + h + 'px;';
		});

	}


	function setWidth(width) {
		viewWidth = width;
		colContentPositions.clear();
		colWidth = Math.floor(viewWidth / colCnt) - hsides($(headCells[0]));
		for (var i = 0, e; i < headCells.length; i++) {
		    headCells[i].style.width = colWidth + "px";
		}
	}



	/* Day clicking and binding
	-----------------------------------------------------------*/


	function dayBind(days) {
		days.click(dayClick)
			.mousedown(daySelectionMousedown);
	}


	function dayClick(ev) {
		if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick
			var index = parseInt(this.className.match(/fc\-day(\d+)/)[1]); // TODO: maybe use .data
			var date = indexDate(index);
			trigger('dayClick', this, date, true, ev);
		}
	}



	/* Semi-transparent Overlay Helpers
	------------------------------------------------------*/


	function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive
		if (refreshCoordinateGrid) {
			coordinateGrid.build();
		}
		var rowStart = cloneDate(t.visStart);
		var rowEnd = addDays(cloneDate(rowStart), colCnt);
		for (var i=0; i<rowCnt; i++) {
			var stretchStart = new Date(Math.max(rowStart, overlayStart));
			var stretchEnd = new Date(Math.min(rowEnd, overlayEnd));
			if (stretchStart < stretchEnd) {
				var colStart, colEnd;
				if (rtl) {
					colStart = dayDiff(stretchEnd, rowStart)*dis+dit+1;
					colEnd = dayDiff(stretchStart, rowStart)*dis+dit+1;
				}else{
					colStart = dayDiff(stretchStart, rowStart);
					colEnd = dayDiff(stretchEnd, rowStart);
				}
				dayBind(
					renderCellOverlay(i, colStart, i, colEnd-1)
				);
			}
			addDays(rowStart, 7);
			addDays(rowEnd, 7);
		}
	}


	function renderCellOverlay(row0, col0, row1, col1) { // row1,col1 is inclusive
		var rect = coordinateGrid.rect(row0, col0, row1, col1, element);
		return renderOverlay(rect, element);
	}



	/* Selection
	-----------------------------------------------------------------------*/


	function defaultSelectionEnd(startDate, allDay) {
		return cloneDate(startDate);
	}


	function renderSelection(startDate, endDate, allDay) {
		renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); // rebuild every time???
	}


	function clearSelection() {
		clearOverlays();
	}


	function reportDayClick(date, allDay, ev) {
		var cell = dateCell(date);
		var _element = bodyCells[cell.row*colCnt + cell.col];
		trigger('dayClick', _element, date, allDay, ev);
	}



	/* External Dragging
	-----------------------------------------------------------------------*/


	function dragStart(_dragElement, ev, ui) {
		hoverListener.start(function(cell) {
			clearOverlays();
			if (cell) {
				renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
			}
		}, ev);
	}


	function dragStop(_dragElement, ev, ui) {
		var cell = hoverListener.stop();
		clearOverlays();
		if (cell) {
			var d = cellDate(cell);
			trigger('drop', _dragElement, d, true, ev, ui);
		}
	}



	/* Utilities
	--------------------------------------------------------*/


	function defaultEventEnd(event) {
		return cloneDate(event.start);
	}


	coordinateGrid = new CoordinateGrid(function(rows, cols) {
		var e, n, p;
		headCells.each(function(i, _e) {
			e = $(_e);
			n = e.offset().left;
			if (i) {
				p[1] = n;
			}
			p = [n];
			cols[i] = p;
		});
		p[1] = n + e.outerWidth();
		bodyRows.each(function(i, _e) {
			if (i < rowCnt) {
				e = $(_e);
				n = e.offset().top;
				if (i) {
					p[1] = n;
				}
				p = [n];
				rows[i] = p;
			}
		});
		p[1] = n + e.outerHeight();
	});


	hoverListener = new HoverListener(coordinateGrid);


	colContentPositions = new ElementsPositionCache(function(col) {
		return bodyCellTopInners.eq(col);
	});


	function colContentLeft(col) {
		return colContentPositions.left(col);
	}


	function colContentRight(col) {
		return colContentPositions.right(col);
	}




	function dateCell(date) {
		return {
			row: Math.floor(dayDiff(date, t.visStart) / 7),
			col: dayOfWeekCol(date.getDay())
		};
	}


	function cellDate(cell) {
		return _cellDate(cell.row, cell.col);
	}


	function _cellDate(row, col) {
		return addDays(cloneDate(t.visStart), row*7 + col*dis+dit);
		// what about weekends in middle of week?
	}


	function indexDate(index) {
		return _cellDate(Math.floor(index/colCnt), index%colCnt);
	}


	function dayOfWeekCol(dayOfWeek) {
		return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt) * dis + dit;
	}




	function allDayRow(i) {
		return bodyRows.eq(i);
	}


	function allDayBounds(i) {
		return {
			left: 0,
			right: viewWidth
		};
	}




	function getCellBounds(row, col) {
		var c = bodyRows.eq(row).find("td:eq(" + col + ")");
		if (c.length > 0) {
			return {
					left:   c[0].offsetLeft,
					top:    c[0].offsetTop,
					right:  c[0].offsetLeft + c[0].offsetWidth,
					bottom: c[0].offsetTop + c[0].offsetHeight};
		}
		return {top:0, right:0, bottom:0, left:0};
	}


}

function BasicEventRenderer() {
	var t = this;


	// exports
	t.renderEvents = renderEvents;
	t.compileDaySegs = compileSegs; // for DayEventRenderer
	t.clearEvents = clearEvents;
	t.bindDaySeg = bindDaySeg;


	// imports
	DayEventRenderer.call(t);
	var opt = t.opt;
	var trigger = t.trigger;
	//var setOverflowHidden = t.setOverflowHidden;
	var isEventDraggable = t.isEventDraggable;
	var isEventResizable = t.isEventResizable;
	var reportEvents = t.reportEvents;
	var reportEventClear = t.reportEventClear;
	var eventElementHandlers = t.eventElementHandlers;
	var showEvents = t.showEvents;
	var hideEvents = t.hideEvents;
	var eventDrop = t.eventDrop;
	var getDaySegmentContainer = t.getDaySegmentContainer;
	var getHoverListener = t.getHoverListener;
	var renderDayOverlay = t.renderDayOverlay;
	var clearOverlays = t.clearOverlays;
	var getRowCnt = t.getRowCnt;
	var getColCnt = t.getColCnt;
	var renderDaySegs = t.renderDaySegs;
	var resizableDayEvent = t.resizableDayEvent;



	/* Rendering
	--------------------------------------------------------------------*/


	function renderEvents(events, modifiedEventId) {
		reportEvents(events);
		renderDaySegs(compileSegs(events), modifiedEventId);
	}


	function clearEvents() {
		reportEventClear();
		var node = getDaySegmentContainer()[0];
		var last;
		while (last = node.lastChild)
			node.removeChild(last);
	}


	function compileSegs(events) {
		var rowCnt = getRowCnt(),
			colCnt = getColCnt(),
			d1 = cloneDate(t.visStart),
			d2 = addDays(cloneDate(d1), colCnt),
			i, row,
			j, level,
			k, seg,
			segs=[];
		for (i=0; i<rowCnt; i++) {
			row = stackSegs(sliceSegs(events, exclEndDay, d1, d2));
			for (j=0; j<row.length; j++) {
				level = row[j];
				for (k=0; k<level.length; k++) {
					seg = level[k];
					seg.row = i;
					seg.level = j; // not needed anymore
					segs.push(seg);
				}
			}
			addDays(d1, 7);
			addDays(d2, 7);
		}
		return segs;
	}


	function bindDaySeg(event, eventElement, seg) {
		if (isEventDraggable(event)) {
			draggableDayEvent(event, eventElement);
		}
		if (seg.isEnd && isEventResizable(event)) {
			resizableDayEvent(event, eventElement, seg);
		}
		eventElementHandlers(event, eventElement);
			// needs to be after, because resizableDayEvent might stopImmediatePropagation on click
	}



	/* Dragging
	----------------------------------------------------------------------------*/


function draggableDayEvent(event, eventElement) {
		var hoverListener = getHoverListener();
		var dayDelta;
		eventElement.draggable({
			zIndex: 9,
			delay: 50,
			opacity: opt('dragOpacity'),
			revertDuration: opt('dragRevertDuration'),
			start: function(ev, ui) {
			
				trigger('eventDragStart', eventElement, event, ev, ui);
				hideEvents(event, eventElement);
				hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
					eventElement.draggable('option', 'revert', !cell || !rowDelta && !colDelta);
					clearOverlays();
					if (cell) {
						//setOverflowHidden(true);
						dayDelta = rowDelta*7 + colDelta * (opt('isRTL') ? -1 : 1);
						renderDayOverlay(
							addDays(cloneDate(event.start), dayDelta),
							addDays(exclEndDay(event), dayDelta)
						);
					}else{
						//setOverflowHidden(false);
						dayDelta = 0;
					}
				}, ev, 'drag');
			},
			 stop: function(ev, ui) {
                    hoverListener.stop();
                    clearOverlays();
                    trigger('eventDragStop', eventElement, event, ev, ui);
                    if (dayDelta) {
                        eventDrop(this, event, dayDelta, 0, event.allDay, ev, ui);
                    } else {
                        eventElement.css('filter', ''); // clear IE opacity side-effects
                        showEvents(event, eventElement);
                    }
                    //setOverflowHidden(false);
                }
		});
	}


}


fcViews.agendaWeek = AgendaWeekView;

function AgendaWeekView(element, calendar) {
	var t = this;


	// imports
	AgendaView.call(t, element, calendar, 'agendaWeek');
	var opt = t.opt;
	var renderAgenda = t.renderAgenda;
	var formatDates = calendar.formatDates;



	this.render = function(date, delta) {
		if (delta) {
			addDays(date, delta * 7);
		}
		var start = addDays(cloneDate(date), -((date.getDay() - opt('firstDay') + 7) % 7));
		var end = addDays(cloneDate(start), 7);
		var visStart = cloneDate(start);
		var visEnd = cloneDate(end);
		var weekends = opt('weekends');
		if (!weekends) {
			skipWeekend(visStart);
			skipWeekend(visEnd, -1, true);
		}
		var titleRender = new TitleRender(calendar);
		t.title = titleRender.render(t.name, start, addDays(cloneDate(start), 6));
		t.start = start;
		t.end = end;
		t.visStart = visStart;
		t.visEnd = visEnd;
		renderAgenda(weekends ? 7 : 5);
	}

}



fcViews.agendaDay = AgendaDayView;

function AgendaDayView(element, calendar) {
	var t = this;


	// exports
	t.render = render;


	// imports
	AgendaView.call(t, element, calendar, 'agendaDay');
	var opt = t.opt;
	var renderAgenda = t.renderAgenda;
	var formatDate = calendar.formatDate;
	var getDayList = t.getDayList;



	function render(date, delta) {
		if (delta) {
			addDays(date, delta);
			if (!opt('weekends')) {
				skipWeekend(date, delta < 0 ? -1 : 1);
			}
		}
		var start = cloneDate(date, true);
		var end = addDays(cloneDate(start), 1);
		var titleRender = new TitleRender(calendar);
		t.title = titleRender.render(t.name, start, end);
		t.start = t.visStart = start;
		t.end = t.visEnd = end;
		renderAgenda(1, false);
		_renderDayList.call(t);
	}

	function _renderDayList() {
		var dayList = getDayList();
		if (!dayList) {return;}

		var textFormat = calendar.options.dayView.dateFormat;
		var alldayTitle = calendar.options.dayView.alldayTasksTitle;
		var todayTitle = calendar.options.dayView.todayTasksTitle;

		dayList.html(
				'<div class="big-date-box">' +
					'<div class="top-text">' +
							htmlEscape(formatDates(t.visStart, t.visEnd, textFormat.topText)) + '</div>' +
					'<div class="big-text">' +
							htmlEscape(formatDates(t.visStart, t.visEnd, textFormat.bigText)) + '</div>' +
					'<div class="bottom-text">' +
							htmlEscape(formatDates(t.visStart, t.visEnd, textFormat.bottomText)) + '</div>' +
					'<div class="today-label">' +
						'<div class="inner">' + opt('todayLabel') + '</div>' +
					'</div>' +
				'</div>' +
				'<div class="allday-box">' +
					'<div class="allday-tasks-title">' + htmlEscape(alldayTitle) + '</div>' +
					'<div class="allday-tasks-scroller">' +
						'<table class="allday-tasks-list" border="0" cellspacing="0" cellpadding="0"/>' +
					'</div>' +
				'</div>' +
				'<div class="tasks-title">' + htmlEscape(todayTitle) + '</div>' +
				'<div class="tasks-scroller">' +
					'<table class="tasks-list" border="0" cellspacing="0" cellpadding="0"/>' +
				'</div>');
	}

	this._onSetHeight = function(height) {
		var dayList = getDayList();
		if (!dayList) {return;}
		//
		var title = dayList.find(".tasks-title");
		var pos = title.position();
		pos.top += title.outerHeight(true);
		dayList.find(".tasks-scroller")
				.css("top", pos.top + "px")
				.css("height", (height - pos.top) + "px");
		//
		var dateBox = dayList.find(".big-date-box");
		dayList.find(".allday-box")
				.css("top", dateBox.position().top + "px")
				.css("height", dateBox.outerHeight(true) + "px");
		title = dayList.find(".allday-tasks-title");
		dayList.find(".allday-tasks-scroller")
				.css("top", (title.position().top + title.outerHeight(true)) + "px");
	};

	this._onSetWidth = function(width) {
		var dayList = getDayList();
		if (!dayList) {return;}
		//
		var title = dayList.find(".tasks-title");
		var pos = title.position();
		dayList.find(".tasks-scroller")
				.css("left", pos.left + "px")
				.css("width", title.outerWidth(true));
		//
		var dateBox = dayList.find(".big-date-box");
		var dateBoxWidth = dateBox.outerWidth(true);
		dayList.find(".allday-box")
				.css("left", (dateBox.position().left + dateBoxWidth) + "px")
				.css("width", (dayList.width() - dateBoxWidth) + "px");
	};

	this._afterRenderSlotSegs = function(segs) {
		var dayList = getDayList();
		if (!dayList) {return;}

		var segCnt = segs.length;
		var tasksList = dayList.find('table.tasks-list');
		var i;
		var event;
		var tbody = '';

		segs.sort(function(l,r) {
			var res =
					l.event.start < r.event.start ? -1 :
					(l.event.start > r.event.start ? 1 :
					(l.event.title.toLowerCase() < r.event.title.toLowerCase() ? -1 : 1));
			return res;
		});

		for (i = 0; i < segCnt; ++i) {
			event = segs[i].event;
			tbody +=
					'<tr>' +
						'<td class="task-img">' +
							'<span class="bullet" style="color:' + htmlEscape(event.source.isHidden ?
									calendar.options.categories.inactiveColor : event.source.backgroundColor) +
									';">' +
								htmlEscape(calendar.options.categories.itemBullet) + '&nbsp;</span>' + '</td>' +
						'<td class="task-title">' +
							'<div class="task-title">' + htmlEscape(event.title) + '</div>' +
							(event.description && event.description.length > 0 ?
									('<div class="task-note">' + htmlEscape(event.description) + '</div>') : '') + '</td>' +
						'<td class="task-time">' +
							'<div class="task-time">' +
								htmlEscape(formatDates(event.start, event.end || event.start,
										opt('taskListTimeFormat'))) + '</div>' + '</td>' +
					'</tr>';
		}

		tasksList.html('<tbody>' + tbody + '</tbody>');
		tasksList.find("tr:last").addClass("last");
	};

	this._afterRenderDaySegs = function(segs) {
		var dayList = getDayList();
		if (!dayList) {return;}

		var segCnt = segs.length;
		var tasksList = dayList.find('table.allday-tasks-list');
		var i;
		var event;
		var tbody = '';

		segs.sort(function(l,r) {
			var res =
					l.event.title.toLowerCase() < r.event.title.toLowerCase() ? -1 : 1;
			return res;
		});

		for (i = 0; i < segCnt; ++i) {
			event = segs[i].event;
			if (!event) {continue;}
			tbody +=
					'<tr>' +
						'<td class="task-img">' +
							'<span class="bullet" style="color:' + htmlEscape(event.source.isHidden ?
									calendar.options.categories.inactiveColor : event.source.backgroundColor) +
									';">' +
								htmlEscape(calendar.options.categories.itemBullet) + '&nbsp;</span>' + '</td>' +
						'<td class="task-title">' +
							'<div class="task-title">' + htmlEscape(event.title) + '</div>' + '</td>' +
					'</tr>';
		}

		tasksList.html('<tbody>' + tbody + '</tbody>');
		tasksList.find("tr:last").addClass("last");
	};

}



// TODO: make it work in quirks mode (event corners, all-day height)
// TODO: test liquid width, especially in IE6

function AgendaView(element, calendar, viewName) {
	var t = this;


	// exports
	t.renderAgenda = renderAgenda;
	t.setWidth = setWidth;
	t.setHeight = setHeight;
	t.beforeHide = beforeHide;
	t.afterShow = afterShow;
	t.defaultEventEnd = defaultEventEnd;
	t.timePosition = timePosition;
	t.dayOfWeekCol = dayOfWeekCol;
	t.dateCell = dateCell;
	t.cellDate = cellDate;
	t.cellIsAllDay = cellIsAllDay;
	t.allDayRow = getAllDayRow;
	t.allDayBounds = allDayBounds;
	t.getHoverListener = function() {return hoverListener;};
	t.colContentLeft = colContentLeft;
	t.colContentRight = colContentRight;
	t.getDaySegmentContainer = function() {return daySegmentContainer;};
	t.getSlotSegmentContainer = function() {return slotSegmentContainer;};
	t.getMinMinute = function() {return minMinute;};
	t.getMaxMinute = function() {return maxMinute;};
	t.getBodyContent = function() {return slotContent;}; // !!??
	t.getRowCnt = function() {return 1;};
	t.getColCnt = function() {return colCnt;};
	t.getColWidth = function() {return colWidth;};
	t.getSlotHeight = function() {return slotHeight;};
	t.defaultSelectionEnd = defaultSelectionEnd;
	t.renderDayOverlay = renderDayOverlay;
	t.renderSelection = renderSelection;
	t.clearSelection = clearSelection;
	t.reportDayClick = reportDayClick; // selection mousedown hack
	t.dragStart = dragStart;
	t.dragStop = dragStop;
	t.getDayList = function() {return dayList;};
	t.resetScroll = resetScroll;
    t.getCellBounds = getCellBounds;
    t.updateHeader = updateHeader;


	// imports
	View.call(t, element, calendar, viewName);
	OverlayManager.call(t);
	SelectionManager.call(t);
	AgendaEventRenderer.call(t);
	var opt = t.opt;
	var trigger = t.trigger;
	var clearEvents = t.clearEvents;
	var renderOverlay = t.renderOverlay;
	var clearOverlays = t.clearOverlays;
	var reportSelection = t.reportSelection;
	var unselect = t.unselect;
	var daySelectionMousedown = t.daySelectionMousedown;
	var slotSegHtml = t.slotSegHtml;
	var formatDate = calendar.formatDate;


	// locals

	var mainContainer;
	var dayList;

	var dayTable;
	var dayHead;
	var dayHeadCells;
	var dayBody;
	var dayBodyCells;
	var dayBodyCellInners;
	var dayBodyFirstCell;
	var dayBodyFirstCellStretcher;
	var slotLayer;
	var daySegmentContainer;
	var allDayTable;
	var allDayRow;
	var slotScroller;
	var slotContent;
	var slotSegmentContainer;
	var slotTable;
	var axisFirstCells;
	var gutterCells;
	var selectionHelper;

	var viewWidth;
	var viewHeight;
	var axisWidth;
	var colWidth;
	var gutterWidth;
	var slotHeight; // TODO: what if slotHeight changes? (see issue 650)
	var savedScrollTop;

	var colCnt;
	var slotCnt;
	var coordinateGrid;
	var hoverListener;
	var colContentPositions;
	var slotTopCache = {};

	var tm;
	var firstDay;
	var nwe;            // no weekends (int)
	var rtl, dis, dit;  // day index sign / translate
	var minMinute, maxMinute;
	var colFormat;

	var marker;
	var markerColumn;
	var markerId;



	/* Rendering
	-----------------------------------------------------------------------------*/


	disableTextSelection(element.addClass('fc-agenda'));


	function renderAgenda(c, renderDayList) {
		colCnt = c;
		updateOptions();
		if (!dayTable) {
			buildSkeleton(renderDayList);
		}else{
			clearEvents();
		}
		updateCells();
	}

    function updateHeader() {
        updateOptions();
        updateCells();
    }

	function updateOptions() {
		tm = opt('theme') ? 'ui' : 'fc';
		nwe = opt('weekends') ? 0 : 1;
		firstDay = opt('firstDay');
		rtl = opt('isRTL');
		if (rtl) {
			dis = -1;
			dit = colCnt - 1;
		}else{
			dis = 1;
			dit = 0;
		}
		minMinute = parseTime(opt('minTime'));
		maxMinute = parseTime(opt('maxTime'));
		colFormat = opt('columnFormat');

		if (t.name == 'agendaWeek') {
		    if (window.innerWidth < 1270) {
		        colFormat = colFormat.replace("dddd", "ddd");
		    } else {
		        if (colFormat.indexOf("dddd") < 0 && colFormat.indexOf("ddd") < 0) {
		            colFormat = "dddd, " + colFormat;
		        }
		    }
		} else {
		    if (colFormat.indexOf("dddd") < 0 && colFormat.indexOf("ddd") < 0) {
		        colFormat = "dddd, " + colFormat;
		    }
		}
		if (colCnt < 2) {
			colFormat = "'<div class=\"center\">'" + colFormat + "'</div>'";
		}
	}

	function calcSlotHeight() {
		slotHeight = slotTable.find("tr:eq(1)").outerHeight(true);
	}

	function buildSkeleton(renderDayList) {
		var headerClass = tm + "-widget-header";
		var contentClass = tm + "-widget-content";
		var s;
		var i;
		var d;
		var maxd;
		var minutes;
		var slotNormal = opt('slotMinutes') % 15 == 0;

		var cont = $(
				"<table class='fc-agenda-inner' cellspacing='0'>" +
					"<tbody>" +
						"<tr>" +
							(colCnt < 2 && renderDayList ?
									"<td class='td-day-list'><div class='day-list'>&nbsp;</div></td>" : "") +
							"<td><div class='main-container'/></td>" +
						"</tr>" +
					"</tbody>" +
				"</table>")
				.appendTo(element);
		dayList = colCnt < 2 && renderDayList ? cont.find(".day-list") : undefined;
		mainContainer = cont.find(".main-container");

		s =
			"<table style='width:100%' class='fc-agenda-days fc-border-separate' cellspacing='0'>" +
			"<thead>" +
			"<tr>" +
			"<th class='fc-agenda-axis " + headerClass + "'>&nbsp;</th>";
		for (i=0; i<colCnt; i++) {
			s +=
				"<th class='fc- fc-col" + i + ' ' + headerClass + "'/>"; // fc- needed for setDayID
		}
		s +=
			"<th class='fc-agenda-gutter " + headerClass + "'>&nbsp;</th>" +
			"</tr>" +
			"</thead>" +
			"<tbody>" +
			"<tr>" +
			"<th class='fc-agenda-axis " + headerClass + "'>&nbsp;</th>";
		for (i=0; i<colCnt; i++) {
			s +=
				"<td class='fc- fc-col" + i + ' ' + contentClass + "'>" + // fc- needed for setDayID
				"<div>" +
				"<div class='fc-day-content'>" +
				"<div style='position:relative;max-height: 150px;'>&nbsp;</div>" +
				"</div>" +
				"</div>" +
				"</td>";
		}
		s +=
			"<td class='fc-agenda-gutter " + contentClass + "'>&nbsp;</td>" +
			"</tr>" +
			"</tbody>" +
			"</table>";
		dayTable = $(s).appendTo(mainContainer);
		dayHead = dayTable.find('thead');
		dayHeadCells = dayHead.find('th').slice(1, -1);
		dayBody = dayTable.find('tbody');
		dayBodyCells = dayBody.find('td').slice(0, -1);
		dayBodyCellInners = dayBodyCells.find('div.fc-day-content div');
		dayBodyFirstCell = dayBodyCells.eq(0);
		dayBodyFirstCellStretcher = dayBodyFirstCell.find('> div');

		markFirstLast(dayHead.add(dayHead.find('tr')));
		markFirstLast(dayBody.add(dayBody.find('tr')));

		axisFirstCells = dayHead.find('th:first');
		gutterCells = dayTable.find('.fc-agenda-gutter');

		slotLayer =
			$("<div style='position:absolute;z-index:2;left:0;width:100%'/>")
				.appendTo(mainContainer);

		if (opt('allDaySlot')) {

			daySegmentContainer =
				$("<div style='position:absolute;z-index:9;top:0;left:0'/>")
					.appendTo(slotLayer);

			s =
				"<table style='width:100%' class='fc-agenda-allday' cellspacing='0'>" +
				"<tr>" +
				"<th class='" + headerClass + " fc-agenda-axis'>" + opt('allDayText') + "</th>" +
				"<td>" +
				"<div class='fc-day-content'><div style='position:relative;max-height: 150px;'/></div>" +
				"</td>" +
				"<th class='" + headerClass + " fc-agenda-gutter'>&nbsp;</th>" +
				"</tr>" +
				"</table>";
			allDayTable = $(s).appendTo(slotLayer);
			allDayRow = allDayTable.find('tr');

			dayBind(allDayRow.find('td'));

			axisFirstCells = axisFirstCells.add(allDayTable.find('th:first'));
			gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter'));

			slotLayer.append(
				"<div class='fc-agenda-divider " + headerClass + "'>" +
				"<div class='fc-agenda-divider-inner'/>" +
				"</div>"
			);

		}else{

			daySegmentContainer = $([]); // in jQuery 1.4, we can just do $()

		}

		slotScroller =
			$("<div style='position:absolute;width:100%;overflow-x:hidden;overflow-y:auto'/>")
				.appendTo(slotLayer);

		slotContent =
			$("<div style='position:relative;width:100%;overflow:hidden'/>")
				.appendTo(slotScroller);

		slotSegmentContainer =
			$("<div style='position:absolute;z-index:8;top:0;left:0'/>")
				.appendTo(slotContent);

		s =
			"<table class='fc-agenda-slots' style='width:100%' cellspacing='0'>" +
			"<tbody>";
		d = zeroDate();
		maxd = addMinutes(cloneDate(d), maxMinute);
		addMinutes(d, minMinute);
		slotCnt = 0;
		for (i=0; d < maxd; i++) {
			minutes = d.getMinutes();
			s +=
				"<tr class='fc-slot" + i + ' ' + (!minutes ? '' : 'fc-minor') + "'>" +
					"<th class='fc-agenda-axis " + headerClass + "'>" +
						((!slotNormal || !minutes) ?
								"<div" + (i==0?' style="margin-top:0;"':'') + ">" + htmlEscape(formatDate(d, opt('axisFormat'))) + "</div>&nbsp;" :
								'&nbsp;') +
					"</th>" +
					"<td class='" + contentClass + "'>" +
						"<div style='position:relative'>&nbsp;</div>" +
					"</td>" +
				"</tr>";
			addMinutes(d, opt('slotMinutes'));
			slotCnt++;
		}
		s +=
			"</tbody>" +
			"</table>";
		slotTable = $(s).appendTo(slotContent);

		calcSlotHeight();

		slotBind(slotTable.find('td'));

		axisFirstCells = axisFirstCells.add(slotTable.find('th:first'));
	}

	function createTimeMarker(col) {
	    if (!marker || marker.length < 1) {
			marker = $(
					"<div class='fc-time-marker'>" +
					    "<span class='title'/>" +
						"<div class='left-side'/>" +
						"<div class='center-line'/>" +
						"<div class='right-side'/>" +
					"</div>")
					.appendTo(slotContent);
			markerColumn = col;
		}
		updateTimeMarker();
	}

	function updateTimeMarker() {
		if (markerId != undefined) {
			clearTimeout(markerId);
		}
		if (marker) {
			if (colCnt > 0) {
				var padding = 3;

				var localDate = new Date();
				var utcDate = new Date(localDate.getTime() + localDate.getTimezoneOffset() * 60000);
				var tenantDate = new Date(utcDate.getTime() + ASC.Resources.Master.CurrentTenantTimeZone.UtcOffset * 60000);

				var time = localDate.getHours() + ":" + (localDate.getMinutes() < 10 ? "0" + localDate.getMinutes() : localDate.getMinutes());

				var top = timePosition(tenantDate, tenantDate);
				var left = colContentLeft(0) - padding;
				var width = colContentRight(colCnt - 1) + padding - left;
				var l = marker.find(".left-side").outerWidth(true);
				var h = marker.find(".left-side").outerHeight(true);
				marker.css("left", (left - l) + "px");
				marker.css("top", Math.round(top - 0.5 * h) + "px");
				marker.find(".center-line").css("width", width + "px");
				marker.find(".title")[0].innerText = time;
				marker.css("visibility", "visible");
				markerId = setTimeout(updateTimeMarker, 1000 * 60);
			} else {
				marker.css("visibility", "hidden");
			}
		}
	}

	function updateCells() {
		var i;
		var todayCol;
		var headCell;
		var bodyCell;
		var leftCell;
		var date;
		var today = clearTime(new Date());
		dayBodyCells.eq(0).prev().removeClass('fc-today-left');
		for (i=0; i<colCnt; i++) {
			date = colDate(i);
			headCell = dayHeadCells.eq(i);
		    headCell.html((date.getFullYear() == today.getFullYear()) && colFormat.indexOf("yyyy") != -1? formatDate(date, colFormat.substring(0, colFormat.indexOf("yyyy"))) : formatDate(date, colFormat));
			(function(d, hc) {
				var num = hc.find(".number");
				if (num.length > 0) {
					num.click(function() {
						calendar.gotoDate(d);
						calendar.changeView("agendaDay");
					});
				}
			}(date, headCell));
			bodyCell = dayBodyCells.eq(i);
			if (+date == +today) {
				bodyCell.addClass(tm + '-state-highlight fc-today');
				headCell.addClass('fc-today');
				todayCol = i;
				leftCell = bodyCell.prev();
				if (leftCell.length > 0) {
					leftCell.addClass("fc-today-left");
				}
			}else{
				bodyCell.removeClass(tm + '-state-highlight fc-today');
				bodyCell.removeClass('fc-today-left');
				headCell.removeClass('fc-today');
			}
			setDayID(headCell[0], date);
			setDayID(bodyCell[0], date);
		}

		if (dayList != undefined) {
			headCell = dayHeadCells.eq(0);
			dayList.removeClass("fc-sat fc-sun fc-today");
			if (headCell.hasClass("fc-sat")) {
				dayList.addClass("fc-sat");
			} else if (headCell.hasClass("fc-sun")) {
				dayList.addClass("fc-sun");
			}
			if (todayCol != undefined) {
				dayList.addClass("fc-today");
			}
		}

		if (marker && marker.length > 0) {
			markerColumn = todayCol;
			updateTimeMarker();
		}else {
			if (todayCol !== undefined) {
				createTimeMarker(todayCol)
			}
		}
	}

	function setHeight(height, dateChanged) {
		if (height === undefined) {
			height = viewHeight;
		}
		viewHeight = height;
		slotTopCache = {};

		var headHeight = dayBody.position().top;
		var allDayHeight = slotScroller.position().top; // including divider
		var bodyHeight = Math.min( // total body height, including borders
			height - headHeight,   // when scrollbars
			slotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border
		);

		dayBodyFirstCellStretcher
			.height(bodyHeight - vsides(dayBodyFirstCell));

		slotLayer.css('top', headHeight);

		slotScroller.height(bodyHeight - allDayHeight - 1);

		calcSlotHeight();

		if (dateChanged) {
			resetScroll();
		}
		updateTimeMarker();

		if ($.isFunction(t._onSetHeight)) {t._onSetHeight(height);}
	}

	function setWidth(width) {
		viewWidth = width;
		colContentPositions.clear();

		axisWidth = 0;
		setOuterWidth(
			axisFirstCells
				.width('')
				.each(function(i, _cell) {
					axisWidth = Math.max(axisWidth, $(_cell).outerWidth());
				}),
			axisWidth
		);

		var slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7)
		//slotTable.width(slotTableWidth);

		gutterWidth = slotScroller.width() - slotTableWidth;
		if (gutterWidth) {
			setOuterWidth(gutterCells, gutterWidth);
			gutterCells
				.show()
				.prev()
				.removeClass('fc-last');
		}else{
			gutterCells
				.hide()
				.prev()
				.addClass('fc-last');
		}

		var tableW = slotTableWidth - axisWidth;
		var rem = tableW % colCnt;
		colWidth = Math.floor(tableW / colCnt);
		if (rem == 0) {
			setOuterWidth(dayHeadCells, colWidth);
		} else {
			setOuterWidth(dayHeadCells.filter(":even"), colWidth);
			setOuterWidth(dayHeadCells.filter(":odd"), colWidth + 1);
			setOuterWidth(dayHeadCells.last(), tableW - colWidth * (colCnt-1) - Math.floor(colCnt/2));
		}
		updateTimeMarker();

		if ($.isFunction(t._onSetWidth)) {t._onSetWidth(width);}
	}

	function resetScroll(hour) {
		var d0 = zeroDate();
		var scrollDate = cloneDate(d0);
		scrollDate.setHours(hour !== undefined ? hour : opt('firstHour'));
		var top = timePosition(d0, scrollDate) + 1; // +1 for the border
		function scroll() {
			slotScroller.scrollTop(top);
		}
		scroll();
		setTimeout(scroll, 0); // overrides any previous scroll state made by the browser
	}

	function beforeHide() {
		savedScrollTop = slotScroller.scrollTop();
	}

	function afterShow() {
		slotScroller.scrollTop(savedScrollTop);
	}



	/* Slot/Day clicking and binding
	-----------------------------------------------------------------------*/


	function dayBind(cells) {
		cells.click(slotClick)
			.mousedown(daySelectionMousedown);
	}

	function slotBind(cells) {
		cells.click(slotClick)
			.mousedown(slotSelectionMousedown);
	}

	function slotClick(ev) {
		if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick
			var col = Math.min(colCnt-1, Math.floor((ev.pageX - dayTable.offset().left - axisWidth) / colWidth));
			var date = colDate(col);
			var rowMatch = this.parentNode.className.match(/fc-slot(\d+)/); // TODO: maybe use data
			if (rowMatch) {
				var mins = parseInt(rowMatch[1]) * opt('slotMinutes');
				var hours = Math.floor(mins/60);
				date.setHours(hours);
				date.setMinutes(mins%60 + minMinute);
				trigger('dayClick', dayBodyCells[col], date, false, ev);
			}else{
				trigger('dayClick', dayBodyCells[col], date, true, ev);
			}
		}
	}



	/* Semi-transparent Overlay Helpers
	-----------------------------------------------------*/


	function renderDayOverlay(startDate, endDate, refreshCoordinateGrid) { // endDate is exclusive
		if (refreshCoordinateGrid) {
			coordinateGrid.build();
		}
		var visStart = cloneDate(t.visStart);
		var startCol, endCol;
		if (rtl) {
			startCol = dayDiff(endDate, visStart)*dis+dit+1;
			endCol = dayDiff(startDate, visStart)*dis+dit+1;
		}else{
			startCol = dayDiff(startDate, visStart);
			endCol = dayDiff(endDate, visStart);
		}
		startCol = Math.max(0, startCol);
		endCol = Math.min(colCnt, endCol);
		if (startCol < endCol) {
			dayBind(
				renderCellOverlay(0, startCol, 0, endCol-1)
			);
		}
	}

	function renderCellOverlay(row0, col0, row1, col1) { // only for all-day?
		var rect = coordinateGrid.rect(row0, col0, row1, col1, slotLayer);
		return renderOverlay(rect, slotLayer);
	}

	function renderSlotOverlay(overlayStart, overlayEnd) {
		var dayStart = cloneDate(t.visStart);
		var dayEnd = addDays(cloneDate(dayStart), 1);
		for (var i=0; i<colCnt; i++) {
			var stretchStart = new Date(Math.max(dayStart, overlayStart));
			var stretchEnd = new Date(Math.min(dayEnd, overlayEnd));
			if (stretchStart < stretchEnd) {
				var col = i*dis+dit;
				var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only use it for horizontal coords
				var top = timePosition(dayStart, stretchStart);
				var bottom = timePosition(dayStart, stretchEnd);
				rect.top = top;
				rect.height = bottom - top;
				slotBind(
					renderOverlay(rect, slotContent)
				);
			}
			addDays(dayStart, 1);
			addDays(dayEnd, 1);
		}
	}



	/* Coordinate Utilities
	-----------------------------------------------------------------------------*/


	coordinateGrid = new CoordinateGrid(function(rows, cols) {
		var e, n, p;
		dayHeadCells.each(function(i, _e) {
			e = $(_e);
			n = e.offset().left;
			if (i) {
				p[1] = n;
			}
			p = [n];
			cols[i] = p;
		});
		p[1] = n + e.outerWidth();
		if (opt('allDaySlot')) {
			e = allDayRow;
			n = e.offset().top;
			rows[0] = [n, n+e.outerHeight()];
		}
		var slotTableTop = slotContent.offset().top;
		var slotScrollerTop = slotScroller.offset().top;
		var slotScrollerBottom = slotScrollerTop + slotScroller.outerHeight();
		var slotTableTh = slotTable.find("th");
		function constrain(n) {
			return Math.max(slotScrollerTop, Math.min(slotScrollerBottom, n));
		}
		for (var i=0; i<slotTableTh.length; i++) {
			var h = slotTableTh.eq(i).outerHeight(true);
			rows.push([
				constrain(slotTableTop),
				constrain(slotTableTop + h)
			]);
			slotTableTop += h;
		}
	});


	hoverListener = new HoverListener(coordinateGrid);


	colContentPositions = new ElementsPositionCache(function(col) {
		return dayBodyCellInners.eq(col);
	});


	function colContentLeft(col) {
		return colContentPositions.left(col);
	}

	function colContentRight(col) {
		return colContentPositions.right(col);
	}




	function dateCell(date) { // "cell" terminology is now confusing
		return {
			row: Math.floor(dayDiff(date, t.visStart) / 7),
			col: dayOfWeekCol(date.getDay())
		};
	}

	function cellDate(cell) {
		var d = colDate(cell.col);
		var slotIndex = cell.row;
		if (opt('allDaySlot')) {
			slotIndex--;
		}
		if (slotIndex >= 0) {
			addMinutes(d, minMinute + slotIndex * opt('slotMinutes'));
		}
		return d;
	}

	function colDate(col) { // returns dates with 00:00:00
		return addDays(cloneDate(t.visStart), col*dis+dit);
	}

	function cellIsAllDay(cell) {
		return opt('allDaySlot') && !cell.row;
	}

	function dayOfWeekCol(dayOfWeek) {
		return ((dayOfWeek - Math.max(firstDay, nwe) + colCnt) % colCnt)*dis+dit;
	}




	// get the Y coordinate of the given time on the given day (both Date objects)
	function timePosition(day, time) { // both date objects. day holds 00:00 of current day
		day = cloneDate(day, true);
		if (time < addMinutes(cloneDate(day), minMinute)) {
			return 0;
		}
		if (time >= addMinutes(cloneDate(day), maxMinute)) {
			return slotTable.height();
		}
		var slotMinutes = opt('slotMinutes'),
			minutes = time.getHours()*60 + time.getMinutes() - minMinute,
			slotI = Math.floor(minutes / slotMinutes),
			slotTop = slotTopCache[slotI];
		if (slotTop === undefined) {
			slotTop = slotTopCache[slotI] = slotTable.find('tr:eq(' + slotI + ') td div')[0].offsetTop; //.position().top; // need this optimization???
		}
		return Math.max(0, Math.round(
			slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes)
		));
	}

	function allDayBounds() {
		return {
			left: axisWidth,
			right: allDayTable.width() - 1 - gutterWidth
		};
	}

	function getAllDayRow(index) {
		return allDayRow;
	}

	function defaultEventEnd(event) {
		var start = cloneDate(event.start);
		if (event.allDay) {
			return start;
		}
		return addMinutes(start, opt('defaultEventMinutes'));
	}



	/* Selection
	---------------------------------------------------------------------------------*/


	function defaultSelectionEnd(startDate, allDay) {
		if (allDay) {
			return cloneDate(startDate);
		}
		return addMinutes(cloneDate(startDate), opt('slotMinutes'));
	}

	function renderSelection(startDate, endDate, allDay) { // only for all-day
		if (allDay) {
			if (opt('allDaySlot')) {
				renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true);
			}
		}else{
			renderSlotSelection(startDate, endDate);
		}
	}

	function renderSlotSelection(startDate, endDate) {
		var helperOption = opt('selectHelper');
		coordinateGrid.build();
		if (helperOption) {
			var col = dayDiff(startDate, t.visStart) * dis + dit;
			if (col >= 0 && col < colCnt) { // only works when times are on same day
				var rect = coordinateGrid.rect(0, col, 0, col, slotContent); // only for horizontal coords
				var top = timePosition(startDate, startDate);
				var bottom = timePosition(startDate, endDate);
				if (bottom > top) { // protect against selections that are entirely before or after visible range
					rect.top = top;
					rect.height = bottom - top;
					rect.left += 2;
					rect.width -= 5;
					if ($.isFunction(helperOption)) {
						var helperRes = helperOption(startDate, endDate);
						if (helperRes) {
							rect.position = 'absolute';
							rect.zIndex = 8;
							selectionHelper = $(helperRes)
								.css(rect)
								.appendTo(slotContent);
						}
					}else{
						rect.isStart = true; // conside rect a "seg" now
						rect.isEnd = true;   //
						selectionHelper = $(slotSegHtml(
							{
								title: '',
								start: startDate,
								end: endDate,
								className: ['fc-select-helper'],
								editable: false
							},
							rect
						));
						selectionHelper.css('opacity', opt('dragOpacity'));
					}
					if (selectionHelper) {
						slotBind(selectionHelper);
						slotContent.append(selectionHelper);
						setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended
						setOuterHeight(selectionHelper, rect.height, true);
					}
				}
			}
		}else{
			renderSlotOverlay(startDate, endDate);
		}
	}

	function clearSelection() {
		clearOverlays();
		if (selectionHelper) {
			selectionHelper.remove();
			selectionHelper = null;
		}
	}

	function slotSelectionMousedown(ev) {
		if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button
			unselect(ev);
			var dates;
			hoverListener.start(function(cell, origCell) {
				clearSelection();
				if (cell && cell.col == origCell.col && !cellIsAllDay(cell)) {
					var d1 = cellDate(origCell);
					var d2 = cellDate(cell);
					dates = [
						d1,
						addMinutes(cloneDate(d1), opt('slotMinutes')),
						d2,
						addMinutes(cloneDate(d2), opt('slotMinutes'))
					].sort(cmp);
					renderSlotSelection(dates[0], dates[3]);
				}else{
					dates = null;
				}
			}, ev);
			$(document).one('mouseup', function(ev) {
				hoverListener.stop();
				if (dates) {
					if (+dates[0] == +dates[1]) {
						reportDayClick(dates[0], false, ev);
					}
					reportSelection(dates[0], dates[3], false, ev);
				}
			});
		}
	}

	function reportDayClick(date, allDay, ev) {
		trigger('dayClick', dayBodyCells[dayOfWeekCol(date.getDay())], date, allDay, ev);
	}



	/* External Dragging
	--------------------------------------------------------------------------------*/


	function dragStart(_dragElement, ev, ui) {
		hoverListener.start(function(cell) {
			clearOverlays();
			if (cell) {
				if (cellIsAllDay(cell)) {
					renderCellOverlay(cell.row, cell.col, cell.row, cell.col);
				}else{
					var d1 = cellDate(cell);
					var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes'));
					renderSlotOverlay(d1, d2);
				}
			}
		}, ev);
	}

	function dragStop(_dragElement, ev, ui) {
		var cell = hoverListener.stop();
		clearOverlays();
		if (cell) {
			trigger('drop', _dragElement, cellDate(cell), cellIsAllDay(cell), ev, ui);
		}
	}

    function getCellBounds(row, col) {
        var isWeekView = dayBodyCells.length > 1;
        var allDayContainer = $(".fc-agenda-allday .fc-day-content:visible")[0];
        var cellContainer = isWeekView ? dayBodyCells[col] : allDayContainer;

        if (allDayContainer && cellContainer) {
            return {
                left: cellContainer.offsetLeft,
                top: allDayContainer.offsetTop,
                right: cellContainer.offsetLeft + cellContainer.offsetWidth - (isWeekView ? 0 : 325),
                bottom: allDayContainer.offsetTop + allDayContainer.offsetHeight
            };
        }
        return {top:0, right:0, bottom:0, left:0};
	}

}

function AgendaEventRenderer() {
	var t = this;


	// exports
	t.renderEvents = renderEvents;
	t.compileDaySegs = compileDaySegs; // for DayEventRenderer
	t.clearEvents = clearEvents;
	t.slotSegHtml = slotSegHtml;
	t.bindDaySeg = bindDaySeg;


	// imports
	DayEventRenderer.call(t);
	var opt = t.opt;
	var trigger = t.trigger;
	//var setOverflowHidden = t.setOverflowHidden;
	var isEventDraggable = t.isEventDraggable;
	var isEventResizable = t.isEventResizable;
	var eventEnd = t.eventEnd;
	var reportEvents = t.reportEvents;
	var reportEventClear = t.reportEventClear;
	var eventElementHandlers = t.eventElementHandlers;
	var setHeight = t.setHeight;
	var getDaySegmentContainer = t.getDaySegmentContainer;
	var getSlotSegmentContainer = t.getSlotSegmentContainer;
	var getHoverListener = t.getHoverListener;
	var getMaxMinute = t.getMaxMinute;
	var getMinMinute = t.getMinMinute;
	var timePosition = t.timePosition;
	var colContentLeft = t.colContentLeft;
	var colContentRight = t.colContentRight;
	var renderDaySegs = t.renderDaySegs;
	var resizableDayEvent = t.resizableDayEvent; // TODO: streamline binding architecture
	var getColCnt = t.getColCnt;
	var getColWidth = t.getColWidth;
	var getSlotHeight = t.getSlotHeight;
	var getBodyContent = t.getBodyContent;
	var reportEventElement = t.reportEventElement;
	var showEvents = t.showEvents;
	var hideEvents = t.hideEvents;
	var eventDrop = t.eventDrop;
	var eventResize = t.eventResize;
	var renderDayOverlay = t.renderDayOverlay;
	var clearOverlays = t.clearOverlays;
	var calendar = t.calendar;
	var formatDate = calendar.formatDate;
	var formatDates = calendar.formatDates;



	/* Rendering
	----------------------------------------------------------------------------*/


	function renderEvents(events, modifiedEventId) {
		reportEvents(events);
		var i, len=events.length,
			dayEvents=[],
			slotEvents=[];
		for (i=0; i<len; i++) {
			if (events[i].allDay) {
				dayEvents.push(events[i]);
			}else{
				slotEvents.push(events[i]);
			}
		}
		if (opt('allDaySlot')) {
		    var compileSlotSeg = compileSlotSegs(slotEvents);
		    if (t.name == "agendaDay") {
		        if (compileSlotSeg.length > 0) {
		            for (var j = 0; j < compileSlotSeg.length; j++) {
		                var startSegm = new Date(compileSlotSeg[j].start);
		                startSegm.setDate(startSegm.getDate() + 1);
		                if(startSegm.getTime() == cloneDate(compileSlotSeg[j].end, true).getTime()){
		                    var _clone = {};
		                    Object.assign(_clone, compileSlotSeg[j].event);
		                    _clone._start = _clone.start = compileSlotSeg[j].event.start;
		                    _clone._end = _clone.end = compileSlotSeg[j].event.end;
		                    _clone.isEditable = false;
		                    _clone.isSegmEvent = true;
		                    dayEvents.push(_clone);
		                }
		            }
		        }
		    }else if (t.name == "agendaWeek") {
		        if (compileSlotSeg.length > 0) {
		            for (var j = 0; j < compileSlotSeg.length; j++) {
		                var startSegm = new Date(compileSlotSeg[j].start);
		                startSegm.setDate(startSegm.getDate() + 1);
		                if(startSegm.getTime() == cloneDate(compileSlotSeg[j].end, true).getTime()){
		                    var _clone = {};
		                    Object.assign(_clone, compileSlotSeg[j].event);
		                    _clone._start = _clone.start = compileSlotSeg[j].event.start;
		                    _clone._end = _clone.end = compileSlotSeg[j].event.end;
		                    compileSlotSeg[j].event.isSegmEventWeek = true;
		                    if (dayEvents.find(function (x) { return x.objectId === _clone.objectId;}) == undefined) dayEvents.push(_clone);
		                }
		            }
		        }
		    }
			renderDaySegs(compileDaySegs(dayEvents), modifiedEventId);
			setHeight(); // no params means set to viewHeight
		}
		renderSlotSegs(compileSlotSegs(slotEvents), modifiedEventId);
	}


	function clearEvents() {
		reportEventClear();
		getDaySegmentContainer().empty();
		getSlotSegmentContainer().empty();
	}


	function compileDaySegs(events) {
		var levels = stackSegs(sliceSegs(events, exclEndDay, t.visStart, t.visEnd)),
			i, levelCnt=levels.length, level,
			j, seg,
			segs=[];
		for (i=0; i<levelCnt; i++) {
			level = levels[i];
			for (j=0; j<level.length; j++) {
				seg = level[j];
				seg.row = 0;
				seg.level = i; // not needed anymore
				segs.push(seg);
			}
		}
		return segs;
	}


	function countForwardSegs(levels) {
		var i, j, k, level, segForward, segBack;
		for (i=levels.length-1; i>0; i--) {
			level = levels[i];
			for (j=0; j<level.length; j++) {
				segForward = level[j];
				for (k=0; k<levels[i-1].length; k++) {
					segBack = levels[i-1][k];
					if (segsCollide(segForward, segBack)) {
						segBack.forward = Math.max(segBack.forward||0, (segForward.forward||0)+1);
					}
				}
			}
		}
	}


	function compileSlotSegs(events) {
		var colCnt = getColCnt(),
			minMinute = getMinMinute(),
			maxMinute = getMaxMinute(),
			d = addMinutes(cloneDate(t.visStart), minMinute),
			i, col,
			j, level,
			k, seg,
			segs=[];
		for (i=0; i<colCnt; i++) {
		    col = stackSegs(sliceSegs(events, slotEventEnd, d, addMinutes(cloneDate(d), maxMinute-minMinute)));
			countForwardSegs(col);
			for (j=0; j<col.length; j++) {
				level = col[j];
				for (k=0; k<level.length; k++) {
					seg = level[k];
					seg.col = i;
					seg.level = j;
					segs.push(seg);
				}
			}
			addDays(d, 1, true);
		}
		return segs;
	}


	function slotEventEnd(event) {
		if (event.end) {
			return cloneDate(event.end);
		}else{
			return addMinutes(cloneDate(event.start), opt('defaultEventMinutes'));
		}
	}


	// renders events in the 'time slots' at the bottom

	function renderSlotSegs(segs, modifiedEventId) {

		var i, segCnt=segs.length, seg,
			event,
			top, bottom,
			colI, levelI, forward,
			leftmost,
			availWidth,
			outerWidth,
			left,
			html='',
			eventElements,
			eventElement,
			titleElement,
			timeElement,
			triggerRes,
			vsideCache={},
			hsideCache={},
			key, val,
			contentElement,
			width, height, cheight,
			slotSegmentContainer = getSlotSegmentContainer(),
			rtl, dis, dit,
			colCnt = getColCnt();

		rtl = opt('isRTL');
		if (rtl) {
			dis = -1;
			dit = colCnt - 1;
		}else{
			dis = 1;
			dit = 0;
		}

		// calculate position/dimensions, create html
		for (i=0; i<segCnt; i++) {
			seg = segs[i];
			event = seg.event;
			top = timePosition(seg.start, seg.start);
			bottom = timePosition(seg.start, seg.end);
			colI = seg.col;
			levelI = seg.level;
			forward = seg.forward || 0;
			leftmost = colContentLeft(colI*dis + dit);
			availWidth = colContentRight(colI*dis + dit) - leftmost;
			availWidth = Math.min(availWidth-6, availWidth*.95); // TODO: move this to CSS
			if (levelI) {
				// indented and thin
				outerWidth = availWidth / (levelI + forward + 1);
			}else{
				if (forward) {
					// moderately wide, aligned left still
					outerWidth = ((availWidth / (forward + 1)) - (12/2)) * 2; // 12 is the predicted width of resizer =
				}else{
					// can be entire width, aligned left
					outerWidth = availWidth;
				}
			}
			left = leftmost +                                  // leftmost possible
				(availWidth / (levelI + forward + 1) * levelI) // indentation
				* dis + (rtl ? availWidth - outerWidth : 0);   // rtl
			seg.top = top;
			seg.left = left;
			seg.outerWidth = outerWidth;
			seg.outerHeight = bottom - top;
			var slotHtml = slotSegHtml(event, seg);
			var slot = $(slotHtml);
			if (t.name == "agendaDay") {
			    var segStart = new Date(seg.start);
			    segStart.setDate(segStart.getDate() + 1);
			    if(segStart.getTime() == cloneDate(seg.end, true).getTime()) {
			        slot.addClass('hidden');
			        slotHtml = $('<div>').append(slot.clone()).html();
			    }
			}else if (t.name == "agendaWeek") {
			    if (seg.event.isSegmEventWeek) {
			        slot.addClass('hidden');
			        slotHtml = $('<div>').append(slot.clone()).html();
			    }
			}
		    html += slotHtml;
		}
		slotSegmentContainer[0].innerHTML = html; // faster than html()
		eventElements = slotSegmentContainer.children();

		// retrieve elements, run through eventRender callback, bind event handlers
		for (i=0; i<segCnt; i++) {
			seg = segs[i];
			event = seg.event;
			eventElement = $(eventElements[i]); // faster than eq()
			triggerRes = trigger('eventRender', event, event, eventElement);
			if (triggerRes === false) {
				eventElement.remove();
			}else{
				if (triggerRes && triggerRes !== true) {
					eventElement.remove();
					eventElement = $(triggerRes)
						.css({
							position: 'absolute',
							top: seg.top,
							left: seg.left
						})
						.appendTo(slotSegmentContainer);
				}
				seg.element = eventElement;
				if (event._id === modifiedEventId) {
					bindSlotSeg(event, eventElement, seg);
				}else{
					eventElement[0]._fci = i; // for lazySegBind
				}
				reportEventElement(event, eventElement);
			}
		}

		lazySegBind(slotSegmentContainer, segs, bindSlotSeg);

		// record event sides and title positions
		for (i=0; i<segCnt; i++) {
			seg = segs[i];
			eventElement = seg.element;
			if (eventElement) {
				val = vsideCache[key = seg.key = cssKey(eventElement[0])];
				seg.vsides = val === undefined ? (vsideCache[key] = vsides(eventElement, true)) : val;
				val = hsideCache[key];
				seg.hsides = val === undefined ? (hsideCache[key] = hsides(eventElement, true)) : val;
				contentElement = eventElement.find('div.fc-event-content');
				if (contentElement.length) {
					seg.contentTop = contentElement[0].offsetTop;
				}
			}
		}

		for (i=0; i<segCnt; i++) {
			seg = segs[i];
			eventElement = seg.element;
			if (eventElement) {
				width = Math.max(0, seg.outerWidth - seg.hsides);
				height = Math.max(0, seg.outerHeight - seg.vsides);
				eventElement[0].style.width = width + 'px';
				eventElement[0].style.height = height > 0 ? height + 'px' : 'auto';
				// set height of event-content
				contentElement = eventElement.find('.fc-event-content');
				cheight = height -
					eventElement.find(".fc-event-head").outerHeight(true);
				contentElement.css("height", cheight + "px");
				titleElement = eventElement.find(".fc-event-title");
				timeElement = eventElement.find('.fc-event-time');
				event = seg.event;
				if (seg.contentTop !== undefined && height - seg.contentTop < 10) {
					// not enough room for title, put it in the time header
					timeElement
						.html(timeElement.html() + ' ' + htmlEscape(titleElement.text()));

					if (titleElement.hasClass("fc-event-cancelled"))
						timeElement.addClass("fc-event-cancelled");
					else
						timeElement.removeClass("fc-event-cancelled");

					titleElement
						.remove();
				}
				trigger('eventAfterRender', event, event, eventElement);
			}
		}

		if ($.isFunction(t._afterRenderSlotSegs)) {t._afterRenderSlotSegs(segs);}
	}


	function slotSegHtml(event, seg) {
		var html = '<';
		var url = event.url;
		var skinCss = getSkinCss(event, opt);
		var skinCssAttr = (skinCss ? ' style="' + skinCss + '"' : "");
		var classes = ["fc-event", "fc-event-skin", "fc-event-vert"];
		if (isEventDraggable(event)) {
			classes.push("fc-event-draggable");
		}
		if (seg.isStart) {
			classes.push("fc-corner-top");
		}
		if (seg.isEnd) {
			classes.push("fc-corner-bottom");
		}
		classes = classes.concat(event.className);
		if (event.source) {
			classes = classes.concat(event.source.className || []);
		}
		//if (url) {
		//	html += 'a href="' + htmlEscape(event.url) + '"';
		//}else{
			html += 'div';
		//}

		var title = htmlEscape(event.title);

		html +=
			' class="' + classes.join(" ") + '"' +
			' style="position:absolute;z-index:8;top:' + seg.top + 'px;left:' + seg.left + 'px;' + skinCss + '"' +
			'>' +
			'<div class="fc-event-inner fc-event-skin"' + skinCssAttr + '>' +
				'<div class="fc-event-head fc-event-skin"' + skinCssAttr + '>' +
					'<div class="fc-event-time">' +
						htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
						(event.repeat && event.repeat.type > kRepeatNever ?
								'<span class="fc-event-repeat"></span>' : '') +
						(event.alert && (event.alert.type > kAlertNever || event.alert.type == kAlertDefault &&
								event.source && event.source.defaultAlert.type > kAlertNever) ?
								'<span class="fc-event-alert"></span>' : '') +
					'</div>' +
				'</div>' +
				'<div class="fc-event-content" title="' + title + '">' +
					'<div class="fc-event-title' + (event.status == 2 ? " fc-event-cancelled" : "") + '">' +
						title +
						//'<div class="fc-event-tooltip">' + htmlEscape(event.title) + '</div>' +
					'</div>' +
				'</div>' +
				'<div class="fc-event-bg"></div>' +
			'</div>'; // close inner
		if (seg.isEnd && isEventResizable(event)) {
			html += '<div class="ui-resizable-handle ui-resizable-s">&nbsp;</div>';
		}
		html +=
			'</' + /*(url ? 'a' :*/ 'div'/*)*/ + '>';
		return html;
	}


	function bindDaySeg(event, eventElement, seg) {
		if (isEventDraggable(event)) {
			draggableDayEvent(event, eventElement, seg.isStart);
		}
		if (seg.isEnd && isEventResizable(event)) {
			resizableDayEvent(event, eventElement, seg);
		}
		eventElementHandlers(event, eventElement);
			// needs to be after, because resizableDayEvent might stopImmediatePropagation on click
	}


	function bindSlotSeg(event, eventElement, seg) {
		var timeElement = eventElement.find('div.fc-event-time');
		if (isEventDraggable(event)) {
			draggableSlotEvent(event, eventElement, timeElement);
		}
		if (seg.isEnd && isEventResizable(event)) {
			resizableSlotEvent(event, eventElement, timeElement);
		}
		eventElementHandlers(event, eventElement);
	}



	/* Dragging
	-----------------------------------------------------------------------------------*/


	// when event starts out FULL-DAY

	function draggableDayEvent(event, eventElement, isStart) {
		var origWidth;
		var revert;
		var allDay=true;
		var dayDelta;
		var dis = opt('isRTL') ? -1 : 1;
		var hoverListener = getHoverListener();
		var colWidth = getColWidth();
		var slotHeight = getSlotHeight();
		var minMinute = getMinMinute();
		eventElement.draggable({
			zIndex: 9,
			opacity: opt('dragOpacity', 'month'), // use whatever the month view was using
			revertDuration: opt('dragRevertDuration'),
			start: function(ev, ui) {
			
				trigger('eventDragStart', eventElement, event, ev, ui);
				hideEvents(event, eventElement);
				origWidth = eventElement.width();
				hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
					clearOverlays();
					if (cell) {
						//setOverflowHidden(true);
						revert = false;
						dayDelta = colDelta * dis;
						if (!cell.row) {
							// on full-days
							renderDayOverlay(
								addDays(cloneDate(event.start), dayDelta),
								addDays(exclEndDay(event), dayDelta)
							);
							resetElement();
						}else{
							// mouse is over bottom slots
							if (isStart) {
								if (allDay) {
									// convert event to temporary slot-event
									eventElement.width(colWidth - 10); // don't use entire width
									setOuterHeight(
										eventElement,
										slotHeight * Math.round(
											(event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes'))
											/ opt('slotMinutes')
										)
									);
									eventElement.draggable('option', 'grid', [colWidth, 1]);
									allDay = false;
								}
							}else{
								revert = true;
							}
						}
						revert = revert || (allDay && !dayDelta);
					}else{
						resetElement();
						//setOverflowHidden(false);
						revert = true;
					}
					eventElement.draggable('option', 'revert', revert);
				}, ev, 'drag');
			},
			stop: function(ev, ui) {
				hoverListener.stop();
				clearOverlays();
				
				trigger('eventDragStop', eventElement, event, ev, ui);
				if (revert) {
					// hasn't moved or is out of bounds (draggable has already reverted)
					resetElement();
					eventElement.css('filter', ''); // clear IE opacity side-effects
					showEvents(event, eventElement);
				}else{
					// changed!
					var minuteDelta = 0;
					if (!allDay) {
						minuteDelta = Math.round((eventElement.offset().top - getBodyContent().offset().top) / slotHeight)
							* opt('slotMinutes')
							+ minMinute
							- (event.start.getHours() * 60 + event.start.getMinutes());
					}
					eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui);
				}
				//setOverflowHidden(false);
			}
		});
		function resetElement() {
			if (!allDay) {
				eventElement
					.width(origWidth)
					.height('')
					.draggable('option', 'grid', null);
				allDay = true;
			}
		}
	}


	// when event starts out IN TIMESLOTS

	function draggableSlotEvent(event, eventElement, timeElement) {
		var origPosition;
		var allDay=false;
		var dayDelta;
		var minuteDelta;
		var prevMinuteDelta;
		var dis = opt('isRTL') ? -1 : 1;
		var hoverListener = getHoverListener();
		var colCnt = getColCnt();
		var colWidth = getColWidth();
		var slotHeight = getSlotHeight();
		eventElement.draggable({
			zIndex: 9,
			scroll: false,
			grid: [colWidth, slotHeight],
			axis: colCnt==1 ? 'y' : false,
			opacity: opt('dragOpacity'),
			revertDuration: opt('dragRevertDuration'),
			start: function(ev, ui) {
				trigger('eventDragStart', eventElement, event, ev, ui);
				hideEvents(event, eventElement);
				origPosition = eventElement.position();
				minuteDelta = prevMinuteDelta = 0;
				hoverListener.start(function(cell, origCell, rowDelta, colDelta) {
					eventElement.draggable('option', 'revert', !cell);
					clearOverlays();
					if (cell) {
						dayDelta = colDelta * dis;
						if (opt('allDaySlot') && !cell.row) {
							// over full days
							if (!allDay) {
								// convert to temporary all-day event
								allDay = true;
								timeElement.hide();
								eventElement.draggable('option', 'grid', null);
							}
							renderDayOverlay(
								addDays(cloneDate(event.start), dayDelta),
								addDays(exclEndDay(event), dayDelta)
							);
						}else{
							// on slots
							resetElement();
						}
					}
				}, ev, 'drag');
			},
			drag: function(ev, ui) {
				minuteDelta = Math.round((ui.position.top - origPosition.top) / slotHeight) * opt('slotMinutes');
				if (minuteDelta != prevMinuteDelta) {
					if (!allDay) {
						updateTimeText(minuteDelta);
					}
					prevMinuteDelta = minuteDelta;
				}
			},
			stop: function(ev, ui) {
				var cell = hoverListener.stop();
				clearOverlays();
				trigger('eventDragStop', eventElement, event, ev, ui);
				if (cell && (dayDelta || minuteDelta || allDay)) {
					// changed!
					eventDrop(this, event, dayDelta, allDay ? 0 : minuteDelta, allDay, ev, ui);
				}else{
					// either no change or out-of-bounds (draggable has already reverted)
					resetElement();
					eventElement.css('filter', ''); // clear IE opacity side-effects
					eventElement.css(origPosition); // sometimes fast drags make event revert to wrong position
					updateTimeText(0);
					showEvents(event, eventElement);
				}
			}
		});
		function updateTimeText(minuteDelta) {
			var newStart = addMinutes(cloneDate(event.start), minuteDelta);
			var newEnd;
			if (event.end) {
				newEnd = addMinutes(cloneDate(event.end), minuteDelta);
			}
			timeElement.text(formatDates(newStart, newEnd, opt('timeFormat')) + (eventElement.height() < 28 ? " " + event.title : ""));
		}
		function resetElement() {
			// convert back to original slot-event
			if (allDay) {
				timeElement.css('display', ''); // show() was causing display=inline
				eventElement.draggable('option', 'grid', [colWidth, slotHeight]);
				allDay = false;
			}
		}
	}



	/* Resizing
	--------------------------------------------------------------------------------------*/


	function resizableSlotEvent(event, eventElement, timeElement) {
		var slotDelta, prevSlotDelta;
		var slotHeight = getSlotHeight();
		eventElement.resizable({
			handles: {
				s: 'div.ui-resizable-s'
			},
			grid: slotHeight,
			start: function(ev, ui) {
				slotDelta = prevSlotDelta = 0;
				hideEvents(event, eventElement);
				eventElement.css('z-index', 9);
				trigger('eventResizeStart', this, event, ev, ui);
			},
			resize: function(ev, ui) {
				// don't rely on ui.size.height, doesn't take grid into account
				slotDelta = Math.round((Math.max(slotHeight, eventElement.height()) - ui.originalSize.height) / slotHeight);
				if (slotDelta != prevSlotDelta) {
					timeElement.text(
						formatDates(
							event.start,
							(!slotDelta && !event.end) ? null : // no change, so don't display time range
								addMinutes(eventEnd(event), opt('slotMinutes')*slotDelta),
							opt('timeFormat')
						)
					);
					prevSlotDelta = slotDelta;
				}
			},
			stop: function(ev, ui) {
				trigger('eventResizeStop', this, event, ev, ui);
				if (slotDelta) {
					eventResize(this, event, 0, opt('slotMinutes')*slotDelta, ev, ui);
				}else{
					eventElement.css('z-index', 8);
					showEvents(event, eventElement);
					// BUG: if event was really short, need to put title back in span
				}
				ev.stopImmediatePropagation();
			}
		});
	}


}



function BasicListView(element, calendar, viewName) {
	var _this = this;

	// exports
	_this.renderBasic = _renderBasic;
	_this.renderEvents = _renderEvents;
	_this.clearEvents = _clearEvents;
	_this.setWidth = _setWidth;
	_this.setHeight = _setHeight;
	_this.beforeHide = _beforeHide;
	_this.afterShow = _afterShow;
	_this.defaultEventEnd = _defaultEventEnd;
	_this.select = _select;
	_this.unselect = _unselect;

	_this.showMonthTitle = false;

	// imports
	View.call(_this, element, calendar, viewName);


	var formatDate = calendar.formatDate;
	var formatDates = calendar.formatDates;


	var _eventsList;


	function _renderBasic() {
		if (_eventsList == undefined) {
			_eventsList = $('<div class="fc-lv-scroller"/>').appendTo(element);
		}
	}

	function _compileSegs(events) {
	    return sliceSegs(events, exclEndDay, _this.start, _this.end).sort(
				function(left, right) {
					var d1 = cloneDate(left.event.start, left.event.allDay);
					var d2 = cloneDate(right.event.start, right.event.allDay);
					var res = d1 < d2 ? -1 : (d1 > d2 ? 1 :
							(left.event.title.toLowerCase() < right.event.title.toLowerCase() ? -1 : 1));
					return res;
				});
	}

	function _renderEvents(events, modifiedEventId) {
		_clearEvents.call(_this);

		var lv = calendar.options.listView;
		var now = new Date();
		var i, j, k;
		var list, monthTitle, dayTitle, mt, dt;
		var seg, event, start, end, eventTitle, eventNote, eventRow;
		var html;
		var first;
		var timeFormat = lv.timeFormat;
		var monthFormat = lv.monthTitleFormat;
		var dayFormat = (lv.dayTitleFormat.indexOf("dddd") < 0 &&
				lv.dayTitleFormat.indexOf("ddd") < 0 ? "dddd, " : "") + lv.dayTitleFormat;

		var segs = _compileSegs.call(_this, events);

		list = {};
		for (i = 0; i < segs.length; ++i) {
		    seg = segs[i];
		    event = seg.event;
			start = cloneDate(seg.start, true);
			end = seg.end != undefined ? cloneDate(seg.end, true) : cloneDate(start);

			eventTitle =
					typeof event.title == "string" ? event.title.replace(/(.+)\.?\s*$/i, "$1") : "";
			eventNote =
					typeof event.description == "string" ? event.description.replace(/(.+)\.?\s*$/i, "$1") : "";
			eventRow =
					'<tr class="event-row" id="event_' + event._id + '">' +
						'<td class="time first">' +
							'<span class="time">' +
								htmlEscape(!event.allDay ?
										formatDates(event.start, event.end || event.start, timeFormat) :
										calendar.options.allDayText) + '</span>' + '</td>' +
						'<td class="bullet">' +
							'<span class="bullet" style="color:' + htmlEscape(event.source.isHidden ?
									calendar.options.categories.inactiveColor : event.source.backgroundColor) +
									';">' +
								htmlEscape(calendar.options.categories.itemBullet) + '&nbsp;</span>' + '</td>' +
						'<td class="title last' + (event.status == 2 ? " fc-event-cancelled" : "") +'">' +
							'<span class="title '+((event.isTodo == true && event.completed == true) ? 'completed':'')+'">' + htmlEscape(eventTitle) + '</span>' +
							(eventNote && eventNote.length > 0 ?
									('<span class="note">' + htmlEscape(eventNote) + '</span>') : '') + '</td>' +
					'</tr>';

			var oneDay = 86400000;
			var startTime = start.getTime();
		    var startEventDay = !event.allDay && event.start != null ? new Date(event.start.getFullYear(), event.start.getMonth(), event.start.getDate()) : null,
                        endEventDay = !event.allDay && event.end != null ? new Date(event.end.getFullYear(), event.end.getMonth(), event.end.getDate()) : null;

            for (; start < end; addDays(start, +1)) {

                var newEventRow = null;
                if (!event.allDay && startEventDay != null && endEventDay != null) {

                    var $eventRow = $(eventRow),
                        spanTime = $eventRow[0].firstChild.firstChild;

                    var startDiff = startTime - startEventDay.getTime(),
                        endDiff = endEventDay.getTime() - startTime;

                    if (startDiff == 0 && endDiff == 0) {
                        spanTime.innerHTML = formatDate(event.start, timeFormat) + "<span class='dash'></span>" + formatDate(event.end, timeFormat);    //one day
                        
                    } else if (startDiff == 0 && endDiff != 0) {
                        spanTime.innerHTML = formatDate(event.start, timeFormat) + "<span class='dash'></span><span>...</span>";                        //first day of N
                        
                    } else if (startDiff != 0 && endDiff == 0) {
                        spanTime.innerHTML = "<span>...</span><span class='dash'></span>" + formatDate(event.end, timeFormat);                          //last day

                    } else if (startDiff != 0 && endDiff != 0) {
                        spanTime.innerHTML = calendar.options.allDayText;
                    }
                    newEventRow = $eventRow[0].outerHTML;
                    startTime += oneDay;
		        }

				monthTitle = formatDate(start, monthFormat);
				dayTitle = start.getFullYear() == now.getFullYear() && dayFormat.indexOf("yyyy") != -1 ? formatDate(start, dayFormat.substring(0, dayFormat.indexOf("yyyy"))) : formatDate(start, dayFormat);
				mt = "_" + encodeURIComponent(monthTitle).replace(/[^a-z0-9_]/gi, "_");
				dt = "_" + encodeURIComponent(dayTitle).replace(/[^a-z0-9_]/gi, "_");

				if (list[mt] === undefined) {
					list[mt] =
							{
								title: '<div class="fc-lv-month-title">' + htmlEscape(monthTitle) + '</div>'
							};
				}
				if (list[mt][dt] === undefined) {
					list[mt][dt] =
							{
							    title: '<tr><th colspan="3"><span>' + htmlEscape(dayTitle.split(',')[0]) + '</span><span>' + htmlEscape(dayTitle.split(',')[1]) + '</span></th></tr>',
								today: now.getDate() == start.getDate() &&
											 now.getMonth() == start.getMonth() &&
											 now.getFullYear() == start.getFullYear(),
								events: []
							};
				}
				list[mt][dt].events.push(newEventRow!=null ? newEventRow : eventRow); 
			}
		}

		first = true;
		html = '';
		// iterate through months
		for (i in list) {
			if (list[i].title === undefined) {
				continue;
			}
			if (_this.showMonthTitle) {
				html += list[i].title;
				first = true;
			}
			// iterate through days
			for (j in list[i]) {
				if (list[i][j].title === undefined) {continue;}
				html += '<table class="fc-lv-events' +
						(first ? (first = false, ' first') : '') +
						(list[i][j].today ? ' today' : '') +
						'" border="0" cellspacing="0" cellpadding="0"><tbody><td style="width: 25%"><table><tbody>' + list[i][j].title + '</tbody></table></td><td style="width: 75%"><table style="width: 100%"><tbody>';
			    // iterate through events
				for (k = 0; k < list[i][j].events.length; ++k) {
					html += list[i][j].events[k];
				}
				html += '</tbody></table></td></tbody></table>';
			}
		}

		if (html.length > 0) {
		    var w = _eventsList[0].clientWidth - 6/* padding in .fc-lv-scroller */;
			_eventsList.html('<div">' + html + '</div>');
			_eventsList.find("table.fc-lv-events").find("tr:last").addClass("last");
			_eventsList.find("tr.event-row").click(function(ev){
				var tr = $(this);
				var id = tr.attr("id");
				var event = calendar.clientEvents(id.substring(id.search("event_") + 6));
				if (event.length > 0 && event[0]) {
					var eventElement = tr.find(".title .title");
					calendar.editEvent(eventElement, event[0]);
					calendar.trigger('eventClick', this, event[0], ev);
				}
			});
		} else {
			_eventsList.html(
					'<div class="fc-lv-no-events">' +
						htmlEscape(calendar.options.listView.noEventsMessage) +
					'</div>');
		}
	}

	function _clearEvents() {
		var node = _eventsList[0];
		var last;
		while (last = node.lastChild)
			node.removeChild(last);
	}


	function _setHeight(height, dateChanged) {
		_eventsList.height(height);
	}

	function _setWidth(width) {
	}

	function _beforeHide() {
	}

	function _afterShow() {
	}


	function _defaultEventEnd(event) {
		var start = cloneDate(event.start);
		if (event.allDay) {
			return start;
		}
		return addMinutes(start, _this.opt('defaultEventMinutes'));
	}


	function _select(startDate, endDate, allDay) {
	}

	function _unselect(ev) {
	}

}


fcViews.list = ListView;

function ListView(element, calendar) {
	var _this = this;

	// imports
	BasicListView.call(_this, element, calendar, "list");
	//_this.showMonthTitle = true;


	var formatDate = calendar.formatDate;
	var formatDates = calendar.formatDates;


	var _initialized;


	this.render = function(date, delta) {
		if (delta) {
			addDays(date, delta);
		}

		var diff;
		if (_initialized) {
			diff = dayDiff(_this.end, _this.start);
		}
		if (!_initialized) {
			_this.start = _this.visStart = cloneDate(date, true);
			_this.end = _this.visEnd = addMonths(cloneDate(_this.start), 3);
		} else {
			if (date < _this.visStart || date >= _this.visEnd) {
				_this.start = _this.visStart = cloneDate(date, true);
			} else {
				_this.start = cloneDate(date, true);
			}
			var d = addDays(cloneDate(_this.start), diff);
			if (d < _this.visStart || d >= _this.visEnd) {
				_this.end = _this.visEnd = d;
			} else {
				_this.end = d;
			}
		}

		_this.title = _renderTitle.call(_this, _this.start, addDays(cloneDate(_this.end), -1));

		_this.renderBasic();
		if (!_initialized) {
			_this.afterShow();
			_initialized = true;
		}
	}

	this.beforeHide = function() {
		var h = $("#fc_container .fc-header");
		h.find(".fc-button-next, .fc-button-prev").show();
	};

	this.afterShow = function() {
		var h = $("#fc_container .fc-header");
		h.find(".fc-button-next, .fc-button-prev").hide();
	};


	function _changeFromDate(label, dp) {
		this.close();

		var date = dp.datepicker("getDate");
		_changeFromLabel.call(_this, label, date);

		if (_this.visStart <= date && date < _this.visEnd) {
			var diff = dayDiff(_this.end, _this.start);
			_this.start = date;
			var d = addDays(cloneDate(_this.start), diff);
			if (d >= _this.visEnd) {
				_this.end = _this.visEnd = d;
				calendar.refetchEvents();
			} else {
				_this.end = d;
				_this.eventsDirty = true;
			}
			_changeToLabel.call(_this, undefined, d);
		}
		calendar.gotoDate(date);
	}

	function _changeToDate(label, dp) {
		this.close();

		var date = dp.datepicker("getDate");
		var date1 = addDays(cloneDate(date), 1);
		_changeToLabel.call(_this, label, date1);

		if (date < _this.visStart) {
			var diff = dayDiff(_this.end, _this.start);
			calendar.gotoDate(addDays(date, -diff));
		} else if (date1 >= _this.visEnd) {
			_this.end = _this.visEnd = date1;
			calendar.refetchEvents();
		} else {
			_this.end = date1;
			calendar.rerenderEvents();
		}
	}

	function _changeFromLabel(elem, date) {
		var label = $(elem);
		var newLabel = formatDate(date, calendar.options.listView.headerDateFormat);
		// update visible label
		if (label != undefined && label.length > 0) {
			label.find(".inner").text(newLabel);
		}
		// update label in unattached DOM Node
		_this.title.find(".from.link .inner").text(newLabel);
	}

	function _changeToLabel(elem, date) {
		var label = $(elem);
		var newLabel = formatDate(
				addDays(cloneDate(date), -1), calendar.options.listView.headerDateFormat);
		// update visible label
		if (label != undefined && label.length > 0) {
			label.find(".inner").text(newLabel);
		}
		// update label in unattached DOM Node
		_this.title.find(".to.link .inner").text(newLabel);
	}

	function _renderTitle(start, end) {
		var lv = calendar.options.listView;
		var title = $(
				'<span>' +
					'<span class="from link">' +
						'<span class="inner">' +
							htmlEscape(formatDate(start, lv.headerDateFormat)) + '</span>' +
					'</span>' +
					'<span class="delimiter">&#8212;</span>' +
					'<span class="to link">' +
						'<span class="inner">' +
							htmlEscape(formatDate(end, lv.headerDateFormat)) + '</span>' +
					'</span>' +
				'</span>');
		title.find(".from.link").click(function() {
			fcDatepicker.open(calendar, this,
					function(dp) {dp.datepicker("setDate", _this.start);},
					_changeFromDate);
		});
		title.find(".to.link").click(function() {
			fcDatepicker.open(calendar, this,
					function(dp) {dp.datepicker("setDate", addDays(cloneDate(_this.end), -1));},
					_changeToDate);
		});
		//
		return title;
	}

}


fcViews.listMonth = ListMonthView;

function ListMonthView(element, calendar) {
	var _this = this;

	BasicListView.call(_this, element, calendar, 'listMonth');


	this.render = function(date, delta) {
		if (delta) {
			addMonths(date, delta);
			date.setDate(1);
		}
		_this.start = _this.visStart = cloneDate(date, true);
		_this.start.setDate(1);
		_this.end = _this.visEnd = addDays(addMonths(cloneDate(_this.start), 1), 0);

		var titleRender = new TitleRender(calendar);
		_this.title = titleRender.render(_this.name, _this.start, _this.end);

		_this.renderBasic();
	};

}


fcViews.listWeek = ListWeekView;

function ListWeekView(element, calendar) {
	var _this = this;

	BasicListView.call(_this, element, calendar, 'listWeek');


	this.render = function(date, delta) {
		if (delta) {
			addDays(date, delta * 7);
		}
		var start = addDays(cloneDate(date), -((date.getDay() - _this.opt('firstDay') + 7) % 7));
		var end = addDays(cloneDate(start), 7);

		_this.start = _this.visStart = start;
		_this.end = _this.visEnd = end;

		var titleRender = new TitleRender(calendar);
		_this.title = titleRender.render(_this.name, _this.start, addDays(cloneDate(_this.end), -1));

		_this.renderBasic();
	};

}


fcViews.listDay = ListDayView;

function ListDayView(element, calendar) {
	var _this = this;

	BasicListView.call(_this, element, calendar, 'listDay');


	this.render = function(date, delta) {
		if (delta) {
			addDays(date, delta);
		}

		_this.start = _this.visStart = cloneDate(date, true);
		_this.end = _this.visEnd = addDays(cloneDate(date, true), 1);

		var titleRender = new TitleRender(calendar);
		_this.title = titleRender.render(_this.name, _this.start, addDays(cloneDate(_this.end), -1));

		_this.renderBasic();
	};

}



function View(element, calendar, viewName) {
	var t = this;


	// exports
	t.element = element;
	t.calendar = calendar;
	t.name = viewName;
	t.opt = opt;
	t.trigger = trigger;
	//t.setOverflowHidden = setOverflowHidden;
	t.isEventDraggable = isEventDraggable;
	t.isEventResizable = isEventResizable;
	t.reportEvents = reportEvents;
	t.eventEnd = eventEnd;
	t.reportEventElement = reportEventElement;
	t.reportEventClear = reportEventClear;
	t.eventElementHandlers = eventElementHandlers;
	t.showEvents = showEvents;
	t.hideEvents = hideEvents;
	t.eventDrop = eventDrop;
	t.eventResize = eventResize;
	t.getEventElement = getEventElement;
	t.getViewRect = _getViewRect;
	// t.title
	// t.start, t.end
	// t.visStart, t.visEnd


	// imports
	var defaultEventEnd = t.defaultEventEnd;
	var normalizeEvent = calendar.normalizeEvent; // in EventManager
	var reportEventChange = calendar.reportEventChange;


	// locals
	var eventsByID = {};
	var eventElements = [];
	var eventElementsByID = {};
	var options = calendar.options;



	function _getViewRect() {
		return fcUtil.getElementRect(element);
	}


	function opt(name, viewNameOverride) {
		var v = options[name];
		if (typeof v == 'object') {
			return smartProperty(v, viewNameOverride || viewName);
		}
		return v;
	}


	function trigger(name, thisObj) {
		return calendar.trigger.apply(
			calendar,
			[name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t])
		);
	}


	/*
	function setOverflowHidden(bool) {
		element.css('overflow', bool ? 'hidden' : '');
	}
	*/


	function isEventDraggable(event) {
		return isEventEditable(event) && !opt('disableDragging');
	}


	function isEventResizable(event) { // but also need to make sure the seg.isEnd == true
		return isEventEditable(event) && !opt('disableResizing');
	}


	function isEventEditable(event) {
		return firstDefined(event.editable, (event.source || {}).editable, opt('editable')) && (
				event.source == undefined ||
				fcUtil.objectIsEditable(event) ||
				fcUtil.objectIsEditable(event.source) ||
				event.source && !event.source.isSubscription);
	}



	/* Event Data
	------------------------------------------------------------------------------*/


	// report when view receives new events
	function reportEvents(events) { // events are already normalized at this point
		eventsByID = {};
		var i, len=events.length, event;
		for (i=0; i<len; i++) {
			event = events[i];
			if (eventsByID[event._id]) {
				eventsByID[event._id].push(event);
			}else{
				eventsByID[event._id] = [event];
			}
		}
	}


	// returns a Date object for an event's end
	function eventEnd(event) {
		return event.end ? cloneDate(event.end) : defaultEventEnd(event);
	}



	/* Event Elements
	------------------------------------------------------------------------------*/


	// report when view creates an element for an event
	function reportEventElement(event, element) {
		eventElements.push(element);
		if (eventElementsByID[event._id]) {
			eventElementsByID[event._id].push(element);
		}else{
			eventElementsByID[event._id] = [element];
		}
	}


	function reportEventClear() {
		eventElements = [];
		eventElementsByID = {};
	}


	// attaches eventClick, eventMouseover, eventMouseout
	function eventElementHandlers(event, eventElement) {
		// in IE onclick triggered if, after resizing the cursor stays on the variable object
		if($.browser.msie) {
			eventElement.mouseup(function (ev) {
				if (!eventElement.hasClass('ui-draggable-dragging') &&
					!eventElement.hasClass('ui-resizable-resizing') &&
					!$(ev.target).hasClass('ui-resizable-handle')) {
					calendar.editEvent(eventElement, event);
					return trigger('eventClick', this, event, ev);
				}
				return undefined;
			});
		} else {
			eventElement.click(function (ev) {
				if (!eventElement.hasClass('ui-draggable-dragging') &&
					!eventElement.hasClass('ui-resizable-resizing') &&
					!$(ev.target).hasClass('ui-resizable-handle')) {
					calendar.editEvent(eventElement, event);
					return trigger('eventClick', this, event, ev);
				}
				return undefined;
			});
		}
		eventElement
			.hover(
				function(ev) {
					trigger('eventMouseover', this, event, ev);
				},
				function(ev) {
					trigger('eventMouseout', this, event, ev);
				}
			);
		// TODO: don't fire eventMouseover/eventMouseout *while* dragging is occuring (on subject element)
		// TODO: same for resizing
	}


	function showEvents(event, exceptElement) {
		eachEventElement(event, exceptElement, 'show');
	}


	function hideEvents(event, exceptElement) {
		eachEventElement(event, exceptElement, 'hide');
	}


	function eachEventElement(event, exceptElement, funcName) {
		var elements = eventElementsByID[event._id],
			i, len = elements.length;
		for (i=0; i<len; i++) {
			if (!exceptElement || elements[i][0] != exceptElement[0]) {
				elements[i][funcName]();
			}
		}
	}


	function getEventElement(event) {
		if (event._id != undefined && eventElementsByID[event._id]) {
			return eventElementsByID[event._id][0];
		}
		return null;
	}



	/* Event Modification Reporting
	---------------------------------------------------------------------------------*/


	function eventDrop(e, event, dayDelta, minuteDelta, allDay, ev, ui) {
		var oldAllDay = event.allDay;
		var eventId = event._id;
		
		if (!event.isTodo) {
		    moveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);
		    trigger(
		        'eventDrop',
		        e,
		        event,
		        dayDelta,
		        minuteDelta,
		        allDay,
		        function() {
		            // TODO: investigate cases where this inverse technique might not work
		            moveEvents(eventsByID[eventId], -dayDelta, -minuteDelta, oldAllDay);
		            reportEventChange(eventId, event);
		        },
		        ev,
		        ui
		    );
		    reportEventChange(eventId, event);
		} else {
		    moveEvents(eventsByID[eventId], dayDelta, minuteDelta, allDay);
		    calendar.todolist.updateTodo(event);

		}
	}


	function eventResize(e, event, dayDelta, minuteDelta, ev, ui) {
		var eventId = event._id;
		elongateEvents(eventsByID[eventId], dayDelta, minuteDelta);
		trigger(
			'eventResize',
			e,
			event,
			dayDelta,
			minuteDelta,
			function() {
				// TODO: investigate cases where this inverse technique might not work
				elongateEvents(eventsByID[eventId], -dayDelta, -minuteDelta);
				reportEventChange(eventId, event);
			},
			ev,
			ui
		);
		reportEventChange(eventId, event);
	}



	/* Event Modification Math
	---------------------------------------------------------------------------------*/


	function moveEvents(events, dayDelta, minuteDelta, allDay) {
		minuteDelta = minuteDelta || 0;
		for (var e, len=events.length, i=0; i<len; i++) {
			e = events[i];
			if (allDay !== undefined) {
				e.allDay = allDay;
			}
			addMinutes(addDays(e.start, dayDelta, true), minuteDelta);
			if (e.end) {
				e.end = addMinutes(addDays(e.end, dayDelta, true), minuteDelta);
			}else if (!allDay) {
			    e.end =  new Date(e.start.getFullYear(), e.start.getMonth(), e.start.getDate(), e.start.getHours(), e.start.getMinutes() + 30);
			}
			normalizeEvent(e, options);
		}
	}


	function elongateEvents(events, dayDelta, minuteDelta) {
		minuteDelta = minuteDelta || 0;
		for (var e, len=events.length, i=0; i<len; i++) {
			e = events[i];
			e.end = addMinutes(addDays(eventEnd(e), dayDelta, true), minuteDelta);
			normalizeEvent(e, options);
		}
	}


}

function DayEventRenderer() {
	var t = this;


	// exports
	t.renderDaySegs = renderDaySegs;
	t.resizableDayEvent = resizableDayEvent;


	// imports
	var opt = t.opt;
	var trigger = t.trigger;
	var isEventDraggable = t.isEventDraggable;
	var isEventResizable = t.isEventResizable;
	var eventEnd = t.eventEnd;
	var reportEventElement = t.reportEventElement;
	var showEvents = t.showEvents;
	var hideEvents = t.hideEvents;
	var eventResize = t.eventResize;
	var getRowCnt = t.getRowCnt;
	var getColCnt = t.getColCnt;
	var getColWidth = t.getColWidth;
	var allDayRow = t.allDayRow;
	var allDayBounds = t.allDayBounds;
	var colContentLeft = t.colContentLeft;
	var colContentRight = t.colContentRight;
	var dayOfWeekCol = t.dayOfWeekCol;
	var dateCell = t.dateCell;
	var cellDate = t.cellDate;
	var compileDaySegs = t.compileDaySegs;
	var getDaySegmentContainer = t.getDaySegmentContainer;
	var bindDaySeg = t.bindDaySeg; //TODO: streamline this
	var formatDates = t.calendar.formatDates;
	var renderDayOverlay = t.renderDayOverlay;
	var clearOverlays = t.clearOverlays;
	var clearSelection = t.clearSelection;
	var getCellBounds = t.getCellBounds;



	/* Rendering
	-----------------------------------------------------------------------------*/

	function calcDaySegs(segs, segmentContainer, modifiedEventId) {
		var i,
			l = segs.length,
			seg,
			element,
			elements = segmentContainer.children();

		for (i = 0; i < l; i++) {
			seg = segs[i];
			element = $(elements[i]);
			daySegElementResolve(seg, element);
			daySegElementReport(seg);
			daySegHandlers(seg, i, modifiedEventId);

			trigger('eventAfterRender', seg.event, seg.event, element);
		}

		for (i = 0, l = elements.length; i < l; i++) {
			element = elements[i];
			if (element.className != "fc-event-info") continue;
			var array = element.id.split('_');
			$(element).click({ row: array[1], col: array[2], segs: segs }, showHiddenEvents);
		}

		lazySegBind(segmentContainer, segs, bindDaySeg);
	}

	function renderDaySegs(segs, modifiedEventId) {
		var segmentContainer = getDaySegmentContainer();

		segmentContainer[0].innerHTML = daySegHTML(segs); // faster than .html()

		calcDaySegs(segs, segmentContainer, modifiedEventId);

		if ($.isFunction(t._afterRenderDaySegs)) {
			t._afterRenderDaySegs(segs);
		}
	}


	function calcTempDaySegs(segs, segmentContainer, adjustRow, adjustTop) {
		var i,
			l = segs.length,
			seg,
		    element,
			elements = segmentContainer.children(),
			result = [];

		for (i = 0; i < l; i++) {
			seg = segs[i];
			element = $(elements[i]);
			daySegElementResolve(seg, element);

			trigger('eventAfterRender', seg.event, seg.event, element);

			element = segs[i].element;
			if (element) {
				if (segs[i].row === adjustRow) {
					element.css('top', adjustTop);
				}
				result.push(element[0]);
			}
		}

		return $(result);
	}

	function renderTempDaySegs(segs, adjustRow, adjustTop) {
		var segmentContainer = getDaySegmentContainer();

		segmentContainer[0].innerHTML = daySegHTML(segs); // faster than .html()

		return calcTempDaySegs(segs, segmentContainer, adjustRow, adjustTop);
	}

	function daySegHTML(segs) { // also sets seg.left and seg.outerWidth
		var rtl = opt('isRTL');
		var i;
		var segCnt=segs.length;
		var seg;
		var event;
		var classes;
		var bounds = allDayBounds();
		var minLeft = bounds.left;
		var maxLeft = bounds.right;
		var leftCol;
		var rightCol;
		var left;
		var right;
		var skinCss;
		var html = '';

		var sizeManager = ASC.CalendarSizeManager.cache;
		var widgetHeaderHeight = 0;
		var dayNumberElementHeight = 0;
		var dayContentElement;
		var dayContentElementHeight;
		var dayContentElementVsides = sizeManager.fcMonthContentCellContentVSides;
		var segHsides = sizeManager.fcMonthContentCellContentSegmentHSides;
		var segHeight = sizeManager.fcMonthContentCellContentSegmentHeight + segHsides;
		var infoBoxes = {};
		var maxLevel = 0;

		if (t.name == "month") {
			widgetHeaderHeight = sizeManager.fcMonthContentTheadHeight;
			dayNumberElementHeight = sizeManager.fcMonthContentCellNumberHeight;
			dayContentElement = document.querySelector(".fc-content .fc-view-month .fc-day-content");
			dayContentElementHeight = parseFloat(dayContentElement.style.height) + dayContentElementVsides;
		} else if (t.name == "agendaWeek") {
			dayContentElement = document.querySelector(".fc-content .fc-view-agendaWeek .fc-agenda-allday .fc-day-content");
			dayContentElementHeight = sizeManager.fcMonthContentCellContentMaxHeight;
		} else if (t.name == "agendaDay") {
			dayContentElement = document.querySelector(".fc-content .fc-view-agendaDay .fc-agenda-allday .fc-day-content");
			dayContentElementHeight = sizeManager.fcMonthContentCellContentMaxHeight;
		}


		for (i=0; i<segCnt; i++) {
			seg = segs[i];
			event = seg.event;

			var isOpened = false;
			if (t.calendar.openEventWin) {
				if (event.objectId == t.calendar.openEventWin.objectId) {
					isOpened = true;
				}
			}

			classes = [
				'fc-event',
				event.allDay ? 'fc-event-skin-day' : 'fc-event-skin',
				event.isTodo && event.completed ? 'fc-todo-completed' : '',
				isOpened ? event.isTodo ? 'fc-todo-open' : 'fc-event-open' : '',
				'fc-event-hori',
				isEventDraggable(event) ? 'fc-event-draggable' : ''
			];

			if (rtl) {
				if (seg.isStart) {
					classes.push('fc-corner-right');
				}
				if (seg.isEnd) {
					classes.push('fc-corner-left');
				}
				leftCol = dayOfWeekCol(seg.end.getDay()-1);
				rightCol = dayOfWeekCol(seg.start.getDay());
				left = seg.isEnd ? colContentLeft(leftCol) : minLeft;
				right = seg.isStart ? colContentRight(rightCol) : maxLeft;
			}else{
				if (seg.isStart) {
					classes.push('fc-corner-left');
				}
				if (seg.isEnd) {
					classes.push('fc-corner-right');
				}
				leftCol = dayOfWeekCol(seg.start.getDay());
				rightCol = dayOfWeekCol(seg.end.getDay()-1);
				left = seg.isStart ? colContentLeft(leftCol) : minLeft;
				right = seg.isEnd ? colContentRight(rightCol) : maxLeft;
			}

			classes = classes.concat(event.className);
			if (event.source) {
				classes = classes.concat(event.source.className || []);
			}

			seg.left = left;
			seg.outerWidth = right - left;
			seg.startCol = leftCol;
			seg.endCol = rightCol + 1; // needs to be exclusive
			seg.hsides = segHsides;
			seg.outerHeight = segHeight;
			seg.top = (seg.outerHeight * seg.level) + (seg.row * (dayNumberElementHeight + dayContentElementHeight) + dayNumberElementHeight + sizeManager.fcMonthContentCellVBorders * seg.row) + widgetHeaderHeight;

			if (maxLevel < seg.level)
				maxLevel = seg.level;

			skinCss = getSkinCss(event, opt, t.name);

			var styles = "";

			if (seg.isStart == false && seg.isEnd == true) {
				classes.push('fc-segm-right');
				styles = 'width:' + (Math.max(0, seg.outerWidth - seg.hsides) - 10) + 'px;';
			} else if (seg.isStart == true && seg.isEnd == false) {
				classes.push('fc-segm-left');
				styles = 'width:' + (Math.max(0, seg.outerWidth - seg.hsides) - 10) + 'px;';
			} else if (seg.isStart == false && seg.isEnd == false) {
				classes.push('fc-segm-right');
				classes.push('fc-segm-left');
				styles = 'width:' + (Math.max(0, seg.outerWidth - seg.hsides) - 20) + 'px;';
			} else {
				styles = 'width:' + Math.max(0, seg.outerWidth - seg.hsides) + 'px;';
			}

			styles += 'top:' + seg.top + 'px;';

			var rowBottom;
			if (t.name == "month") {
				rowBottom = (seg.row + 1) * (dayNumberElementHeight + dayContentElementHeight) + widgetHeaderHeight;
			} else if (t.name == "agendaWeek") {
				rowBottom = dayContentElementHeight + widgetHeaderHeight;
			} else if (t.name == "agendaDay") {
				rowBottom = dayContentElementHeight + widgetHeaderHeight;
			}

			if (seg.top + seg.outerHeight > rowBottom - seg.outerHeight) {

				styles += "display: none;";

				var cellId = "cell_" + seg.row + "_" + seg.startCol;

				if (!infoBoxes[cellId])
					infoBoxes[cellId] = { seg: seg, text: "" };

				var s = infoBoxes[cellId].text.match(/(\d+)/);
				var cnt = parseInt((s ? s[1] : 0), 10) || 0;
				infoBoxes[cellId].text = t.calendar.options.moreEventsLabel.replace("%d", cnt + 1);
			}

			html +=
				"<div class='" + classes.join(' ') + "'" +
				" style='position:absolute;z-index:7;left:" + left + "px;" + styles + skinCss + "'" +
				">" +
				"<div" + (event.allDay ?
					" class='fc-event-inner fc-event-skin-day'" :
					" class='fc-event-inner fc-event-skin'") +
					(skinCss ? " style='" + skinCss + "'" : '') +
				">";

			if (!event.allDay && seg.isStart) {
				html +=
					"<span class='fc-event-time'>" +
						htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) +
						"&nbsp;" +
					"</span>";

				html += "<span class='bullet' style='color:" + htmlEscape(event.source ?
						event.source.backgroundColor : (event.backgroundColor || t.calendar.options.eventBackgroundColor)) +
						";'>" + htmlEscape(t.calendar.options.categories.itemBullet) + "&nbsp;</span>";
			} else {
				html += '<span>&nbsp;</span>';      // to prevent collapsing
			}

			var title = htmlEscape(event.title);

			html +=
				"<span class='fc-event-title" + (event.status == 2 ? " fc-event-cancelled" : "") + "' title='" + title + "'>" + title + "</span>" +
				"</div>";
			if (seg.isEnd && isEventResizable(event) && event.allDay) {
				html +=  event.isTodo == true ? "" :
					"<div class='ui-resizable-handle ui-resizable-" + (rtl ? 'w' : 'e') + "'>" +
					"&nbsp;&nbsp;&nbsp;" + // makes hit area a lot better for IE6/7
					"</div>";
			}
			html += "</div>";
		}

		for (var name in infoBoxes) {
			var item = infoBoxes[name];
			html += "<div id='" + name + "' style='width:" + item.seg.outerWidth + "px;top:" + item.seg.top + "px;left:" + item.seg.left + "px;height:" + item.seg.outerHeight + "px;line-height:" + item.seg.outerHeight + "px;' class='fc-event-info'>" + item.text + "</div>";
		}

		if (t.name == "agendaWeek" || t.name == "agendaDay") {
			dayContentElement.style.height = Math.min(segHeight * (maxLevel + 2), dayContentElementHeight) + "px";
		}

		return html;
	}


    function daySegElementResolve(seg, element) { // sets seg.element
        var event = seg.event;
        var triggerRes = trigger('eventRender', event, event, element);

        if (triggerRes === false) {
            element.remove();
        } else {
            if (triggerRes && triggerRes !== true) {
                triggerRes = $(triggerRes)
                    .css({
                        position: 'absolute',
                        left: seg.left
                    });
                element.replaceWith(triggerRes);
                element = triggerRes;
            }
            seg.element = element;
        }
    }


    function daySegElementReport(seg) {
        if (seg.element) {
            reportEventElement(seg.event, seg.element);
        }
    }


    function daySegHandlers(seg, index, modifiedEventId) {
        var element = seg.element;

        if (element) {
            var event = seg.event;
            if (event._id === modifiedEventId) {
                bindDaySeg(event, element, seg);
            } else {
                element[0]._fci = index; // for lazySegBind
            }
        }
    }


	function showHiddenEvents(evData) {
		var co = t.calendar.options;
		var evInfo = $(this);
		var parent = evInfo.parent();
		var popup = parent.find("#cell_popup");
		
		if (popup.length < 1) {
			popup = $("<div id='cell_popup' class='fc-event-popup'/>");
            $(document).mouseup(function (e) {
                if (popup.has(e.target).length === 0 && $(e.target)[0].id != popup[0].id) {
                    if (!t.calendar.isEditingEvent()) {
                        popup.hide();
                    }
                }
            });
            document.onkeydown = function (e) {
                e = e || window.event;
                if (e.keyCode === 27) {
                    if (popup.has(e.target).length === 0 && $(e.target)[0].id !== popup[0].id) {
                        if (!t.calendar.isEditingEvent()) {
                            popup.hide();
                        }
                    }
                }
            };
            popup.appendTo(parent);
		}
		
		var cb = getCellBounds(evData.data.row, evData.data.col);
		var cw = cb.right - cb.left;
		var ch = cb.bottom - cb.top;
		var wratio = 1.4;
		var hratio = 1.4;
		
		popup.width(Math.floor(cw * wratio));
		popup.height("auto");

		var celld = cellDate(evData.data);

		popup.empty();
		popup.append($(
				"<div class='fc-day-number'>" +
					htmlEscape(co.dayNames[celld.getDay()] + ", " +
							formatDates(celld, null, t.calendar.options.popupCellFormat)) +
				"</div>"));
		popup.show();

		for (var i = 0; i < evData.data.segs.length; ++i) {
			var seg = evData.data.segs[i];
			if (seg.row == evData.data.row && seg.startCol == evData.data.col) {
				var el = seg.element.clone();
				el.css("display", "block")
					.css("left", "")
					.css("top", "")
					.css("position", "")
					.css("width", "auto")
					.show();
				t.eventElementHandlers(seg.event, el);
				popup.append(el);
			}
		}
		popup.find(".ui-resizable-e").remove();

		var h1 = Math.floor(ch * hratio);
		var h2 = popup.height();
		var h = h1 > h2 ? h1 : h2;
		popup.height(h);

		var pw = popup.outerWidth(true);
		var left = evData.data.col == 0 ?
				cb.left + 1 :
				(evData.data.col == getColCnt() - 1 ?
						Math.floor(cb.left - (pw - cw)) - 1 :
						Math.floor(cb.left - (pw - cw) * 0.5));
						
		var ph = popup.outerHeight(true);
		if (ph > 190) {
			popup.css("overflow-y", "auto").css("overflow-x", "hidden").css("max-height", "190px");
			ph = 190;
		}
		else {
			popup.css("overflow-y", "hidden");
		}
		
		var top = evData.data.row == 0 ?
				cb.top + 1 :
				(evData.data.row == getRowCnt() - 1 ?
						Math.floor(cb.top - (ph - ch)) - 1 :
						Math.floor(cb.top - (ph - ch) * 0.5));
		
		
		popup.css("left", left + "px");
		popup.css("top", top + "px");
	}



	/* Resizing
	-----------------------------------------------------------------------------------*/


	function resizableDayEvent(event, element, seg) {
		var rtl = opt('isRTL');
		var direction = rtl ? 'w' : 'e';
		var handle = element.find('div.ui-resizable-' + direction);
		var isResizing = false;

		// TODO: look into using jquery-ui mouse widget for this stuff
		disableTextSelection(element); // prevent native <a> selection for IE
		element
			.mousedown(function(ev) { // prevent native <a> selection for others
				ev.preventDefault();
			})
			.click(function(ev) {
				if (isResizing) {
					ev.preventDefault(); // prevent link from being visited (only method that worked in IE6)
					ev.stopImmediatePropagation(); // prevent fullcalendar eventClick handler from being called
					                               // (eventElementHandlers needs to be bound after resizableDayEvent)
				}
			});

		handle.mousedown(function(ev) {
			if (ev.which != 1) {
				return; // needs to be left mouse button
			}
			isResizing = true;
			var hoverListener = t.getHoverListener();
			var rowCnt = getRowCnt();
			var colCnt = getColCnt();
			var dis = rtl ? -1 : 1;
			var dit = rtl ? colCnt-1 : 0;
			var elementTop = element.css('top');
			var dayDelta;
			var helpers;
			var eventCopy = $.extend({}, event);
			var minCell = dateCell(event.start);
			clearSelection();
			$('body')
				.css('cursor', direction + '-resize')
				.one('mouseup', mouseup);
			trigger('eventResizeStart', this, event, ev);
			hoverListener.start(function(cell, origCell) {
				if (cell) {
					var r = Math.max(minCell.row, cell.row);
					var c = cell.col;
					if (rowCnt == 1) {
						r = 0; // hack for all-day area in agenda views
					}
					if (r == minCell.row) {
						if (rtl) {
							c = Math.min(minCell.col, c);
						}else{
							c = Math.max(minCell.col, c);
						}
					}
					dayDelta = (r*7 + c*dis+dit) - (origCell.row*7 + origCell.col*dis+dit);
					var newEnd = addDays(eventEnd(event), dayDelta, true);
					if (dayDelta) {
						eventCopy.end = newEnd;
						var oldHelpers = helpers;
						helpers = renderTempDaySegs(compileDaySegs([eventCopy]), seg.row, elementTop);
						helpers.find('*').css('cursor', direction + '-resize');
						if (oldHelpers) {
							oldHelpers.remove();
						}
						hideEvents(event);
					}else{
						if (helpers) {
							showEvents(event);
							helpers.remove();
							helpers = null;
						}
					}
					clearOverlays();
					renderDayOverlay(event.start, addDays(cloneDate(newEnd), 1)); // coordinate grid already rebuild at hoverListener.start
				}
			}, ev);

			function mouseup(ev) {
				trigger('eventResizeStop', this, event, ev);
				$('body').css('cursor', '');
				hoverListener.stop();
				clearOverlays();
				if (dayDelta) {
					eventResize(this, event, dayDelta, 0, ev);
					// event redraw will clear helpers
				} else {
					t.calendar.rerenderEvents();
					// otherwise, the drag handler already restored the old events
				}
				setTimeout(function() { // make this happen after the element's click event
					isResizing = false;
				},0);
			}

		});
	}


}

//BUG: unselect needs to be triggered when events are dragged+dropped

function SelectionManager() {
	var t = this;


	// exports
	t.select = select;
	t.unselect = unselect;
	t.reportSelection = reportSelection;
	t.daySelectionMousedown = daySelectionMousedown;


	// imports
	var opt = t.opt;
	var trigger = t.trigger;
	var defaultSelectionEnd = t.defaultSelectionEnd;
	var renderSelection = t.renderSelection;
	var clearSelection = t.clearSelection;


	// locals
	var selected = false;



	// unselectAuto
	if (opt('selectable') && opt('unselectAuto')) {
		$(document).mousedown(function(ev) {
			var ignore = opt('unselectCancel');
			if (ignore) {
				if ($(ev.target).parents(ignore).length) { // could be optimized to stop after first match
					return;
				}
			}
			unselect(ev);
		});
	}


	function select(startDate, endDate, allDay) {
		unselect();
		if (!endDate) {
			endDate = defaultSelectionEnd(startDate, allDay);
		}
		renderSelection(startDate, endDate, allDay);
		//reportSelection(startDate, endDate, allDay);
	}


	function unselect(ev) {
		if (selected) {
			selected = false;
			clearSelection();
			trigger('unselect', null, ev);
		}
	}


	function reportSelection(startDate, endDate, allDay, ev) {
		selected = true;

		t.calendar.addAndEditEvent(startDate, endDate, allDay);

		trigger('select', null, startDate, endDate, allDay, ev);
		t.calendar.unselect();
	}


	function daySelectionMousedown(ev) { // not really a generic manager method, oh well
		var cellDate = t.cellDate;
		var cellIsAllDay = t.cellIsAllDay;
		var hoverListener = t.getHoverListener();
		var reportDayClick = t.reportDayClick; // this is hacky and sort of weird
		if (ev.which == 1 && opt('selectable')) { // which==1 means left mouse button
			unselect(ev);
			var _mousedownElement = this;
			var dates;
			hoverListener.start(function(cell, origCell) { // TODO: maybe put cellDate/cellIsAllDay info in cell
				clearSelection();
				if (cell && cellIsAllDay(cell)) {
					dates = [ cellDate(origCell), cellDate(cell) ].sort(cmp);
					renderSelection(dates[0], dates[1], true);
				}else{
					dates = null;
				}
			}, ev);
			$(document).one('mouseup', function(ev) {
				hoverListener.stop();
				if (dates) {
					if (+dates[0] == +dates[1]) {
						reportDayClick(dates[0], true, ev);
					}
					reportSelection(dates[0], dates[1], true, ev);
				}
			});
		}
	}


}

function OverlayManager() {
	var t = this;


	// exports
	t.renderOverlay = renderOverlay;
	t.clearOverlays = clearOverlays;


	// locals
	var usedOverlays = [];
	var unusedOverlays = [];


	function renderOverlay(rect, parent) {
		var e = unusedOverlays.shift();
		if (!e) {
			e = $("<div class='fc-cell-overlay' style='position:absolute;z-index:3'/>");
		}
		if (e[0].parentNode != parent[0]) {
			e.appendTo(parent);
		}
		usedOverlays.push(e.css(rect).show());
		return e;
	}


	function clearOverlays() {
		var e;
		while (e = usedOverlays.shift()) {
			unusedOverlays.push(e.hide().unbind());
		}
	}


}

function CoordinateGrid(buildFunc) {

	var t = this;
	var rows;
	var cols;


	this.build = function() {
		rows = [];
		cols = [];
		buildFunc(rows, cols);
	};


	this.cell = function(x, y) {
		var rowCnt = rows.length;
		var colCnt = cols.length;
		var i, r=-1, c=-1;
		for (i=0; i<rowCnt; i++) {
			if (y >= rows[i][0] && y < rows[i][1]) {
				r = i;
				break;
			}
		}
		for (i=0; i<colCnt; i++) {
			if (x >= cols[i][0] && x < cols[i][1]) {
				c = i;
				break;
			}
		}
		return (r>=0 && c>=0) ? {row:r, col:c} : null;
	};


	this.rect = function(row0, col0, row1, col1, originElement) { // row1,col1 is inclusive
		var origin = originElement.offset();
		return {
			top: rows[row0][0] - origin.top,
			left: cols[col0][0] - origin.left,
			width: cols[col1][1] - cols[col0][0],
			height: rows[row1][1] - rows[row0][0]
		};
	};

}

function HoverListener(coordinateGrid) {


	var t = this;
	var bindType;
	var change;
	var firstCell;
	var cell;


	t.start = function(_change, ev, _bindType) {
		change = _change;
		firstCell = cell = null;
		coordinateGrid.build();
		mouse(ev);
		bindType = _bindType || 'mousemove';
		$(document).bind(bindType, mouse);
	};


	function mouse(ev) {
	_fixUIEvent(ev);
		var newCell = coordinateGrid.cell(ev.pageX, ev.pageY);
		if (!newCell != !cell || newCell && (newCell.row != cell.row || newCell.col != cell.col)) {
			if (newCell) {
				if (!firstCell) {
					firstCell = newCell;
				}
				change(newCell, firstCell, newCell.row-firstCell.row, newCell.col-firstCell.col);
			}else{
				change(newCell, firstCell);
			}
			cell = newCell;
		}
	}


	t.stop = function() {
		$(document).unbind(bindType, mouse);
		return cell;
	};


}

function ElementsPositionCache(getElement) {

	var t = this;
	var elements = {};
	var lefts = {};
	var rights = {};

	function e(i) {
		return elements[i] = elements[i] || getElement(i);
	}

	this.left = function(i) {
		return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];
	};

	this.right = function(i) {
		return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];
	};

	this.clear = function() {
		elements = {};
		lefts = {};
		rights = {};
	};

}

// select elements
function preventSelection(element){
  var preventSelection = false;

  function addHandler(element, event, handler){
    if (element.attachEvent) 
      element.attachEvent('on' + event, handler);
    else 
      if (element.addEventListener) 
        element.addEventListener(event, handler, false);
  }
  function removeSelection(){
    if (window.getSelection) { window.getSelection().removeAllRanges(); }
    else if (document.selection && document.selection.clear)
      document.selection.clear();
  }
  function killCtrlA(event){
    var event = event || window.event;
    var sender = event.target || event.srcElement;

    if (sender.tagName.match(/INPUT|TEXTAREA/i))
      return;

    var key = event.keyCode || event.which;
    if (event.ctrlKey && key == 'A'.charCodeAt(0))  // 'A'.charCodeAt(0) or 65
    {
      removeSelection();

      if (event.preventDefault) 
        event.preventDefault();
      else
        event.returnValue = false;
    }
  }

  // mouse selection
  addHandler(element, 'mousemove', function(){
    if(preventSelection)
      removeSelection();
  });
  addHandler(element, 'mousedown', function(event){
    var event = event || window.event;
    var sender = event.target || event.srcElement;
    preventSelection = !sender.tagName.match(/INPUT|TEXTAREA/i);
  });

  // dblclick  
  addHandler(element, 'mouseup', function(){
    if (preventSelection)
      removeSelection();
    preventSelection = false;
  });

  // ctrl+A  
  addHandler(element, 'keydown', killCtrlA);
  addHandler(element, 'keyup', killCtrlA);
}

  // this fix was only necessary for jQuery UI 1.8.16 (and jQuery 1.7 or 1.7.1)
    // upgrading to jQuery UI 1.8.17 (and using either jQuery 1.7 or 1.7.1) fixed the problem
    // but keep this in here for 1.8.16 users
    // and maybe remove it down the line

    function _fixUIEvent(event) { // for issue 1168
        if (event.pageX === undefined) {
            event.pageX = event.originalEvent.pageX;
            event.pageY = event.originalEvent.pageY;
        }
    }
    function HorizontalPositionCache(getElement) {

        var t = this,
		elements = {},
		lefts = {},
		rights = {};

        function e(i) {
            return elements[i] = elements[i] || getElement(i);
        }

        t.left = function(i) {
            return lefts[i] = lefts[i] === undefined ? e(i).position().left : lefts[i];
        };

        t.right = function(i) {
            return rights[i] = rights[i] === undefined ? t.left(i) + e(i).width() : rights[i];
        };

        t.clear = function() {
            elements = {};
            lefts = {};
            rights = {};
        };

    }

})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/UserControls/RecentActivityControl.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI.WebControls;

using ASC.Core.Users;
using ASC.Forum;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Forum.Common;

namespace ASC.Web.UserControls.Forum
{
    public class RecentActivityControl : WebControl
    {
        public Guid SettingsID { get; set; }
        public int MaxTopicCount { get; set; }
        public bool AutoInitView { get; set; }

        private Settings _settings = null;

        public List<Topic> TopicList { get; set; }

        public RecentActivityControl()
        {
            this.MaxTopicCount = 8;
            AutoInitView = true;
            TopicList = new List<Topic>();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (AutoInitView)
                InitView();

        }

        public void InitView()
        {
            _settings = Community.Forum.ForumManager.Settings;
            TopicList = ForumDataProvider.GetLastUpdateTopics(TenantProvider.CurrentTenantID, MaxTopicCount);
        }

        protected override void RenderContents(System.Web.UI.HtmlTextWriter writer)
        {
            StringBuilder sb = new StringBuilder();

            foreach (var topic in TopicList)
            {
                if (topic.RecentPostID != 0)
                {
                    //poster
                    sb.Append("<div class='clearFix' style='margin-bottom:20px;'>");
                    sb.Append(topic.RecentPostAuthor.RenderCustomProfileLink("describe-text", "link gray"));

                    //topic
                    sb.Append("<div style='margin-top:5px;'>");
                    sb.Append("<a href='" + _settings.LinkProvider.RecentPost(topic.RecentPostID, topic.ID, topic.PostCount) + "'>" + HttpUtility.HtmlEncode(topic.Title) + "</a>");
                    sb.Append("</div>");


                    //date
                    sb.Append("<div style='margin-top:5px;'>");
                    sb.Append(DateTimeService.DateTime2StringPostStyle(topic.RecentPostCreateDate));
                    sb.Append("</div>");

                    sb.Append("</div>");
                }

            }

            writer.Write(sb.ToString());
        }
    }
}


<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Core/DbSchema/Tables/AliasTable.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Server.Core.DbSchema.Interfaces;

namespace ASC.Mail.Server.Core.DbSchema.Tables
{
    public class AliasTable : ITable
    {
        public const string TABLE_NAME = "alias";

        public static class Columns
        {
            public const string ADDRESS = "address";
            public const string GOTO = "goto";
            public const string DOMAIN = "domain";
            public const string CREATED = "created";
            public const string MODIFIED = "modified";
            public const string ACTIVE = "active";
            public const string IS_GROUP = "islist";
        }

        public string Name { get { return TABLE_NAME; } }

        public IEnumerable<string> OrderedColumnCollection { get; private set; }

        public AliasTable()
        {
            OrderedColumnCollection = new List<string>
            {
                Columns.ADDRESS,
                Columns.GOTO,
                Columns.DOMAIN,
                Columns.CREATED,
                Columns.MODIFIED,
                Columns.ACTIVE,
                Columns.IS_GROUP
            };
        }
    }
}


<|start_filename|>module/ASC.AuditTrail/AuditActionsMapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using ASC.AuditTrail.Model;
using ASC.MessagingSystem.Contracts;
using System.Linq;

namespace ASC.AuditTrail.Data
{
    public class AuditActionsMapper
    {
        private static readonly Dictionary<MessageAction, MessageMaps> actions = new Dictionary
            <MessageAction, MessageMaps>
            {
                #region login
                
                {MessageAction.LoginSuccess, new MessageMaps {ActionText = AuditReportResource.LoginSuccess}},
                {MessageAction.LoginSuccessThirdParty, new MessageMaps {ActionText = AuditReportResource.LoginSuccessThirdParty}},
                {MessageAction.LoginFail, new MessageMaps {ActionText = AuditReportResource.LoginFail}},
                {MessageAction.LoginFailInvalidCombination, new MessageMaps {ActionText = AuditReportResource.LoginFailInvalidCombination}},
                {MessageAction.LoginFailThirdPartyNotFound, new MessageMaps {ActionText = AuditReportResource.LoginFailThirdPartyNotFound}},
                {MessageAction.LoginFailDisabledProfile, new MessageMaps {ActionText = AuditReportResource.LoginFailDisabledProfile}},
                {MessageAction.Logout, new MessageMaps {ActionText = AuditReportResource.Logout}},

                #endregion

                #region projects
                
                {
                    MessageAction.ProjectCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ProjectCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectCreatedFromTemplate, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ProjectCreatedFromTemplate,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ProjectUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ProjectUpdatedStatus,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ProjectDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectFollowed, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.FollowActionType,
                            ActionText = AuditReportResource.ProjectFollowed,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectUnfollowed, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnfollowActionType,
                            ActionText = AuditReportResource.ProjectUnfollowed,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectExcludedMember, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ProjectExcludedMember,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectUpdatedMembers, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ProjectUpdatedMembers,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectUpdatedMemberRights, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateAccessActionType,
                            ActionText = AuditReportResource.ProjectUpdatedMemberRights,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.MilestoneCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.MilestoneCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.MilestonesModule
                        }
                },
                {
                    MessageAction.MilestoneUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.MilestoneUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.MilestonesModule
                        }
                },
                {
                    MessageAction.MilestoneUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.MilestoneUpdatedStatus,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.MilestonesModule
                        }
                },
                {
                    MessageAction.MilestoneDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.MilestoneDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.MilestonesModule
                        }
                },
                {
                    MessageAction.TaskCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.TaskCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskCreatedFromDiscussion, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.TaskCreatedFromDiscussion,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TaskUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TaskUpdatedStatus,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskMovedToMilestone, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TaskMovedToMilestone,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.TaskDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskUpdatedFollowing, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.FollowActionType,
                            ActionText = AuditReportResource.TaskUpdatedFollowing,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskCommentCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.TaskCommentCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskCommentUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TaskCommentUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskCommentDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.TaskCommentDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TasksLinked, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.TasksLinked,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TasksUnlinked, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.TasksUnlinked,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskAttachedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.TaskAttachedFiles,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskDetachedFile, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DetachActionType,
                            ActionText = AuditReportResource.TaskDetachedFile,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskUnlinkedMilestone, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TaskUnlinkedMilestone,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.SubtaskCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.SubtaskCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.SubtaskUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.SubtaskUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.SubtaskUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.SubtaskUpdatedStatus,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.SubtaskDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.SubtaskDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TasksModule
                        }
                },
                {
                    MessageAction.TaskTimeCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.TaskTimeCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TimeTrackingModule
                        }
                },
                {
                    MessageAction.TaskTimeUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TaskTimeUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TimeTrackingModule
                        }
                },
                {
                    MessageAction.TaskTimesUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TaskTimesUpdatedStatus,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TimeTrackingModule
                        }
                },
                {
                    MessageAction.TaskTimesDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.TaskTimesDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TimeTrackingModule
                        }
                },
                {
                    MessageAction.DiscussionCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.DiscussionCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DiscussionUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.DiscussionDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionUpdatedFollowing, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.FollowActionType,
                            ActionText = AuditReportResource.DiscussionUpdatedFollowing,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionCommentCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.DiscussionCommentCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionCommentUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DiscussionCommentUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionCommentDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.DiscussionCommentDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionAttachedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.DiscussionAttachedFiles,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.DiscussionDetachedFile, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DetachActionType,
                            ActionText = AuditReportResource.DiscussionDetachedFile,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.DiscussionsModule
                        }
                },
                {
                    MessageAction.ProjectTemplateCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ProjectTemplateCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TemplatesModule
                        }
                },
                {
                    MessageAction.ProjectTemplateUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ProjectTemplateUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TemplatesModule
                        }
                },
                {
                    MessageAction.ProjectTemplateDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ProjectTemplateDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.TemplatesModule
                        }
                },
                {
                    MessageAction.ReportTemplateCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ReportTemplateCreated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ReportsModule
                        }
                },
                {
                    MessageAction.ReportTemplateUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ReportTemplateUpdated,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ReportsModule
                        }
                },
                {
                    MessageAction.ReportTemplateDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ReportTemplateDeleted,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ReportsModule
                        }
                },
                {
                    MessageAction.ProjectLinkedCompany, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.ProjectLinkedCompany,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectUnlinkedCompany, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.ProjectUnlinkedCompany,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectLinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.ProjectLinkedPerson,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectUnlinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.ProjectUnlinkedPerson,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectLinkedContacts, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.ProjectLinkedContacts,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },
                {
                    MessageAction.ProjectsImportedFromBasecamp, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ImportActionType,
                            ActionText = AuditReportResource.ProjectsImportedFromBasecamp,
                            Product = AuditReportResource.ProjectsProduct,
                            Module = AuditReportResource.ProjectsModule
                        }
                },

                #endregion

                #region crm

                #region companies

                {
                    MessageAction.CompanyCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CompanyCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompanyUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompanyUpdatedStatus,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUpdatedPersonsStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompanyUpdatedPersonsStatus,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUpdatedPrincipalInfo, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompanyUpdatedPrincipalInfo,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUpdatedPhoto, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompanyUpdatedPhoto,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyLinkedProject, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.CompanyLinkedProject,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUnlinkedProject, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.CompanyUnlinkedProject,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompaniesMerged, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompaniesMerged,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyCreatedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CompanyCreatedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyCreatedPersonsTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CompanyCreatedPersonsTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyDeletedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CompanyDeletedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyCreatedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CompanyCreatedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyDeletedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CompanyDeletedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyLinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.CompanyLinkedPerson,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUnlinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.CompanyUnlinkedPerson,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyUploadedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.CompanyUploadedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyAttachedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.CompanyAttachedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },
                {
                    MessageAction.CompanyDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CompanyDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CompaniesModule
                        }
                },

                #endregion

                #region persons
                
                {
                    MessageAction.PersonCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.PersonCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonsCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.PersonsCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonUpdatedStatus,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonUpdatedCompanyStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonUpdatedCompanyStatus,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonUpdatedPrincipalInfo, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonUpdatedPrincipalInfo,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonUpdatedPhoto, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonUpdatedPhoto,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonLinkedProject, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.PersonLinkedProject,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonUnlinkedProject, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.PersonUnlinkedProject,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonsMerged, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonsMerged,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonCreatedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.PersonCreatedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonCreatedCompanyTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.PersonCreatedCompanyTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonDeletedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.PersonDeletedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonCreatedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.PersonCreatedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonDeletedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.PersonDeletedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonUploadedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.PersonUploadedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonAttachedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.PersonAttachedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },
                {
                    MessageAction.PersonDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.PersonDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.PersonsModule
                        }
                },

                #endregion

                #region contacts
                
                {
                    MessageAction.ContactLinkedProject, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.ContactLinkedProject,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsModule
                        }
                },
                {
                    MessageAction.ContactUnlinkedProject, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.ContactUnlinkedProject,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsModule
                        }
                },
                {
                    MessageAction.ContactsDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ContactsDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsModule
                        }
                },

                #endregion

                #region tasks

                {
                    MessageAction.CrmTaskCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CrmTaskCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },
                {
                    MessageAction.CrmTaskUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmTaskUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },
                {
                    MessageAction.CrmTaskOpened, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmTaskOpened,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },
                {
                    MessageAction.CrmTaskClosed, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmTaskClosed,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },
                {
                    MessageAction.CrmTaskDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CrmTaskDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },
                {
                    MessageAction.ContactsCreatedCrmTasks, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ContactsCreatedCrmTasks,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },

                #endregion

                #region opportunities

                {
                    MessageAction.OpportunityCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.OpportunityCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OpportunityUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityUpdatedStage, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OpportunityUpdatedStage,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityCreatedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.OpportunityCreatedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityDeletedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.OpportunityDeletedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityCreatedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.OpportunityCreatedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityDeletedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.OpportunityDeletedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityLinkedCompany, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.OpportunityLinkedCompany,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityUnlinkedCompany, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.OpportunityUnlinkedCompany,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityLinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.OpportunityLinkedPerson,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityUnlinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.OpportunityUnlinkedPerson,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityUploadedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.OpportunityUploadedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityAttachedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.OpportunityAttachedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityOpenedAccess, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateAccessActionType,
                            ActionText = AuditReportResource.OpportunityOpenedAccess,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityRestrictedAccess, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateAccessActionType,
                            ActionText = AuditReportResource.OpportunityRestrictedAccess,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunityDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.OpportunityDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.OpportunitiesDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.OpportunitiesDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },

                #endregion

                #region cases

                {
                    MessageAction.CaseCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CaseCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CaseUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseOpened, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CaseOpened,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseClosed, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CaseClosed,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseCreatedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CaseCreatedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseDeletedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CaseDeletedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseCreatedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CaseCreatedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseDeletedHistory, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CaseDeletedHistory,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseLinkedCompany, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.CaseLinkedCompany,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseUnlinkedCompany, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.CaseUnlinkedCompany,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseLinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.CaseLinkedPerson,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseUnlinkedPerson, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.CaseUnlinkedPerson,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseUploadedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.CaseUploadedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseAttachedFiles, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.AttachActionType,
                            ActionText = AuditReportResource.CaseAttachedFiles,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseOpenedAccess, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateAccessActionType,
                            ActionText = AuditReportResource.CaseOpenedAccess,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseRestrictedAccess, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateAccessActionType,
                            ActionText = AuditReportResource.CaseRestrictedAccess,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CaseDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CaseDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },
                {
                    MessageAction.CasesDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CasesDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },

                #endregion

                #region import

                {
                    MessageAction.ContactsImportedFromCSV, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ImportActionType,
                            ActionText = AuditReportResource.ContactsImportedFromCSV,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsModule
                        }
                },
                {
                    MessageAction.CrmTasksImportedFromCSV, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ImportActionType,
                            ActionText = AuditReportResource.CrmTasksImportedFromCSV,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },
                {
                    MessageAction.OpportunitiesImportedFromCSV, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ImportActionType,
                            ActionText = AuditReportResource.OpportunitiesImportedFromCSV,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.CasesImportedFromCSV, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ImportActionType,
                            ActionText = AuditReportResource.CasesImportedFromCSV,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },

                #endregion

                #region export

                {
                    MessageAction.ContactsExportedToCsv, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ExportActionType,
                            ActionText = AuditReportResource.ContactsExportedToCsv,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsModule
                        }
                },
                {
                    MessageAction.CrmTasksExportedToCsv, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ExportActionType,
                            ActionText = AuditReportResource.CrmTasksExportedToCsv,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmTasksModule
                        }
                },
                {
                    MessageAction.OpportunitiesExportedToCsv, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ExportActionType,
                            ActionText = AuditReportResource.OpportunitiesExportedToCsv,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OpportunitiesModule
                        }
                },
                {
                    MessageAction.CasesExportedToCsv, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ExportActionType,
                            ActionText = AuditReportResource.CasesExportedToCsv,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CasesModule
                        }
                },

                #endregion

                #region common settings

                {
                    MessageAction.CrmSmtpSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmSmtpSettingsUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CommonCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmTestMailSent, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.SendActionType,
                            ActionText = AuditReportResource.CrmTestMailSent,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CommonCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmDefaultCurrencyUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmDefaultCurrencyUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CommonCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmAllDataExported, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ExportActionType,
                            ActionText = AuditReportResource.CrmAllDataExported,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CommonCrmSettingsModule
                        }
                },
                {
                    MessageAction.ContactsTemperatureLevelSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactsTemperatureLevelSettingsUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CommonCrmSettingsModule
                        }
                },
                {
                    MessageAction.ContactsTagSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactsTagSettingsUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CommonCrmSettingsModule
                        }
                },

                #endregion

                #region contact settings

                {
                    MessageAction.ContactsTemperatureLevelCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ContactsTemperatureLevelCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsSettingsModule
                        }
                },
                {
                    MessageAction.ContactsTemperatureLevelUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactsTemperatureLevelUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsSettingsModule
                        }
                },
                {
                    MessageAction.ContactsTemperatureLevelUpdatedColor, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactsTemperatureLevelUpdatedColor,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsSettingsModule
                        }
                },
                {
                    MessageAction.ContactsTemperatureLevelsUpdatedOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactsTemperatureLevelsUpdatedOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsSettingsModule
                        }
                },
                {
                    MessageAction.ContactsTemperatureLevelDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ContactsTemperatureLevelDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactsSettingsModule
                        }
                },
                {
                    MessageAction.ContactTypeCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ContactTypeCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactTypesModule
                        }
                },
                {
                    MessageAction.ContactTypeUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactTypeUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactTypesModule
                        }
                },
                {
                    MessageAction.ContactTypesUpdatedOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactTypesUpdatedOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactTypesModule
                        }
                },
                {
                    MessageAction.ContactTypeDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ContactTypeDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.ContactTypesModule
                        }
                },

                #endregion

                #region user fields settings

                {
                    MessageAction.ContactsCreatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ContactsCreatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.ContactsUpdatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactsUpdatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.ContactsUpdatedUserFieldsOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ContactsUpdatedUserFieldsOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.ContactsDeletedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ContactsDeletedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.PersonsCreatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.PersonsCreatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.PersonsUpdatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonsUpdatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.PersonsUpdatedUserFieldsOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PersonsUpdatedUserFieldsOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.PersonsDeletedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.PersonsDeletedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CompaniesCreatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CompaniesCreatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CompaniesUpdatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompaniesUpdatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CompaniesUpdatedUserFieldsOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CompaniesUpdatedUserFieldsOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CompaniesDeletedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CompaniesDeletedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunitiesCreatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.OpportunitiesCreatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunitiesUpdatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OpportunitiesUpdatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunitiesUpdatedUserFieldsOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OpportunitiesUpdatedUserFieldsOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunitiesDeletedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.OpportunitiesDeletedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CasesCreatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CasesCreatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CasesUpdatedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CasesUpdatedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CasesUpdatedUserFieldsOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CasesUpdatedUserFieldsOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CasesDeletedUserField, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CasesDeletedUserField,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },

                #endregion

                #region history categories settings

                {
                    MessageAction.HistoryCategoryCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.HistoryCategoryCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.HistoryCategoryUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.HistoryCategoryUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.HistoryCategoryUpdatedIcon, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.HistoryCategoryUpdatedIcon,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.HistoryCategoriesUpdatedOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.HistoryCategoriesUpdatedOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.HistoryCategoryDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.HistoryCategoryDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },

                #endregion

                #region task actegories settings

                {
                    MessageAction.CrmTaskCategoryCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CrmTaskCategoryCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmTaskCategoryUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmTaskCategoryUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmTaskCategoryUpdatedIcon, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmTaskCategoryUpdatedIcon,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmTaskCategoriesUpdatedOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.CrmTaskCategoriesUpdatedOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmTaskCategoryDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CrmTaskCategoryDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },

                #endregion

                #region opportunity stages settings

                {
                    MessageAction.OpportunityStageCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.OpportunityStageCreated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunityStageUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OpportunityStageUpdated,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunityStageUpdatedColor, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OpportunityStageUpdatedColor,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunityStagesUpdatedOrder, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OpportunityStagesUpdatedOrder,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunityStageDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.OpportunityStageDeleted,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },

                #endregion

                #region tags settings

                {
                    MessageAction.ContactsCreatedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ContactsCreatedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.ContactsDeletedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ContactsDeletedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunitiesCreatedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.OpportunitiesCreatedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.OpportunitiesDeletedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.OpportunitiesDeletedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CasesCreatedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.CasesCreatedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CasesDeletedTag, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.CasesDeletedTag,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },

                #endregion

                {
                    MessageAction.WebsiteContactFormUpdatedKey, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.WebsiteContactFormUpdatedKey,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.OtherCrmSettingsModule
                        }
                },
                {
                    MessageAction.CrmEntityDetachedFile, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DetachActionType,
                            ActionText = AuditReportResource.CrmEntityDetachedFile,
                            Product = AuditReportResource.CrmProduct,
                            Module = AuditReportResource.CrmFilesModule
                        }
                },

                #endregion

                #region people
                
                {
                    MessageAction.UserCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.UserCreated,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },                
                {
                    MessageAction.GuestCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.GuestCreated,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UserUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UserUpdated,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UserUpdatedAvatar, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UserUpdatedAvatar,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UserSentActivationInstructions, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.SendActionType,
                            ActionText = AuditReportResource.UserSentActivationInstructions,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UserSentPasswordInstructions, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.SendActionType,
                            ActionText = AuditReportResource.UserSentPasswordInstructions,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UserSentEmailInstructions, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.SendActionType,
                            ActionText = AuditReportResource.UserSentEmailInstructions,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UserDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.UserDeleted,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UsersUpdatedType, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UsersUpdatedType,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UsersUpdatedStatus, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UsersUpdatedStatus,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UsersSentActivationInstructions, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.SendActionType,
                            ActionText = AuditReportResource.UsersSentActivationInstructions,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.UsersDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.UsersDeleted,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },
                {
                    MessageAction.GroupCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.GroupCreated,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.GroupsModule
                        }
                },
                {
                    MessageAction.GroupUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.GroupUpdated,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.GroupsModule
                        }
                },
                {
                    MessageAction.GroupDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.GroupDeleted,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.GroupsModule
                        }
                },                
                {
                    MessageAction.UserUpdatedPassword, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UserUpdatedPassword,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },                
                {
                    MessageAction.UserLinkedSocialAccount, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.LinkActionType,
                            ActionText = AuditReportResource.UserLinkedSocialAccount,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },               
                {
                    MessageAction.UserUnlinkedSocialAccount, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UnlinkActionType,
                            ActionText = AuditReportResource.UserUnlinkedSocialAccount,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },                
                {
                    MessageAction.UserUpdatedLanguage, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UserUpdatedLanguage,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },                
                {
                    MessageAction.UserActivatedEmail, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UserActivatedEmail,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },                
                {
                    MessageAction.UserUpdatedAvatarThumbnails, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.UserUpdatedAvatarThumbnails,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },                
                {
                    MessageAction.UserSentDeleteInstructions, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.SendActionType,
                            ActionText = AuditReportResource.UserSentDeleteInstructions,
                            Product = AuditReportResource.PeopleProduct,
                            Module = AuditReportResource.UsersModule
                        }
                },

                #endregion

                #region documents
                
                {
                    MessageAction.FolderCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.FolderCreated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FolderRenamed, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.FolderRenamed,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FolderUpdatedAccess, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateAccessActionType,
                            ActionText = AuditReportResource.FolderUpdatedAccess,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FileCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.FileCreated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileRenamed, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.FileRenamed,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.FileUpdated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileCreatedVersion, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.FileCreatedVersion,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileUpdatedToVersion, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.FileUpdatedToVersion,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileDeletedVersion, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.FileDeletedVersion,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileUpdatedRevisionComment, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.FileUpdatedRevisionComment,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileLocked, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.FileLocked,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileUnlocked, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.FileUnlocked,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileUpdatedAccess, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateAccessActionType,
                            ActionText = AuditReportResource.FileUpdatedAccess,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileDownloaded, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DownloadActionType,
                            ActionText = AuditReportResource.FileDownloaded,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileDownloadedAs, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DownloadActionType,
                            ActionText = AuditReportResource.FileDownloadedAs,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.DocumentsDownloaded, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DownloadActionType,
                            ActionText = AuditReportResource.DocumentsDownloaded,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsModule
                        }
                },
                {
                    MessageAction.DocumentsCopied, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CopyActionType,
                            ActionText = AuditReportResource.DocumentsCopied,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsModule
                        }
                },
                {
                    MessageAction.DocumentsMoved, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DocumentsMoved,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsModule
                        }
                },
                {
                    MessageAction.DocumentsDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.DocumentsDeleted,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsModule
                        }
                },
                {
                    MessageAction.TrashCleaned, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.TrashCleaned,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsModule
                        }
                },
                {
                    MessageAction.FileMovedToTrash, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.MoveActionType,
                            ActionText = AuditReportResource.FileMovedToTrash,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.FileDeleted,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FolderMovedToTrash, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.MoveActionType,
                            ActionText = AuditReportResource.FolderMovedToTrash,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FolderDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.FolderDeleted,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FileCopied, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CopyActionType,
                            ActionText = AuditReportResource.FileCopied,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileCopiedWithOverwriting, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CopyActionType,
                            ActionText = AuditReportResource.FileCopiedWithOverwriting,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileMoved, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.MoveActionType,
                            ActionText = AuditReportResource.FileMoved,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileMovedWithOverwriting, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.MoveActionType,
                            ActionText = AuditReportResource.FileMovedWithOverwriting,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FolderCopied, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CopyActionType,
                            ActionText = AuditReportResource.FolderCopied,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FolderCopiedWithOverwriting, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CopyActionType,
                            ActionText = AuditReportResource.FolderCopiedWithOverwriting,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FolderMoved, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.MoveActionType,
                            ActionText = AuditReportResource.FolderMoved,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FolderMovedWithOverwriting, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.MoveActionType,
                            ActionText = AuditReportResource.FolderMovedWithOverwriting,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FoldersModule
                        }
                },
                {
                    MessageAction.FilesImportedFromBoxNet, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.FilesImportedFromBoxNet,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FilesImportedFromGoogleDocs, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.FilesImportedFromGoogleDocs,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FilesImportedFromZoho, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.FilesImportedFromZoho,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.FileImported, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.ImportActionType,
                            ActionText = AuditReportResource.FileImported,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.DocumentsThirdPartySettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DocumentsThirdPartySettingsUpdated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsSettingsModule
                        }
                },
                {
                    MessageAction.DocumentsOverwritingSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DocumentsOverwritingSettingsUpdated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsSettingsModule
                        }
                },
                {
                    MessageAction.DocumentsUploadingFormatsSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DocumentsUploadingFormatsSettingsUpdated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsSettingsModule
                        }
                },
                {
                    MessageAction.FileUploaded, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UploadActionType,
                            ActionText = AuditReportResource.FileUploaded,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.FilesModule
                        }
                },
                {
                    MessageAction.ThirdPartyCreated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.ThirdPartyCreated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsSettingsModule
                        }
                },
                {
                    MessageAction.ThirdPartyUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ThirdPartyUpdated,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsSettingsModule
                        }
                },
                {
                    MessageAction.ThirdPartyDeleted, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.DeleteActionType,
                            ActionText = AuditReportResource.ThirdPartyDeleted,
                            Product = AuditReportResource.DocumentsProduct,
                            Module = AuditReportResource.DocumentsSettingsModule
                        }
                },

                #endregion

                #region settings

                {
                    MessageAction.LanguageSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.LanguageSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.TimeZoneSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TimeZoneSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.DnsSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DnsSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.TrustedMailDomainSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TrustedMailDomainSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.PasswordStrengthSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.PasswordStrengthSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.TwoFactorAuthenticationSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.TwoFactorAuthenticationSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.AdministratorMessageSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.AdministratorMessageSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.DefaultStartPageSettingsUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.DefaultStartPageSettingsUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.GeneralModule
                        }
                },
                {
                    MessageAction.ProductsListUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.ProductsListUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.ProductsModule
                        }
                },
                {
                    MessageAction.OwnerUpdated, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.OwnerUpdated,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.ProductsModule
                        }
                },
                {
                    MessageAction.AdministratorUpdatedProductAccess, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.UpdateActionType,
                            ActionText = AuditReportResource.AdministratorUpdatedProductAccess,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.ProductsModule
                        }
                },
                {
                    MessageAction.AdministratorAdded, new MessageMaps
                        {
                            ActionTypeText = AuditReportResource.CreateActionType,
                            ActionText = AuditReportResource.AdministratorAdded,
                            Product = AuditReportResource.SettingsProduct,
                            Module = AuditReportResource.ProductsModule
                        }
                },

                #endregion
            };

        public static string GetActionText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            if (!actions.ContainsKey(action))
                throw new ArgumentException(string.Format("There is no action text for \"{0}\" type of event", action));

            var text = actions[(MessageAction)evt.Action].ActionText;

            return evt.Ids == null || !evt.Ids.Any()
                       ? text
                       : string.Format(text, evt.Ids.Select(GetLimitedText).ToArray());
        }

        public static string GetActionText(LoginEvent evt)
        {
            var action = (MessageAction)evt.Action;
            if (!actions.ContainsKey(action))
                throw new ArgumentException(string.Format("There is no action text for \"{0}\" type of event", action));

            var text = actions[(MessageAction)evt.Action].ActionText;

            return evt.Ids == null || !evt.Ids.Any()
                       ? text
                       : string.Format(text, evt.Ids.Select(GetLimitedText).ToArray());
        }

        public static string GetActionTypeText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            return !actions.ContainsKey(action)
                       ? string.Empty
                       : actions[(MessageAction)evt.Action].ActionTypeText;
        }

        public static string GetProductText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            return !actions.ContainsKey(action)
                       ? string.Empty
                       : actions[(MessageAction)evt.Action].Product;
        }

        public static string GetModuleText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            return !actions.ContainsKey(action)
                       ? string.Empty
                       : actions[(MessageAction)evt.Action].Module;
        }

        private static string GetLimitedText(string text)
        {
            if (text == null) throw new ArgumentException("text");
            return text.Length < 50 ? text : string.Format("[{0}...]", text.Substring(0, 47));
        }

        private class MessageMaps
        {
            public string ActionTypeText { get; set; }
            public string ActionText { get; set; }
            public string Product { get; set; }
            public string Module { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/contacts/filter/tlfilter.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.tlFilter = (function($) {
    var isInit = false;
    var filter;
    var events = $({});

    var init = function() {
        if (!isInit) {
            isInit = true;

            $('#tlFilter').advansedFilter({
                anykey: true,
                anykeytimeout: 1000,
                maxfilters: -1,
                hintDefaultDisable: false,
                sorters: [
                    { id: 'firstname', title: ASC.Resources.Master.ResourceJS.FirstName, sortOrder: 'ascending', def: ASC.Mail.Master.userDisplayFormat == 1 },
                    { id: 'lastname', title: ASC.Resources.Master.ResourceJS.LastName, sortOrder: 'ascending', def: ASC.Mail.Master.userDisplayFormat == 2 }
                ],
                filters: [
                    {
                        type: "combobox",
                        id: "group",
                        apiparamname: "group",
                        title: Encoder.htmlDecode(ASC.Mail.Constants.FiLTER_BY_GROUP_LOCALIZE),
                        group: MailScriptResource.FilterShowGroup,
                        options: [],
                        defaulttitle: MailScriptResource.FilterChoose
                    }
                ]
            }).bind('setfilter', onSetFilter).bind('resetfilter', onResetFilter).bind('resetallfilters', onResetAllFilters);

            // filter object initialization should follow after advanced filter plugin call - because
            // its replace target element with new markup
            filter = $('#tlFilter');

            tlGroups.events.bind('update', onUpdateGroups);
        }
    };

    var onSetFilter = function(evt, $container, filterItem, value, selectedfilters) {
        events.trigger('set', [filterItem, value, selectedfilters]);
    };

    var onResetFilter = function(evt, $container, filterItem, selectedfilters) {
        events.trigger('reset', [filterItem, selectedfilters]);
    };

    var onResetAllFilters = function(evt, $container, filterid, selectedfilters) {
        events.trigger('resetall', [selectedfilters]);
    };

    var show = function() {
        filter.parent().show();
    };

    var hide = function() {
        filter.parent().hide();
    };

    var update = function() {
        filter.advansedFilter('resize');
        tlGroups.update();
    };

    var onUpdateGroups = function() {
        var groups = [];
        $.each(tlGroups.getGroups(), function(index, value) {
            groups.push({ value: value.id, classname: '', title: value.name });
        });
        filter.advansedFilter({ filters: [{ type: 'combobox', id: 'group', options: groups, enable: groups.length > 0 }] });
        events.trigger('ready');
    };

    var clear = function() {
        filter.advansedFilter(null);
    };

    var setGroup = function(value) {
        filter.advansedFilter({ filters: [{ type: 'combobox', id: 'group', params: { value: value } }] });
    };

    var setSearch = function(text) {
        filter.advansedFilter({ filters: [{ type: 'text', id: 'text', params: { value: text } }] });
    };

    var setSort = function(sort, order) {
        filter.advansedFilter({ sorters: [{ id: sort, selected: true, dsc: 'descending' == order }] });
    };

    return {
        init: init,

        clear: clear,
        update: update,

        show: show,
        hide: hide,

        setGroup: setGroup,
        setSearch: setSearch,
        setSort: setSort,

        events: events
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileStorageServiceController.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Text;
using System.Web;
using System.Web.Http;

using ASC.Core;
using ASC.Core.Users;
using ASC.Data.Storage;
using ASC.ElasticSearch;
using ASC.FederatedLogin.LoginProviders;
using ASC.Files.Core;
using ASC.Files.Core.Security;
using ASC.MessagingSystem;
using ASC.Web.Core.Files;
using ASC.Web.Core.Users;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Core.Compress;
using ASC.Web.Files.Core.Entries;
using ASC.Web.Files.Core.Search;
using ASC.Web.Files.Helpers;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Services.DocumentService;
using ASC.Web.Files.Services.NotifyService;
using ASC.Web.Files.Services.WCFService.FileOperations;
using ASC.Web.Files.ThirdPartyApp;
using ASC.Web.Files.Utils;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

using Newtonsoft.Json.Linq;

using File = ASC.Files.Core.File;
using FileShare = ASC.Files.Core.Security.FileShare;
using SecurityContext = ASC.Core.SecurityContext;
using UrlShortener = ASC.Web.Core.Utility.UrlShortener;

namespace ASC.Web.Files.Services.WCFService
{
    [Authorize]
    [FileExceptionFilter]
    public class FileStorageServiceController : ApiController, IFileStorageService
    {
        private static readonly FileOperationsManager fileOperations = new FileOperationsManager();
        private static readonly FileEntrySerializer serializer = new FileEntrySerializer();

        #region Folder Manager

        [ActionName("folders-folder"), HttpGet]
        public Folder GetFolder(String folderId)
        {
            using (var folderDao = GetFolderDao())
            {
                var folder = folderDao.GetFolder(folderId);

                ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound);
                ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ReadFolder);

                return folder;
            }
        }

        [ActionName("folders-subfolders"), HttpGet]
        public ItemList<Folder> GetFolders(String parentId)
        {
            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                try
                {
                    int total;
                    var folders = EntryManager.GetEntries(folderDao, fileDao, folderDao.GetFolder(parentId), 0, 0, FilterType.FoldersOnly, false, Guid.Empty, string.Empty, false, false, new OrderBy(SortedByType.AZ, true), out total);
                    return new ItemList<Folder>(folders.OfType<Folder>());
                }
                catch (Exception e)
                {
                    throw GenerateException(e);
                }
            }
        }

        [ActionName("folders-path"), HttpGet]
        public ItemList<object> GetPath(String folderId)
        {
            using (var folderDao = GetFolderDao())
            {
                var folder = folderDao.GetFolder(folderId);

                ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound);
                ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder);

                return new ItemList<object>(EntryManager.GetBreadCrumbs(folderId, folderDao).Select(f => f.ID));
            }
        }

        public DataWrapper GetFolderItems(String parentId, int from, int count, FilterType filter, bool subjectGroup, String ssubject, String searchText, bool searchInContent, bool withSubfolders, OrderBy orderBy)
        {
            var subjectId = string.IsNullOrEmpty(ssubject) ? Guid.Empty : new Guid(ssubject);

            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                Folder parent = null;
                try
                {
                    parent = folderDao.GetFolder(parentId);
                    if (parent != null && !string.IsNullOrEmpty(parent.Error)) throw new Exception(parent.Error);
                }
                catch (Exception e)
                {
                    if (parent != null && parent.ProviderEntry)
                    {
                        throw GenerateException(new Exception(FilesCommonResource.ErrorMassage_SharpBoxException, e));
                    }
                    throw GenerateException(e);
                }

                ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound);
                ErrorIf(!FileSecurity.CanRead(parent), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder);
                ErrorIf(parent.RootFolderType == FolderType.TRASH && !Equals(parent.ID, Global.FolderTrash), FilesCommonResource.ErrorMassage_ViewTrashItem);

                if (orderBy != null)
                {
                    FilesSettings.DefaultOrder = orderBy;
                }
                else
                {
                    orderBy = FilesSettings.DefaultOrder;
                }
                if (Equals(parent.ID, Global.FolderShare) && orderBy.SortedBy == SortedByType.DateAndTime)
                    orderBy.SortedBy = SortedByType.New;

                int total;
                IEnumerable<FileEntry> entries;
                try
                {
                    entries = EntryManager.GetEntries(folderDao, fileDao, parent, from, count, filter, subjectGroup, subjectId, searchText, searchInContent, withSubfolders, orderBy, out total);
                }
                catch (Exception e)
                {
                    if (parent.ProviderEntry)
                    {
                        throw GenerateException(new Exception(FilesCommonResource.ErrorMassage_SharpBoxException, e));
                    }
                    throw GenerateException(e);
                }

                var breadCrumbs = EntryManager.GetBreadCrumbs(parentId, folderDao);

                var prevVisible = breadCrumbs.ElementAtOrDefault(breadCrumbs.Count() - 2);
                if (prevVisible != null)
                {
                    parent.ParentFolderID = prevVisible.ID;
                }

                parent.Shareable = FileSharing.CanSetAccess(parent)
                    || parent.FolderType == FolderType.SHARE
                    || parent.RootFolderType == FolderType.Privacy;

                entries = entries.Where(x => x.FileEntryType == FileEntryType.Folder || !FileConverter.IsConverting((File)x));

                var result = new DataWrapper
                {
                    Total = total,
                    Entries = new ItemList<FileEntry>(entries.ToList()),
                    FolderPathParts = new ItemList<object>(breadCrumbs.Select(f => f.ID)),
                    FolderInfo = parent,
                    RootFoldersIdMarkedAsNew = FileMarker.GetRootFoldersIdMarkedAsNew()
                };

                return result;
            }
        }

        [ActionName("folders"), HttpPost]
        public object GetFolderItemsXml(String parentId, int from, int count, FilterType filter, bool subjectGroup, String subjectID, String search, bool searchInContent, bool withSubfolders, [FromBody] OrderBy orderBy)
        {
            var folderItems = GetFolderItems(parentId, from, count, filter, subjectGroup, subjectID, search, searchInContent, withSubfolders, orderBy);
            var response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StreamContent(serializer.ToXml(folderItems))
            };
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
            return response;
        }

        [ActionName("folders-entries"), HttpPost]
        public ItemList<FileEntry> GetItems([FromBody] ItemList<String> items, FilterType filter, bool subjectGroup, String subjectID, String search)
        {
            List<object> filesId;
            List<object> foldersId;
            ParseArrayItems(items, out foldersId, out filesId);

            var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID);

            var entries = Enumerable.Empty<FileEntry>();

            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                var folders = folderDao.GetFolders(foldersId.ToArray()).Cast<FileEntry>();
                folders = FileSecurity.FilterRead(folders);
                entries = entries.Concat(folders);

                var files = fileDao.GetFiles(filesId.ToArray()).Cast<FileEntry>();
                files = FileSecurity.FilterRead(files);
                entries = entries.Concat(files);

                entries = EntryManager.FilterEntries(entries, filter, subjectGroup, subjectId, search, true);

                foreach (var fileEntry in entries)
                {
                    if (fileEntry.RootFolderType == FolderType.USER
                        && !Equals(fileEntry.RootFolderCreator, SecurityContext.CurrentAccount.ID)
                        && !Global.GetFilesSecurity().CanRead(folderDao.GetFolder(fileEntry.FolderIdDisplay)))
                        fileEntry.FolderIdDisplay = Global.FolderShare;
                }
            }

            EntryManager.SetFileStatus(entries.OfType<File>().Where(r => r.ID != null).ToList());

            return new ItemList<FileEntry>(entries);
        }

        [ActionName("folders-create"), HttpGet]
        public Folder CreateNewFolder(String parentId, String title)
        {
            if (string.IsNullOrEmpty(title) || String.IsNullOrEmpty(parentId)) throw new ArgumentException();

            using (var folderDao = GetFolderDao())
            {
                var parent = folderDao.GetFolder(parentId);
                ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound);
                ErrorIf(!FileSecurity.CanCreate(parent), FilesCommonResource.ErrorMassage_SecurityException_Create);

                try
                {
                    var folderId = folderDao.SaveFolder(new Folder { Title = title, ParentFolderID = parent.ID });
                    var folder = folderDao.GetFolder(folderId);
                    FilesMessageService.Send(folder, GetHttpHeaders(), MessageAction.FolderCreated, folder.Title);

                    return folder;
                }
                catch (Exception e)
                {
                    throw GenerateException(e);
                }
            }
        }

        [ActionName("folders-rename"), HttpGet]
        public Folder FolderRename(String folderId, String title)
        {
            using (var tagDao = GetTagDao())
            using (var folderDao = GetFolderDao())
            {
                var folder = folderDao.GetFolder(folderId);
                ErrorIf(folder == null, FilesCommonResource.ErrorMassage_FolderNotFound);
                ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException_RenameFolder);
                if (!Global.GetFilesSecurity().CanDelete(folder) && CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor()) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_RenameFolder);
                ErrorIf(folder.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem);

                var folderAccess = folder.Access;

                if (String.Compare(folder.Title, title, false) != 0)
                {
                    var newFolderID = folderDao.RenameFolder(folder, title);
                    folder = folderDao.GetFolder(newFolderID);
                    folder.Access = folderAccess;

                    FilesMessageService.Send(folder, GetHttpHeaders(), MessageAction.FolderRenamed, folder.Title);

                    if (!folder.ProviderEntry)
                    {
                        FactoryIndexer<FoldersWrapper>.IndexAsync(folder);
                    }
                }

                var tag = tagDao.GetNewTags(SecurityContext.CurrentAccount.ID, folder).FirstOrDefault();
                if (tag != null)
                {
                    folder.NewForMe = tag.Count;
                }

                if (folder.RootFolderType == FolderType.USER
                    && !Equals(folder.RootFolderCreator, SecurityContext.CurrentAccount.ID)
                    && !Global.GetFilesSecurity().CanRead(folderDao.GetFolder(folder.ParentFolderID)))
                    folder.FolderIdDisplay = Global.FolderShare;

                return folder;
            }
        }

        #endregion

        #region File Manager

        [ActionName("folders-files-getversion"), HttpGet]
        public File GetFile(String fileId, int version)
        {
            using (var fileDao = GetFileDao())
            {
                fileDao.InvalidateCache(fileId);

                var file = version > 0
                               ? fileDao.GetFile(fileId, version)
                               : fileDao.GetFile(fileId);
                ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
                ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);

                EntryManager.SetFileStatus(file);

                if (file.RootFolderType == FolderType.USER
                    && !Equals(file.RootFolderCreator, SecurityContext.CurrentAccount.ID))
                {
                    using (var folderDao = GetFolderDao())
                    {
                        if (!Global.GetFilesSecurity().CanRead(folderDao.GetFolder(file.FolderID)))
                            file.FolderIdDisplay = Global.FolderShare;
                    }
                }

                return file;
            }
        }

        [ActionName("folders-files-siblings"), HttpPost]
        public ItemList<File> GetSiblingsFile(String fileId, String parentId, FilterType filter, bool subjectGroup, String subjectID, String search, bool searchInContent, bool withSubfolders, [FromBody] OrderBy orderBy)
        {
            var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID);

            using (var fileDao = GetFileDao())
            using (var folderDao = GetFolderDao())
            {
                var file = fileDao.GetFile(fileId);
                ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
                ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);

                var parent = folderDao.GetFolder(string.IsNullOrEmpty(parentId) ? file.FolderID : parentId);
                ErrorIf(parent == null, FilesCommonResource.ErrorMassage_FolderNotFound);
                ErrorIf(parent.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem);

                if (filter == FilterType.FoldersOnly)
                {
                    return new ItemList<File>();
                }
                if (filter == FilterType.None)
                {
                    filter = FilterType.FilesOnly;
                }

                if (orderBy == null)
                {
                    orderBy = FilesSettings.DefaultOrder;
                }
                if (Equals(parent.ID, Global.FolderShare) && orderBy.SortedBy == SortedByType.DateAndTime)
                {
                    orderBy.SortedBy = SortedByType.New;
                }

                var entries = Enumerable.Empty<FileEntry>();

                if (!FileSecurity.CanRead(parent))
                {
                    file.FolderID = Global.FolderShare;
                    entries = entries.Concat(new[] { file });
                }
                else
                {
                    try
                    {
                        int total;
                        entries = EntryManager.GetEntries(folderDao, fileDao, parent, 0, 0, filter, subjectGroup, subjectId, search, searchInContent, withSubfolders, orderBy, out total);
                    }
                    catch (Exception e)
                    {
                        if (parent.ProviderEntry)
                        {
                            throw GenerateException(new Exception(FilesCommonResource.ErrorMassage_SharpBoxException, e));
                        }
                        throw GenerateException(e);
                    }
                }

                var previewedType = new[] { FileType.Image, FileType.Audio, FileType.Video };

                var result =
                    FileSecurity.FilterRead(entries)
                                .OfType<File>()
                                .Where(f => previewedType.Contains(FileUtility.GetFileTypeByFileName(f.Title)));

                return new ItemList<File>(result);
            }
        }

        [ActionName("folders-files-createfile"), HttpGet]
        public File CreateNewFile(String parentId, String title, String templateId)
        {
            using (var fileDao = GetFileDao())
            using (var folderDao = GetFolderDao())
            {
                Folder folder = null;
                if (!string.IsNullOrEmpty(parentId))
                {
                    folder = folderDao.GetFolder(parentId);

                    if (!FileSecurity.CanCreate(folder))
                    {
                        folder = null;
                    }
                }
                if (folder == null)
                {
                    folder = folderDao.GetFolder(Global.FolderMy);
                }

                var file = new File
                {
                    FolderID = folder.ID,
                    Comment = FilesCommonResource.CommentCreate,
                };

                if (string.IsNullOrEmpty(title))
                {
                    title = UserControlsCommonResource.NewDocument + ".docx";
                }

                var fileExt = FileUtility.GetInternalExtension(title);
                if (!FileUtility.InternalExtension.Values.Contains(fileExt))
                {
                    fileExt = FileUtility.InternalExtension[FileType.Document];
                    file.Title = title + fileExt;
                }
                else
                {
                    file.Title = FileUtility.ReplaceFileExtension(title, fileExt);
                }

                if (string.IsNullOrEmpty(templateId))
                {
                    var culture = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).GetCulture();
                    var storeTemplate = GetStoreTemplate();

                    var path = FileConstant.NewDocPath + culture + "/";
                    if (!storeTemplate.IsDirectory(path))
                    {
                        path = FileConstant.NewDocPath + "en-US/";
                    }

                    try
                    {
                        var pathNew = path + "new" + fileExt;
                        using (var stream = storeTemplate.GetReadStream("", pathNew))
                        {
                            file.ContentLength = stream.CanSeek ? stream.Length : storeTemplate.GetFileSize(pathNew);
                            file = fileDao.SaveFile(file, stream);
                        }

                        var pathThumb = path + fileExt.Trim('.') + "." + Global.ThumbnailExtension;
                        if (storeTemplate.IsFile("", pathThumb))
                        {
                            using (var streamThumb = storeTemplate.GetReadStream("", pathThumb))
                            {
                                fileDao.SaveThumbnail(file, streamThumb);
                            }
                            file.ThumbnailStatus = Thumbnail.Created;
                        }
                    }
                    catch (Exception e)
                    {
                        throw GenerateException(e);
                    }
                }
                else
                {
                    var template = fileDao.GetFile(templateId);
                    ErrorIf(template == null, FilesCommonResource.ErrorMassage_FileNotFound);
                    ErrorIf(!FileSecurity.CanRead(template), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);

                    try
                    {
                        using (var stream = fileDao.GetFileStream(template))
                        {
                            file.ContentLength = template.ContentLength;
                            file = fileDao.SaveFile(file, stream);
                        }

                        if (template.ThumbnailStatus == Thumbnail.Created)
                        {
                            using (var thumb = fileDao.GetThumbnail(template))
                            {
                                fileDao.SaveThumbnail(file, thumb);
                            }
                            file.ThumbnailStatus = Thumbnail.Created;
                        }
                    }
                    catch (Exception e)
                    {
                        throw GenerateException(e);
                    }
                }

                FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileCreated, file.Title);

                FileMarker.MarkAsNew(file);

                return file;
            }
        }

        [ActionName("trackeditfile"), HttpGet, AllowAnonymous]
        public KeyValuePair<bool, String> TrackEditFile(String fileId, Guid tabId, String docKeyForTrack, String doc = null, bool isFinish = false)
        {
            try
            {
                var id = FileShareLink.Parse(doc);
                if (string.IsNullOrEmpty(id))
                {
                    if (!SecurityContext.IsAuthenticated) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);
                    if (!string.IsNullOrEmpty(doc)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);
                    id = fileId;
                }

                if (docKeyForTrack != DocumentServiceHelper.GetDocKey(id, -1, DateTime.MinValue)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

                if (isFinish)
                {
                    FileTracker.Remove(id, tabId);
                    Global.SocketManager.FilesChangeEditors(id, true);
                }
                else
                {
                    EntryManager.TrackEditing(id, tabId, SecurityContext.CurrentAccount.ID, doc);
                }

                return new KeyValuePair<bool, string>(true, string.Empty);
            }
            catch (Exception ex)
            {
                return new KeyValuePair<bool, string>(false, ex.Message);
            }
        }

        [ActionName("checkediting"), HttpPost]
        public ItemDictionary<String, String> CheckEditing([FromBody] ItemList<String> filesId)
        {
            ErrorIf(!SecurityContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException);
            var result = new ItemDictionary<string, string>();

            using (var fileDao = GetFileDao())
            {
                var ids = filesId.Where(FileTracker.IsEditing).Select(id => (object)id).ToArray();

                foreach (var file in fileDao.GetFiles(ids))
                {
                    if (file == null
                        || !FileSecurity.CanEdit(file)
                            && !FileSecurity.CanCustomFilterEdit(file)
                            && !FileSecurity.CanReview(file)
                            && !FileSecurity.CanFillForms(file)
                            && !FileSecurity.CanComment(file)) continue;

                    var usersId = FileTracker.GetEditingBy(file.ID);
                    var value = string.Join(", ", usersId.Select(userId => Global.GetUserName(userId, true)).ToArray());
                    result[file.ID.ToString()] = value;
                }
            }

            return result;
        }

        public File SaveEditing(String fileId, string fileExtension, string fileuri, Stream stream, String doc = null, bool forcesave = false)
        {
            try
            {
                if (!forcesave && FileTracker.IsEditingAlone(fileId))
                {
                    FileTracker.Remove(fileId);
                }

                var file = EntryManager.SaveEditing(fileId, fileExtension, fileuri, stream, doc, forcesave: forcesave ? ForcesaveType.User : ForcesaveType.None);

                if (file != null)
                    FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdated, file.Title);

                Global.SocketManager.FilesChangeEditors(fileId, !forcesave);
                return file;
            }
            catch (Exception e)
            {
                throw GenerateException(e);
            }
        }

        public File UpdateFileStream(String fileId, Stream stream, bool encrypted, bool forcesave)
        {
            try
            {
                if (!forcesave && FileTracker.IsEditing(fileId))
                {
                    FileTracker.Remove(fileId);
                }

                var file = EntryManager.SaveEditing(fileId,
                    null,
                    null,
                    stream,
                    null,
                    encrypted ? FilesCommonResource.CommentEncrypted : null,
                    encrypted: encrypted,
                    forcesave: forcesave ? ForcesaveType.User : ForcesaveType.None);

                if (file != null)
                    FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdated, file.Title);

                Global.SocketManager.FilesChangeEditors(fileId, true);
                return file;
            }
            catch (Exception e)
            {
                throw GenerateException(e);
            }
        }

        [ActionName("startedit"), HttpGet, AllowAnonymous]
        public string StartEdit(String fileId, bool editingAlone = false, String doc = null)
        {
            try
            {
                IThirdPartyApp app;
                if (editingAlone)
                {
                    ErrorIf(FileTracker.IsEditing(fileId), FilesCommonResource.ErrorMassage_SecurityException_EditFileTwice);

                    app = ThirdPartySelector.GetAppByFileId(fileId);
                    if (app == null)
                    {
                        EntryManager.TrackEditing(fileId, Guid.Empty, SecurityContext.CurrentAccount.ID, doc, true);
                    }

                    //without StartTrack, track via old scheme
                    return DocumentServiceHelper.GetDocKey(fileId, -1, DateTime.MinValue);
                }

                DocumentService.Configuration configuration;

                app = ThirdPartySelector.GetAppByFileId(fileId);
                if (app == null)
                {
                    DocumentServiceHelper.GetParams(fileId, -1, doc, true, true, false, out configuration);
                }
                else
                {
                    bool editable;
                    var file = app.GetFile(fileId, out editable);
                    DocumentServiceHelper.GetParams(file, true, editable ? FileShare.ReadWrite : FileShare.Read, false, editable, editable, editable, false, out configuration);
                }

                ErrorIf(!configuration.EditorConfig.ModeWrite
                        || !(configuration.Document.Permissions.Edit
                             || configuration.Document.Permissions.ModifyFilter
                             || configuration.Document.Permissions.Review
                             || configuration.Document.Permissions.FillForms
                             || configuration.Document.Permissions.Comment),
                        !string.IsNullOrEmpty(configuration.ErrorMessage) ? configuration.ErrorMessage : FilesCommonResource.ErrorMassage_SecurityException_EditFile);
                var key = configuration.Document.Key;

                if (!DocumentServiceTracker.StartTrack(fileId, key))
                {
                    throw new Exception(FilesCommonResource.ErrorMassage_StartEditing);
                }

                return key;
            }
            catch (Exception e)
            {
                FileTracker.Remove(fileId);
                throw GenerateException(e);
            }
        }

        [ActionName("folders-files-rename"), HttpGet]
        public File FileRename(String fileId, String title)
        {
            try
            {
                File file;
                var renamed = EntryManager.FileRename(fileId, title, out file);
                if (renamed)
                {
                    FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRenamed, file.Title);

                    if (!file.ProviderEntry)
                    {
                        FactoryIndexer<FilesWrapper>.UpdateAsync(file, true, r => r.Title);
                    }
                }

                if (file.RootFolderType == FolderType.USER
                    && !Equals(file.RootFolderCreator, SecurityContext.CurrentAccount.ID))
                {
                    using (var folderDao = GetFolderDao())
                    {
                        if (!Global.GetFilesSecurity().CanRead(folderDao.GetFolder(file.FolderID)))
                            file.FolderIdDisplay = Global.FolderShare;
                    }
                }

                return file;
            }
            catch (Exception ex)
            {
                throw GenerateException(ex);
            }
        }

        [ActionName("folders-files-history"), HttpGet]
        public ItemList<File> GetFileHistory(String fileId)
        {
            using (var fileDao = GetFileDao())
            {
                var file = fileDao.GetFile(fileId);
                ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);

                return new ItemList<File>(fileDao.GetFileHistory(fileId));
            }
        }

        [ActionName("folders-files-updateToVersion"), HttpGet]
        public KeyValuePair<File, ItemList<File>> UpdateToVersion(String fileId, int version)
        {
            var file = EntryManager.UpdateToVersionFile(fileId, version);
            FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRestoreVersion, file.Title, version.ToString(CultureInfo.InvariantCulture));

            if (file.RootFolderType == FolderType.USER
                && !Equals(file.RootFolderCreator, SecurityContext.CurrentAccount.ID))
            {
                using (var folderDao = GetFolderDao())
                {
                    if (!Global.GetFilesSecurity().CanRead(folderDao.GetFolder(file.FolderID)))
                        file.FolderIdDisplay = Global.FolderShare;
                }
            }

            return new KeyValuePair<File, ItemList<File>>(file, GetFileHistory(fileId));
        }

        [ActionName("folders-files-updateComment"), HttpGet]
        public string UpdateComment(String fileId, int version, String comment)
        {
            using (var fileDao = GetFileDao())
            {
                var file = fileDao.GetFile(fileId, version);
                ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
                ErrorIf(!FileSecurity.CanEdit(file) || CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor(), FilesCommonResource.ErrorMassage_SecurityException_EditFile);
                ErrorIf(EntryManager.FileLockedForMe(file.ID), FilesCommonResource.ErrorMassage_LockedFile);
                ErrorIf(file.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem);

                comment = fileDao.UpdateComment(fileId, version, comment);

                FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdatedRevisionComment, file.Title, version.ToString(CultureInfo.InvariantCulture));
            }

            return comment;
        }

        [ActionName("folders-files-completeVersion"), HttpGet]
        public KeyValuePair<File, ItemList<File>> CompleteVersion(String fileId, int version, bool continueVersion)
        {
            var file = EntryManager.CompleteVersionFile(fileId, version, continueVersion);

            FilesMessageService.Send(file, GetHttpHeaders(),
                                     continueVersion ? MessageAction.FileDeletedVersion : MessageAction.FileCreatedVersion,
                                     file.Title, version == 0 ? (file.Version - 1).ToString(CultureInfo.InvariantCulture) : version.ToString(CultureInfo.InvariantCulture));

            if (file.RootFolderType == FolderType.USER
                && !Equals(file.RootFolderCreator, SecurityContext.CurrentAccount.ID))
            {
                using (var folderDao = GetFolderDao())
                {
                    if (!Global.GetFilesSecurity().CanRead(folderDao.GetFolder(file.FolderID)))
                        file.FolderIdDisplay = Global.FolderShare;
                }
            }

            return new KeyValuePair<File, ItemList<File>>(file, GetFileHistory(fileId));
        }

        [ActionName("folders-files-lock"), HttpGet]
        public File LockFile(String fileId, bool lockfile)
        {
            using (var tagDao = GetTagDao())
            using (var fileDao = GetFileDao())
            {
                var file = fileDao.GetFile(fileId);

                ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
                ErrorIf(!FileSecurity.CanEdit(file) || lockfile && CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor(), FilesCommonResource.ErrorMassage_SecurityException_EditFile);
                ErrorIf(file.RootFolderType == FolderType.TRASH, FilesCommonResource.ErrorMassage_ViewTrashItem);

                var tagLocked = tagDao.GetTags(file.ID, FileEntryType.File, TagType.Locked).FirstOrDefault();

                ErrorIf(tagLocked != null
                        && tagLocked.Owner != SecurityContext.CurrentAccount.ID
                        && !Global.IsAdministrator
                        && (file.RootFolderType != FolderType.USER || file.RootFolderCreator != SecurityContext.CurrentAccount.ID), FilesCommonResource.ErrorMassage_LockedFile);

                if (lockfile)
                {
                    if (tagLocked == null)
                    {
                        tagLocked = new Tag("locked", TagType.Locked, SecurityContext.CurrentAccount.ID, file, 0);

                        tagDao.SaveTags(tagLocked);
                    }

                    var usersDrop = FileTracker.GetEditingBy(file.ID).Where(uid => uid != SecurityContext.CurrentAccount.ID).Select(u => u.ToString()).ToArray();
                    if (usersDrop.Any())
                    {
                        var fileStable = file.Forcesave == ForcesaveType.None ? file : fileDao.GetFileStable(file.ID, file.Version);
                        var docKey = DocumentServiceHelper.GetDocKey(fileStable);
                        DocumentServiceHelper.DropUser(docKey, usersDrop, file.ID);
                    }

                    FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileLocked, file.Title);
                }
                else
                {
                    if (tagLocked != null)
                    {
                        tagDao.RemoveTags(tagLocked);

                        FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUnlocked, file.Title);
                    }

                    if (!file.ProviderEntry)
                    {
                        file = EntryManager.CompleteVersionFile(file.ID, 0, false);
                        UpdateComment(file.ID.ToString(), file.Version, FilesCommonResource.UnlockComment);
                    }
                }

                EntryManager.SetFileStatus(file);

                if (file.RootFolderType == FolderType.USER
                    && !Equals(file.RootFolderCreator, SecurityContext.CurrentAccount.ID))
                {
                    using (var folderDao = GetFolderDao())
                    {
                        if (!Global.GetFilesSecurity().CanRead(folderDao.GetFolder(file.FolderID)))
                            file.FolderIdDisplay = Global.FolderShare;
                    }
                }

                return file;
            }
        }

        [ActionName("edit-history"), HttpGet, AllowAnonymous]
        public ItemList<EditHistory> GetEditHistory(String fileId, String doc = null)
        {
            using (var fileDao = GetFileDao())
            {
                File file;
                var readLink = FileShareLink.Check(doc, true, fileDao, out file);
                if (file == null)
                    file = fileDao.GetFile(fileId);

                ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
                ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
                ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest);

                return new ItemList<EditHistory>(fileDao.GetEditHistory(file.ID));
            }
        }

        [ActionName("edit-diff-url"), HttpGet, AllowAnonymous]
        public EditHistoryData GetEditDiffUrl(String fileId, int version = 0, String doc = null)
        {
            using (var fileDao = GetFileDao())
            {
                File file;
                var readLink = FileShareLink.Check(doc, true, fileDao, out file);

                if (file != null)
                {
                    fileId = file.ID.ToString();
                }

                if (file == null
                    || version > 0 && file.Version != version)
                {
                    file = version > 0
                               ? fileDao.GetFile(fileId, version)
                               : fileDao.GetFile(fileId);
                }

                ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);
                ErrorIf(!readLink && !FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
                ErrorIf(file.ProviderEntry, FilesCommonResource.ErrorMassage_BadRequest);

                var result = new EditHistoryData
                {
                    Key = DocumentServiceHelper.GetDocKey(file),
                    Url = DocumentServiceConnector.ReplaceCommunityAdress(PathProvider.GetFileStreamUrl(file, doc)),
                    Version = version,
                };

                if (fileDao.ContainChanges(file.ID, file.Version))
                {
                    string previouseKey;
                    string sourceFileUrl;
                    if (file.Version > 1)
                    {
                        var previousFileStable = fileDao.GetFileStable(file.ID, file.Version - 1);
                        ErrorIf(previousFileStable == null, FilesCommonResource.ErrorMassage_FileNotFound);

                        sourceFileUrl = PathProvider.GetFileStreamUrl(previousFileStable, doc);

                        previouseKey = DocumentServiceHelper.GetDocKey(previousFileStable);
                    }
                    else
                    {
                        var culture = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).GetCulture();
                        var storeTemplate = GetStoreTemplate();

                        var path = FileConstant.NewDocPath + culture + "/";
                        if (!storeTemplate.IsDirectory(path))
                        {
                            path = FileConstant.NewDocPath + "en-US/";
                        }

                        var fileExt = FileUtility.GetFileExtension(file.Title);

                        path += "new" + fileExt;

                        sourceFileUrl = storeTemplate.GetUri("", path).ToString();
                        sourceFileUrl = CommonLinkUtility.GetFullAbsolutePath(sourceFileUrl);

                        previouseKey = DocumentServiceConnector.GenerateRevisionId(Guid.NewGuid().ToString());
                    }

                    result.Previous = new EditHistoryUrl
                    {
                        Key = previouseKey,
                        Url = DocumentServiceConnector.ReplaceCommunityAdress(sourceFileUrl),
                    };
                    result.ChangesUrl = PathProvider.GetFileChangesUrl(file, doc);
                }

                result.Token = DocumentServiceHelper.GetSignature(result);

                return result;
            }
        }

        [ActionName("restore-version"), HttpGet, AllowAnonymous]
        public ItemList<EditHistory> RestoreVersion(String fileId, int version, String url = null, String doc = null)
        {
            File file;
            if (string.IsNullOrEmpty(url))
            {
                file = EntryManager.UpdateToVersionFile(fileId, version, doc);
            }
            else
            {
                string modifiedOnString;
                using (var fileDao = GetFileDao())
                {
                    var fromFile = fileDao.GetFile(fileId, version);
                    modifiedOnString = fromFile.ModifiedOnString;
                }
                file = EntryManager.SaveEditing(fileId, null, url, null, doc, string.Format(FilesCommonResource.CommentRevertChanges, modifiedOnString));
            }

            FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileRestoreVersion, file.Title, version.ToString(CultureInfo.InvariantCulture));

            using (var fileDao = GetFileDao())
            {
                return new ItemList<EditHistory>(fileDao.GetEditHistory(file.ID));
            }
        }

        [ActionName("presigned"), HttpGet]
        public Web.Core.Files.DocumentService.FileLink GetPresignedUri(String fileId)
        {
            var file = GetFile(fileId, -1);
            var result = new Web.Core.Files.DocumentService.FileLink
            {
                FileType = FileUtility.GetFileExtension(file.Title),
                Url = DocumentServiceConnector.ReplaceCommunityAdress(PathProvider.GetFileStreamUrl(file))
            };

            result.Token = DocumentServiceHelper.GetSignature(result);

            return result;
        }

        #endregion

        #region News

        [ActionName("getnews"), HttpGet]
        public object GetNewItems(String folderId)
        {
            try
            {
                Folder folder;
                using (var folderDao = GetFolderDao())
                {
                    folder = folderDao.GetFolder(folderId);
                }

                var result = FileMarker.MarkedItems(folder);

                result = new List<FileEntry>(EntryManager.SortEntries(result, new OrderBy(SortedByType.DateAndTime, false)));

                if (!result.ToList().Any())
                {
                    MarkAsRead(new ItemList<string> { "folder_" + folderId });
                }

                var response = new HttpResponseMessage(HttpStatusCode.OK);
                response.Content = new StreamContent(serializer.ToXml(new ItemList<FileEntry>(result)));
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
                return response;
            }
            catch (Exception e)
            {
                throw GenerateException(e);
            }
        }

        [ActionName("markasread"), HttpPost]
        public ItemList<FileOperationResult> MarkAsRead([FromBody] ItemList<String> items)
        {
            if (items.Count == 0) return GetTasksStatuses();

            List<object> foldersId;
            List<object> filesId;
            ParseArrayItems(items, out foldersId, out filesId);

            return fileOperations.MarkAsRead(foldersId, filesId);
        }

        #endregion

        #region ThirdParty

        public ItemList<ThirdPartyParams> GetThirdParty()
        {
            using (var providerDao = GetProviderDao())
            {
                if (providerDao == null) return new ItemList<ThirdPartyParams>();

                var providersInfo = providerDao.GetProvidersInfo();

                var resultList = providersInfo
                    .Select(r =>
                            new ThirdPartyParams
                            {
                                CustomerTitle = r.CustomerTitle,
                                Corporate = r.RootFolderType == FolderType.COMMON,
                                ProviderId = r.ID.ToString(),
                                ProviderKey = r.ProviderKey
                            }
                    );
                return new ItemList<ThirdPartyParams>(resultList.ToList());
            }
        }

        [ActionName("thirdparty-list"), HttpGet]
        public ItemList<Folder> GetThirdPartyFolder(int folderType = 0)
        {
            if (!FilesSettings.EnableThirdParty) return new ItemList<Folder>();

            using (var providerDao = GetProviderDao())
            {
                if (providerDao == null) return new ItemList<Folder>();

                var providersInfo = providerDao.GetProvidersInfo((FolderType)folderType);

                var folders = providersInfo.Select(providerInfo =>
                    {
                        var folder = EntryManager.GetFakeThirdpartyFolder(providerInfo);
                        folder.NewForMe = folder.RootFolderType == FolderType.COMMON ? 1 : 0;
                        return folder;
                    });

                return new ItemList<Folder>(folders);
            }
        }

        [ActionName("thirdparty-save"), HttpPost]
        public Folder SaveThirdParty([FromBody] ThirdPartyParams thirdPartyParams)
        {
            using (var folderDao = GetFolderDao())
            using (var providerDao = GetProviderDao())
            {
                if (providerDao == null) return null;

                ErrorIf(thirdPartyParams == null, FilesCommonResource.ErrorMassage_BadRequest);
                var parentFolder = folderDao.GetFolder(thirdPartyParams.Corporate && !CoreContext.Configuration.Personal ? Global.FolderCommon : Global.FolderMy);
                ErrorIf(!FileSecurity.CanCreate(parentFolder), FilesCommonResource.ErrorMassage_SecurityException_Create);
                ErrorIf(!FilesSettings.EnableThirdParty, FilesCommonResource.ErrorMassage_SecurityException_Create);

                var lostFolderType = FolderType.USER;
                var folderType = thirdPartyParams.Corporate ? FolderType.COMMON : FolderType.USER;

                int curProviderId;

                MessageAction messageAction;
                if (string.IsNullOrEmpty(thirdPartyParams.ProviderId))
                {
                    ErrorIf(!ThirdpartyConfiguration.SupportInclusion
                            ||
                            (!FilesSettings.EnableThirdParty
                             && !CoreContext.Configuration.Personal)
                            , FilesCommonResource.ErrorMassage_SecurityException_Create);

                    thirdPartyParams.CustomerTitle = Global.ReplaceInvalidCharsAndTruncate(thirdPartyParams.CustomerTitle);
                    ErrorIf(string.IsNullOrEmpty(thirdPartyParams.CustomerTitle), FilesCommonResource.ErrorMassage_InvalidTitle);

                    try
                    {
                        curProviderId = providerDao.SaveProviderInfo(thirdPartyParams.ProviderKey, thirdPartyParams.CustomerTitle, thirdPartyParams.AuthData, folderType);
                        messageAction = MessageAction.ThirdPartyCreated;
                    }
                    catch (UnauthorizedAccessException e)
                    {
                        throw GenerateException(e, true);
                    }
                    catch (Exception e)
                    {
                        throw GenerateException(e);
                    }
                }
                else
                {
                    curProviderId = Convert.ToInt32(thirdPartyParams.ProviderId);

                    var lostProvider = providerDao.GetProviderInfo(curProviderId);
                    ErrorIf(lostProvider.Owner != SecurityContext.CurrentAccount.ID, FilesCommonResource.ErrorMassage_SecurityException);

                    lostFolderType = lostProvider.RootFolderType;
                    if (lostProvider.RootFolderType == FolderType.COMMON && !thirdPartyParams.Corporate)
                    {
                        var lostFolder = folderDao.GetFolder(lostProvider.RootFolderId);
                        FileMarker.RemoveMarkAsNewForAll(lostFolder);
                    }

                    curProviderId = providerDao.UpdateProviderInfo(curProviderId, thirdPartyParams.CustomerTitle, thirdPartyParams.AuthData, folderType);
                    messageAction = MessageAction.ThirdPartyUpdated;
                }

                var provider = providerDao.GetProviderInfo(curProviderId);
                provider.InvalidateStorage();

                var folder = folderDao.GetFolder(provider.RootFolderId);
                ErrorIf(!FileSecurity.CanRead(folder), FilesCommonResource.ErrorMassage_SecurityException_ViewFolder);

                FilesMessageService.Send(parentFolder, GetHttpHeaders(), messageAction, folder.ID.ToString(), provider.ProviderKey);

                if (thirdPartyParams.Corporate && lostFolderType != FolderType.COMMON)
                {
                    FileMarker.MarkAsNew(folder);
                }

                return folder;
            }
        }

        [ActionName("thirdparty-delete"), HttpGet]
        public object DeleteThirdParty(String providerId)
        {
            using (var providerDao = GetProviderDao())
            {
                if (providerDao == null) return null;

                var curProviderId = Convert.ToInt32(providerId);
                var providerInfo = providerDao.GetProviderInfo(curProviderId);

                var folder = EntryManager.GetFakeThirdpartyFolder(providerInfo);
                ErrorIf(!FileSecurity.CanDelete(folder), FilesCommonResource.ErrorMassage_SecurityException_DeleteFolder);

                if (providerInfo.RootFolderType == FolderType.COMMON)
                {
                    FileMarker.RemoveMarkAsNewForAll(folder);
                }

                providerDao.RemoveProviderInfo(folder.ProviderId);
                FilesMessageService.Send(folder, GetHttpHeaders(), MessageAction.ThirdPartyDeleted, folder.ID.ToString(), providerInfo.ProviderKey);

                return folder.ID;
            }
        }

        [ActionName("thirdparty"), HttpGet]
        public bool ChangeAccessToThirdparty(bool enable)
        {
            ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException);

            FilesSettings.EnableThirdParty = enable;
            FilesMessageService.Send(GetHttpHeaders(), MessageAction.DocumentsThirdPartySettingsUpdated);

            return FilesSettings.EnableThirdParty;
        }

        [ActionName("docusign-save"), HttpPost]
        public bool SaveDocuSign([FromBody] String code)
        {
            ErrorIf(!SecurityContext.IsAuthenticated
                    || CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor()
                    || !FilesSettings.EnableThirdParty
                    || !ThirdpartyConfiguration.SupportDocuSignInclusion, FilesCommonResource.ErrorMassage_SecurityException_Create);

            var token = DocuSignLoginProvider.Instance.GetAccessToken(code);
            DocuSignHelper.ValidateToken(token);
            DocuSignToken.SaveToken(token);
            return true;
        }

        [ActionName("docusign-delete"), HttpGet]
        public object DeleteDocuSign()
        {
            DocuSignToken.DeleteToken();
            return null;
        }

        [ActionName("docusign"), HttpPost]
        public String SendDocuSign(String fileId, [FromBody] DocuSignData docuSignData)
        {
            try
            {
                ErrorIf(CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor()
                    || !FilesSettings.EnableThirdParty
                    || !ThirdpartyConfiguration.SupportDocuSignInclusion, FilesCommonResource.ErrorMassage_SecurityException_Create);

                return DocuSignHelper.SendDocuSign(fileId, docuSignData, GetHttpHeaders());
            }
            catch (Exception e)
            {
                throw GenerateException(e);
            }
        }

        #endregion

        #region Operation

        [ActionName("tasks-statuses"), HttpGet]
        public ItemList<FileOperationResult> GetTasksStatuses()
        {
            ErrorIf(!SecurityContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException);

            return fileOperations.GetOperationResults();
        }

        [ActionName("tasks"), HttpGet]
        public ItemList<FileOperationResult> TerminateTasks()
        {
            ErrorIf(!SecurityContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException);

            return fileOperations.CancelOperations();
        }

        [ActionName("bulkdownload"), HttpPost]
        public ItemList<FileOperationResult> BulkDownload([FromBody] Dictionary<String, String> items)
        {
            Dictionary<object, string> folders;
            Dictionary<object, string> files;

            ParseArrayItems(items, out folders, out files);
            ErrorIf(folders.Count == 0 && files.Count == 0, FilesCommonResource.ErrorMassage_BadRequest);

            return fileOperations.Download(folders, files, GetHttpHeaders());
        }

        [ActionName("folders-files-moveOrCopyFilesCheck"), HttpPost]
        public ItemDictionary<String, String> MoveOrCopyFilesCheck([FromBody] ItemList<String> items, String destFolderId)
        {
            if (items.Count == 0) return new ItemDictionary<String, String>();

            List<object> foldersId;
            List<object> filesId;
            ParseArrayItems(items, out foldersId, out filesId);

            return new ItemDictionary<String, String>(MoveOrCopyFilesCheck(filesId, foldersId, destFolderId));
        }

        private Dictionary<String, String> MoveOrCopyFilesCheck(IEnumerable<object> filesId, IEnumerable<object> foldersId, object destFolderId)
        {
            var result = new Dictionary<string, string>();
            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                var toFolder = folderDao.GetFolder(destFolderId);
                ErrorIf(toFolder == null, FilesCommonResource.ErrorMassage_FolderNotFound);
                ErrorIf(!FileSecurity.CanCreate(toFolder), FilesCommonResource.ErrorMassage_SecurityException_Create);

                foreach (var id in filesId)
                {
                    var file = fileDao.GetFile(id);
                    if (file != null
                        && !file.Encrypted
                        && fileDao.IsExist(file.Title, toFolder.ID))
                    {
                        result.Add(id.ToString(), file.Title);
                    }
                }

                var folders = folderDao.GetFolders(foldersId.ToArray());
                var foldersProject = folders.Where(folder => folder.FolderType == FolderType.BUNCH).ToList();
                if (foldersProject.Any())
                {
                    var toSubfolders = folderDao.GetFolders(toFolder.ID);

                    foreach (var folderProject in foldersProject)
                    {
                        var toSub = toSubfolders.FirstOrDefault(to => Equals(to.Title, folderProject.Title));
                        if (toSub == null) continue;

                        var filesPr = fileDao.GetFiles(folderProject.ID);
                        var foldersPr = folderDao.GetFolders(folderProject.ID).Select(d => d.ID);

                        var recurseItems = MoveOrCopyFilesCheck(filesPr, foldersPr, toSub.ID);
                        foreach (var recurseItem in recurseItems)
                        {
                            result.Add(recurseItem.Key, recurseItem.Value);
                        }
                    }
                }
                try
                {
                    foreach (var pair in folderDao.CanMoveOrCopy(foldersId.ToArray(), toFolder.ID))
                    {
                        result.Add(pair.Key.ToString(), pair.Value);
                    }
                }
                catch (Exception e)
                {
                    throw GenerateException(e);
                }
            }
            return result;
        }

        [ActionName("moveorcopy"), HttpPost]
        public ItemList<FileOperationResult> MoveOrCopyItems([FromBody] ItemList<string> items, string destFolderId, FileConflictResolveType resolve, bool ic, bool deleteAfter = false)
        {
            ItemList<FileOperationResult> result;
            if (items.Count != 0)
            {
                List<object> foldersId;
                List<object> filesId;
                ParseArrayItems(items, out foldersId, out filesId);

                result = fileOperations.MoveOrCopy(foldersId, filesId, destFolderId, ic, resolve, !deleteAfter, GetHttpHeaders());
            }
            else
            {
                result = fileOperations.GetOperationResults();
            }
            return result;
        }

        [ActionName("folders-files"), HttpPost]
        public ItemList<FileOperationResult> DeleteItems(string action, [FromBody] ItemList<String> items, bool ignoreException = false, bool deleteAfter = false, bool immediately = false)
        {
            List<object> foldersId;
            List<object> filesId;
            ParseArrayItems(items, out foldersId, out filesId);

            return fileOperations.Delete(foldersId, filesId, ignoreException, !deleteAfter, immediately, GetHttpHeaders());
        }

        [ActionName("emptytrash"), HttpGet]
        public ItemList<FileOperationResult> EmptyTrash()
        {
            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                var trashId = folderDao.GetFolderIDTrash(true);
                var foldersId = folderDao.GetFolders(trashId).Select(f => f.ID).ToList();
                var filesId = fileDao.GetFiles(trashId).ToList();

                return fileOperations.Delete(foldersId, filesId, false, true, false, GetHttpHeaders());
            }
        }

        [ActionName("checkconversion"), HttpPost]
        public ItemList<FileOperationResult> CheckConversion([FromBody] ItemList<ItemList<string>> filesInfoJSON)
        {
            if (filesInfoJSON == null || filesInfoJSON.Count == 0) return new ItemList<FileOperationResult>();

            using (var fileDao = GetFileDao())
            {
                var files = new List<KeyValuePair<File, bool>>();
                foreach (var fileInfo in filesInfoJSON)
                {
                    object fileId;

                    var fileIdAsString = fileInfo[0];

                    int fileIdAsInt;
                    if (int.TryParse(fileIdAsString, out fileIdAsInt))
                        fileId = fileIdAsInt;
                    else
                        fileId = fileIdAsString;

                    int version;
                    var file = int.TryParse(fileInfo[1], out version) && version > 0
                                   ? fileDao.GetFile(fileId, version)
                                   : fileDao.GetFile(fileId);

                    if (file == null)
                    {
                        files.Add(new KeyValuePair<File, bool>(
                                      new File
                                      {
                                          ID = fileId,
                                          Version = version
                                      },
                                      true));
                        continue;
                    }

                    ErrorIf(!FileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);

                    var startConvert = Convert.ToBoolean(fileInfo[2]);
                    if (startConvert && FileConverter.MustConvert(file))
                    {
                        try
                        {
                            FileConverter.ExecAsync(file, false, fileInfo.Count > 3 ? fileInfo[3] : null);
                        }
                        catch (Exception e)
                        {
                            throw GenerateException(e);
                        }
                    }

                    files.Add(new KeyValuePair<File, bool>(file, false));
                }

                var results = FileConverter.GetStatus(files).ToList();

                return new ItemList<FileOperationResult>(results);
            }
        }

        public void ReassignStorage(Guid userFromId, Guid userToId)
        {
            //check current user have access
            ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException);

            //check exist userFrom
            var userFrom = CoreContext.UserManager.GetUsers(userFromId);
            ErrorIf(Equals(userFrom, Constants.LostUser), FilesCommonResource.ErrorMassage_UserNotFound);

            //check exist userTo
            var userTo = CoreContext.UserManager.GetUsers(userToId);
            ErrorIf(Equals(userTo, Constants.LostUser), FilesCommonResource.ErrorMassage_UserNotFound);
            ErrorIf(userTo.IsVisitor(), FilesCommonResource.ErrorMassage_SecurityException);

            using (var providerDao = GetProviderDao())
            {
                if (providerDao != null)
                {
                    var providersInfo = providerDao.GetProvidersInfo(userFrom.ID);
                    var commonProvidersInfo = providersInfo.Where(provider => provider.RootFolderType == FolderType.COMMON).ToList();

                    //move common thirdparty storage userFrom
                    foreach (var commonProviderInfo in commonProvidersInfo)
                    {
                        Global.Logger.InfoFormat("Reassign provider {0} from {1} to {2}", commonProviderInfo.ID, userFrom.ID, userTo.ID);
                        providerDao.UpdateProviderInfo(commonProviderInfo.ID, null, null, FolderType.DEFAULT, userTo.ID);
                    }
                }
            }

            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                if (!userFrom.IsVisitor())
                {
                    var folderIdFromMy = folderDao.GetFolderIDUser(false, userFrom.ID);

                    if (!Equals(folderIdFromMy, 0))
                    {
                        //create folder with name userFrom in folder userTo
                        var folderIdToMy = folderDao.GetFolderIDUser(true, userTo.ID);
                        var newFolderTo = folderDao.SaveFolder(new Folder
                        {
                            Title = string.Format(CustomNamingPeople.Substitute<FilesCommonResource>("TitleDeletedUserFolder"), userFrom.DisplayUserName(false)),
                            ParentFolderID = folderIdToMy
                        });

                        //move items from userFrom to userTo
                        EntryManager.MoveSharedItems(folderIdFromMy, newFolderTo, folderDao, fileDao);

                        EntryManager.ReassignItems(newFolderTo, userFrom.ID, userTo.ID, folderDao, fileDao);
                    }
                }

                EntryManager.ReassignItems(Global.FolderCommon, userFrom.ID, userTo.ID, folderDao, fileDao);
            }
        }

        public void DeleteStorage(Guid userId)
        {
            //check current user have access
            ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException);

            //delete docuSign
            DocuSignToken.DeleteToken(userId);

            using (var providerDao = GetProviderDao())
            {
                if (providerDao != null)
                {
                    var providersInfo = providerDao.GetProvidersInfo(userId);

                    //delete thirdparty storage
                    foreach (var myProviderInfo in providersInfo)
                    {
                        Global.Logger.InfoFormat("Delete provider {0} for {1}", myProviderInfo.ID, userId);
                        providerDao.RemoveProviderInfo(myProviderInfo.ID);
                    }
                }
            }

            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                //delete all markAsNew
                var rootFoldersId = new List<object>
                    {
                        Global.FolderShare,
                        Global.FolderCommon,
                        Global.FolderProjects,
                    };

                var folderIdFromMy = folderDao.GetFolderIDUser(false, userId);
                if (!Equals(folderIdFromMy, 0))
                {
                    rootFoldersId.Add(folderIdFromMy);
                }

                var rootFolders = folderDao.GetFolders(rootFoldersId.ToArray());
                foreach (var rootFolder in rootFolders)
                {
                    FileMarker.RemoveMarkAsNew(rootFolder, userId);
                }

                //delete all from My
                if (!Equals(folderIdFromMy, 0))
                {
                    EntryManager.DeleteSubitems(folderIdFromMy, folderDao, fileDao);

                    //delete My userFrom folder
                    folderDao.DeleteFolder(folderIdFromMy);
                    Global.FolderMy = userId;
                }

                //delete all from Trash
                var folderIdFromTrash = folderDao.GetFolderIDTrash(false, userId);
                if (!Equals(folderIdFromTrash, 0))
                {
                    EntryManager.DeleteSubitems(folderIdFromTrash, folderDao, fileDao);
                    folderDao.DeleteFolder(folderIdFromTrash);
                    Global.FolderTrash = userId;
                }

                EntryManager.ReassignItems(Global.FolderCommon, userId, SecurityContext.CurrentAccount.ID, folderDao, fileDao);
            }
        }

        #endregion

        #region Favorites Manager

        [ActionName("file-favorite"), HttpGet]
        public bool ToggleFileFavorite(String fileId, bool favorite)
        {
            if (favorite)
            {
                AddToFavorites(new ItemList<string> { }, new ItemList<string> { fileId });
            }
            else
            {
                DeleteFavorites(new ItemList<string> { }, new ItemList<string> { fileId });
            }
            return favorite;
        }

        public ItemList<FileEntry> AddToFavorites(ItemList<String> foldersId, ItemList<String> filesId)
        {
            if (CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor()) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

            using (var tagDao = GetTagDao())
            using (var fileDao = GetFileDao())
            using (var folderDao = GetFolderDao())
            {
                var entries = Enumerable.Empty<FileEntry>();

                var files = fileDao.GetFiles(filesId.ToArray())
                    .Where(file => !file.Encrypted);
                entries = entries.Concat(files);

                var folders = folderDao.GetFolders(foldersId.ToArray());
                entries = entries.Concat(folders);

                entries = FileSecurity.FilterRead(entries);

                var tags = entries.Select(entry => Tag.Favorite(SecurityContext.CurrentAccount.ID, entry));

                tagDao.SaveTags(tags);

                return new ItemList<FileEntry>(entries);
            }
        }

        public ItemList<FileEntry> DeleteFavorites(ItemList<String> foldersId, ItemList<String> filesId)
        {
            using (var tagDao = GetTagDao())
            using (var fileDao = GetFileDao())
            using (var folderDao = GetFolderDao())
            {
                var entries = Enumerable.Empty<FileEntry>();

                var files = fileDao.GetFiles(filesId.ToArray());
                entries = entries.Concat(files);

                var folders = folderDao.GetFolders(foldersId.ToArray());
                entries = entries.Concat(folders);

                entries = FileSecurity.FilterRead(entries);

                var tags = entries.Select(entry => Tag.Favorite(SecurityContext.CurrentAccount.ID, entry));

                tagDao.RemoveTags(tags);

                return new ItemList<FileEntry>(entries);
            }
        }

        #endregion

        #region Templates Manager

        public ItemList<FileEntry> AddToTemplates(ItemList<String> filesId)
        {
            if (CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor()) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

            using (var tagDao = GetTagDao())
            using (var fileDao = GetFileDao())
            {
                var files = fileDao.GetFiles(filesId.ToArray());

                files = FileSecurity.FilterRead(files)
                    .Where(file => FileUtility.ExtsWebTemplate.Contains(FileUtility.GetFileExtension(file.Title), StringComparer.CurrentCultureIgnoreCase))
                    .ToList();

                var tags = files.Select(file => Tag.Template(SecurityContext.CurrentAccount.ID, file));

                tagDao.SaveTags(tags);

                return new ItemList<FileEntry>(files);
            }
        }

        public ItemList<FileEntry> DeleteTemplates(ItemList<String> filesId)
        {
            using (var tagDao = GetTagDao())
            using (var fileDao = GetFileDao())
            {
                var files = fileDao.GetFiles(filesId.ToArray());

                files = FileSecurity.FilterRead(files).ToList();

                var tags = files.Select(file => Tag.Template(SecurityContext.CurrentAccount.ID, file));

                tagDao.RemoveTags(tags);

                return new ItemList<FileEntry>(files);
            }
        }

        [ActionName("gettemplates"), HttpGet]
        public object GetTemplates(FilterType filter, int from, int count, bool subjectGroup, String subjectID, String search, bool searchInContent)
        {
            try
            {
                IEnumerable<File> result;

                var subjectId = string.IsNullOrEmpty(subjectID) ? Guid.Empty : new Guid(subjectID);
                using (var folderDao = GetFolderDao())
                using (var fileDao = GetFileDao())
                {
                    result = EntryManager.GetTemplates(folderDao, fileDao, filter, subjectGroup, subjectId, search, searchInContent);
                }

                if (result.Count() <= from)
                    return null;

                result = result.Skip(from).Take(count);

                var response = new HttpResponseMessage(HttpStatusCode.OK);
                response.Content = new StreamContent(serializer.ToXml(new ItemList<FileEntry>(result)));
                response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
                return response;
            }
            catch (Exception e)
            {
                throw GenerateException(e);
            }
        }

        #endregion

        #region Ace Manager

        [ActionName("sharedinfo"), HttpPost]
        public ItemList<AceWrapper> GetSharedInfo([FromBody] ItemList<String> objectIds)
        {
            ErrorIf(!SecurityContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException);

            var result = new List<AceWrapper>();

            using (var folderDao = GetFolderDao())
            using (var fileDao = GetFileDao())
            {
                foreach (var objectId in objectIds)
                {
                    ErrorIf(string.IsNullOrEmpty(objectId), FilesCommonResource.ErrorMassage_BadRequest);

                    Debug.Assert(objectId != null, "objectId != null");
                    var entryType = objectId.StartsWith("file_") ? FileEntryType.File : FileEntryType.Folder;
                    var entryId = objectId.Substring((entryType == FileEntryType.File ? "file_" : "folder_").Length);

                    var entry = entryType == FileEntryType.File
                                    ? (FileEntry)fileDao.GetFile(entryId)
                                    : (FileEntry)folderDao.GetFolder(entryId);

                    IEnumerable<AceWrapper> acesForObject;
                    try
                    {
                        acesForObject = FileSharing.GetSharedInfo(entry);
                    }
                    catch (Exception e)
                    {
                        throw GenerateException(e);
                    }

                    foreach (var aceForObject in acesForObject)
                    {
                        var duplicate = result.FirstOrDefault(ace => ace.SubjectId == aceForObject.SubjectId);
                        if (duplicate == null)
                        {
                            if (result.Any())
                            {
                                aceForObject.Owner = false;
                                aceForObject.Share = FileShare.Varies;
                            }
                            continue;
                        }

                        if (duplicate.Share != aceForObject.Share)
                        {
                            aceForObject.Share = FileShare.Varies;
                        }
                        if (duplicate.Owner != aceForObject.Owner)
                        {
                            aceForObject.Owner = false;
                            aceForObject.Share = FileShare.Varies;
                        }
                        result.Remove(duplicate);
                    }

                    var withoutAce = result.Where(ace =>
                                                  acesForObject.FirstOrDefault(aceForObject =>
                                                                               aceForObject.SubjectId == ace.SubjectId) == null);
                    foreach (var ace in withoutAce)
                    {
                        ace.Share = FileShare.Varies;
                    }

                    var notOwner = result.Where(ace =>
                                                ace.Owner &&
                                                acesForObject.FirstOrDefault(aceForObject =>
                                                                             aceForObject.Owner
                                                                             && aceForObject.SubjectId == ace.SubjectId) == null);
                    foreach (var ace in notOwner)
                    {
                        ace.Owner = false;
                        ace.Share = FileShare.Varies;
                    }

                    result.AddRange(acesForObject);
                }
            }


            var ownerAce = result.FirstOrDefault(ace => ace.Owner);
            result.Remove(ownerAce);

            var meAce = result.FirstOrDefault(ace => ace.SubjectId == SecurityContext.CurrentAccount.ID);
            result.Remove(meAce);

            AceWrapper linkAce = null;
            if (objectIds.Count > 1)
            {
                result.RemoveAll(ace => ace.SubjectId == FileConstant.ShareLinkId);
            }
            else
            {
                linkAce = result.FirstOrDefault(ace => ace.SubjectId == FileConstant.ShareLinkId);
            }

            result.Sort((x, y) => string.Compare(x.SubjectName, y.SubjectName));

            if (ownerAce != null)
            {
                result = new List<AceWrapper> { ownerAce }.Concat(result).ToList();
            }
            if (meAce != null)
            {
                result = new List<AceWrapper> { meAce }.Concat(result).ToList();
            }
            if (linkAce != null)
            {
                result.Remove(linkAce);
                result = new List<AceWrapper> { linkAce }.Concat(result).ToList();
            }

            return new ItemList<AceWrapper>(result);
        }

        [ActionName("sharedinfoshort"), HttpGet]
        public ItemList<AceShortWrapper> GetSharedInfoShort(String objectId)
        {
            var aces = GetSharedInfo(new ItemList<string> { objectId });

            return new ItemList<AceShortWrapper>(
                aces.Where(aceWrapper => !aceWrapper.SubjectId.Equals(FileConstant.ShareLinkId) || aceWrapper.Share != FileShare.Restrict)
                    .Select(aceWrapper => new AceShortWrapper(aceWrapper)));
        }

        [ActionName("setaceobject"), HttpPost]
        public ItemList<string> SetAceObject([FromBody] AceCollection aceCollection, bool notify)
        {
            using (var fileDao = GetFileDao())
            using (var folderDao = GetFolderDao())
            {
                var result = new ItemList<string>();
                foreach (var objectId in aceCollection.Entries)
                {
                    Debug.Assert(objectId != null, "objectId != null");
                    var entryType = objectId.StartsWith("file_") ? FileEntryType.File : FileEntryType.Folder;
                    var entryId = objectId.Substring((entryType == FileEntryType.File ? "file_" : "folder_").Length);
                    var entry = entryType == FileEntryType.File
                                    ? (FileEntry)fileDao.GetFile(entryId)
                                    : (FileEntry)folderDao.GetFolder(entryId);

                    try
                    {
                        var changed = FileSharing.SetAceObject(aceCollection.Aces, entry, notify, aceCollection.Message);
                        if (changed)
                        {
                            FilesMessageService.Send(entry, GetHttpHeaders(),
                                                     entryType == FileEntryType.Folder ? MessageAction.FolderUpdatedAccess : MessageAction.FileUpdatedAccess,
                                                     entry.Title);
                        }
                    }
                    catch (Exception e)
                    {
                        throw GenerateException(e);
                    }

                    using (var securityDao = GetSecurityDao())
                    {
                        if (securityDao.IsShared(entry.ID, entryType))
                        {
                            result.Add(objectId);
                        }
                    }
                }
                return result;
            }
        }

        [ActionName("removeace"), HttpPost]
        public void RemoveAce([FromBody] ItemList<String> items)
        {
            ErrorIf(!SecurityContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException);
            List<object> filesId;
            List<object> foldersId;
            ParseArrayItems(items, out foldersId, out filesId);

            var entries = new List<FileEntry>();

            using (var fileDao = GetFileDao())
            using (var folderDao = GetFolderDao())
            {
                entries.AddRange(filesId.Select(fileId => fileDao.GetFile(fileId)));
                entries.AddRange(foldersId.Select(folderDao.GetFolder));

                FileSharing.RemoveAce(entries);
            }
        }

        [ActionName("shorten"), HttpGet]
        public String GetShortenLink(String fileId)
        {
            File file;
            using (var fileDao = GetFileDao())
            {
                file = fileDao.GetFile(fileId);
                ErrorIf(!FileSharing.CanSetAccess(file), FilesCommonResource.ErrorMassage_SecurityException);
            }
            var shareLink = FileShareLink.GetLink(file);

            try
            {
                return UrlShortener.Instance.GetShortenLink(shareLink);
            }
            catch (Exception e)
            {
                throw GenerateException(e);
            }
        }

        [ActionName("setacelink"), HttpGet]
        public bool SetAceLink(String fileId, FileShare share)
        {
            FileEntry file;
            using (var fileDao = GetFileDao())
            {
                file = fileDao.GetFile(fileId);
            }
            var aces = new List<AceWrapper>
                {
                    new AceWrapper
                        {
                            Share = share,
                            SubjectId = FileConstant.ShareLinkId,
                            SubjectGroup = true,
                        }
                };

            try
            {

                var changed = FileSharing.SetAceObject(aces, file, false, null);
                if (changed)
                {
                    FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdatedAccess, file.Title);
                }
            }
            catch (Exception e)
            {
                throw GenerateException(e);
            }

            using (var securityDao = GetSecurityDao())
            {
                return securityDao.IsShared(file.ID, FileEntryType.File);
            }
        }

        [ActionName("sharedusers"), HttpGet]
        public ItemList<MentionWrapper> SharedUsers(String fileId)
        {
            if (!SecurityContext.IsAuthenticated || CoreContext.Configuration.Personal)
                return null;

            FileEntry file;
            using (var fileDao = GetFileDao())
            {
                file = fileDao.GetFile(fileId);
            }

            ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);

            var usersIdWithAccess = new List<Guid>();
            if (FileSharing.CanSetAccess(file))
            {
                var access = FileSharing.GetSharedInfo(file);
                usersIdWithAccess = access.Where(aceWrapper => !aceWrapper.SubjectGroup && aceWrapper.Share != FileShare.Restrict)
                                          .Select(aceWrapper => aceWrapper.SubjectId)
                                          .ToList();
            }
            else
            {
                usersIdWithAccess.Add(file.CreateBy);
            }

            var users = CoreContext.UserManager.GetUsersByGroup(Constants.GroupEveryone.ID)
                                   .Where(user => !user.ID.Equals(SecurityContext.CurrentAccount.ID)
                                                  && !user.ID.Equals(Constants.LostUser.ID))
                                   .Select(user => new MentionWrapper(user) { HasAccess = usersIdWithAccess.Contains(user.ID) })
                                   .ToList();

            users = users
                .OrderBy(user => !user.HasAccess)
                .ThenBy(user => user.User, UserInfoComparer.Default)
                .ToList();

            return new ItemList<MentionWrapper>(users);
        }

        [ActionName("sendeditornotify"), HttpPost]
        public ItemList<AceShortWrapper> SendEditorNotify(String fileId, [FromBody] MentionMessageWrapper mentionMessage)
        {
            ErrorIf(!SecurityContext.IsAuthenticated, FilesCommonResource.ErrorMassage_SecurityException);

            File file;
            using (var fileDao = GetFileDao())
            {
                file = fileDao.GetFile(fileId);
            }

            ErrorIf(file == null, FilesCommonResource.ErrorMassage_FileNotFound);

            var fileSecurity = Global.GetFilesSecurity();
            ErrorIf(!fileSecurity.CanRead(file), FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
            ErrorIf(mentionMessage == null || mentionMessage.Emails == null, FilesCommonResource.ErrorMassage_BadRequest);

            var showSharingSettings = false;
            bool? canShare = null;

            if (file.Encrypted)
            {
                canShare = false;
                showSharingSettings = true;
            }

            var recipients = new List<Guid>();
            foreach (var email in mentionMessage.Emails)
            {
                if (!canShare.HasValue)
                {
                    canShare = FileSharing.CanSetAccess(file);
                }

                var recipient = CoreContext.UserManager.GetUserByEmail(email);
                if (recipient == null || recipient.ID == Constants.LostUser.ID)
                {
                    showSharingSettings = canShare.Value;
                    continue;
                }

                if (!fileSecurity.CanRead(file, recipient.ID))
                {
                    if (!canShare.Value)
                    {
                        continue;
                    }

                    try
                    {
                        var aces = new List<AceWrapper>
                            {
                                new AceWrapper
                                    {
                                        Share = FileShare.Read,
                                        SubjectId = recipient.ID,
                                        SubjectGroup = false,
                                    }
                            };

                        showSharingSettings |= FileSharing.SetAceObject(aces, file, false, null);

                        recipients.Add(recipient.ID);
                    }
                    catch (Exception e)
                    {
                        throw GenerateException(e);
                    }
                }
                else
                {
                    recipients.Add(recipient.ID);
                }
            }

            if (showSharingSettings)
            {
                FilesMessageService.Send(file, GetHttpHeaders(), MessageAction.FileUpdatedAccess, file.Title);
            }

            var fileLink = FilesLinkUtility.GetFileWebEditorUrl(file.ID);
            if (mentionMessage.ActionLink != null)
            {
                fileLink += "&" + FilesLinkUtility.Anchor + "=" + HttpUtility.UrlEncode(
                    DocumentService.Configuration.EditorConfiguration.ActionLinkConfig.Serialize(mentionMessage.ActionLink));
            }

            var message = (mentionMessage.Message ?? "").Trim();
            const int maxMessageLength = 200;
            if (message.Length > maxMessageLength)
            {
                message = message.Substring(0, maxMessageLength) + "...";
            }

            NotifyClient.SendEditorMentions(file, fileLink, recipients, message);

            return showSharingSettings ? GetSharedInfoShort("file_" + fileId) : null;
        }

        [ActionName("publickeys"), HttpGet]
        public ItemList<EncryptionKeyPair> GetEncryptionAccess(String fileId)
        {
            ErrorIf(!PrivacyRoomSettings.Enabled, FilesCommonResource.ErrorMassage_SecurityException);

            var fileKeyPair = EncryptionKeyPair.GetKeyPair(fileId);
            return new ItemList<EncryptionKeyPair>(fileKeyPair);
        }

        #endregion

        #region MailMerge

        [ActionName("mailaccounts")]
        public ItemList<string> GetMailAccounts()
        {
            var apiServer = new ASC.Api.ApiServer();
            var apiUrl = String.Format("{0}mail/accounts.json", SetupInfo.WebApiBaseUrl);

            var accounts = new List<string>();

            var responseBody = apiServer.GetApiResponse(apiUrl, "GET");
            if (responseBody != null)
            {
                var responseApi = JObject.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(responseBody)));

                var responseData = responseApi["response"];
                if (responseData is JArray)
                {
                    accounts.AddRange(
                        from account in responseData.Children()
                        orderby account["isDefault"].Value<Boolean>() descending
                        where account["enabled"].Value<Boolean>() && !account["isGroup"].Value<Boolean>()
                        select account["email"].Value<String>()
                        );
                }
            }
            ErrorIf(!accounts.Any(), FilesCommonResource.ErrorMassage_MailAccountNotFound);

            return new ItemList<string>(accounts);
        }

        #endregion

        [ActionName("changeowner"), HttpPost]
        public ItemList<FileEntry> ChangeOwner([FromBody] ItemList<String> items, Guid userId)
        {
            var userInfo = CoreContext.UserManager.GetUsers(userId);
            ErrorIf(Equals(userInfo, Constants.LostUser) || userInfo.IsVisitor(), FilesCommonResource.ErrorMassage_ChangeOwner);

            List<object> filesId;
            List<object> foldersId;
            ParseArrayItems(items, out foldersId, out filesId);

            var entries = new List<FileEntry>();

            using (var folderDao = GetFolderDao())
            {
                var folders = folderDao.GetFolders(foldersId.ToArray());

                foreach (var folder in folders)
                {
                    ErrorIf(!FileSecurity.CanEdit(folder), FilesCommonResource.ErrorMassage_SecurityException);
                    ErrorIf(folder.RootFolderType != FolderType.COMMON, FilesCommonResource.ErrorMassage_SecurityException);
                    if (folder.ProviderEntry) continue;

                    var newFolder = folder;
                    if (folder.CreateBy != userInfo.ID)
                    {
                        var folderAccess = folder.Access;

                        newFolder.CreateBy = userInfo.ID;
                        var newFolderID = folderDao.SaveFolder((Folder)newFolder);

                        newFolder = folderDao.GetFolder(newFolderID);
                        newFolder.Access = folderAccess;

                        FilesMessageService.Send(newFolder, GetHttpHeaders(), MessageAction.FileChangeOwner, new[] { newFolder.Title, userInfo.DisplayUserName(false) });
                    }
                    entries.Add(newFolder);
                }
            }

            using (var fileDao = GetFileDao())
            {
                var files = fileDao.GetFiles(filesId.ToArray());

                foreach (var file in files)
                {
                    ErrorIf(!FileSecurity.CanEdit(file), FilesCommonResource.ErrorMassage_SecurityException);
                    ErrorIf(EntryManager.FileLockedForMe(file.ID), FilesCommonResource.ErrorMassage_LockedFile);
                    ErrorIf(FileTracker.IsEditing(file.ID), FilesCommonResource.ErrorMassage_UpdateEditingFile);
                    ErrorIf(file.RootFolderType != FolderType.COMMON, FilesCommonResource.ErrorMassage_SecurityException);
                    if (file.ProviderEntry) continue;

                    var newFile = file;
                    if (file.CreateBy != userInfo.ID)
                    {
                        newFile = new File
                        {
                            ID = file.ID,
                            Version = file.Version + 1,
                            VersionGroup = file.VersionGroup + 1,
                            Title = file.Title,
                            FileStatus = file.FileStatus,
                            FolderID = file.FolderID,
                            CreateBy = userInfo.ID,
                            CreateOn = file.CreateOn,
                            ConvertedType = file.ConvertedType,
                            Comment = FilesCommonResource.CommentChangeOwner,
                            Encrypted = file.Encrypted,
                        };

                        using (var stream = fileDao.GetFileStream(file))
                        {
                            newFile.ContentLength = stream.CanSeek ? stream.Length : file.ContentLength;
                            newFile = fileDao.SaveFile(newFile, stream);
                        }

                        if (file.ThumbnailStatus == Thumbnail.Created)
                        {
                            using (var thumbnail = fileDao.GetThumbnail(file))
                            {
                                fileDao.SaveThumbnail(newFile, thumbnail);
                            }
                            newFile.ThumbnailStatus = Thumbnail.Created;
                        }

                        FileMarker.MarkAsNew(newFile);

                        EntryManager.SetFileStatus(newFile);

                        FilesMessageService.Send(newFile, GetHttpHeaders(), MessageAction.FileChangeOwner, new[] { newFile.Title, userInfo.DisplayUserName(false) });
                    }
                    entries.Add(newFile);
                }
            }

            return new ItemList<FileEntry>(entries);
        }

        public bool StoreOriginal(bool set)
        {
            FilesSettings.StoreOriginalFiles = set;
            FilesMessageService.Send(GetHttpHeaders(), MessageAction.DocumentsUploadingFormatsSettingsUpdated);

            return FilesSettings.StoreOriginalFiles;
        }

        public bool HideConfirmConvert(bool isForSave)
        {
            if (isForSave)
            {
                FilesSettings.HideConfirmConvertSave = true;
            }
            else
            {
                FilesSettings.HideConfirmConvertOpen = true;
            }

            return true;
        }

        [ActionName("updateifexist"), HttpGet]
        public bool UpdateIfExist(bool set)
        {
            FilesSettings.UpdateIfExist = set;
            FilesMessageService.Send(GetHttpHeaders(), MessageAction.DocumentsOverwritingSettingsUpdated);

            return FilesSettings.UpdateIfExist;
        }

        [ActionName("forcesave"), HttpGet]
        public bool Forcesave(bool set)
        {
            FilesSettings.Forcesave = set;
            FilesMessageService.Send(GetHttpHeaders(), MessageAction.DocumentsForcesave);

            return FilesSettings.Forcesave;
        }

        [ActionName("storeforcesave"), HttpGet]
        public bool StoreForcesave(bool set)
        {
            ErrorIf(!Global.IsAdministrator, FilesCommonResource.ErrorMassage_SecurityException);

            FilesSettings.StoreForcesave = set;
            FilesMessageService.Send(GetHttpHeaders(), MessageAction.DocumentsStoreForcesave);

            return FilesSettings.StoreForcesave;
        }

        public bool DisplayRecent(bool set)
        {
            if (!SecurityContext.IsAuthenticated) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

            FilesSettings.RecentSection = set;

            return FilesSettings.RecentSection;
        }

        public bool DisplayFavorite(bool set)
        {
            if (!SecurityContext.IsAuthenticated) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

            FilesSettings.FavoritesSection = set;

            return FilesSettings.FavoritesSection;
        }

        public bool DisplayTemplates(bool set)
        {
            if (!SecurityContext.IsAuthenticated) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException);

            FilesSettings.TemplatesSection = set;

            return FilesSettings.TemplatesSection;
        }

        [ActionName("changedeleteconfrim"), HttpGet]
        public bool ChangeDeleteConfrim(bool set)
        {
            FilesSettings.ConfirmDelete = set;

            return FilesSettings.ConfirmDelete;
        }

        [ActionName("downloadtargz"), HttpGet]
        public ICompress ChangeDownloadTarGz(bool set)
        {
            FilesSettings.DownloadTarGz = set;

            return CompressToArchive.Instance;
        }

        public String GetHelpCenter()
        {
            return Studio.UserControls.Common.HelpCenter.HelpCenter.RenderControlToString();
        }

        #region private

        private static FileSecurity FileSecurity
        {
            get { return Global.GetFilesSecurity(); }
        }

        private static IFolderDao GetFolderDao()
        {
            return Global.DaoFactory.GetFolderDao();
        }

        private static IFileDao GetFileDao()
        {
            return Global.DaoFactory.GetFileDao();
        }

        private static ITagDao GetTagDao()
        {
            return Global.DaoFactory.GetTagDao();
        }

        private static IDataStore GetStoreTemplate()
        {
            return Global.GetStoreTemplate();
        }

        private static IProviderDao GetProviderDao()
        {
            return Global.DaoFactory.GetProviderDao();
        }

        private static ISecurityDao GetSecurityDao()
        {
            return Global.DaoFactory.GetSecurityDao();
        }

        private static void ParseArrayItems(IEnumerable<string> data, out List<object> foldersId, out List<object> filesId)
        {
            //TODO:!!!!Fix
            foldersId = new List<object>();
            filesId = new List<object>();
            foreach (var id in data)
            {
                if (id.StartsWith("file_")) filesId.Add(id.Substring("file_".Length));
                if (id.StartsWith("folder_")) foldersId.Add(id.Substring("folder_".Length));
            }
        }

        private static void ParseArrayItems(Dictionary<String, String> items, out Dictionary<object, String> folders, out Dictionary<object, String> files)
        {
            //TODO:!!!!Fix
            folders = new Dictionary<object, String>();
            files = new Dictionary<object, String>();
            foreach (var item in (items ?? new Dictionary<String, String>()))
            {
                if (item.Key.StartsWith("file_")) files.Add(item.Key.Substring("file_".Length), item.Value);
                if (item.Key.StartsWith("folder_")) folders.Add(item.Key.Substring("folder_".Length), item.Value);
            }
        }

        private static void ErrorIf(bool condition, string errorMessage)
        {
            if (condition) throw new InvalidOperationException(errorMessage);
        }

        private static Exception GenerateException(Exception error, bool warning = false)
        {
            if (warning)
            {
                Global.Logger.Info(error);
            }
            else
            {
                Global.Logger.Error(error);
            }
            return new InvalidOperationException(error.Message, error);
        }

        private Dictionary<string, string> GetHttpHeaders()
        {
            if (Request != null && Request.Headers != null)
            {
                return Request.Headers.ToDictionary(h => h.Key, h => string.Join(", ", h.Value.ToArray()));
            }
            else if (HttpContext.Current != null && HttpContext.Current.Request != null && HttpContext.Current.Request.Headers != null)
            {
                var headers = new Dictionary<string, string>();
                foreach (var k in HttpContext.Current.Request.Headers.AllKeys)
                {
                    headers[k] = string.Join(", ", HttpContext.Current.Request.Headers.GetValues(k));
                }
                return headers;
            }
            return null;
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Data.Backup/Storage/ConsumerBackupStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using ASC.Data.Storage;
using ASC.Data.Storage.Configuration;

namespace ASC.Data.Backup.Storage
{
    internal class ConsumerBackupStorage : IBackupStorage
    {
        private readonly IDataStore store;
        private const string Domain = "backup";

        public ConsumerBackupStorage(IReadOnlyDictionary<string, string> storageParams)
        {
            var settings = new StorageSettings { Module = storageParams["module"], Props = storageParams.Where(r => r.Key != "module").ToDictionary(r => r.Key, r => r.Value) };
            store = settings.DataStore;
        }

        public string Upload(string storageBasePath, string localPath, Guid userId)
        {
            using (var stream = File.OpenRead(localPath))
            {
                var storagePath = Path.GetFileName(localPath);
                store.Save(Domain, storagePath, stream, ACL.Private);
                return storagePath;
            }
        }

        public void Download(string storagePath, string targetLocalPath)
        {
            using (var source = store.GetReadStream(Domain, storagePath))
            using (var destination = File.OpenWrite(targetLocalPath))
            {
                source.CopyTo(destination);
            }
        }

        public void Delete(string storagePath)
        {
            if (store.IsFile(Domain, storagePath))
            {
                store.Delete(Domain, storagePath);
            }
        }

        public bool IsExists(string storagePath)
        {
            return store.IsFile(Domain, storagePath);
        }

        public string GetPublicLink(string storagePath)
        {
            return store.GetInternalUri(Domain, storagePath, TimeSpan.FromDays(1), null).AbsoluteUri;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Domain/Reports/ReportType.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Projects.Core.Domain.Reports
{
    public enum ReportType
    {
        MilestonesExpired,
        MilestonesNearest,
        UsersWithoutActiveTasks,
        ProjectsWithoutActiveMilestones,
        ProjectsWithoutActiveTasks,
        UsersActivity,
        UsersWorkload,
        ProjectsList,
        TimeSpend,
        TasksByProjects,
        TasksByUsers,
        TasksExpired,
        EmptyReport
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Extensions/DataContractsExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Mail.Core.Engine;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Enums;
using ASC.Web.Studio.Utility;

using ContactInfo = ASC.Mail.Data.Contracts.ContactInfo;

namespace ASC.Mail.Extensions
{
    public static class DataContractsExtensions
    {
        public static List<MailAccountData> ToAccountData(this AccountInfo account)
        {
            var fromEmailList = new List<MailAccountData>();
            var mailBoxAccountSettings = MailBoxAccountSettings.LoadForCurrentUser();

            var emailData = new MailAccountData
            {
                MailboxId = account.Id,
                Email = account.Email,
                Name = account.Name,
                Enabled = account.Enabled,
                OAuthConnection = account.OAuthConnection,
                AuthError = account.AuthError,
                QuotaError = account.QuotaError,
                Signature = account.Signature,
                Autoreply = account.Autoreply,
                EMailInFolder = account.EMailInFolder,
                IsAlias = false,
                IsGroup = false,
                IsTeamlabMailbox = account.IsTeamlabMailbox,
                IsDefault = mailBoxAccountSettings.DefaultEmail == account.Email,
                IsSharedDomainMailbox = account.IsSharedDomainMailbox
            };
            fromEmailList.Add(emailData);

            foreach (var alias in account.Aliases)
            {
                emailData = new MailAccountData
                {
                    MailboxId = account.Id,
                    Email = alias.Email,
                    Name = account.Name,
                    Enabled = account.Enabled,
                    OAuthConnection = false,
                    AuthError = account.AuthError,
                    QuotaError = account.QuotaError,
                    Signature = account.Signature,
                    Autoreply = account.Autoreply,
                    EMailInFolder = account.EMailInFolder,
                    IsAlias = true,
                    IsGroup = false,
                    IsTeamlabMailbox = account.IsTeamlabMailbox,
                    IsDefault = mailBoxAccountSettings.DefaultEmail == alias.Email
                };
                fromEmailList.Add(emailData);
            }

            foreach (
                var @group in
                    account.Groups.Where(@group => fromEmailList.FindIndex(e => e.Email.Equals(@group.Email)) == -1))
            {
                emailData = new MailAccountData
                {
                    MailboxId = account.Id,
                    Email = @group.Email,
                    Name = "",
                    Enabled = true,
                    OAuthConnection = false,
                    AuthError = false,
                    QuotaError = false,
                    Signature = new MailSignatureData(-1, account.Signature.Tenant, "", false),
                    Autoreply = new MailAutoreplyData(-1, account.Signature.Tenant, false, false,
                        false, DateTime.MinValue, DateTime.MinValue, String.Empty, String.Empty),
                    EMailInFolder = "",
                    IsAlias = false,
                    IsGroup = true,
                    IsTeamlabMailbox = true
                };
                fromEmailList.Add(emailData);
            }

            return fromEmailList;
        }

        public static List<MailAccountData> ToAccountData(this List<AccountInfo> accounts)
        {
            var fromEmailList = new List<MailAccountData>();

            fromEmailList = accounts.Aggregate(fromEmailList, (current, account) => current.Concat(account.ToAccountData()).ToList());

            return fromEmailList.DistinctBy(a => a.Email).ToList();
        }

        private const string BASE_VIRTUAL_PATH = "~/addons/mail/";

        public static MailContactData ToMailContactData(this ContactCard contactCard)
        {
            var baseAbsolutePath = CommonLinkUtility.ToAbsolute(BASE_VIRTUAL_PATH).ToLower();

            var emails = new MailContactData.EmailsList<ContactInfo>();
            var phones = new MailContactData.PhoneNumgersList<ContactInfo>();

            foreach (var contact in contactCard.ContactItems)
            {
                if (contact.Type == (int)ContactInfoType.Email)
                {
                    if (contact.IsPrimary)
                        emails.Insert(0,
                            new ContactInfo { Id = contact.Id, Value = contact.Data, IsPrimary = contact.IsPrimary });
                    else
                        emails.Add(new ContactInfo
                        {
                            Id = contact.Id,
                            Value = contact.Data,
                            IsPrimary = contact.IsPrimary
                        });
                }
                else if (contact.Type == (int)ContactInfoType.Phone)
                {
                    if (contact.IsPrimary)
                        phones.Insert(0,
                            new ContactInfo { Id = contact.Id, Value = contact.Data, IsPrimary = contact.IsPrimary });
                    else
                        phones.Add(new ContactInfo
                        {
                            Id = contact.Id,
                            Value = contact.Data,
                            IsPrimary = contact.IsPrimary
                        });
                }
            }

            var contactData = new MailContactData
            {
                ContactId = contactCard.ContactInfo.Id,
                Name = contactCard.ContactInfo.ContactName,
                Description = contactCard.ContactInfo.Description,
                Emails = emails,
                PhoneNumbers = phones,
                Type = (int)contactCard.ContactInfo.Type,
                SmallFotoUrl =
                    string.Format("{0}HttpHandlers/contactphoto.ashx?cid={1}&ps=1", baseAbsolutePath, contactCard.ContactInfo.Id)
                        .ToLower(),
                MediumFotoUrl =
                    string.Format("{0}HttpHandlers/contactphoto.ashx?cid={1}&ps=2", baseAbsolutePath, contactCard.ContactInfo.Id)
                        .ToLower()
            };

            return contactData;
        }

        public static List<MailContactData> ToMailContactDataList(this List<ContactCard> contacts)
        {
            var contactsList = contacts.Select(contact => contact.ToMailContactData()).ToList();

            return contactsList;
        }

        public static void GetNeededAccounts(this List<MailAccountData> accounts, out MailAccountData defaultAccount,
            out List<MailAccountData> commonAccounts, out List<MailAccountData> serverAccounts,
            out List<MailAccountData> aliases, out List<MailAccountData> groups)
        {
            defaultAccount = null;
            commonAccounts = new List<MailAccountData>();
            serverAccounts = new List<MailAccountData>();
            aliases = new List<MailAccountData>();
            groups = new List<MailAccountData>();

            if (accounts == null)
            {
                return;
            }

            foreach (var account in accounts)
            {
                if (account.IsDefault)
                {
                    defaultAccount = account;
                }
                else if (account.IsGroup)
                {
                    groups.Add(account);
                }
                else if (account.IsAlias)
                {
                    aliases.Add(account);
                }
                else if (account.IsTeamlabMailbox)
                {
                    serverAccounts.Add(account);
                }
                else
                {
                    commonAccounts.Add(account);
                }
            }
        }

        public static List<MailFolderData> ToFolderData(this List<FolderEngine.MailFolderInfo> folders)
        {
            return folders.Select(ToFolderData).ToList();
        }

        public static MailFolderData ToFolderData(this FolderEngine.MailFolderInfo folder)
        {
            return new MailFolderData
            {
                Id = folder.id,
                UnreadCount = folder.unread,
                UnreadMessagesCount = folder.unreadMessages,
                TotalCount = folder.total,
                TotalMessgesCount = folder.totalMessages,
                TimeModified = folder.timeModified
            };
        }

        public static MailTagData ToTagData(this Tag tag)
        {
            return new MailTagData
            {
                Id = tag.Id,
                Name = tag.TagName,
                Style = tag.Style,
                Addresses = new MailTagData.AddressesList<string>(tag.Addresses.Split(';')),
                LettersCount = tag.Count
            };
        }

        public static List<MailTagData> ToTagData(this List<Tag> tags)
        {
            return tags
                .Select(t => new MailTagData
                {
                    Id = t.Id,
                    Name = t.TagName,
                    Style = t.Style,
                    Addresses = new MailTagData.AddressesList<string>(t.Addresses.Split(';')),
                    LettersCount = t.Count
                })
                .ToList();
        }

        public static Attachment ToAttachmnet(this MailAttachmentData a, int mailId, bool isRemoved = false)
        {
            var attachment = new Attachment
            {
                Id = a.fileId,
                MailId = mailId,
                Name = a.fileName,
                StoredName = a.storedName,
                Type = a.contentType,
                Size = a.size,
                FileNumber = a.fileNumber,
                IsRemoved = isRemoved,
                ContentId = a.contentId,
                Tenant = a.tenant,
                MailboxId = a.mailboxId
            };

            return attachment;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Wizard.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Core;
using ASC.Web.Core.Files;
using ASC.Web.Core.Utility.Settings;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.FirstTime;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio
{
    public partial class Wizard : MainPage
    {
        protected override bool MayNotAuth
        {
            get { return true; }
        }

        protected override bool MayNotPaid
        {
            get { return true; }
        }

        protected override bool CheckWizardCompleted
        {
            get { return false; }
        }

        protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);
            var wizardSettings = WizardSettings.Load();
            if (wizardSettings.Completed)
                Response.Redirect(CommonLinkUtility.GetDefault());

            if (CoreContext.Configuration.Personal)
                Context.Response.Redirect(FilesLinkUtility.FilesBaseAbsolutePath);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!SecurityContext.IsAuthenticated)
            {
                try
                {
                    var owner = CoreContext.UserManager.GetUsers(CoreContext.TenantManager.GetCurrentTenant().OwnerId);
                    SecurityContext.AuthenticateMe(owner.ID);
                }
                catch (System.Security.Authentication.InvalidCredentialException)
                {
                }
                catch (System.Security.SecurityException)
                {
                }
            }

            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

            Page.RegisterBodyScripts("~/js/third-party/head.load.js",
                "~/js/asc/core/asc.listscript.js");

            Title = Resource.WizardPageTitle;

            Master.DisabledSidePanel = true;
            Master.TopStudioPanel.DisableProductNavigation = true;
            Master.TopStudioPanel.DisableUserInfo = true;
            Master.TopStudioPanel.DisableSearch = true;
            Master.TopStudioPanel.DisableSettings = true;
            Master.TopStudioPanel.DisableTariff = true;
            Master.TopStudioPanel.DisableGift = true;

            content.Controls.Add(LoadControl(StepContainer.Location));
        }
    }
}

<|start_filename|>common/ASC.Common/Notify/Engine/InterceptorStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;

namespace ASC.Notify.Engine
{
    class InterceptorStorage
    {
        private readonly string CallContext_Prefix = "InterceptorStorage.CALLCONTEXT_KEY." + Guid.NewGuid();
        private readonly object syncRoot = new object();
        private readonly Dictionary<string, ISendInterceptor> globalInterceptors = new Dictionary<string, ISendInterceptor>(10);


        private Dictionary<string, ISendInterceptor> callInterceptors
        {
            get
            {
                var storage = CallContext.GetData(CallContext_Prefix) as Dictionary<string, ISendInterceptor>;
                if (storage == null)
                {
                    storage = new Dictionary<string, ISendInterceptor>(10);
                    CallContext.SetData(CallContext_Prefix, storage);
                }
                return storage;
            }
        }


        public void Add(ISendInterceptor interceptor)
        {
            if (interceptor == null) throw new ArgumentNullException("interceptor");
            if (String.IsNullOrEmpty(interceptor.Name)) throw new ArgumentException("empty name property", "interceptor");

            switch (interceptor.Lifetime)
            {
                case InterceptorLifetime.Call:
                    AddInternal(interceptor, callInterceptors);
                    break;
                case InterceptorLifetime.Global:
                    AddInternal(interceptor, globalInterceptors);
                    break;
                default:
                    throw new NotImplementedException();
            }
        }

        public ISendInterceptor Get(string name)
        {
            if (String.IsNullOrEmpty(name)) throw new ArgumentException("empty name", "name");

            ISendInterceptor result = null;
            result = GetInternal(name, callInterceptors);
            if (result == null) result = GetInternal(name, globalInterceptors);
            return result;
        }

        public void Remove(string name)
        {
            if (String.IsNullOrEmpty(name)) throw new ArgumentException("empty name", "name");

            RemoveInternal(name, callInterceptors);
            RemoveInternal(name, globalInterceptors);
        }

        public void Clear()
        {
            Clear(InterceptorLifetime.Call | InterceptorLifetime.Global);
        }

        public void Clear(InterceptorLifetime lifetime)
        {
            lock (syncRoot)
            {
                if ((lifetime & InterceptorLifetime.Call) == InterceptorLifetime.Call) callInterceptors.Clear();
                if ((lifetime & InterceptorLifetime.Global) == InterceptorLifetime.Global) globalInterceptors.Clear();
            }
        }

        public List<ISendInterceptor> GetAll()
        {
            var result = new List<ISendInterceptor>();
            result.AddRange(callInterceptors.Values);
            result.AddRange(globalInterceptors.Values);
            return result;
        }


        private void AddInternal(ISendInterceptor interceptor, Dictionary<string, ISendInterceptor> storage)
        {
            lock (syncRoot)
            {
                storage[interceptor.Name] = interceptor;
            }
        }

        private ISendInterceptor GetInternal(string name, Dictionary<string, ISendInterceptor> storage)
        {
            ISendInterceptor interceptor = null;
            lock (syncRoot)
            {
                storage.TryGetValue(name, out interceptor);
            }
            return interceptor;
        }

        private void RemoveInternal(string name, Dictionary<string, ISendInterceptor> storage)
        {
            lock (syncRoot)
            {
                storage.Remove(name);
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/TagAddressDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;

namespace ASC.Mail.Core.Dao
{
    public class TagAddressDao : BaseDao, ITagAddressDao
    {
        protected static ITable table = new MailTableFactory().Create<TagAddressTable>();

        protected string CurrentUserId { get; private set; }

        public TagAddressDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public List<int> GetTagIds(string email)
        {
            var query = new SqlQuery(TagAddressTable.TABLE_NAME)
                .Distinct()
                .Select(TagAddressTable.Columns.TagId)
                .Where(TagAddressTable.Columns.Address, email)
                .Where(Exp.In(TagAddressTable.Columns.TagId,
                    new SqlQuery(TagTable.TABLE_NAME)
                        .Select(TagTable.Columns.Id)
                        .Where(TagTable.Columns.Tenant, Tenant)
                        .Where(TagTable.Columns.User, CurrentUserId)
                    )
                );

            var tagIds = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToInt32(r[0]));

            return tagIds;
        }

        public List<string> GetTagAddresses(int tagId)
        {
            var query = new SqlQuery(TagAddressTable.TABLE_NAME)
                .Select(TagAddressTable.Columns.Address)
                .Where(TagAddressTable.Columns.TagId, tagId)
                .Where(TagAddressTable.Columns.Tenant, Tenant);

            var list = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToString(r[0]));

            return list;
        }

        public int Save(int tagId, string email)
        {
            var query = new SqlInsert(TagAddressTable.TABLE_NAME, true)
                .InColumnValue(TagAddressTable.Columns.TagId, tagId)
                .InColumnValue(TagAddressTable.Columns.Address, email)
                .InColumnValue(TagAddressTable.Columns.Tenant, Tenant);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }

        public int Delete(int tagId, string email = null)
        {
            var query = new SqlDelete(TagAddressTable.TABLE_NAME)
                .Where(TagAddressTable.Columns.TagId, tagId)
                .Where(TagAddressTable.Columns.Tenant, Tenant);

            if (!string.IsNullOrEmpty(email))
            {
                query.Where(TagAddressTable.Columns.Address, email);
            }

            var result = Db.ExecuteNonQuery(query);
            return result;
        }

        public int DeleteAll()
        {
            var query = new SqlDelete(TagAddressTable.TABLE_NAME)
                .Where(TagAddressTable.Columns.Tenant, Tenant);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/ABNF/ABNF_Alternation.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.ABNF
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.IO;

    #endregion

    /// <summary>
    /// This class represent ABNF "alternation". Defined in RFC 5234 4.
    /// </summary>
    public class ABNF_Alternation
    {
        #region Members

        private readonly List<ABNF_Concatenation> m_pItems;

        #endregion

        #region Properties

        /// <summary>
        /// Gets alternation items.
        /// </summary>
        public List<ABNF_Concatenation> Items
        {
            get { return m_pItems; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public ABNF_Alternation()
        {
            m_pItems = new List<ABNF_Concatenation>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static ABNF_Alternation Parse(StringReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // alternation = concatenation *(*c-wsp "/" *c-wsp concatenation)

            ABNF_Alternation retVal = new ABNF_Alternation();

            while (true)
            {
                ABNF_Concatenation item = ABNF_Concatenation.Parse(reader);
                if (item != null)
                {
                    retVal.m_pItems.Add(item);
                }

                // We reached end of string.
                if (reader.Peek() == -1)
                {
                    break;
                }
                    // We have next alternation item.
                else if (reader.Peek() == '/')
                {
                    reader.Read();
                }
                    // We have unexpected value, probably alternation ends.
                else
                {
                    break;
                }
            }

            return retVal;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/TagEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;

using ASC.Common.Logging;
using ASC.ElasticSearch;
using ASC.Mail.Core.Dao.Expressions.Message;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Search;
using ASC.Web.Core;

namespace ASC.Mail.Core.Engine
{
    public class TagEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }
        public ILog Log { get; private set; }
        public EngineFactory Factory { get; private set; }

        public TagEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.TagEngine");
            Factory = new EngineFactory(Tenant, User);
        }

        public Tag GetTag(int id)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoTag = daoFactory.CreateTagDao(Tenant, User);

                var tag = daoTag.GetTag(id);

                return tag;
            }
        }

        public Tag GetTag(string name)
        {
            using (var daoFactory = new DaoFactory())
            {
                var dao = daoFactory.CreateTagDao(Tenant, User);

                var tag = dao.GetTag(name);

                return tag;
            }
        }

        public List<Tag> GetTags()
        {
            using (var daoFactory = new DaoFactory())
            {
                var dao = daoFactory.CreateTagDao(Tenant, User);

                var tagList = dao.GetTags();

                if (!WebItemSecurity.IsAvailableForMe(WebItemManager.CRMProductID))
                {
                    return tagList
                        .Where(p => p.TagName != "")
                        .OrderByDescending(p => p.Id)
                        .ToList();
                }

                var actualCrmTags = dao.GetCrmTags();

                var removedCrmTags =
                    tagList.Where(t => t.Id < 0 && !actualCrmTags.Exists(ct => ct.Id == t.Id))
                        .ToList();

                if (removedCrmTags.Any())
                {
                    dao.DeleteTags(removedCrmTags.Select(t => t.Id).ToList());
                    removedCrmTags.ForEach(t => tagList.Remove(t));
                }

                foreach (var crmTag in actualCrmTags)
                {
                    var tag = tagList.FirstOrDefault(t => t.Id == crmTag.Id);
                    if (tag != null)
                        tag.TagName = crmTag.TagName;
                    else
                        tagList.Add(crmTag);
                }

                return tagList
                    .Where(p => !string.IsNullOrEmpty(p.TagName))
                    .OrderByDescending(p => p.Id)
                    .ToList();
            }
        }

        public List<Tag> GetCrmTags(string email)
        {
            var tags = new List<Tag>();

            using (var daoFactory = new DaoFactory())
            {
                var daoCrmContacts = daoFactory.CreateCrmContactDao(Tenant, User);

                var allowedContactIds = daoCrmContacts.GetCrmContactIds(email);

                if (!allowedContactIds.Any())
                    return tags;

                var daoTag = daoFactory.CreateTagDao(Tenant, User);

                tags = daoTag.GetCrmTags(allowedContactIds);

                return tags
                    .Where(p => !string.IsNullOrEmpty(p.TagName))
                    .OrderByDescending(p => p.Id)
                    .ToList();
            }
        }

        public bool IsTagExists(string name)
        {
            using (var daoFactory = new DaoFactory())
            {
                var dao = daoFactory.CreateTagDao(Tenant, User);

                var tag = dao.GetTag(name);

                return tag != null;
            }
        }

        public Tag CreateTag(string name, string style, IEnumerable<string> addresses)
        {
            if (string.IsNullOrEmpty(name))
                throw new ArgumentNullException("name");

            using (var daoFactory = new DaoFactory())
            {
                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var tagDao = daoFactory.CreateTagDao(Tenant, User);

                    var tagAddressDao = daoFactory.CreateTagAddressDao(Tenant, User);

                    var tag = tagDao.GetTag(name);

                    if (tag != null)
                        throw new ArgumentException("Tag name already exists");

                    var emails = addresses as IList<string> ?? addresses.ToList();

                    tag = new Tag
                    {
                        Id = 0,
                        TagName = name,
                        Tenant = Tenant,
                        User = User,
                        Addresses = string.Join(";", emails),
                        Style = style,
                        Count = 0,
                        CrmId = 0
                    };

                    var id = tagDao.SaveTag(tag);

                    if (id < 0)
                        throw new Exception("Save failed");

                    foreach (var email in emails)
                    {
                        tagAddressDao.Save(id, email);
                    }

                    tag.Id = id;

                    tx.Commit();

                    return tag;
                }
            }
        }

        public Tag UpdateTag(int id, string name, string style, IEnumerable<string> addresses)
        {
            using (var daoFactory = new DaoFactory())
            {
                var tagDao = daoFactory.CreateTagDao(Tenant, User);

                var tagAddressDao = daoFactory.CreateTagAddressDao(Tenant, User);

                var tag = tagDao.GetTag(id);

                if (tag == null)
                    throw new ArgumentException(@"Tag not found");

                if (!tag.TagName.Equals(name))
                {
                    var tagByName = tagDao.GetTag(name);

                    if (tagByName != null && tagByName.Id != id)
                        throw new ArgumentException(@"Tag name already exists");

                    tag.TagName = name;
                }

                if (!tag.Style.Equals(style))
                {
                    tag.Style = style;
                }

                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var oldAddresses = tagAddressDao.GetTagAddresses(tag.Id);

                    var newAddresses = addresses as IList<string> ?? addresses.ToList();
                    tag.Addresses = string.Join(";", newAddresses);

                    tagDao.SaveTag(tag);

                    if (!newAddresses.Any())
                    {
                        if (oldAddresses.Any())
                            tagAddressDao.Delete(tag.Id);
                    }
                    else
                    {
                        foreach (var oldAddress in oldAddresses)
                        {
                            if (!newAddresses.Contains(oldAddress))
                            {
                                tagAddressDao.Delete(tag.Id, oldAddress);
                            }
                        }

                        foreach (var newAddress in newAddresses)
                        {
                            if (!oldAddresses.Contains(newAddress))
                            {
                                tagAddressDao.Save(tag.Id, newAddress);
                            }
                        }
                    }

                    tx.Commit();

                    return tag;
                }
            }
        }

        public bool DeleteTag(int id)
        {
            using (var daoFactory = new DaoFactory())
            {
                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var tagDao = daoFactory.CreateTagDao(Tenant, User);

                    var tagAddressDao = daoFactory.CreateTagAddressDao(Tenant, User);

                    var tagMailDao = daoFactory.CreateTagMailDao(Tenant, User);

                    tagDao.DeleteTag(id);

                    tagAddressDao.Delete(id);

                    tagMailDao.DeleteByTagId(id);

                    tx.Commit();
                }
            }

            return true;
        }

        public List<int> GetOrCreateTags(int tenant, string user, string[] names)
        {
            var tagIds = new List<int>();

            if (!names.Any())
                return tagIds;

            using (var daoFactory = new DaoFactory())
            {
                var dao = daoFactory.CreateTagDao(Tenant, User);

                var tags = dao.GetTags();

                foreach (var name in names)
                {
                    var tag =
                        tags.FirstOrDefault(t => t.TagName.Equals(name, StringComparison.InvariantCultureIgnoreCase));

                    if (tag != null)
                    {
                        tagIds.Add(tag.Id);
                        continue;
                    }

                    tag = new Tag
                    {
                        Id = 0,
                        TagName = name,
                        Addresses = "",
                        Count = 0,
                        CrmId = 0,
                        Style = (Math.Abs(name.GetHashCode() % 16) + 1).ToString(CultureInfo.InvariantCulture),
                        Tenant = tenant,
                        User = user
                    };

                    var id = dao.SaveTag(tag);

                    if (id > 0)
                    {
                        Log.InfoFormat("TagEngine->GetOrCreateTags(): new tag '{0}' with id = {1} has bee created",
                            name, id);

                        tagIds.Add(id);
                    }
                }
            }

            return tagIds;
        }

        public void SetMessagesTag(List<int> messageIds, int tagId)
        {
            using (var daoFactory = new DaoFactory())
            {
                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    if (!SetMessagesTag(daoFactory, messageIds, tagId))
                    {
                        tx.Rollback();
                        return;
                    }

                    tx.Commit();
                }
            }

            UpdateIndexerTags(messageIds, UpdateAction.Add, tagId);

            Log.InfoFormat("TagEngine->SetMessagesTag(): tag with id = {0} has bee added to messages [{1}]", tagId,
                string.Join(",", messageIds));
        }

        public bool SetMessagesTag(IDaoFactory daoFactory, List<int> messageIds, int tagId)
        {
            var daoTag = daoFactory.CreateTagDao(Tenant, User);

            var tag = daoTag.GetTag(tagId);

            if (tag == null)
            {
                return false;
            }

            List<int> validIds;
            List<ChainInfo> chains;

            GetValidForUserMessages(daoFactory, messageIds, out validIds, out chains);

            var daoTagMail = daoFactory.CreateTagMailDao(Tenant, User);

            daoTagMail.SetMessagesTag(validIds, tag.Id);

            UpdateTagsCount(daoTagMail, daoTag, tag);

            foreach (var chain in chains)
            {
                Factory.ChainEngine.UpdateChainTags(daoFactory, chain.Id, chain.Folder, chain.MailboxId, Tenant, User);
            }

            var daoMail = daoFactory.CreateMailDao(Tenant, User);

            // Change time_modified for index
            daoMail.SetMessagesChanged(validIds);

            return true;
        }

        public void UnsetMessagesTag(List<int> messageIds, int tagId)
        {
            List<int> validIds;

            using (var daoFactory = new DaoFactory())
            {
                var daoTagMail = daoFactory.CreateTagMailDao(Tenant, User);

                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var daoTag = daoFactory.CreateTagDao(Tenant, User);

                    List<ChainInfo> chains;

                    GetValidForUserMessages(daoFactory, messageIds, out validIds, out chains);

                    daoTagMail.Delete(tagId, validIds);

                    var tag = daoTag.GetTag(tagId);

                    if (tag != null)
                        UpdateTagsCount(daoTagMail, daoTag, tag);

                    foreach (var chain in chains)
                    {
                        Factory.ChainEngine.UpdateChainTags(daoFactory, chain.Id, chain.Folder, chain.MailboxId, Tenant,
                            User);
                    }

                    var daoMail = daoFactory.CreateMailDao(Tenant, User);

                    // Change time_modified for index
                    daoMail.SetMessagesChanged(validIds);

                    tx.Commit();
                }
            }

            UpdateIndexerTags(validIds, UpdateAction.Remove, tagId);
        }

        public void SetConversationsTag(IEnumerable<int> messagesIds, int tagId)
        {
            var ids = messagesIds as IList<int> ?? messagesIds.ToList();

            if (!ids.Any()) return;

            List<int> validIds;

            using (var daoFactory = new DaoFactory())
            {
                var daoTagMail = daoFactory.CreateTagMailDao(Tenant, User);

                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var daoTag = daoFactory.CreateTagDao(Tenant, User);

                    var tag = daoTag.GetTag(tagId);

                    if (tag == null)
                    {
                        tx.Rollback();
                        return;
                    }

                    var foundedChains = Factory.ChainEngine.GetChainedMessagesInfo(daoFactory, (List<int>)messagesIds);

                    if (!foundedChains.Any())
                    {
                        tx.Rollback();
                        return;
                    }

                    validIds = foundedChains.Select(r => r.Id).ToList();
                    var chains =
                        foundedChains.GroupBy(r => new { r.ChainId, r.Folder, r.MailboxId })
                            .Select(
                                r =>
                                    new ChainInfo
                                    {
                                        Id = r.Key.ChainId,
                                        Folder = r.Key.Folder,
                                        MailboxId = r.Key.MailboxId
                                    });

                    daoTagMail.SetMessagesTag(validIds, tag.Id);

                    UpdateTagsCount(daoTagMail, daoTag, tag);

                    foreach (var chain in chains)
                    {
                        Factory.ChainEngine.UpdateChainTags(daoFactory, chain.Id, chain.Folder, chain.MailboxId, Tenant,
                            User);
                    }

                    var daoMail = daoFactory.CreateMailDao(Tenant, User);

                    // Change time_modified for index
                    daoMail.SetMessagesChanged(validIds);

                    tx.Commit();
                }
            }

            UpdateIndexerTags(validIds, UpdateAction.Add, tagId);
        }

        public void UnsetConversationsTag(IEnumerable<int> messagesIds, int tagId)
        {
            var ids = messagesIds as IList<int> ?? messagesIds.ToList();

            if (!ids.Any()) return;

            List<int> validIds;

            using (var daoFactory = new DaoFactory())
            {
                var daoTagMail = daoFactory.CreateTagMailDao(Tenant, User);

                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var daoTag = daoFactory.CreateTagDao(Tenant, User);

                    var foundedChains = Factory.ChainEngine.GetChainedMessagesInfo(daoFactory, (List<int>)messagesIds);

                    if (!foundedChains.Any())
                    {
                        tx.Rollback();
                        return;
                    }

                    validIds = foundedChains.Select(r => r.Id).ToList();

                    var chains =
                        foundedChains.GroupBy(r => new { r.ChainId, r.Folder, r.MailboxId })
                            .Select(
                                r =>
                                    new ChainInfo
                                    {
                                        Id = r.Key.ChainId,
                                        Folder = r.Key.Folder,
                                        MailboxId = r.Key.MailboxId
                                    });

                    daoTagMail.Delete(tagId, validIds);

                    var tag = daoTag.GetTag(tagId);

                    if (tag != null)
                        UpdateTagsCount(daoTagMail, daoTag, tag);

                    foreach (var chain in chains)
                    {
                        Factory.ChainEngine.UpdateChainTags(daoFactory, chain.Id, chain.Folder, chain.MailboxId, Tenant,
                            User);
                    }

                    var daoMail = daoFactory.CreateMailDao(Tenant, User);

                    // Change time_modified for index
                    daoMail.SetMessagesChanged(validIds);

                    tx.Commit();
                }
            }

            UpdateIndexerTags(validIds, UpdateAction.Remove, tagId);
        }

        private void UpdateIndexerTags(List<int> ids, UpdateAction action, int tagId)
        {
            if (!FactoryIndexer<MailWrapper>.Support || !FactoryIndexer.CheckState(false))
                return;

            if (ids == null || !ids.Any())
                return;

            var data = new MailWrapper
            {
                Tags = new List<TagWrapper>
                    {
                        new TagWrapper
                        {
                            Id = tagId
                        }
                    }
            };

            Expression<Func<Selector<MailWrapper>, Selector<MailWrapper>>> exp =
                s => s.In(m => m.Id, ids.ToArray());

            Factory.IndexEngine.Update(data, exp, action, s => s.Tags);
        }

        private static void UpdateTagsCount(ITagMailDao daoTagMail, ITagDao daoTag, Tag tag)
        {
            var count = daoTagMail.CalculateTagCount(tag.Id);

            tag.Count = count;

            daoTag.SaveTag(tag);
        }

        private void GetValidForUserMessages(IDaoFactory daoFactory, List<int> messagesIds, out List<int> validIds,
            out List<ChainInfo> chains)
        {
            var daoMailInfo = daoFactory.CreateMailInfoDao(Tenant, User);

            var mailInfoList = daoMailInfo.GetMailInfoList(
                SimpleMessagesExp.CreateBuilder(Tenant, User)
                    .SetMessageIds(messagesIds)
                    .Build());

            validIds = new List<int>();
            chains = new List<ChainInfo>();

            foreach (var mailInfo in mailInfoList)
            {
                validIds.Add(mailInfo.Id);
                chains.Add(new ChainInfo
                {
                    Id = mailInfo.ChainId,
                    Folder = mailInfo.Folder,
                    MailboxId = mailInfo.MailboxId
                });
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Helpers/PathProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;

using ASC.Files.Core;
using ASC.Security.Cryptography;
using ASC.Web.Core.Files;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Files.Resources;
using ASC.Web.Studio.Utility;

using File = ASC.Files.Core.File;

namespace ASC.Web.Files.Classes
{
    public static class PathProvider
    {
        public static readonly String ProjectVirtualPath = "~/Products/Projects/TMDocs.aspx";

        public static readonly String TemplatePath = "/Products/Files/Templates/";

        public static readonly String StartURL = FilesLinkUtility.FilesBaseVirtualPath;

        public static readonly String GetFileServicePath = CommonLinkUtility.ToAbsolute("~/Products/Files/Services/WCFService/service.svc/");

        public static string GetImagePath(string imgFileName)
        {
            return WebImageSupplier.GetAbsoluteWebPath(imgFileName, Configuration.ProductEntryPoint.ID);
        }

        public static string GetFileStaticRelativePath(string fileName)
        {
            var ext = FileUtility.GetFileExtension(fileName);
            switch (ext)
            {
                case ".js": //Attention: Only for ResourceBundleControl
                    return VirtualPathUtility.ToAbsolute("~/Products/Files/js/" + fileName);
                case ".ascx":
                    return CommonLinkUtility.ToAbsolute("~/Products/Files/Controls/" + fileName);
                case ".css": //Attention: Only for ResourceBundleControl
                    return VirtualPathUtility.ToAbsolute("~/Products/Files/App_Themes/default/" + fileName);
            }

            return fileName;
        }

        public static String GetFileControlPath(String fileName)
        {
            return CommonLinkUtility.ToAbsolute("~/Products/Files/Controls/" + fileName);
        }

        public static string GetFolderUrl(Folder folder, int projectID = 0)
        {
            if (folder == null) throw new ArgumentNullException("folder", FilesCommonResource.ErrorMassage_FolderNotFound);

            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                switch (folder.RootFolderType)
                {
                    case FolderType.BUNCH:
                        if (projectID == 0)
                        {
                            var path = folderDao.GetBunchObjectID(folder.RootFolderId);

                            var projectIDFromDao = path.Split('/').Last();

                            if (string.IsNullOrEmpty(projectIDFromDao)) return string.Empty;

                            projectID = Convert.ToInt32(projectIDFromDao);
                        }
                        return CommonLinkUtility.GetFullAbsolutePath(string.Format("{0}?prjid={1}#{2}", ProjectVirtualPath, projectID, folder.ID));
                    default:
                        return CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FilesBaseAbsolutePath + "#" + HttpUtility.UrlPathEncode(folder.ID.ToString()));
                }
            }
        }

        public static String GetFolderUrl(object folderId)
        {
            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                var folder = folderDao.GetFolder(folderId);

                return GetFolderUrl(folder);
            }
        }

        public static string GetFileStreamUrl(File file, string doc = null, bool lastVersion = false)
        {
            if (file == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound);

            //NOTE: Always build path to handler!
            var uriBuilder = new UriBuilder(CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath));
            var query = uriBuilder.Query;
            query += FilesLinkUtility.Action + "=stream&";
            query += FilesLinkUtility.FileId + "=" + HttpUtility.UrlEncode(file.ID.ToString()) + "&";
            var version = 0;
            if (!lastVersion)
            {
                version = file.Version;
                query += FilesLinkUtility.Version + "=" + file.Version + "&";
            }
            query += FilesLinkUtility.AuthKey + "=" + EmailValidationKeyProvider.GetEmailKey(file.ID.ToString() + version);
            if (!string.IsNullOrEmpty(doc))
            {
                query += "&" + FilesLinkUtility.DocShareKey + "=" + HttpUtility.UrlEncode(doc);
            }

            return uriBuilder.Uri + "?" + query;
        }

        public static string GetFileChangesUrl(File file, string doc = null)
        {
            if (file == null) throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound);

            var uriBuilder = new UriBuilder(CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath));
            var query = uriBuilder.Query;
            query += FilesLinkUtility.Action + "=diff&";
            query += FilesLinkUtility.FileId + "=" + HttpUtility.UrlEncode(file.ID.ToString()) + "&";
            query += FilesLinkUtility.Version + "=" + file.Version + "&";
            query += FilesLinkUtility.AuthKey + "=" + EmailValidationKeyProvider.GetEmailKey(file.ID + file.Version.ToString(CultureInfo.InvariantCulture));
            if (!string.IsNullOrEmpty(doc))
            {
                query += "&" + FilesLinkUtility.DocShareKey + "=" + HttpUtility.UrlEncode(doc);
            }

            return uriBuilder.Uri + "?" + query;
        }

        public static string GetTempUrl(Stream stream, string ext)
        {
            if (stream == null) throw new ArgumentNullException("stream");

            var store = Global.GetStore();
            var fileName = string.Format("{0}{1}", Guid.NewGuid(), ext);
            var path = Path.Combine("temp_stream", fileName);

            if (store.IsFile(FileConstant.StorageDomainTmp, path))
            {
                store.Delete(FileConstant.StorageDomainTmp, path);
            }

            store.Save(
                FileConstant.StorageDomainTmp,
                path,
                stream,
                MimeMapping.GetMimeMapping(ext),
                "attachment; filename=\"" + fileName + "\"");

            var uriBuilder = new UriBuilder(CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath));
            var query = uriBuilder.Query;
            query += FilesLinkUtility.Action + "=tmp&";
            query += FilesLinkUtility.FileTitle + "=" + HttpUtility.UrlEncode(fileName) + "&";
            query += FilesLinkUtility.AuthKey + "=" + EmailValidationKeyProvider.GetEmailKey(fileName);

            return uriBuilder.Uri + "?" + query;
        }

        public static string GetEmptyFileUrl(string extension)
        {
            var uriBuilder = new UriBuilder(CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.FileHandlerPath));
            var query = uriBuilder.Query;
            query += FilesLinkUtility.Action + "=empty&";
            query += FilesLinkUtility.FileTitle + "=" + HttpUtility.UrlEncode(extension);

            return uriBuilder.Uri + "?" + query;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/TagEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Projects.Core.DataInterfaces;

namespace ASC.Projects.Engine
{
    public class TagEngine
    {
        public IDaoFactory DaoFactory { get; set; }

        public KeyValuePair<int, string> Create(string data)
        {
            return DaoFactory.TagDao.Create(data);
        }

        public Dictionary<int, string> GetTags()
        {
            return DaoFactory.TagDao.GetTags();
        }

        public Dictionary<int, string> GetTags(string prefix)
        {
            return DaoFactory.TagDao.GetTags(prefix);
        }

        public string GetById(int id)
        {
            return DaoFactory.TagDao.GetById(id);
        }

        public int[] GetTagProjects(string tagName)
        {
            return DaoFactory.TagDao.GetTagProjects(tagName);
        }

        public int[] GetTagProjects(int tagID)
        {
            return DaoFactory.TagDao.GetTagProjects(tagID);
        }

        public Dictionary<int, string> GetProjectTags(int projectId)
        {
            return DaoFactory.TagDao.GetProjectTags(projectId);
        }

        public void SetProjectTags(int projectId, string tags)
        {
            DaoFactory.TagDao.SetProjectTags(projectId, FromString(tags));
        }

        public void SetProjectTags(int projectId, IEnumerable<int> tags)
        {
            DaoFactory.TagDao.SetProjectTags(projectId, tags);
        }

        private string[] FromString(string tags)
        {
            return (tags ?? string.Empty)
                .Split(',', ';')
                .Select(t => t.Trim())
                .Where(t => !string.IsNullOrEmpty(t))
                .ToArray();
        }
    }
}


<|start_filename|>web/core/ASC.Web.Core/WarmupPage.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;

using ASC.Common.Logging;

namespace ASC.Web.Core
{
    public abstract class WarmupPage : BasePage
    {
        protected virtual List<string> Pages { get; }
        protected virtual List<string> Exclude { get; }
        protected void Page_Load(object sender, EventArgs e)
        {
            var path = Path.GetDirectoryName(HttpContext.Current.Request.PhysicalPath);

            var files = Directory.GetFiles(path, "*.aspx", SearchOption.TopDirectoryOnly)
                .Select(r => Path.GetFileName(r))
                .Where(r => !r.EndsWith("warmup.aspx", StringComparison.OrdinalIgnoreCase))
                .ToList();

            if (Pages != null && Pages.Any())
            {
                files.AddRange(Pages);
            }

            if (Exclude != null && Exclude.Any())
            {
                files = files.Except(Exclude).ToList();
            }

            foreach (var file in files.Distinct())
            {
                var page = Path.GetFileName(file);
                try
                {
                    HttpContext.Current.Server.Execute(page);
                }
                catch (Exception ex)
                {
                    LogManager.GetLogger("ASC").Error("Warmup " + page, ex);
                }
            }

            HttpContext.Current.Response.Clear();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/ConfirmInviteActivation/ConfirmInviteActivation.ascx.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Web;
using System.Web.UI;

using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Users;
using ASC.FederatedLogin;
using ASC.FederatedLogin.Profile;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Core.Users;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.UserControls.Users.UserProfile;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    public partial class ConfirmInviteActivation : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/ConfirmInviteActivation/ConfirmInviteActivation.ascx"; }
        }

        protected string _errorMessage;

        protected string _userName;
        protected string _userPost;
        protected string _userAvatar;

        protected string _email
        {
            get { return (Request["email"] ?? String.Empty).Trim(); }
        }

        protected ConfirmType _type
        {
            get { return typeof(ConfirmType).TryParseEnum(Request["type"] ?? "", ConfirmType.EmpInvite); }
        }

        protected EmployeeType _employeeType
        {
            get { return typeof(EmployeeType).TryParseEnum(Request["emplType"] ?? "", EmployeeType.User); }
        }

        protected string GetEmailAddress()
        {
            if (!String.IsNullOrEmpty(Request["emailInput"]))
                return Request["emailInput"].Trim();

            if (!String.IsNullOrEmpty(Request["email"]))
                return Request["email"].Trim();

            return String.Empty;
        }

        private string GetEmailAddress(LoginProfile account)
        {
            var value = GetEmailAddress();
            return String.IsNullOrEmpty(value) ? account.EMail : value;
        }

        protected string GetFirstName()
        {
            var value = string.Empty;
            if (!string.IsNullOrEmpty(Request["firstname"])) value = Request["firstname"].Trim();
            if (!string.IsNullOrEmpty(Request["firstnameInput"])) value = Request["firstnameInput"].Trim();
            return HtmlUtil.GetText(value);
        }

        private string GetFirstName(LoginProfile account)
        {
            var value = GetFirstName();
            return String.IsNullOrEmpty(value) ? account.FirstName : value;
        }

        protected string GetLastName()
        {
            var value = string.Empty;
            if (!string.IsNullOrEmpty(Request["lastname"])) value = Request["lastname"].Trim();
            if (!string.IsNullOrEmpty(Request["lastnameInput"])) value = Request["lastnameInput"].Trim();
            return HtmlUtil.GetText(value);
        }

        private string GetLastName(LoginProfile account)
        {
            var value = GetLastName();
            return String.IsNullOrEmpty(value) ? account.LastName : value;
        }

        protected bool isPersonal
        {
            get { return CoreContext.Configuration.Personal; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterBodyScripts("~/js/third-party/xregexp.js", "~/UserControls/Management/ConfirmInviteActivation/js/confirm_invite_activation.js")
                .RegisterStyle("~/UserControls/Management/ConfirmInviteActivation/css/confirm_invite_activation.less");

            var uid = Guid.Empty;
            try
            {
                uid = new Guid(Request["uid"]);
            }
            catch
            {
            }

            var email = GetEmailAddress();

            if (_type != ConfirmType.Activation && AccountLinkControl.IsNotEmpty && !CoreContext.Configuration.Personal)
            {
                var thrd = (AccountLinkControl)LoadControl(AccountLinkControl.Location);
                thrd.InviteView = true;
                thrd.ClientCallback = "loginJoinCallback";
                thrdParty.Visible = true;
                thrdParty.Controls.Add(thrd);
            }

            Page.Title = HeaderStringHelper.GetPageTitle(Resource.Authorization);

            UserInfo user;
            try
            {
                SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);

                user = CoreContext.UserManager.GetUserByEmail(email);
                var usr = CoreContext.UserManager.GetUsers(uid);
                if (usr.ID.Equals(Constants.LostUser.ID) || usr.ID.Equals(ASC.Core.Configuration.Constants.Guest.ID))
                    usr = CoreContext.UserManager.GetUsers(CoreContext.TenantManager.GetCurrentTenant().OwnerId);

                var photoData = UserPhotoManager.GetUserPhotoData(usr.ID, UserPhotoManager.MediumFotoSize);

                _userAvatar = photoData == null ? usr.GetMediumPhotoURL() : "data:image/png;base64," + Convert.ToBase64String(photoData);
                _userName = usr.DisplayUserName(true);
                _userPost = (usr.Title ?? "").HtmlEncode();
            }
            finally
            {
                SecurityContext.Logout();
            }

            if (_type == ConfirmType.LinkInvite || _type == ConfirmType.EmpInvite)
            {
                if (!CoreContext.Configuration.Personal)
                {
                    if (_employeeType == EmployeeType.User && TenantStatisticsProvider.GetUsersCount() >= TenantExtra.GetTenantQuota().ActiveUsers)
                    {
                        ShowError(UserControlsCommonResource.TariffUserLimitReason);
                        return;
                    }

                    if (_employeeType == EmployeeType.Visitor && !(CoreContext.Configuration.Standalone || TenantStatisticsProvider.GetVisitorsCount() < TenantExtra.GetTenantQuota().ActiveUsers * Constants.CoefficientOfVisitors))
                    {
                        ShowError(UserControlsCommonResource.TariffVisitorLimitReason);
                        return;
                    }
                }

                if (!user.ID.Equals(Constants.LostUser.ID))
                {
                    ShowError(CustomNamingPeople.Substitute<Resource>("ErrorEmailAlreadyExists"));
                    return;
                }
            }

            else if (_type == ConfirmType.Activation)
            {
                if (user.IsActive)
                {
                    Response.Redirect(CommonLinkUtility.GetDefault());
                    return;
                }

                if (user.ID.Equals(Constants.LostUser.ID) || user.Status == EmployeeStatus.Terminated)
                {
                    ShowError(string.Format(Resource.ErrorUserNotFoundByEmail, email));
                    return;
                }
            }

            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            if (tenant != null)
            {
                var settings = IPRestrictionsSettings.Load();
                if (settings.Enable && !IPSecurity.IPSecurity.Verify(tenant))
                {
                    ShowError(Resource.ErrorAccessRestricted);
                    return;
                }
            }

            if (!IsPostBack)
                return;

            var firstName = GetFirstName();
            var lastName = GetLastName();

            var passwordHash = (Request["passwordHash"] ?? "").Trim();
            var mustChangePassword = false;
            LoginProfile thirdPartyProfile;

            //thirdPartyLogin confirmInvite
            if (Request["__EVENTTARGET"] == "thirdPartyLogin")
            {
                var valueRequest = Request["__EVENTARGUMENT"];
                thirdPartyProfile = new LoginProfile(valueRequest);

                if (!string.IsNullOrEmpty(thirdPartyProfile.AuthorizationError))
                {
                    // ignore cancellation
                    if (thirdPartyProfile.AuthorizationError != "Canceled at provider")
                        ShowError(HttpUtility.HtmlEncode(thirdPartyProfile.AuthorizationError));
                    return;
                }

                if (string.IsNullOrEmpty(thirdPartyProfile.EMail))
                {
                    ShowError(HttpUtility.HtmlEncode(Resource.ErrorNotCorrectEmail));
                    return;
                }
            }

            if (Request["__EVENTTARGET"] == "confirmInvite")
            {
                if (String.IsNullOrEmpty(email))
                {
                    _errorMessage = Resource.ErrorEmptyUserEmail;
                    return;
                }

                if (!email.TestEmailRegex())
                {
                    _errorMessage = Resource.ErrorNotCorrectEmail;
                    return;
                }

                if (String.IsNullOrEmpty(firstName))
                {
                    _errorMessage = Resource.ErrorEmptyUserFirstName;
                    return;
                }

                if (String.IsNullOrEmpty(lastName))
                {
                    _errorMessage = Resource.ErrorEmptyUserLastName;
                    return;
                }

                if (String.IsNullOrEmpty(passwordHash))
                {
                    _errorMessage = Resource.ErrorPasswordEmpty;
                    return;
                }
            }
            var userID = Guid.Empty;
            try
            {
                SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);
                if (_type == ConfirmType.EmpInvite || _type == ConfirmType.LinkInvite)
                {
                    if (!CoreContext.Configuration.Personal && TenantStatisticsProvider.GetUsersCount() >= TenantExtra.GetTenantQuota().ActiveUsers && _employeeType == EmployeeType.User)
                    {
                        ShowError(UserControlsCommonResource.TariffUserLimitReason);
                        return;
                    }

                    UserInfo newUser;
                    if (Request["__EVENTTARGET"] == "confirmInvite")
                    {
                        var fromInviteLink = _type == ConfirmType.LinkInvite;
                        newUser = CreateNewUser(firstName, lastName, email, passwordHash, _employeeType, fromInviteLink);

                        var messageAction = _employeeType == EmployeeType.User ? MessageAction.UserCreatedViaInvite : MessageAction.GuestCreatedViaInvite;
                        MessageService.Send(HttpContext.Current.Request, MessageInitiator.System, messageAction, MessageTarget.Create(newUser.ID), newUser.DisplayUserName(false));

                        userID = newUser.ID;
                    }

                    if (Request["__EVENTTARGET"] == "thirdPartyLogin")
                    {
                        if (String.IsNullOrEmpty(passwordHash))
                        {
                            passwordHash = <PASSWORD>();
                            mustChangePassword = true;
                        }

                        var valueRequest = Request["__EVENTARGUMENT"];
                        thirdPartyProfile = new LoginProfile(valueRequest);
                        newUser = CreateNewUser(GetFirstName(thirdPartyProfile), GetLastName(thirdPartyProfile), GetEmailAddress(thirdPartyProfile), passwordHash, _employeeType, false);

                        var messageAction = _employeeType == EmployeeType.User ? MessageAction.UserCreatedViaInvite : MessageAction.GuestCreatedViaInvite;
                        MessageService.Send(HttpContext.Current.Request, MessageInitiator.System, messageAction, MessageTarget.Create(newUser.ID), newUser.DisplayUserName(false));

                        userID = newUser.ID;
                        if (!String.IsNullOrEmpty(thirdPartyProfile.Avatar))
                        {
                            SaveContactImage(userID, thirdPartyProfile.Avatar);
                        }

                        var linker = new AccountLinker("webstudio");
                        linker.AddLink(userID.ToString(), thirdPartyProfile);
                    }
                }
                else if (_type == ConfirmType.Activation)
                {
                    if (!UserFormatter.IsValidUserName(firstName, lastName))
                        throw new Exception(Resource.ErrorIncorrectUserName);

                    SecurityContext.SetUserPasswordHash(user.ID, passwordHash);

                    user.ActivationStatus = EmployeeActivationStatus.Activated;
                    user.FirstName = firstName;
                    user.LastName = lastName;
                    CoreContext.UserManager.SaveUserInfo(user);

                    userID = user.ID;

                    //notify
                    if (user.IsVisitor())
                    {
                        StudioNotifyService.Instance.GuestInfoAddedAfterInvite(user);
                        MessageService.Send(HttpContext.Current.Request, MessageInitiator.System, MessageAction.GuestActivated, MessageTarget.Create(user.ID), user.DisplayUserName(false));
                    }
                    else
                    {
                        StudioNotifyService.Instance.UserInfoAddedAfterInvite(user);
                        MessageService.Send(HttpContext.Current.Request, MessageInitiator.System, MessageAction.UserActivated, MessageTarget.Create(user.ID), user.DisplayUserName(false));
                    }
                }
            }
            catch (SecurityContext.PasswordException)
            {
                _errorMessage = HttpUtility.HtmlEncode(Resource.ErrorPasswordRechange);
                return;
            }
            catch (Exception exception)
            {
                _errorMessage = HttpUtility.HtmlEncode(exception.Message);
                return;
            }
            finally
            {
                SecurityContext.Logout();
            }

            user = CoreContext.UserManager.GetUsers(userID);
            try
            {
                var cookiesKey = SecurityContext.AuthenticateMe(user.Email, passwordHash);
                CookiesManager.SetCookies(CookiesType.AuthKey, cookiesKey);
                MessageService.Send(HttpContext.Current.Request, MessageAction.LoginSuccess);
                StudioNotifyService.Instance.UserHasJoin();

                if (mustChangePassword)
                {
                    StudioNotifyService.Instance.UserPasswordChange(user);
                }
            }
            catch (Exception exception)
            {
                (Page as Confirm).ErrorMessage = HttpUtility.HtmlEncode(exception.Message);
                return;
            }

            UserHelpTourHelper.IsNewUser = true;
            if (CoreContext.Configuration.Personal)
                PersonalSettings.IsNewUser = true;
            Response.Redirect(CommonLinkUtility.GetDefault());
        }

        private static void SaveContactImage(Guid userID, string url)
        {
            using (var memstream = new MemoryStream())
            {
                var req = WebRequest.Create(url);
                using (var response = req.GetResponse())
                using (var stream = response.GetResponseStream())
                {
                    var buffer = new byte[512];
                    int bytesRead;
                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                        memstream.Write(buffer, 0, bytesRead);
                    var bytes = memstream.ToArray();

                    UserPhotoManager.SaveOrUpdatePhoto(userID, bytes);
                }
            }
        }

        private void ShowError(string message)
        {
            (Page as Confirm).ErrorMessage = message.Trim();
            (Page as Confirm)._confirmHolder2.Visible = false;
            (Page as Confirm)._confirmHolder.Visible = false;
            (Page as Confirm)._contentWithControl.Visible = true;

            if (SecurityContext.IsAuthenticated == false)
                (Page as Confirm).ErrorMessage +=
                    (message.EndsWith(".") ? "" : ".")
                    + " "
                    + String.Format(Resource.ForSignInFollowMessage,
                                    string.Format("<a href=\"{0}\">",
                                                  VirtualPathUtility.ToAbsolute("~/Auth.aspx")),
                                    "</a>");

            _confirmHolder.Visible = false;
        }

        private static UserInfo CreateNewUser(string firstName, string lastName, string email, string passwordHash, EmployeeType employeeType, bool fromInviteLink)
        {
            var isVisitor = employeeType == EmployeeType.Visitor;

            if (SetupInfo.IsSecretEmail(email))
            {
                fromInviteLink = false;
            }

            var userInfo = new UserInfo
            {
                FirstName = string.IsNullOrEmpty(firstName) ? UserControlsCommonResource.UnknownFirstName : firstName,
                LastName = string.IsNullOrEmpty(lastName) ? UserControlsCommonResource.UnknownLastName : lastName,
                Email = email,
            };

            if (CoreContext.Configuration.Personal)
            {
                userInfo.ActivationStatus = EmployeeActivationStatus.Activated;
                userInfo.CultureName = CoreContext.Configuration.CustomMode ? "ru-RU" : Thread.CurrentThread.CurrentUICulture.Name;
            }

            return UserManagerWrapper.AddUser(userInfo, passwordHash, true, true, isVisitor, fromInviteLink);
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Data/DbAzService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Security.Authorizing;
using ASC.Core.Tenants;

namespace ASC.Core.Data
{
    public class DbAzService : DbBaseService, IAzService
    {
        public DbAzService(ConnectionStringSettings connectionString)
            : base(connectionString, "tenant")
        {
        }

        public IEnumerable<AzRecord> GetAces(int tenant, DateTime from)
        {
            // row with tenant = -1 - common for all tenants, but equal row with tenant != -1 escape common row for the portal
            var q = new SqlQuery("core_acl")
                .Select("subject", "action", "object", "acetype")
                .Where(Exp.Eq("tenant", Tenant.DEFAULT_TENANT));

            var commonAces = ExecList(q)
                .ConvertAll(r => ToAzRecord(r, tenant))
                .ToDictionary(a => string.Concat(a.Tenant.ToString(), a.SubjectId.ToString(), a.ActionId.ToString(), a.ObjectId));

            q = new SqlQuery("core_acl")
                .Select("subject", "action", "object", "acetype")
                .Where(Exp.Eq("tenant", tenant));

            var tenantAces = ExecList(q)
                .ConvertAll(r => new AzRecord(new Guid((string)r[0]), new Guid((string)r[1]), (AceType)Convert.ToInt32(r[3]), string.Empty.Equals(r[2]) ? null : (string)r[2]) { Tenant = tenant });

            // remove excaped rows
            foreach (var a in tenantAces.ToList())
            {
                var key = string.Concat(a.Tenant.ToString(), a.SubjectId.ToString(), a.ActionId.ToString(), a.ObjectId);
                if (commonAces.ContainsKey(key))
                {
                    var common = commonAces[key];
                    commonAces.Remove(key);
                    if (common.Reaction == a.Reaction)
                    {
                        tenantAces.Remove(a);
                    }
                }
            }

            return commonAces.Values.Concat(tenantAces);
        }

        public AzRecord SaveAce(int tenant, AzRecord r)
        {
            r.Tenant = tenant;
            using (var db = GetDb())
            using (var tx = db.BeginTransaction())
            {
                if (!ExistEscapeRecord(db, r))
                {
                    InsertRecord(db, r);
                }
                else
                {
                    // unescape
                    DeleteRecord(db, r);
                }
                tx.Commit();
            }

            return r;
        }

        public void RemoveAce(int tenant, AzRecord r)
        {
            r.Tenant = tenant;
            using (var db = GetDb())
            using (var tx = db.BeginTransaction())
            {
                if (ExistEscapeRecord(db, r))
                {
                    // escape
                    InsertRecord(db, r);
                }
                else
                {
                    DeleteRecord(db, r);
                }
                tx.Commit();
            }
        }


        private bool ExistEscapeRecord(IDbManager db, AzRecord r)
        {
            var q = Query("core_acl", Tenant.DEFAULT_TENANT)
                .SelectCount()
                .Where("subject", r.SubjectId.ToString())
                .Where("action", r.ActionId.ToString())
                .Where("object", r.ObjectId ?? string.Empty)
                .Where("acetype", r.Reaction);
            return db.ExecuteScalar<int>(q) != 0;
        }

        private void DeleteRecord(IDbManager db, AzRecord r)
        {
            var q = Delete("core_acl", r.Tenant)
                .Where("subject", r.SubjectId.ToString())
                .Where("action", r.ActionId.ToString())
                .Where("object", r.ObjectId ?? string.Empty)
                .Where("acetype", r.Reaction);
            db.ExecuteNonQuery(q);
        }

        private void InsertRecord(IDbManager db, AzRecord r)
        {
            var q = Insert("core_acl", r.Tenant)
                .InColumnValue("subject", r.SubjectId.ToString())
                .InColumnValue("action", r.ActionId.ToString())
                .InColumnValue("object", r.ObjectId ?? string.Empty)
                .InColumnValue("acetype", r.Reaction);
            db.ExecuteNonQuery(q);
        }

        private AzRecord ToAzRecord(object[] r, int tenant)
        {
            return new AzRecord(
                new Guid((string)r[0]),
                new Guid((string)r[1]),
                (AceType)Convert.ToInt32(r[3]),
                string.Empty.Equals(r[2]) ? null : (string)r[2])
            { Tenant = tenant };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/js/tasks.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined") {
    ASC = {};
}

if (typeof ASC.CRM === "undefined") {
    ASC.CRM = function() { return {} };
}


ASC.CRM.myTaskContactFilter = {
    filterId: 'tasksAdvansedFilter',
    idFilterByContact: 'contactID',

    type: 'custom-contact',
    hiddenContainerId: 'hiddenBlockForTaskContactSelector',
    headerContainerId: 'taskContactSelectorForFilter',
    isInProc: false,

    onSelectContact: function (event, item) {
        jq("#" + ASC.CRM.myTaskContactFilter.headerContainerId).find(".inner-text .value").text(item.title);

        var $filter = jq('#' + ASC.CRM.myTaskContactFilter.filterId);
        $filter.advansedFilter(ASC.CRM.myTaskContactFilter.idFilterByContact, { id: item.id, displayName: item.title, value: jq.toJSON([item.id, "contact"]) });
        $filter.advansedFilter('resize');
    },

    createFilterByContact: function (filter) {
        var o = document.createElement('div');
        o.classList.add("default-value");
        o.innerHTML = [
            '<span class="title">',
              filter.title,
            '</span>',
            '<span class="selector-wrapper">',
              '<span class="contact-selector"></span>',
            '</span>',
            '<span class="btn-delete">&times;</span>',
        ].join('');
        return o;
    },

    customizeFilterByContact: function ($container, $filteritem, filter) {
        var $filterSwitcher = jq("#" + ASC.CRM.myTaskContactFilter.headerContainerId);

        if ($filterSwitcher.parent().is("#" + ASC.CRM.myTaskContactFilter.hiddenContainerId)) {
            $filterSwitcher
                .off("showList")
                .on("showList", function (event, item) {
                    ASC.CRM.myTaskContactFilter.onSelectContact(event, item);
                    $filteritem.removeClass("default-value");
                });

            $filterSwitcher.next().andSelf().appendTo($filteritem.find('span.contact-selector:first'));

            if (!filter.isset) {
                setTimeout(function () {
                    if ($filteritem.hasClass("default-value")) {
                        $filterSwitcher.click();
                    }
                }, 0);
            }
        }
    },

    destroyFilterByContact: function ($container, $filteritem, filter) {
        var $filterSwitcher = jq('#' + ASC.CRM.myTaskContactFilter.headerContainerId);

        if (!$filterSwitcher.parent().is("#" + ASC.CRM.myTaskContactFilter.hiddenContainerId)) {
            $filterSwitcher.off("showList");
            $filterSwitcher.find(".inner-text .value").text(ASC.CRM.Resources.CRMCommonResource.Select);
            $filterSwitcher.next().andSelf().appendTo(jq('#' + ASC.CRM.myTaskContactFilter.hiddenContainerId));
            $filterSwitcher.contactadvancedSelector("reset");
        }
    },

    processFilter: function ($container, $filteritem, filtervalue, params) {
        if (params && params.id && isFinite(params.id)) {
            var $filterSwitcher = jq('#' + ASC.CRM.myTaskContactFilter.headerContainerId);
            $filterSwitcher.find(".inner-text .value").text(params.displayName);
            $filterSwitcher.contactadvancedSelector("select", [params.id]);
            $filteritem.removeClass("default-value");
        }
    }
};


/*******************************************************************************
ListTaskView.ascx
*******************************************************************************/
ASC.CRM.ListTaskView = new function() {

    //Teamlab.bind(Teamlab.events.getException, _onGetException);

    function _onGetException(params, errors) {
        console.log('tasks.js ', errors);
        LoadingBanner.hideLoading();
    };

    var _setCookie = function (page, countOnPage) {
        if (ASC.CRM.ListTaskView.cookieKey && ASC.CRM.ListTaskView.cookieKey != "") {
            var cookie = {
                page: page,
                countOnPage: countOnPage
            };
            jq.cookies.set(ASC.CRM.ListTaskView.cookieKey, cookie, { path: location.pathname });
        }
    };

    var _renderNoTasksEmptyScreen = function () {
        jq("#taskFilterContainer, #taskList, #tableForTaskNavigation").hide();
        ASC.CRM.Common.hideExportButtons();
        jq("#emptyContentForTasksFilter:not(.display-none)").addClass("display-none");
        jq("#tasksEmptyScreen.display-none").removeClass("display-none");

        LoadingBanner.hideLoading();
        return false;
    };

    var _renderNoTasksForQueryEmptyScreen = function () {
        jq("#taskList, #tableForTaskNavigation").hide();
        ASC.CRM.Common.hideExportButtons();
        jq("#taskFilterContainer").show();
        ASC.CRM.ListTaskView.resizeFilter();
        jq("#emptyContentForTasksFilter.display-none").removeClass("display-none");

        LoadingBanner.hideLoading();
        return false;
    };


    var _initPageNavigatorControl = function (isTab, countOfRows, currentPageNumber) {
        window.taskPageNavigator = new ASC.Controls.PageNavigator.init("taskPageNavigator", "#divForTaskPager", countOfRows, ASC.CRM.Data.VisiblePageCount, currentPageNumber,
                                                                        ASC.CRM.Resources.CRMJSResource.Previous, ASC.CRM.Resources.CRMJSResource.Next);

        window.taskPageNavigator.changePageCallback = function (page) {
            _setCookie(page, window.taskPageNavigator.EntryCountOnPage);

            var startIndex = window.taskPageNavigator.EntryCountOnPage * (page - 1);
            if (isTab == true) {
                _getTasksForEntity(startIndex)
            } else {
                _renderContent(startIndex);
            }
        };
    };

    var _renderTaskPageNavigator = function (startIndex) {
        var tmpTotal;
        if (startIndex >= ASC.CRM.ListTaskView.Total) {
            tmpTotal = startIndex + 1;
        } else {
            tmpTotal = ASC.CRM.ListTaskView.Total;
        }
        window.taskPageNavigator.drawPageNavigator((startIndex / ASC.CRM.ListTaskView.CountOfRows).toFixed(0) * 1 + 1, tmpTotal);
    };

    var _changeFilter = function () {
        var defaultStartIndex = 0;
        if (ASC.CRM.ListTaskView.defaultCurrentPageNumber != 0) {
            _setCookie(ASC.CRM.ListTaskView.defaultCurrentPageNumber, window.taskPageNavigator.EntryCountOnPage);
            defaultStartIndex = (ASC.CRM.ListTaskView.defaultCurrentPageNumber - 1) * window.taskPageNavigator.EntryCountOnPage;
            ASC.CRM.ListTaskView.defaultCurrentPageNumber = 0;
        } else {
            _setCookie(0, window.taskPageNavigator.EntryCountOnPage);
        }

        _renderContent(defaultStartIndex);
    };

    var _renderContent = function (startIndex) {
        if (!ASC.CRM.ListTaskView.isFirstLoad) {
            LoadingBanner.displayLoading();
            jq("#taskFilterContainer, #taskList, #tableForTaskNavigation").show();
            jq('#tasksAdvansedFilter').advansedFilter("resize");
        }

        _getTasks(startIndex);
    };

    var hideFirstLoader = function () {
        ASC.CRM.ListContactView.isFirstLoad = false;
        jq(".containerBodyBlock").children(".loader-page").hide();
        if (!jq("#tasksEmptyScreen").is(":visible") && !jq("#emptyContentForTasksFilter").is(":visible")) {
            jq("#taskFilterContainer, #taskList, #tableForTaskNavigation").show();
            jq('#tasksAdvansedFilter').advansedFilter("resize");
        }
    };

    var _getTasksForEntity = function (startIndex) {
        LoadingBanner.displayLoading();
        var filterSettings = {
            entityid : ASC.CRM.ListTaskView.ContactID != 0 ? ASC.CRM.ListTaskView.ContactID : ASC.CRM.ListTaskView.EntityID,
            entitytype : ASC.CRM.ListTaskView.EntityType,
            sortBy : 'deadLine',
            sortOrder : 'descending',
            count : ASC.CRM.ListTaskView.CountOfRows,
            startIndex : startIndex
        };

        Teamlab.getCrmTasks({
            __startIndex: startIndex
        }, { filter: filterSettings, success: ASC.CRM.ListTaskView.CallbackMethods.get_tasks_for_entity });
    };

    var _getTasks = function(startIndex) {
        var filterSettings = ASC.CRM.ListTaskView.getFilterSettings();

        filterSettings.Count = ASC.CRM.ListTaskView.CountOfRows;
        filterSettings.startIndex = startIndex;

        Teamlab.getCrmTasks({
            __startIndex: startIndex
        }, { filter: filterSettings, success: ASC.CRM.ListTaskView.CallbackMethods.get_tasks_by_filter });
    };

    var _deleteTaskItem = function(taskID) {
        Teamlab.removeCrmTask({}, taskID,
            {
                success: ASC.CRM.ListTaskView.CallbackMethods.delete_task,
                before: function() {
                    jq("#task_" + taskID + " .check").hide();
                    jq("#task_" + taskID + " .ajax_edit_task").show();
                    jq("#taskMenu_" + taskID).hide();
                    PopupKeyUpActionProvider.EnableEsc = true;
                    jq.unblockUI();
                }
            });
    };

    var _changeTaskItemStatus = function(task_id, isClosed) {

        Teamlab.updateCrmTask({}, task_id, { id: task_id, isClosed: isClosed },
            {
                success: ASC.CRM.TaskActionView.CallbackMethods.edit_task,
                error: function (params, error) {
                    var taskErrorBox = jq("#addTaskPanel .error-popup");
                    taskErrorBox.text(error[0]);
                    taskErrorBox.removeClass("display-none").show();
                },
                before: function() {
                    jq('#taskStatusListContainer').hide();
                    jq("#task_" + task_id + " .check").hide();
                    jq("#task_" + task_id + " .ajax_edit_task").show();
                    jq("#taskMenu_" + task_id).hide();
                },
                after: function() {
                    jq("#task_" + task_id + " .ajax_edit_task").hide();
                    jq("#task_" + task_id + " .check").show();
                    jq("#taskMenu_" + task_id).show();
                }
            });

        if (isClosed) {
            var task = ASC.CRM.ListTaskView.TaskList[ASC.CRM.ListTaskView.findIndexOfTaskByID(task_id)],
                dataEvent = {
                    content    : jq.format(ASC.CRM.Resources.CRMJSResource.TaskIsOver, task.title),
                    categoryId : ASC.CRM.Data.HistoryCategorySystem.TaskClosed,
                    created    : Teamlab.serializeTimestamp(new Date())
                };

            if (task.contact != null) {
                dataEvent.contactId = task.contact.id;
            }
            if (task.entity != null) {
                dataEvent.entityId = task.entity.entityId;
                dataEvent.entityType = task.entity.entityType;
            }

            if (task.contact != null || task.entity != null) {

                var callbackMethod;
                if (ASC.CRM.ListTaskView.ContactID == 0 && ASC.CRM.ListTaskView.EntityID == 0) {
                    callbackMethod = new function(params, response) {
                    };
                } else {
                    callbackMethod = ASC.CRM.HistoryView.CallbackMethods.add_event;
                }

                Teamlab.addCrmHistoryEvent({}, dataEvent, callbackMethod);
            }
        }
    };

    var _initTaskStatusesMenu = function() {
        if (jq('#taskStatusListContainer').length === 1) {
            jq.dropdownToggle({
                dropdownID: 'taskStatusListContainer',
                switcherSelector: '#taskTable .changeStatusCombobox.canEdit',
                addTop: 4,
                addLeft: 0,
                showFunction: function(switcherObj, dropdownItem) {
                    jq('#taskTable .changeStatusCombobox.selected').removeClass('selected');

                    if (dropdownItem.is(":hidden")) {
                        switcherObj.addClass('selected');
                        if (jq('#taskStatusListContainer').attr('taskid') != switcherObj.attr('taskid')) {
                            jq('#taskStatusListContainer').attr('taskid', switcherObj.attr('taskid'));
                        }
                    }
                },
                hideFunction: function() {
                    jq('#taskTable .changeStatusCombobox.selected').removeClass('selected');
                }
            });

            jq('#taskStatusListContainer li').bind({
                click: function() {
                    if (jq(this).is('.selected')) {
                        jq('#taskStatusListContainer').hide();
                        jq('#taskTable .changeStatusCombobox.selected').removeClass('selected');
                        return;
                    }
                    var taskid = jq('#taskStatusListContainer').attr('taskid'),
                        status = jq(this).attr('class');
                    if (status == jq('#task_' + taskid + ' .changeStatusCombobox span').attr('class')) {
                        jq('#taskStatusListContainer').hide();
                        jq('#taskTable .changeStatusCombobox.selected').removeClass('selected');
                        return;
                    }
                    _changeTaskItemStatus(taskid, status == "closed");
                }
            });
        }
    };

    var _initChangeFilterByClickOnResponsible = function() {
        jq("#taskList").on("click", ".divForUser:not(.removedUser) span", function () {
            var resp_id = jq(this).attr("resp_id"),
                filters = [];
            filters.push({ type: "person", id: "responsibleID", isset: true, params: { id: resp_id} });
            jq("#tasksAdvansedFilter").advansedFilter({ filters: filters });
        });
    };

    var _initEmptyScreen = function () {

        //init emptyScreen for all list
        var buttonHTML = ["<a class='link dotline plus'>",
                        ASC.CRM.Resources.CRMTaskResource.CreateFirstTask,
                        "</a>"].join('');
        
        if (jq.browser.mobile != true) {
            buttonHTML += ["<br/><a class='crm-importLink link' href='Tasks.aspx?action=import'>",
                        ASC.CRM.Resources.CRMTaskResource.ImportTasks,
                        "</a>"].join('');
        }
        
        jq.tmpl("template-emptyScreen",
            {
                ID: "tasksEmptyScreen",
                ImgSrc: ASC.CRM.Data.EmptyScrImgs["empty_screen_tasks"],
                Header: ASC.CRM.Resources.CRMTaskResource.EmptyContentTasksHeader,
                Describe: jq.format(ASC.CRM.Resources.CRMTaskResource.EmptyContentTasksDescribe,
                    "<span class='hintCategories baseLinkAction'>", "</span>"),
                ButtonHTML: buttonHTML,
                CssClass: "display-none"
            }).insertAfter("#taskList");

        //init emptyScreen for filter
        jq.tmpl("template-emptyScreen",
            {
                ID: "emptyContentForTasksFilter",
                ImgSrc: ASC.CRM.Data.EmptyScrImgs["empty_screen_filter"],
                Header: ASC.CRM.Resources.CRMTaskResource.EmptyContentTasksFilterHeader,
                Describe: ASC.CRM.Resources.CRMTaskResource.EmptyContentTasksFilterDescribe,
                ButtonHTML: ["<a class='clearFilterButton link dotline' href='javascript:void(0);' onclick='ASC.CRM.ListTaskView.advansedFilter.advansedFilter(null);'>",
                    ASC.CRM.Resources.CRMCommonResource.ClearFilter,
                    "</a>"].join(''),
                CssClass: "display-none"
            }).insertAfter("#taskList");
    };
    
    var _initFilter = function () {
        if (!jq("#tasksAdvansedFilter").advansedFilter) return;

        var now = new Date(),
            todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0),
            todayEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59, 0),

            nowString = Teamlab.serializeTimestamp(now),
            todayStartString = Teamlab.serializeTimestamp(todayStart),
            todayEndString = Teamlab.serializeTimestamp(todayEnd);

        ASC.CRM.ListTaskView.advansedFilter = jq("#tasksAdvansedFilter")
            .advansedFilter({
                anykey      : false,
                hint        : ASC.CRM.Resources.CRMCommonResource.AdvansedFilterInfoText.format(
                            '<b>',
                            '</b>',
                            '<br/><br/><a href="' + ASC.Resources.Master.FilterHelpCenterLink + '" target="_blank">',
                            '</a>'),
                hintDefaultDisable: false,
                maxfilters  : -1,
                colcount    : 2,
                maxlength   : "100",
                store       : true,
                inhash      : true,
                filters     : [
                            {
                                type        : "person",
                                id          : "my",
                                apiparamname: "responsibleID",
                                title       : ASC.CRM.Resources.CRMTaskResource.MyTasksFilter,
                                filtertitle : ASC.CRM.Resources.CRMCommonResource.FilterByResponsible,
                                group       : ASC.CRM.Resources.CRMCommonResource.FilterByResponsible,
                                groupby     : "responsible",
                                bydefault   : { id: Teamlab.profile.id, value: Teamlab.profile.id }
                            },
                            {
                                type        : "person",
                                id          : "responsibleID",
                                apiparamname: "responsibleID",
                                title       : ASC.CRM.Resources.CRMTaskResource.CustomResponsibleFilter,
                                filtertitle : ASC.CRM.Resources.CRMCommonResource.FilterByResponsible,
                                group       : ASC.CRM.Resources.CRMCommonResource.FilterByResponsible,
                                groupby     : "responsible"
                            },

                            {
                                type        : "combobox",
                                id          : "overdue",
                                apiparamname: jq.toJSON(["fromDate", "toDate"]),
                                title       : ASC.CRM.Resources.CRMTaskResource.OverdueTasksFilter,
                                filtertitle : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                group       : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                groupby     : "deadline",
                                options     :
                                        [
                                        { value: jq.toJSON(["", nowString]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.OverdueTasksFilter, def: true },
                                        { value: jq.toJSON([todayStartString, todayEndString]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.TodayTasksFilter },
                                        { value: jq.toJSON([nowString, ""]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.TheNextTasksFilter }
                                        ]
                            },
                            {
                                type        : "combobox",
                                id          : "today",
                                apiparamname: jq.toJSON(["fromDate", "toDate"]),
                                title       : ASC.CRM.Resources.CRMTaskResource.TodayTasksFilter,
                                filtertitle : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                group       : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                groupby     : "deadline",
                                options     :
                                        [
                                        { value: jq.toJSON(["", nowString]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.OverdueTasksFilter },
                                        { value: jq.toJSON([todayStartString, todayEndString]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.TodayTasksFilter, def: true },
                                        { value: jq.toJSON([nowString, ""]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.TheNextTasksFilter }
                                        ]
                            },
                            {
                                type        : "combobox",
                                id          : "theNext",
                                apiparamname: jq.toJSON(["fromDate", "toDate"]),
                                title       : ASC.CRM.Resources.CRMTaskResource.TheNextTasksFilter,
                                filtertitle : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                group       : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                groupby     : "deadline",
                                options     :
                                        [
                                        { value: jq.toJSON(["", nowString]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.OverdueTasksFilter },
                                        { value: jq.toJSON([todayStartString, todayEndString]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.TodayTasksFilter },
                                        { value: jq.toJSON([nowString, ""]), classname: '', title: ASC.CRM.Resources.CRMTaskResource.TheNextTasksFilter, def: true }
                                        ]
                            },
                            {
                                type        : "daterange",
                                id          : "fromToDate",
                                title       : ASC.CRM.Resources.CRMTaskResource.CustomDateFilter,
                                filtertitle : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                group       : ASC.CRM.Resources.CRMTaskResource.ByDueDate,
                                groupby     : "deadline"
                            },
                            {
                                type        : "combobox",
                                id          : "openTask",
                                apiparamname: "isClosed",
                                title       : ASC.CRM.Resources.CRMTaskResource.OnlyOpenTasks,
                                filtertitle : ASC.CRM.Resources.CRMTaskResource.TasksByStatus,
                                group       : ASC.CRM.Resources.CRMTaskResource.TasksByStatus,
                                groupby     : "taskStatus",
                                options     :
                                        [
                                        { value: false, classname: '', title: ASC.CRM.Resources.CRMTaskResource.OnlyOpenTasks, def: true },
                                        { value: true, classname: '', title: ASC.CRM.Resources.CRMTaskResource.OnlyClosedTasks }
                                        ]
                            },
                            {
                                type        : "combobox",
                                id          : "closedTask",
                                apiparamname: "isClosed",
                                title       : ASC.CRM.Resources.CRMTaskResource.OnlyClosedTasks,
                                filtertitle : ASC.CRM.Resources.CRMTaskResource.TasksByStatus,
                                group       : ASC.CRM.Resources.CRMTaskResource.TasksByStatus,
                                groupby     : "taskStatus",
                                options     :
                                        [
                                        { value: false, classname: '', title: ASC.CRM.Resources.CRMTaskResource.OnlyOpenTasks },
                                        { value: true, classname: '', title: ASC.CRM.Resources.CRMTaskResource.OnlyClosedTasks, def: true }
                                        ]
                            },
                            {
                                type        : "combobox",
                                id          : "categoryID",
                                apiparamname: "categoryID",
                                title       : ASC.CRM.Resources.CRMCommonResource.ByCategory,
                                group       : ASC.CRM.Resources.CRMCommonResource.Other,
                                options     : ASC.CRM.Data.taskCategories,
                                defaulttitle: ASC.CRM.Resources.CRMCommonResource.Choose
                            },
                            {
                                type        : ASC.CRM.myTaskContactFilter.type,
                                id          : ASC.CRM.myTaskContactFilter.idFilterByContact,
                                apiparamname: jq.toJSON(["entityid", "entityType"]),
                                title       : ASC.CRM.Resources.CRMContactResource.Contact,
                                group       : ASC.CRM.Resources.CRMCommonResource.Other,
                                hashmask    : '',
                                create      : ASC.CRM.myTaskContactFilter.createFilterByContact,
                                customize   : ASC.CRM.myTaskContactFilter.customizeFilterByContact,
                                destroy     : ASC.CRM.myTaskContactFilter.destroyFilterByContact,
                                process     : ASC.CRM.myTaskContactFilter.processFilter
                            }
                ],

                sorters: [
                            { id: "title", title: ASC.CRM.Resources.CRMCommonResource.Title, dsc: false, def: false },
                            { id: "category", title: ASC.CRM.Resources.CRMCommonResource.Category, dsc: false, def: false },
                            { id: "deadline", title: ASC.CRM.Resources.CRMTaskResource.DueDate, dsc: false, def: true },
                            { id: "contactmanager", title: ASC.CRM.Resources.CRMCommonResource.Responsible, dsc: false, def: false },
                            { id: "contact", title: ASC.CRM.Resources.CRMContactResource.Contact, dsc: false, def: false }
                ]
            })
            .bind("setfilter", ASC.CRM.ListTaskView.setFilter)
            .bind("resetfilter", ASC.CRM.ListTaskView.resetFilter);
    };

    var _initTaskActionMenu = function (isTab) {

        jq.dropdownToggle({
            dropdownID: "taskActionMenu",
            switcherSelector: "#taskTable .entity-menu",
            addTop: 0,
            addLeft: 10,
            rightPos: true,
            showFunction: function (switcherObj, dropdownItem) {
                jq("#taskTable .entity-menu.active").removeClass("active");
                if (dropdownItem.is(":hidden")) {
                    switcherObj.addClass("active");
                }
            },
            hideFunction: function () {
                jq("#taskTable .entity-menu.active").removeClass("active");
            }
        });


        if (!isTab) {
            jq("body").unbind("contextmenu").bind("contextmenu", function (event) {
                var e = jq.fixEvent(event);

                if (typeof e == "undefined" || !e) {
                    return true;
                }

                var target = jq(e.srcElement || e.target);

                if (!target.parents("#taskTable").length) {
                    jq("#taskActionMenu").hide();
                    return true;
                }

                var row = target.closest("tr.with-entity-menu");
                var taskId = parseInt(row.attr("id").split('_')[1]);
                if (!taskId || !row.find(".entity-menu").length) {
                    return true;
                }
                ASC.CRM.ListTaskView.showActionMenu(taskId);
                jq("#taskTable .entity-menu.active").removeClass("active");

                jq.showDropDownByContext(e, target, jq("#taskActionMenu"));
                return false;
            });
        }
    };


    return {
        CallbackMethods: {
            get_tasks_by_filter: function(params, tasks) {

                ASC.CRM.ListTaskView.TaskList = [];
                ASC.CRM.ListTaskView.Total = params.__total || 0;
                var startIndex = params.__startIndex || 0;


                for (var i = 0, n = tasks.length; i < n; i++) {
                    ASC.CRM.ListTaskView.taskItemFactory(tasks[i]);
                    ASC.CRM.ListTaskView.TaskList.push(tasks[i]);
                }

                if (ASC.CRM.ListTaskView.Total === 0 && typeof (ASC.CRM.ListTaskView.advansedFilter) != "undefined" &&
                            ASC.CRM.ListTaskView.advansedFilter.advansedFilter().length == 1) {
                    ASC.CRM.ListTaskView.noTasks = true;
                    ASC.CRM.ListTaskView.noTasksForQuery = true;
                } else {
                    ASC.CRM.ListTaskView.noTasks = false;
                    if (ASC.CRM.ListTaskView.Total === 0) {
                        ASC.CRM.ListTaskView.noTasksForQuery = true;
                    } else {
                        ASC.CRM.ListTaskView.noTasksForQuery = false;
                    }
                }

                if (ASC.CRM.ListTaskView.noTasks) {
                    _renderNoTasksEmptyScreen();
                    ASC.CRM.ListTaskView.isFirstLoad ? hideFirstLoader() : LoadingBanner.hideLoading();
                    return false;
                }

                if (ASC.CRM.ListTaskView.noTasksForQuery) {
                    _renderNoTasksForQueryEmptyScreen();

                    jq("#taskFilterContainer").show();
                    ASC.CRM.ListTaskView.resizeFilter();

                    ASC.CRM.ListTaskView.isFirstLoad ? hideFirstLoader() : LoadingBanner.hideLoading();
                    return false;
                }

                if (tasks.length == 0) {//it can happen when select page without elements after deleting
                    jq("tasksEmptyScreen:not(.display-none)").addClass("display-none");
                    jq("#emptyContentForTasksFilter:not(.display-none)").addClass("display-none");
                    jq("#taskTable tbody tr").remove();
                    jq("#tableForTasksNavigation").show();
                    ASC.CRM.Common.hideExportButtons();
                    LoadingBanner.hideLoading();
                    return false;
                }

                jq("#totalTasksOnPage").text(ASC.CRM.ListTaskView.Total);
                jq("#emptyContentForTasksFilter:not(.display-none)").addClass("display-none");
                jq("#tasksEmptyScreen:not(.display-none)").addClass("display-none");
                ASC.CRM.Common.showExportButtons();

                jq("#taskFilterContainer").show();
                ASC.CRM.ListTaskView.resizeFilter();

                jq("#taskTable tbody").replaceWith(jq.tmpl("taskListTmpl", { tasks: ASC.CRM.ListTaskView.TaskList }));
                jq("#taskList").show();

                ASC.CRM.Common.RegisterContactInfoCard();

                for (var i = 0, n = ASC.CRM.ListTaskView.TaskList.length; i < n; i++) {
                    ASC.CRM.Common.tooltip("#taskTitle_" + ASC.CRM.ListTaskView.TaskList[i].id, "tooltip");
                }

                _renderTaskPageNavigator(startIndex);

                window.scrollTo(0, 0);
                ASC.CRM.ListTaskView.isFirstLoad ? hideFirstLoader() : LoadingBanner.hideLoading();
            },

            get_tasks_for_entity: function (params, tasks) {

                ASC.CRM.ListTaskView.TaskList = [];
                ASC.CRM.ListTaskView.Total = params.__total || 0;
                var startIndex = params.__startIndex || 0;

                for (var i = 0, n = tasks.length; i < n; i++) {
                    ASC.CRM.ListTaskView.taskItemFactory(tasks[i]);
                    ASC.CRM.ListTaskView.TaskList.push(tasks[i]);
                }

                ASC.CRM.ListTaskView.noTasks = ASC.CRM.ListTaskView.Total === 0;
  
                if (ASC.CRM.ListTaskView.noTasks) {
                    _renderNoTasksEmptyScreen();
                    LoadingBanner.hideLoading();
                    return false;
                }

                if (tasks.length == 0) {//it can happen when select page without elements after deleting
                    jq("tasksEmptyScreen:not(.display-none)").addClass("display-none");
                    jq("#taskTable tbody tr").remove();
                    jq("#tableForTasksNavigation").show();
                    ASC.CRM.Common.hideExportButtons();
                    LoadingBanner.hideLoading();
                    return false;
                }

                jq("#totalTasksOnPage").text(ASC.CRM.ListTaskView.Total);
                jq("#tasksEmptyScreen:not(.display-none)").addClass("display-none");
                ASC.CRM.Common.showExportButtons();

                jq("#taskList").show();
                jq("#taskTable tbody").replaceWith(jq.tmpl("taskListTmpl", { tasks: ASC.CRM.ListTaskView.TaskList }));
                ASC.CRM.Common.RegisterContactInfoCard();

                for (var i = 0, n = ASC.CRM.ListTaskView.TaskList.length; i < n; i++) {
                    ASC.CRM.Common.tooltip("#taskTitle_" + ASC.CRM.ListTaskView.TaskList[i].id, "tooltip");
                }

                _renderTaskPageNavigator(startIndex);

                window.scrollTo(0, 0);
                LoadingBanner.hideLoading();
            },

            delete_task: function(params, task) {
                jq("#task_" + task.id).animate({ opacity: "hide" }, 500);
                //ASC.CRM.Common.changeCountInTab("delete", "tasks");

                ASC.CRM.UpdateCRMCaldavCalendar(task, 2);
                setTimeout(function() {
                    jq("#task_" + task.id).remove();
                    ASC.CRM.ListTaskView.Total -= 1;
                    jq("#totalTasksOnPage").text(ASC.CRM.ListTaskView.Total);

                    var index = ASC.CRM.ListTaskView.findIndexOfTaskByID(task.id);
                    if (index != -1) {
                        ASC.CRM.ListTaskView.TaskList.splice(index, 1);
                    }


                    if (ASC.CRM.ListTaskView.Total == 0
                            && (typeof (ASC.CRM.ListTaskView.advansedFilter) == "undefined"
                            || ASC.CRM.ListTaskView.advansedFilter.advansedFilter().length == 1)) {
                        ASC.CRM.ListTaskView.noTasks = true;
                        ASC.CRM.ListTaskView.noTasksForQuery = true;
                    } else {
                        ASC.CRM.ListTaskView.noTasks = false;
                        if (ASC.CRM.ListTaskView.Total === 0) {
                            ASC.CRM.ListTaskView.noTasksForQuery = true;
                        } else {
                            ASC.CRM.ListTaskView.noTasksForQuery = false;
                        }
                    }

                    PopupKeyUpActionProvider.EnableEsc = true;
                    if (ASC.CRM.ListTaskView.noTasks) {
                        _renderNoTasksEmptyScreen();
                        jq.unblockUI();
                        return;
                    }

                    if (ASC.CRM.ListTaskView.noTasksForQuery) {
                        _renderNoTasksForQueryEmptyScreen();
                        jq.unblockUI();
                        return;
                    }

                    if (jq("#taskTable tbody tr").length == 0) {
                        jq.unblockUI();

                        var startIndex = ASC.CRM.ListTaskView.CountOfRows * (window.taskPageNavigator.CurrentPageNumber - 1);
                        while (startIndex >= ASC.CRM.ListTaskView.Total && startIndex >= ASC.CRM.ListTaskView.CountOfRows) {
                            startIndex -= ASC.CRM.ListTaskView.CountOfRows;
                        }
                        _renderContent(startIndex);
                    } else {
                        jq.unblockUI();
                    }
                }, 500);
            }
        },

        init: function (parentSelector, filterSelector, pagingSelector) {
            if (jq(parentSelector).length == 0) return;
            ASC.CRM.Common.setDocumentTitle(ASC.CRM.Resources.CRMTaskResource.Tasks);
            jq(parentSelector).removeClass("display-none");

            jq.tmpl("tasksListFilterTmpl").appendTo(filterSelector);
            jq.tmpl("tasksListPagingTmpl").appendTo(pagingSelector);

            jq('#privatePanelWrapper').appendTo("#permissionsDealsPanelInnerHtml");

            ASC.CRM.ListTaskView.ContactID = 0;
            ASC.CRM.ListTaskView.EntityType = "";
            ASC.CRM.ListTaskView.EntityID = 0;

            ASC.CRM.ListTaskView.cookieKey = ASC.CRM.Data.CookieKeyForPagination["tasks"];
            ASC.CRM.ListTaskView.TaskList = [];

            ASC.CRM.ListTaskView.isFilterVisible = false;
            ASC.CRM.ListTaskView.isTabActive = false;
            ASC.CRM.ListTaskView.Total = 0;
            ASC.CRM.ListTaskView.advansedFilter = null;

            jq.tmpl("taskExtendedListTmpl", { IsTab: false }).appendTo(parentSelector);

            _initEmptyScreen();

            _initTaskActionMenu(false);

            var settings = {
                page: 1,
                countOnPage: jq("#tableForTaskNavigation select:first>option:first").val()
            },
                key = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + location.pathname + location.search,
                currentAnchor = location.hash,
                cookieKey = encodeURIComponent(key);

            currentAnchor = currentAnchor && typeof currentAnchor === 'string' && currentAnchor.charAt(0) === '#'
                ? currentAnchor.substring(1)
                : currentAnchor;

            var cookieAnchor = jq.cookies.get(cookieKey);
            if (currentAnchor == "" || cookieAnchor == currentAnchor) {
                var tmp = ASC.CRM.Common.getPagingParamsFromCookie(ASC.CRM.ListTaskView.cookieKey);
                if (tmp != null) {
                    settings = tmp;
                }
            } else {
                _setCookie(settings.page, settings.countOnPage);
            }

            ASC.CRM.ListTaskView.CountOfRows = settings.countOnPage;
            ASC.CRM.ListTaskView.defaultCurrentPageNumber = settings.page;

            jq("#tableForTaskNavigation select:first").val(ASC.CRM.ListTaskView.CountOfRows)
                    .change(function (evt) {
                        ASC.CRM.ListTaskView.changeCountOfRows(this.value, false);
                    })
                    .tlCombobox();

            _initTaskStatusesMenu();

            jq("#menuCreateNewTask").on("click", function () { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
            jq("#tasksEmptyScreen .emptyScrBttnPnl>a.link.plus").on("click", function () { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });

            _initChangeFilterByClickOnResponsible();
            _initPageNavigatorControl(false, ASC.CRM.ListTaskView.CountOfRows, ASC.CRM.ListTaskView.defaultCurrentPageNumber);

            ASC.CRM.ListTaskView.isFirstLoad = true;
            jq(".containerBodyBlock").children(".loader-page").show();

            ASC.CRM.Common.registerChangeHoverStateByParent("label.task_category", "#taskTable .with-entity-menu");

            jq("#" + ASC.CRM.myTaskContactFilter.headerContainerId).contactadvancedSelector(
            {
                showme: true,
                addtext: ASC.CRM.Resources.CRMContactResource.AddNewCompany,
                noresults: ASC.CRM.Resources.CRMCommonResource.NoMatches,
                noitems: ASC.CRM.Resources.CRMCommonResource.NoMatches,
                inPopup: true,
                onechosen: true,
                isTempLoad: true
            });

            jq(window).bind("afterResetSelectedContact", function (event, obj, objName) {
                if (objName === "taskContactSelectorForFilter" && ASC.CRM.myTaskContactFilter.filterId) {
                    jq('#' + ASC.CRM.myTaskContactFilter.filterId).advansedFilter('resize');
                }
            });

            _initFilter();

            ASC.CRM.PartialExport.init(ASC.CRM.ListTaskView.advansedFilter, "task");
        },

        isFirstLoad: true,

        initTab: function(ContactID, EntityType, EntityID) {
            ASC.CRM.ListTaskView.ContactID = ContactID;
            ASC.CRM.ListTaskView.EntityType = EntityType;
            ASC.CRM.ListTaskView.EntityID = EntityID;

            ASC.CRM.ListTaskView.CountOfRows = ASC.CRM.Data.DefaultEntryCountOnPage;

            ASC.CRM.ListTaskView.TaskList = [];

            ASC.CRM.ListTaskView.isFilterVisible = false;
            ASC.CRM.ListTaskView.isTabActive = false;

           // ASC.CRM.ListTaskView.isFirstTime = true;

            jq.tmpl("template-emptyScreen",
                {   ID: "tasksEmptyScreen",
                    ImgSrc: ASC.CRM.Data.EmptyScrImgs["empty_screen_tasks"],
                    Header: ASC.CRM.Resources.CRMTaskResource.EmptyContentTasksHeader,
                    Describe: jq.format(ASC.CRM.Resources.CRMTaskResource.EmptyContentTasksDescribe,
                                    "<span class='hintCategories baseLinkAction' >", "</span>"),
                    ButtonHTML: ["<a class='link dotline plus'>",
                            ASC.CRM.Resources.CRMTaskResource.CreateTask,
                            "</a>"
                            ].join(''),
                    CssClass: "display-none"
                }).insertAfter("#taskListTab");
            jq.tmpl("taskExtendedListTmpl", { IsTab: true }).appendTo("#taskListTab");
            jq("#tableForTaskNavigation select").val(ASC.CRM.ListTaskView.CountOfRows)
                    .change(function (evt) {
                        ASC.CRM.ListTaskView.changeCountOfRows(this.value, true);
                    })
                    .tlCombobox();

            _initTaskStatusesMenu();
            _initTaskActionMenu(true);
            _initPageNavigatorControl(true, ASC.CRM.ListTaskView.CountOfRows, 0);

            ASC.CRM.Common.registerChangeHoverStateByParent("label.task_category", "#taskTable .with-entity-menu");
        },

        bindEmptyScrBtnEvent: function(params) {
            jq("#tasksEmptyScreen .emptyScrBttnPnl>a.link.plus").bind("click", function() {
                ASC.CRM.TaskActionView.showTaskPanel(0, ASC.CRM.ListTaskView.EntityType, ASC.CRM.ListTaskView.EntityID, window.contactForInitTaskActionPanel, params);
            });
        },

        setFilter: function (evt, $container, filter, params, selectedfilters) { _changeFilter(); },
        resetFilter: function (evt, $container, filter, selectedfilters) { _changeFilter(); },

        activate: function() {
            if (ASC.CRM.ListTaskView.isTabActive == false) {
                ASC.CRM.ListTaskView.isTabActive = true;
                _getTasksForEntity(0);
            }
        },

        resizeFilter: function() {
            var visible = jq("#taskFilterContainer").is(":hidden") == false;
            if (ASC.CRM.ListTaskView.isFilterVisible == false && visible) {
                ASC.CRM.ListTaskView.isFilterVisible = true;
                if (ASC.CRM.ListTaskView.advansedFilter) {
                    jq("#tasksAdvansedFilter").advansedFilter("resize");
                }
            }
        },

        getFilterSettings: function() {
            var settings = {};
            if (ASC.CRM.ListTaskView.advansedFilter.advansedFilter == null) {
                return settings;
            }

            var param = ASC.CRM.ListTaskView.advansedFilter.advansedFilter();

            jq(param).each(function(i, item) {
                switch (item.id) {
                    case "sorter":
                        settings.sortBy = item.params.id;
                        settings.sortOrder = item.params.dsc == true ? 'descending' : 'ascending';
                        break;
                    case "text":
                        settings.filterValue = item.params.value;
                        break;
                    case "fromToDate":
                        settings.fromDate = new Date(item.params.from);
                        settings.toDate = new Date(item.params.to);
                        settings.toDate = new Date(settings.toDate.getFullYear(), settings.toDate.getMonth(), settings.toDate.getDate(), 23, 59, 59, 0);
                        break;
                    default:
                        if (item.hasOwnProperty("apiparamname") && item.params.hasOwnProperty("value") && item.params.value != null) {
                            try {
                                var apiparamnames = jq.parseJSON(item.apiparamname),
                                    apiparamvalues = jq.parseJSON(item.params.value);
                                if (apiparamnames.length != apiparamvalues.length) {
                                    settings[item.apiparamname] = item.params.value;
                                }
                                for (var i = 0, len = apiparamnames.length; i < len; i++) {
                                    if (typeof (apiparamvalues[i]) != "string" || apiparamvalues[i].trim().length != 0) {
                                        settings[apiparamnames[i]] = apiparamvalues[i];
                                    }
                                }
                            } catch (err) {
                                settings[item.apiparamname] = item.params.value;
                            }
                        }
                        break;
                }
            });
            return settings;
        },

        taskItemFactory: function(taskItem) {

            if (taskItem.isClosed) {
                taskItem.classForTitle = "header-base-small gray-text";
                taskItem.classForTaskDeadline = "gray-text";
            } else {
                if (taskItem.deadLine < new Date()) {
                    taskItem.classForTitle = "header-base-small red-text";
                    taskItem.classForTaskDeadline = "red-text";
                } else {
                    taskItem.classForTitle = "header-base-small";
                    taskItem.classForTaskDeadline = "";
                }
            }

            if (taskItem.entity != null) {
                switch (taskItem.entity.entityType) {
                    case "opportunity":
                        taskItem.entityURL = "Deals.aspx?id=" + taskItem.entity.entityId;
                        taskItem.entityType = ASC.CRM.Resources.CRMJSResource.Deal;
                        break;
                    case "case":
                        taskItem.entityURL = "Cases.aspx?id=" + taskItem.entity.entityId;
                        taskItem.entityType = ASC.CRM.Resources.CRMJSResource.Case;
                        break;
                    default:
                        taskItem.entityURL = "";
                        taskItem.entityType = "";
                        break;
                }
            }
            taskItem.category.cssClass = taskItem.category.imagePath.split('/')[taskItem.category.imagePath.split('/').length - 1].split('.')[0];

            if (window.UserManager.getUser(taskItem.responsible.id) == null) {
                taskItem.responsible.displayName = ASC.CRM.Data.ProfileRemoved;
                taskItem.responsible.activationStatus = 2;
            }

        },

        showConfirmationPanelForDelete: function(taskID) {
            jq("#confirmationDeleteOneTaskPanel .middle-button-container>.button.blue.middle").unbind("click").bind("click", function () {
                _deleteTaskItem(taskID);
            });
            PopupKeyUpActionProvider.EnableEsc = false;
            StudioBlockUIManager.blockUI("#confirmationDeleteOneTaskPanel", 500);
        },

        findIndexOfTaskByID: function(taskID) {
            var length = ASC.CRM.ListTaskView.TaskList.length;
            for (var i = 0; i < length; i++) {
                if (ASC.CRM.ListTaskView.TaskList[i].id == taskID) {
                    return i;
                }
            }
            return -1;
        },

        showActionMenu: function (taskID) {
            var index = ASC.CRM.ListTaskView.findIndexOfTaskByID(taskID);
            if (index === -1) return;
            var task = ASC.CRM.ListTaskView.TaskList[index];

            var contactID = task.contact != null ? task.contact.id : 0,
                contactDisplayName = task.contact != null ? task.contact.displayName : '',
                entityType =  task.entity != null ? task.entity.entityType : '',
                entityID = task.entity != null ? task.entity.entityId : 0,
                isEmailCategory = task.category.imagePath.indexOf('task_category_email') != -1,
                email = task.contact != null && task.contact.email != null ? task.contact.email.data : '';


            jq("#editTaskLink").unbind("click").bind("click", function() {
                jq("#taskActionMenu").hide();
                jq("#taskTable .entity-menu.active").removeClass("active");
                ASC.CRM.TaskActionView.showTaskPanel(taskID, entityType, entityID, window.contactForInitTaskActionPanel, {});
            });
            jq("#deleteTaskLink").unbind("click").bind("click", function() {
                jq("#taskActionMenu").hide();
                jq("#taskTable .entity-menu.active").removeClass("active");
                ASC.CRM.ListTaskView.showConfirmationPanelForDelete(taskID);
            });

            if (isEmailCategory) {
                jq("#sendEmailLink").removeClass("display-none");
                
                var basePathMail = ASC.CRM.Common.getMailModuleBasePath(),
                    pathCreateEmail = "";

                if (email != '') {
                    pathCreateEmail = [
                        basePathMail,
                        "#composeto/email='",
                        contactDisplayName,
                        "' <",
                        email,
                        ">"
                    ].join('');
                } else {
                    pathCreateEmail = [
                        basePathMail,
                        "#composeto/"
                    ].join('');
                }
                jq("#sendEmailLink").attr("href", pathCreateEmail);
            } else {
                jq("#sendEmailLink").addClass("display-none");
            }
        },

        changeCountOfRows: function(newValue, isTab) {
            if (isNaN(newValue)) return;
            var newCountOfRows = newValue * 1;
            ASC.CRM.ListTaskView.CountOfRows = newCountOfRows;
            taskPageNavigator.EntryCountOnPage = newCountOfRows;
            if (isTab == true) {
                _getTasksForEntity(0);
            } else {
                _setCookie(1, newCountOfRows);
                _renderContent(0);
            }
        }
    };
};

/*******************************************************************************
TaskActionView.ascx
*******************************************************************************/
ASC.CRM.TaskActionView = new function() {

    var _changeSelectionDeadlineButtons = function(daysCount) {
        jq("#taskDeadlineContainer").find("a").each(function() {
            jq(this).css("border-bottom", "");
            jq(this).css("font-weight", "normal");
        });

        if (daysCount == 0 || daysCount == 3 || daysCount == 7) {
            jq("#deadline_" + daysCount).css("border-bottom", "none");
            jq("#deadline_" + daysCount).css("font-weight", "bold");
        }
    };

    var _initTaskContactSelector = function (contact) {
        window.taskContactSelector.ShowAddButton = false;
        window.taskContactSelector.clearSelector();

        if (typeof (contact) === "object" && contact != null && contact.length != 0) {
            if (!ASC.CRM.Common.isArray(contact)) {
                window.taskContactSelector.setContact(jq("#contactTitle_taskContactSelector_0"), contact.id, contact.displayName, contact.smallFotoUrl);
                window.taskContactSelector.showInfoContent(jq("#contactTitle_taskContactSelector_0"));
            } else {
                window.taskContactSelector.setContact(jq("#contactTitle_taskContactSelector_0"), contact[0].id, contact[0].displayName, contact[0].smallFotoUrl);
                window.taskContactSelector.showInfoContent(jq("#contactTitle_taskContactSelector_0"));
                for (var i = 1, n = contact.length; i < n; i++) {
                    window.taskContactSelector.AddNewSelectorWithSelectedContact(contact[i]);
                    window.taskContactSelector.SelectedContacts.push(contact[i].id);
                }
            }
        } else {
            window.taskContactSelector.changeContact('taskContactSelector_0');
            window.taskContactSelector.crossButtonEventClick('taskContactSelector_0');
        }
    };

    var _initTaskResponsibleSelector = function(contact, task) {

        var $selector = jq("#taskActionViewAdvUsrSrContainer");
        var allUsers = ($selector.data("items") || []).map(function(item) { return item.id; });

        $selector.useradvancedSelector("undisable", allUsers);

        if (contact && contact.isPrivate && contact.accessList) {
            var accessList = contact.accessList.map(function (item) { return item.id; });
            var adminList = ASC.CRM.Data.crmAdminList.map(function (item) { return item.id; });
            var userList = accessList.concat(adminList);
            var disabledList = allUsers.filter(function (item) { return !userList.includes(item); });

            $selector.useradvancedSelector("disable", disabledList);
        }

        var selected = task && task.responsible && task.responsible.activationStatus != 2 ? task.responsible : Teamlab.profile;

        $selector.useradvancedSelector("select", [selected.id]);
        $selector.useradvancedSelector("reset");
    };

    var _initTaskCategorySelector = function () {
        var selectedCategory = {};
        if (ASC.CRM.Data.taskCategories.length > 0) {
            selectedCategory = ASC.CRM.Data.taskCategories[0];
        } else {
            selectedCategory = { id: 0, title: "", imgSrc: "" };
        }
        window.taskCategorySelector = new ASC.CRM.CategorySelector("taskCategorySelector", selectedCategory);
        taskCategorySelector.renderControl(ASC.CRM.Data.taskCategories, selectedCategory, "#taskCategorySelectorContainer", 0, "");
    };

    var _initHoursAndMinutesSelects = function(){
        var html = "<option value='-1' id='optDeadlineHours_-1'>--</option>";
        for (var i = 0; i < 24; i++)
        {
            html += ["<option value='",
                    i,
                    "' id='optDeadlineHours_",
                    i,
                    "'>",
                    i < 10 ? "0" + i : i,
                    "</option>"]
                    .join('');
        }
        jq("#taskDeadlineHours").html(html).val("-1");
            
        html = "<option value='-1' id='optDeadlineMinutes_-1'>--</option>";
        for (var i = 0; i < 60; i++)
        {
            html += ["<option value='",
                    i,
                    "' id='optDeadlineMinutes_",
                    i,
                    "'>",
                    i < 10 ? "0" + i : i,
                    "</option>"]
                    .join('');
        }
        jq("#taskDeadlineMinutes").html(html).val("-1");
    };

    var _readDataTask = function (taskID, entityType, entityID, contactid) {
        var dataTask = {},
            isValid = true,
            deadLine = null;

        if (jq.trim(jq("#addTaskPanel input[id$=taskDeadline]").val()) != "") {
            deadLine = jq("#taskDeadline").datepicker('getDate');
            if (parseInt(jq("#taskDeadlineHours option:selected").val()) != -1) {
                deadLine.setHours(parseInt(jq("#taskDeadlineHours option:selected").val()));
            } else {
                deadLine.setHours(0);
            }

            if (parseInt(jq("#taskDeadlineMinutes option:selected").val()) != -1) {
                deadLine.setMinutes(parseInt(jq("#taskDeadlineMinutes option:selected").val()));
            } else {
                deadLine.setMinutes(0);
            }

            deadLine = Teamlab.serializeTimestamp(deadLine);
        }

        dataTask = {
            id: taskID,
            title: jq("#tbxTitle").val(),
            description: jq("#tbxDescribe").val(),
            deadline: deadLine,
            responsibleid: jq("#taskActionViewAdvUsrSrContainer").attr("data-responsible-id"),
            categoryid: window.taskCategorySelector.CategoryID,
            isnotify: jq("#notifyResponsible").is(":checked"),
            contactid: contactid,
            alertValue: jq("#taskAlertInterval").val()
        };

        if (entityID != 0) {
            dataTask.entityType = entityType;
            dataTask.entityid = entityID;
        }

        var invalidTaskTime = (parseInt(jq("#taskDeadlineHours option:selected").val()) == -1
                            && parseInt(jq("#taskDeadlineMinutes option:selected").val()) != -1)
                            || (parseInt(jq("#taskDeadlineHours option:selected").val()) != -1
                            && parseInt(jq("#taskDeadlineMinutes option:selected").val()) == -1);

        if (jq.trim(jq("#tbxTitle").val()) == "") {
            AddRequiredErrorText(jq("#tbxTitle"), ASC.CRM.Resources.CRMJSResource.EmptyTaskTitle);
            ShowRequiredError(jq("#tbxTitle"), true);
            isValid = false;
        } else {
            RemoveRequiredErrorClass(jq("#tbxTitle"));
        }

        if (dataTask.responsibleid == "") {
            AddRequiredErrorText(jq("#taskActionViewAdvUsrSrContainer"), ASC.CRM.Resources.CRMJSResource.EmptyTaskResponsible);
            ShowRequiredError(jq("#taskActionViewAdvUsrSrContainer"), true);
            isValid = false;
        } else {
            RemoveRequiredErrorClass(jq("#taskActionViewAdvUsrSrContainer"));
        }

        if (dataTask.deadline == null || invalidTaskTime) {
            AddRequiredErrorText(jq("#taskDeadline"), ASC.CRM.Resources.CRMJSResource.EmptyTaskDeadline);
            ShowRequiredError(jq("#taskDeadline"), true);

            if (invalidTaskTime) {
                jq("#taskDeadlineHours").addClass("requiredInputError");
                jq("#taskDeadlineMinutes").addClass("requiredInputError");
            } else {
                jq("#taskDeadlineHours").removeClass("requiredInputError");
                jq("#taskDeadlineMinutes").removeClass("requiredInputError");
            }

            isValid = false;
        } else {
            RemoveRequiredErrorClass(jq("#taskDeadline"));
            jq("#taskDeadlineHours").removeClass("requiredInputError");
            jq("#taskDeadlineMinutes").removeClass("requiredInputError");
        }

        if (isValid) {
            return dataTask;
        } else {
            return null
        }
    };

    return {
        CallbackMethods: {
            add_task: function (params, task) {
                ASC.CRM.UpdateCRMCaldavCalendar(task, 0);
                var isTab = typeof (ASC.CRM.ListTaskView) == "undefined" || typeof (ASC.CRM.ListTaskView.advansedFilter) == "undefined";
                if (typeof (ASC.CRM.ListTaskView) != "undefined" && typeof (ASC.CRM.ListTaskView.TaskList) != "undefined") {
                    var newTask = task;
                    ASC.CRM.ListTaskView.taskItemFactory(newTask);
                    ASC.CRM.ListTaskView.TaskList.push(newTask);

                    if (jq("#taskTable tbody tr").length == 0) {
                        if (!isTab) {
                            jq("#emptyContentForTasksFilter:not(.display-none)").addClass("display-none");
                        }
                        jq("#tasksEmptyScreen:not(.display-none)").addClass("display-none");

                        if (!isTab) {
                            jq("#taskFilterContainer").show();
                            ASC.CRM.ListTaskView.resizeFilter();
                        }

                        jq("#taskList").show();
                    }

                    jq.tmpl("taskTmpl", newTask).prependTo("#taskTable tbody");
                    ASC.CRM.ListTaskView.Total += 1;
                    jq("#totalTasksOnPage").text(ASC.CRM.ListTaskView.Total);
                    jq("#tableForTaskNavigation").show();

                    ASC.CRM.Common.tooltip("#taskTitle_" + newTask.id, "tooltip");
                    ASC.CRM.Common.RegisterContactInfoCard();
                }
                PopupKeyUpActionProvider.EnableEsc = true;
                jq.unblockUI();
            },

            edit_task: function (params, task, oldResponsible) {
                ASC.CRM.UpdateCRMCaldavCalendar(task, (task.isClosed ? 2 : 1), oldResponsible);
                var newTask = task;

                ASC.CRM.ListTaskView.taskItemFactory(newTask);
                ASC.CRM.ListTaskView.TaskList.push(newTask);


                jq("#task_" + newTask.id).attr("id", "old_task").hide();
                jq.tmpl("taskTmpl", newTask).insertBefore(jq("#old_task"));
                jq("#old_task").remove();

                ASC.CRM.Common.tooltip("#taskTitle_" + newTask.id, "tooltip");

                PopupKeyUpActionProvider.EnableEsc = true;
                jq.unblockUI();

                ASC.CRM.Common.RegisterContactInfoCard();
            }
        },

        init: function (_showChangeButton) {

            jq.tmpl("template-blockUIPanel", {
                id: "addTaskPanel",
                headerTest: ASC.CRM.Resources.CRMTaskResource.AddNewTask,
                questionText: "",
                innerHtmlText:"<div class=\"addTaskPanelContainer\"></div>",
                progressText: ""
            }).appendTo("#studioPageContent .mainPageContent .containerBodyBlock:first");

            jq("#addTaskPanel .addTaskPanelContainer").replaceWith(jq.tmpl("taskActionViewTmpl", {}).appendTo("#addTaskPanel .addTaskPanelContainer"));

            _initHoursAndMinutesSelects();

            jq("#taskDeadline").mask(ASC.Resources.Master.DatePatternJQ);
            jq("#taskDeadline").datepickerWithButton({
                onSelect: function(date) {
                    var selectedDate = jq("#taskDeadline").datepicker("getDate") || new Date(),
                        tmpDate = new Date(),
                        today = new Date(tmpDate.getFullYear(), tmpDate.getMonth(), tmpDate.getDate(), 0, 0, 0, 0),
                        daysCount = Math.floor((selectedDate.getTime() - today.getTime()) / (24 * 60 * 60 * 1000));
                    _changeSelectionDeadlineButtons(daysCount);
                    setTimeout(function () {
                        jq("#taskDeadline").datepicker("setDate", selectedDate).datepicker("hide");
                        jq('<input type="text" />').insertAfter("#taskDeadline").focus().remove();
                    }, 100);
                }
            });

            if (jq.browser.mobile)
                jq("#ui-datepicker-div").addClass("blockMsg");

            _initTaskCategorySelector();

            //init task ContactSelector
            window["taskContactSelector"] = new ASC.CRM.ContactSelector.ContactSelector("taskContactSelector",
                       {
                           SelectorType: ASC.CRM.Data.ContactSelectorTypeEnum.All,
                           EntityType: 0,
                           EntityID: 0,
                           ShowOnlySelectorContent: false,
                           DescriptionText: ASC.CRM.Resources.CRMCommonResource.FindContactByName,
                           DeleteContactText: "",
                           AddContactText: "",
                           IsInPopup: true,
                           ShowChangeButton: _showChangeButton,
                           ShowAddButton: false,
                           ShowDeleteButton: false,
                           ShowContactImg: true,
                           ShowNewCompanyContent: true,
                           ShowNewContactContent: true,
                           presetSelectedContactsJson: '',
                           ExcludedArrayIDs: [],
                           HTMLParent: "#addTaskPanel .connectWithContactContainer"
                       });

            window.taskContactSelector.SelectItemEvent = function (contact, params) {
                window.taskContactSelector.setContact(params.input, contact.id, contact.displayName, contact.smallFotoUrl);
                window.taskContactSelector.showInfoContent(params.input);
                _initTaskResponsibleSelector(contact);
            };
        },

        showTaskPanel: function(taskID, entityType, entityID, contact, params) {
            var index = ASC.CRM.TaskActionView.initPanel(taskID, contact, params);
            PopupKeyUpActionProvider.EnableEsc = false;
            HideRequiredError();
            jq("#addTaskPanel .error-popup").addClass("display-none");
            jq("#createNewButton").hide();
            StudioBlockUIManager.blockUI("#addTaskPanel", 650);

            jq("#addTaskPanel input[id$=tbxTitle]").focus();
            jq("#taskActionPopupOK").unbind("click").bind("click", function () {
                if (jq(this).hasClass("disable"))
                    return;

                if (window.taskContactSelector.SelectedContacts.length > 1) {
                    ASC.CRM.TaskActionView.saveTaskGroup(entityType, entityID, window.taskContactSelector.SelectedContacts, index, params);
                } else {
                    var contactid=0;
                    if (window.taskContactSelector.SelectedContacts.length == 1) {
                        contactid = window.taskContactSelector.SelectedContacts[0];
                    }
                    ASC.CRM.TaskActionView.saveTask(taskID, entityType, entityID, contactid, index, params);
                }
            });
        },

        keyPress: function(event) {
            var code;
            if (!e) var e = event;
            if (!e) var e = window.event;

            if (e.keyCode) code = e.keyCode;
            else if (e.which) code = e.which;

            if (code >= 48 && code <= 57) {
                jq("#taskDeadlineContainer").find("a").each(function() { jq(this).css("border-bottom", ""); });
            }
        },

        changeDeadline: function(object) {
            var daysCount = parseInt(jq.trim(jq(object).attr('id').split('_')[1])),
                tmp = new Date(),
                newDate = new Date(tmp.setDate(tmp.getDate() + daysCount));
            jq("#taskDeadline").datepicker('setDate', newDate);

            _changeSelectionDeadlineButtons(daysCount);
        },

        saveTask: function(taskID, entityType, entityID, contactid, index, params) {

            var dataTask = _readDataTask(taskID, entityType, entityID, contactid);
            if (dataTask == null) {
                return false;
            }

            if (taskID != 0) {
                var taskIndex = ASC.CRM.ListTaskView.findIndexOfTaskByID(taskID);
                var oldResponsible = ASC.CRM.ListTaskView.TaskList[taskIndex].responsible.id;
                ASC.CRM.ListTaskView.TaskList.splice(index, 1);

                Teamlab.updateCrmTask({}, taskID, dataTask,
                {
                    success: function (params, task) { ASC.CRM.TaskActionView.CallbackMethods.edit_task(params, task, oldResponsible); },
                    error: function (params, error) {
                        var taskErrorBox = jq("#addTaskPanel .error-popup");
                        taskErrorBox.text(error[0]);
                        taskErrorBox.removeClass("display-none").show();
                    },
                    before: function (params) {
                        LoadingBanner.strLoading = ASC.CRM.Resources.CRMTaskResource.SavingTask;
                        LoadingBanner.showLoaderBtn("#addTaskPanel");
                    },
                    after: function (params) {
                        LoadingBanner.hideLoaderBtn("#addTaskPanel");
                    }
                });
            } else {
                var callbackFunc = ASC.CRM.TaskActionView.CallbackMethods.add_task;
                if (typeof (params) === "object" && params != null && params.hasOwnProperty("success") && typeof (params.success) === "function") {
                    callbackFunc = params.success;
                }

                Teamlab.addCrmTask({}, dataTask,
                    {
                        success: callbackFunc,
                        error: function(params, error) {
                            var taskErrorBox = jq("#addTaskPanel .error-popup");
                            taskErrorBox.text(error[0]);
                            taskErrorBox.removeClass("display-none").show();
                        },
                        before: function (params) {
                            LoadingBanner.strLoading = ASC.CRM.Resources.CRMTaskResource.SavingTask;
                            LoadingBanner.showLoaderBtn("#addTaskPanel");
                        },
                        after: function (params) {
                            LoadingBanner.hideLoaderBtn("#addTaskPanel");
                        }
                    });
            }
        },

        saveTaskGroup: function (entityType, entityID, contactids, index, params) {
            var dataTask = _readDataTask(0, entityType, entityID, contactids);
            if (dataTask == null) {
                return false;
            }

            var callbackFunc = function (params, tasks) { jq.unblockUI(); };
            if (typeof (params) === "object" && params.hasOwnProperty("success") && typeof (params.success) === "function") {
                callbackFunc = params.success;
            }

            Teamlab.addCrmTaskGroup({}, dataTask,
                {
                    success: callbackFunc,
                    error: function (params, error) {
                        var taskErrorBox = jq("#addTaskPanel .error-popup");
                        taskErrorBox.text(error[0]);
                        taskErrorBox.removeClass("display-none").show();
                    },
                    before: function (params) {
                        LoadingBanner.strLoading = ASC.CRM.Resources.CRMTaskResource.SavingTask;
                        LoadingBanner.showLoaderBtn("#addTaskPanel");
                    },
                    after: function (params) {
                        LoadingBanner.hideLoaderBtn("#addTaskPanel");
                    }
                });
        },


        initPanel: function(taskID, contact, params) {
            if (!jq("#taskActionViewAdvUsrSrContainer").next().is(".advanced-selector-container")) {
                jq("#taskActionViewAdvUsrSrContainer").useradvancedSelector({
                    showme: false,
                    inPopup: true,
                    onechosen: true,
                    showGroups: true,
                    withGuests: false
                });

                if (ASC.CRM.Data.isCrmAvailableForAllUsers == false) {
                    var users = [],
                        items = jq("#taskActionViewAdvUsrSrContainer").data("items");

                    for (var i = 0, n = ASC.CRM.Data.crmAvailableWithAdminList.length; i < n; i++) {
                        for (var j = 0, m = items.length; j < m; j++) {
                            if (ASC.CRM.Data.crmAvailableWithAdminList[i].id == items[j].id) {
                                users.push(items[j]);
                                continue;
                            }
                        }
                    }
                    jq("#taskActionViewAdvUsrSrContainer").useradvancedSelector("rewriteItemList", users, []);
                }

                jq("#taskActionViewAdvUsrSrContainer").on("showList", function (event, item) {
                    if (item.id == Teamlab.profile.id) {
                        jq("#notifyResponsible").prop("checked", false).prop("disabled", true);
                    } else {
                        jq("#notifyResponsible").prop("disabled", false).prop("checked", true);
                    }
                    jq("#taskActionViewAdvUsrSrContainer").attr("data-responsible-id", item.id)
                    jq("#taskActionViewAdvUsrSrContainer .taskResponsibleLabel").text(Encoder.htmlDecode(item.title));
                });


                if (typeof (params) != "undefined" && params != null && params.hasOwnProperty("taskResponsibleSelectorUserIDs")) {
                    var adminsGuids = [],
                        items = [],
                        taskResponsibleSelectorUserIDs = [],
                        taskResponsibleSelectorUsers = [];
                    for (var i = 0, n = ASC.CRM.Data.crmAdminList.length; i < n; i++) {
                        adminsGuids.push(ASC.CRM.Data.crmAdminList[i].id);
                    }
                    taskResponsibleSelectorUserIDs = params.taskResponsibleSelectorUserIDs.concat(adminsGuids);
                    items = jq("#taskActionViewAdvUsrSrContainer").data("items");
                    for (var i = 0, n = items.length; i < n; i++) {
                        if (taskResponsibleSelectorUserIDs.indexOf(items[i].id) != -1) {
                            taskResponsibleSelectorUsers.push(items[i]);
                        }
                    }
                    jq("#taskActionViewAdvUsrSrContainer").useradvancedSelector("rewriteItemList", taskResponsibleSelectorUsers, []);
                }
            }

            if (taskID > 0) {
                jq("div.noMatches").hide();

                var index = ASC.CRM.ListTaskView.findIndexOfTaskByID(taskID);
                if (index != -1) {
                    var task = ASC.CRM.ListTaskView.TaskList[index];
                    jq("#tbxTitle").val(task.title);
                    jq("#tbxDescribe").val(task.description);

                    jq("#taskDeadline").datepicker('setDate', task.deadLine);


                    if (task.deadLine.getHours() == 0 && task.deadLine.getMinutes() == 0) {
                        jq("#taskDeadlineHours").val("-1");
                        jq("#taskDeadlineMinutes").val('-1');
                    } else {
                        jq("#taskDeadlineHours").val(task.deadLine.getHours());
                        jq("#taskDeadlineMinutes").val(task.deadLine.getMinutes());
                    }

                    var obj = window.taskCategorySelector.getRowByContactID(task.category.id);
                    window.taskCategorySelector.changeContact(obj);

                    _initTaskResponsibleSelector(task.contact, task);
                    _initTaskContactSelector(task.contact);

                    jq("#taskAlertInterval").val(task.alertValue);

                    jq("#taskActionPopupOK").html(ASC.CRM.Resources.CRMJSResource.SaveChanges);
                    jq("#addTaskPanel div.containerHeaderBlock td:first").html(ASC.CRM.Resources.CRMJSResource.EditTask);

                }
                return index;
            } else {
                jq("#taskActionPopupOK").html(ASC.CRM.Resources.CRMJSResource.AddThisTask);
                jq("#addTaskPanel div.containerHeaderBlock td:first").html(ASC.CRM.Resources.CRMJSResource.AddNewTask);

                jq("#tbxTitle").val("");
                jq("#tbxDescribe").val("");


                jq("#taskDeadline").datepicker('setDate', new Date());
                _changeSelectionDeadlineButtons(0);

                jq("#optDeadlineHours_-1").attr('selected', true);
                jq("#optDeadlineMinutes_-1").attr('selected', true);

                var obj = window.taskCategorySelector.getRowByContactID(0);
                window.taskCategorySelector.changeContact(obj);

                _initTaskResponsibleSelector(contact, null);
                _initTaskContactSelector(contact);
                jq("#taskAlertInterval").val("1440");
                return -1;
            }

        },

        changeTime: function(obj) {
            if (jq(obj).val() == "-1") {
                jq("#taskDeadlineHours").val("-1");
                jq("#taskDeadlineMinutes").val("-1");
            }
        }
    }
};

jq(document).ready(function() {
    jq.dropdownToggle({
        switcherSelector: ".noContentBlock .hintCategories",
        dropdownID: "files_hintCategoriesPanel",
        fixWinSize: false
    });
});

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/UserControls/PostControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core.Users;
using ASC.Forum;
using ASC.Web.Community.Modules.Forum.UserControls.Resources;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Forum.Common;

namespace ASC.Web.UserControls.Forum
{
    [AjaxNamespace("PostManager")]
    public partial class PostControl : UserControl
    {
        public Post Post { get; set; }
        public Guid SettingsID { get; set; }
        protected Settings _settings;
        private ForumManager _forumManager;
        public int PostsCount { get; set; }

        public int CurrentPageNumber { get; set; }

        public PostControl()
        {
            CurrentPageNumber = -1;
        }

        public bool IsEven { get; set; }

        protected string _postCSSClass;
        protected string _messageCSSClass;

        protected void Page_Load(object sender, EventArgs e)
        {
            Utility.RegisterTypeForAjax(GetType());

            _settings = Community.Forum.ForumManager.Settings;
            _forumManager = _settings.ForumManager;

            _postCSSClass = IsEven ? "tintMedium" : "";

            _messageCSSClass = "forum_mesBox";
            if (!Post.IsApproved && _forumManager.ValidateAccessSecurityAction(ForumAction.ApprovePost, Post))
                _messageCSSClass = "tintDangerous forum_mesBox";

        }

        protected string RenderEditedData()
        {
            if (Post.EditCount <= 0)
                return "";

            var sb = new StringBuilder();
            sb.Append("<div class='text-medium-describe' style='padding:2px 5px;'>" + ForumUCResource.Edited + "&nbsp;&nbsp;");
            sb.Append(Post.EditDate.ToShortDateString() + " " + Post.EditDate.ToShortTimeString());
            sb.Append("<span style='margin-left:5px;'>" + Post.Editor.RenderCustomProfileLink("describe-text", "link gray") + "</span>");
            sb.Append("</div>");

            return sb.ToString();
        }

        protected void ReferenceToPost()
        {
            string refToPost;
            if (CurrentPageNumber != -1)
                refToPost = "<a class=\"link\" href=\"" + _settings.LinkProvider.Post(Post.ID, Post.TopicID, CurrentPageNumber) + "\">#" + Post.ID.ToString() + "</a>";
            else
                refToPost = "&nbsp;";
            Response.Write(refToPost);
        }

        protected string ControlButtons()
        {
            var topic = ForumDataProvider.GetTopicByID(TenantProvider.CurrentTenantID, Post.TopicID);
            if (topic.Closed)
                return string.Empty;

            var sb = new StringBuilder();

            if (_forumManager.ValidateAccessSecurityAction(ForumAction.PostCreate, new Topic { ID = Post.TopicID }))
            {
                sb.Append("<a class=\"link gray\" style=\"float:left;\" href=\"" + _settings.LinkProvider.NewPost(Post.TopicID, PostAction.Quote, Post.ID) + "\">" + ForumUCResource.Quote + "</a>");
                sb.Append("<a class=\"link gray\" style=\"float:left;  margin-left:8px;\" href=\"" + _settings.LinkProvider.NewPost(Post.TopicID, PostAction.Reply, Post.ID) + "\">" + ForumUCResource.Reply + "</a>");
                sb.Append("<a class=\"link gray\" style=\"float:left; margin-left:8px;\" href=\"" + _settings.LinkProvider.NewPost(Post.TopicID) + "\">" + ForumUCResource.NewPostButton + "</a>");
            }

            var isFirst = true;

            if (_forumManager.ValidateAccessSecurityAction(ForumAction.PostDelete, Post) && ShowDeletePostLink())
            {
                sb.AppendFormat("<a class=\"link\" style=\"float:right;\" id='PostDeleteLink{0}' href=\"javascript:ForumManager.DeletePost('" + Post.ID + "')\">" + ForumUCResource.DeleteButton + "</a>", Post.ID);
                isFirst = false;
            }

            if (_forumManager.ValidateAccessSecurityAction(ForumAction.PostEdit, Post))
            {
                if (!isFirst && ShowDeletePostLink())
                    sb.AppendFormat("<span class='splitter' id='PostDeleteSplitter{0}' style='float:right;'>|</span>", Post.ID);

                sb.Append("<a class=\"link\" style=\"float:right;\" href=\"" + _settings.LinkProvider.NewPost(Post.TopicID, PostAction.Edit, Post.ID) + "\">" + ForumUCResource.EditButton + "</a>");
                isFirst = false;
            }

            if (!Post.IsApproved && _forumManager.ValidateAccessSecurityAction(ForumAction.ApprovePost, Post))
            {
                if (!isFirst)
                    sb.Append("<span class='splitter' style='float:right;'>|</span>");

                sb.Append("<a id=\"forum_btap_" + Post.ID + "\" class=\"link\" style=\"margin-left:5px; float:right;\" href=\"javascript:ForumManager.ApprovePost('" + Post.ID + "')\">" + ForumUCResource.ApproveButton + "</a>");
            }

            return sb.ToString();
        }

        private bool ShowDeletePostLink()
        {
            return PostsCount > 1;
        }

        public static string AttachmentsList(Post post, Guid settingsID)
        {
            var forumManager = Community.Forum.ForumManager.Settings.ForumManager;
            var sb = new StringBuilder();
            if (post.Attachments.Count <= 0)
                return "";

            var closedTopic = ForumDataProvider.GetTopicByID(TenantProvider.CurrentTenantID, post.TopicID).Closed;

            sb.Append("<div class=\"cornerAll borderBase forum_attachmentsBox\">");
            sb.Append("<div class='headerPanel'>" + ForumUCResource.AttachFiles + "</div>");
            foreach (var attachment in post.Attachments)
            {
                sb.Append("<div id=\"forum_attach_" + attachment.ID + "\" class=\"borderBase  forum_attachItem clearFix\">");
                sb.Append("<table cellspacing='0' cellpadding='0' style='width:100%;'><tr>");
                sb.Append("<td>");
                sb.Append("<a class = 'link' target=\"_blank\" href=\"" + forumManager.GetAttachmentWebPath(attachment) + "\">" + HttpUtility.HtmlEncode(attachment.Name) + "</a>");
                sb.Append("</td>");

                sb.Append("<td style=\"text-align:right;width:100px;\"><span class=\"text-medium-describe\">" + (attachment.Size / 1024f).ToString("####0.##") + " KB</span></td>");

                if (forumManager.ValidateAccessSecurityAction(ForumAction.AttachmentDelete, post) && !closedTopic)
                {
                    sb.Append("<td style=\"text-align:right;width:100px;\">");
                    sb.Append("<a class=\"link\" href=\"javascript:ForumManager.DeleteAttachment('" + attachment.ID + "','" + post.ID + "');\">" + ForumUCResource.DeleteButton + "</a>");
                    sb.Append("</td>");
                }

                sb.Append("</tr></table>");
                sb.Append("</div>");
            }
            sb.Append("</div>");
            return sb.ToString();
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse DoDeletePost(int idPost, Guid settingsID)
        {
            _forumManager = Community.Forum.ForumManager.Settings.ForumManager;
            var resp = new AjaxResponse { rs2 = idPost.ToString() };

            var post = ForumDataProvider.GetPostByID(TenantProvider.CurrentTenantID, idPost);
            if (post == null)
            {
                resp.rs1 = "0";
                resp.rs3 = ForumUCResource.ErrorAccessDenied;
                return resp;
            }

            if (!_forumManager.ValidateAccessSecurityAction(ForumAction.PostDelete, post))
            {
                resp.rs1 = "0";
                resp.rs3 = ForumUCResource.ErrorAccessDenied;
                return resp;
            }

            try
            {
                var result = RemoveDataHelper.RemovePost(post);
                if (result == DeletePostResult.Successfully)
                {
                    resp.rs1 = "1";
                    resp.rs3 = ForumUCResource.SuccessfullyDeletePostMessage;
                }
                else if (result == DeletePostResult.ReferencesBlock)
                {
                    resp.rs1 = "0";
                    resp.rs3 = ForumUCResource.ExistsReferencesChildPosts;
                }
                else
                {
                    resp.rs1 = "0";
                    resp.rs3 = ForumUCResource.ErrorDeletePost;
                }
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs3 = HttpUtility.HtmlEncode(e.Message);
            }

            return resp;
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse DoApprovedPost(int idPost, Guid settingsID)
        {
            _forumManager = Community.Forum.ForumManager.Settings.ForumManager;
            var resp = new AjaxResponse { rs2 = idPost.ToString() };

            var post = ForumDataProvider.GetPostByID(TenantProvider.CurrentTenantID, idPost);
            if (post == null)
            {
                resp.rs1 = "0";
                resp.rs3 = ForumUCResource.ErrorAccessDenied;
                return resp;
            }

            if (!_forumManager.ValidateAccessSecurityAction(ForumAction.ApprovePost, post))
            {
                resp.rs1 = "0";
                resp.rs3 = ForumUCResource.ErrorAccessDenied;
                return resp;
            }

            try
            {
                ForumDataProvider.ApprovePost(TenantProvider.CurrentTenantID, post.ID);
                resp.rs1 = "1";
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs3 = HttpUtility.HtmlEncode(e.Message);
            }
            return resp;
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse DoDeleteAttachment(int idAttachment, int idPost, Guid settingsID)
        {
            _forumManager = Community.Forum.ForumManager.Settings.ForumManager;
            var resp = new AjaxResponse { rs2 = idAttachment.ToString() };

            var post = ForumDataProvider.GetPostByID(TenantProvider.CurrentTenantID, idPost);
            if (post == null)
            {
                resp.rs1 = "0";
                resp.rs3 = ForumUCResource.ErrorAccessDenied;
                return resp;
            }

            if (!_forumManager.ValidateAccessSecurityAction(ForumAction.AttachmentDelete, post))
            {
                resp.rs1 = "0";
                resp.rs3 = ForumUCResource.ErrorAccessDenied;
                return resp;
            }

            try
            {
                var attachment = post.Attachments.Find(a => a.ID == idAttachment);
                if (attachment != null)
                {
                    ForumDataProvider.RemoveAttachment(TenantProvider.CurrentTenantID, attachment.ID);
                    _forumManager.RemoveAttachments(attachment.OffsetPhysicalPath);
                }

                resp.rs1 = "1";
                resp.rs3 = ForumUCResource.SuccessfullyDeleteAttachmentMessage;
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs3 = HttpUtility.HtmlEncode(e.Message);
            }

            return resp;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Resources/ProjectTemplatesResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Projects.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class ProjectTemplatesResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal ProjectTemplatesResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Projects.Resources.ProjectTemplatesResource", typeof(ProjectTemplatesResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add Milestone Title.
        /// </summary>
        public static string AddMilestoneTitle {
            get {
                return ResourceManager.GetString("AddMilestoneTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add Task.
        /// </summary>
        public static string AddTask {
            get {
                return ResourceManager.GetString("AddTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add Task Title.
        /// </summary>
        public static string AddTaskTitle {
            get {
                return ResourceManager.GetString("AddTaskTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All Project Templates.
        /// </summary>
        public static string AllProjectTmpl {
            get {
                return ResourceManager.GetString("AllProjectTmpl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose Responsible.
        /// </summary>
        public static string ChooseResponsible {
            get {
                return ResourceManager.GetString("ChooseResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create Project.
        /// </summary>
        public static string CreateProject {
            get {
                return ResourceManager.GetString("CreateProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new project template.
        /// </summary>
        public static string CreateProjTmpl {
            get {
                return ResourceManager.GetString("CreateProjTmpl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create from Template - {0}.
        /// </summary>
        public static string DefaultProjTitle {
            get {
                return ResourceManager.GetString("DefaultProjTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string Delete {
            get {
                return ResourceManager.GetString("Delete", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string Edit {
            get {
                return ResourceManager.GetString("Edit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit Project Structure.
        /// </summary>
        public static string EditProjStructure {
            get {
                return ResourceManager.GetString("EditProjStructure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit Project Template.
        /// </summary>
        public static string EditProjTmpl {
            get {
                return ResourceManager.GetString("EditProjTmpl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create the First Template.
        /// </summary>
        public static string EmptyListTemplateButton {
            get {
                return ResourceManager.GetString("EmptyListTemplateButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Project templates help you create similar projects with associated stuff like building a project team, planning milestones, tasks and discussions saving time spent each time on entering the same data..
        /// </summary>
        public static string EmptyListTemplateDescr {
            get {
                return ResourceManager.GetString("EmptyListTemplateDescr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no project templates.
        /// </summary>
        public static string EmptyListTemplateHeader {
            get {
                return ResourceManager.GetString("EmptyListTemplateHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each milestone must have a title.
        /// </summary>
        public static string MilestoneError {
            get {
                return ResourceManager.GetString("MilestoneError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to milestones.
        /// </summary>
        public static string Milestones {
            get {
                return ResourceManager.GetString("Milestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nobody.
        /// </summary>
        public static string NoResponsible {
            get {
                return ResourceManager.GetString("NoResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Notify Responsibles.
        /// </summary>
        public static string NotifyResponsibles {
            get {
                return ResourceManager.GetString("NotifyResponsibles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete this template?.
        /// </summary>
        public static string RemoveQuestion {
            get {
                return ResourceManager.GetString("RemoveQuestion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Remove Template.
        /// </summary>
        public static string RemoveTemplateTitlePopup {
            get {
                return ResourceManager.GetString("RemoveTemplateTitlePopup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save &amp; Create project from template.
        /// </summary>
        public static string SaveAndCreateProjFromTmpl {
            get {
                return ResourceManager.GetString("SaveAndCreateProjFromTmpl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save Changes.
        /// </summary>
        public static string SaveChanges {
            get {
                return ResourceManager.GetString("SaveChanges", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string SaveTemplate {
            get {
                return ResourceManager.GetString("SaveTemplate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task.
        /// </summary>
        public static string Task {
            get {
                return ResourceManager.GetString("Task", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each task must have a title.
        /// </summary>
        public static string TaskError {
            get {
                return ResourceManager.GetString("TaskError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to tasks.
        /// </summary>
        public static string Tasks {
            get {
                return ResourceManager.GetString("Tasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks without milestone.
        /// </summary>
        public static string TasksWithoutMilestone {
            get {
                return ResourceManager.GetString("TasksWithoutMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string TemplateTitle {
            get {
                return ResourceManager.GetString("TemplateTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each template must have a title.
        /// </summary>
        public static string TitleErrorTemplate {
            get {
                return ResourceManager.GetString("TitleErrorTemplate", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/helpcenter/panel.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.helpPanel = (function($) {
    var isInit = false,
        panelContent;

    var init = function() {
        if (isInit === false) {
            isInit = true;
            panelContent = $('#studio_sidePanel .help-center');
        }
    };

    var unmarkSettings = function() {
        var $sections = $(panelContent).find('.menu-sub-list').children();

        if ($(panelContent).hasClass('active')) {
            $(panelContent).toggleClass('active');
        }

        if ($(panelContent).hasClass('currentCategory')) {
            $(panelContent).toggleClass('currentCategory');
        }


        for (var i = 0, n = $sections.length; i < n; i++) {
            var $item = $($sections[i]);
            if ($item.hasClass('active')) {
                $item.toggleClass('active', false);
            }
        }
    };

    var selectItem = function(number) {
        if (number == 'all') {
            $(panelContent).toggleClass('active', true);
        } else {
            var $sections = $(panelContent).find('.menu-sub-list').children();
            $($sections[number]).toggleClass('active', true);
        }

    };

    return {
        init: init,
        selectItem: selectItem,
        unmarkSettings: unmarkSettings
    };

})(jQuery);

<|start_filename|>module/ASC.AuditTrail/Mappers/CrmActionMapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.MessagingSystem;

namespace ASC.AuditTrail.Mappers
{
    internal class CrmActionMapper
    {
        public static Dictionary<MessageAction, MessageMaps> GetMaps()
        {
            return new Dictionary<MessageAction, MessageMaps>
                {
                    #region companies

                    {
                        MessageAction.CompanyCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CompanyCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyCreatedWithWebForm, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CompanyCreatedWithWebForm",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompanyUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyUpdatedPrincipalInfo, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompanyUpdatedPrincipalInfo",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyUpdatedPhoto, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompanyUpdatedPhoto",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyUpdatedTemperatureLevel, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompanyUpdatedTemperatureLevel",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyUpdatedPersonsTemperatureLevel, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompanyUpdatedPersonsTemperatureLevel",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyCreatedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CompanyCreatedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyCreatedPersonsTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CompanyCreatedPersonsTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyDeletedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CompanyDeletedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyCreatedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CompanyCreatedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyDeletedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CompanyDeletedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyLinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "CompanyLinkedPerson",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyUnlinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "CompanyUnlinkedPerson",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyLinkedProject, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "CompanyLinkedProject",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyUnlinkedProject, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "CompanyUnlinkedProject",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyAttachedFiles, new MessageMaps
                            {
                                ActionTypeTextResourceName = "AttachActionType",
                                ActionTextResourceName = "CompanyAttachedFiles",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyDetachedFile, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DetachActionType",
                                ActionTextResourceName = "CompanyDetachedFile",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompaniesMerged, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompaniesMerged",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },
                    {
                        MessageAction.CompanyDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CompanyDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CompaniesModule"
                            }
                    },

                    #endregion

                    #region persons
                
                    {
                        MessageAction.PersonCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "PersonCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonCreatedWithWebForm, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "PersonCreatedWithWebForm",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonsCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "PersonsCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonUpdatedPrincipalInfo, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonUpdatedPrincipalInfo",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonUpdatedPhoto, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonUpdatedPhoto",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonUpdatedTemperatureLevel, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonUpdatedTemperatureLevel",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonUpdatedCompanyTemperatureLevel, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonUpdatedCompanyTemperatureLevel",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonCreatedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "PersonCreatedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonCreatedCompanyTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "PersonCreatedCompanyTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonDeletedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "PersonDeletedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonCreatedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "PersonCreatedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonDeletedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "PersonDeletedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonLinkedProject, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "PersonLinkedProject",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonUnlinkedProject, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "PersonUnlinkedProject",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonAttachedFiles, new MessageMaps
                            {
                                ActionTypeTextResourceName = "AttachActionType",
                                ActionTextResourceName = "PersonAttachedFiles",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonDetachedFile, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DetachActionType",
                                ActionTextResourceName = "PersonDetachedFile",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonsMerged, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonsMerged",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },
                    {
                        MessageAction.PersonDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "PersonDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "PersonsModule"
                            }
                    },

                    #endregion

                    #region contacts
                    
                    {
                        MessageAction.ContactsDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ContactsDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsModule"
                            }
                    },
                    {
                        MessageAction.CrmSmtpMailSent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "SendActionType",
                                ActionTextResourceName = "CrmSmtpMailSent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsModule"
                            }
                    },

                    #endregion

                    #region tasks

                    {
                        MessageAction.CrmTaskCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CrmTaskCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },
                    {
                        MessageAction.ContactsCreatedCrmTasks, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ContactsCreatedCrmTasks",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmTaskUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskOpened, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmTaskOpened",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskClosed, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmTaskClosed",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CrmTaskDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },

                    #endregion

                    #region opportunities

                    {
                        MessageAction.OpportunityCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "OpportunityCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OpportunityUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUpdatedStage, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OpportunityUpdatedStage",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityCreatedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "OpportunityCreatedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityDeletedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "OpportunityDeletedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityCreatedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "OpportunityCreatedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityDeletedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "OpportunityDeletedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityLinkedCompany, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "OpportunityLinkedCompany",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUnlinkedCompany, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "OpportunityUnlinkedCompany",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityLinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "OpportunityLinkedPerson",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUnlinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "OpportunityUnlinkedPerson",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityAttachedFiles, new MessageMaps
                            {
                                ActionTypeTextResourceName = "AttachActionType",
                                ActionTextResourceName = "OpportunityAttachedFiles",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityDetachedFile, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DetachActionType",
                                ActionTextResourceName = "OpportunityDetachedFile",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityOpenedAccess, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "OpportunityOpenedAccess",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityRestrictedAccess, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "OpportunityRestrictedAccess",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunityDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "OpportunityDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.OpportunitiesDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "OpportunitiesDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },

                    #endregion

                    #region invoices

                    {
                        MessageAction.InvoiceCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "InvoiceCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },
                    {
                        MessageAction.InvoiceUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "InvoiceUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },
                    {
                        MessageAction.InvoicesUpdatedStatus, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "InvoicesUpdatedStatus",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },
                    {
                        MessageAction.InvoiceDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "InvoiceDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },
                    {
                        MessageAction.InvoicesDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "InvoicesDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },

                    {
                        MessageAction.CurrencyRateUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CurrencyRateUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },
                    {
                        MessageAction.InvoiceDefaultTermsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "InvoiceDefaultTermsUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },
                    {
                        MessageAction.InvoiceDownloaded, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DownloadActionType",
                                ActionTextResourceName = "InvoiceDownloaded",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoicesModule"
                            }
                    },

                    #endregion

                    #region cases

                    {
                        MessageAction.CaseCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CaseCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CaseUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseOpened, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CaseOpened",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseClosed, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CaseClosed",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseCreatedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CaseCreatedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseDeletedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CaseDeletedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseCreatedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CaseCreatedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseDeletedHistoryEvent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CaseDeletedHistoryEvent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseLinkedCompany, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "CaseLinkedCompany",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseUnlinkedCompany, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "CaseUnlinkedCompany",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseLinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "CaseLinkedPerson",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseUnlinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "CaseUnlinkedPerson",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseAttachedFiles, new MessageMaps
                            {
                                ActionTypeTextResourceName = "AttachActionType",
                                ActionTextResourceName = "CaseAttachedFiles",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseDetachedFile, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DetachActionType",
                                ActionTextResourceName = "CaseDetachedFile",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseOpenedAccess, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "CaseOpenedAccess",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseRestrictedAccess, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "CaseRestrictedAccess",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CaseDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CaseDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },
                    {
                        MessageAction.CasesDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CasesDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },

                    #endregion

                    #region common settings

                    {
                        MessageAction.CrmSmtpSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmSmtpSettingsUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CommonCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CrmTestMailSent, new MessageMaps
                            {
                                ActionTypeTextResourceName = "SendActionType",
                                ActionTextResourceName = "CrmTestMailSent",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CommonCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CrmDefaultCurrencyUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmDefaultCurrencyUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CommonCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CrmAllDataExported, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ExportActionType",
                                ActionTextResourceName = "CrmAllDataExported",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CommonCrmSettingsModule"
                            }
                    },

                    #endregion

                    #region contact settings

                    {
                        MessageAction.ContactTemperatureLevelCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ContactTemperatureLevelCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactTemperatureLevelUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactTemperatureLevelUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactTemperatureLevelUpdatedColor, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactTemperatureLevelUpdatedColor",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactTemperatureLevelsUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactTemperatureLevelsUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactTemperatureLevelDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ContactTemperatureLevelDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactTemperatureLevelSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactTemperatureLevelSettingsUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CommonCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactTypeCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ContactTypeCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactTypesModule"
                            }
                    },
                    {
                        MessageAction.ContactTypeUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactTypeUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactTypesModule"
                            }
                    },
                    {
                        MessageAction.ContactTypesUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactTypesUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactTypesModule"
                            }
                    },
                    {
                        MessageAction.ContactTypeDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ContactTypeDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactTypesModule"
                            }
                    },

                    #endregion

                    #region invoice settings

                    {
                        MessageAction.InvoiceItemCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "InvoiceItemCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.InvoiceItemUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "InvoiceItemUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.InvoiceItemDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "InvoiceItemDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.InvoiceItemsDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "InvoiceItemsDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.InvoiceTaxCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "InvoiceTaxCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.InvoiceTaxUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "InvoiceTaxUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.InvoiceTaxDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "InvoiceTaxDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.OrganizationProfileUpdatedCompanyName, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OrganizationProfileUpdatedCompanyName",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.OrganizationProfileUpdatedInvoiceLogo, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OrganizationProfileUpdatedInvoiceLogo",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.OrganizationProfileUpdatedAddress, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OrganizationProfileUpdatedAddress",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },
                    {
                        MessageAction.InvoiceNumberFormatUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "InvoiceNumberFormatUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "InvoiceSettingsModule"
                            }
                    },

                    #endregion

                    #region user fields settings

                    {
                        MessageAction.ContactUserFieldCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ContactUserFieldCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactUserFieldUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactUserFieldUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactUserFieldsUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactUserFieldsUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactUserFieldDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ContactUserFieldDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CompanyUserFieldCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CompanyUserFieldCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CompanyUserFieldUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompanyUserFieldUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CompanyUserFieldsUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CompanyUserFieldsUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CompanyUserFieldDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CompanyUserFieldDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.PersonUserFieldCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "PersonUserFieldCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.PersonUserFieldUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonUserFieldUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.PersonUserFieldsUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PersonUserFieldsUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.PersonUserFieldDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "PersonUserFieldDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUserFieldCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "OpportunityUserFieldCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUserFieldUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OpportunityUserFieldUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUserFieldsUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OpportunityUserFieldsUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityUserFieldDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "OpportunityUserFieldDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CaseUserFieldCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CaseUserFieldCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CaseUserFieldUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CaseUserFieldUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CaseUserFieldsUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CaseUserFieldsUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CaseUserFieldDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CaseUserFieldDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },

                    #endregion

                    #region history events categories settings

                    {
                        MessageAction.HistoryEventCategoryCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "HistoryEventCategoryCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.HistoryEventCategoryUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "HistoryEventCategoryUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.HistoryEventCategoryUpdatedIcon, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "HistoryEventCategoryUpdatedIcon",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.HistoryEventCategoriesUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "HistoryEventCategoriesUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.HistoryEventCategoryDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "HistoryEventCategoryDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },

                    #endregion

                    #region task actegories settings

                    {
                        MessageAction.CrmTaskCategoryCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CrmTaskCategoryCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskCategoryUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmTaskCategoryUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskCategoryUpdatedIcon, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmTaskCategoryUpdatedIcon",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskCategoriesUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CrmTaskCategoriesUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CrmTaskCategoryDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CrmTaskCategoryDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },

                    #endregion

                    #region opportunity stages settings

                    {
                        MessageAction.OpportunityStageCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "OpportunityStageCreated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityStageUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OpportunityStageUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityStageUpdatedColor, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OpportunityStageUpdatedColor",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityStagesUpdatedOrder, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OpportunityStagesUpdatedOrder",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunityStageDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "OpportunityStageDeleted",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },

                    #endregion

                    #region tags settings

                    {
                        MessageAction.ContactsCreatedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ContactsCreatedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactsDeletedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ContactsDeletedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunitiesCreatedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "OpportunitiesCreatedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.OpportunitiesDeletedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "OpportunitiesDeletedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CasesCreatedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "CasesCreatedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.CasesDeletedTag, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "CasesDeletedTag",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },
                    {
                        MessageAction.ContactsTagSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ContactsTagSettingsUpdated",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CommonCrmSettingsModule"
                            }
                    },

                    #endregion

                    #region other settings

                    {
                        MessageAction.WebsiteContactFormUpdatedKey, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "WebsiteContactFormUpdatedKey",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OtherCrmSettingsModule"
                            }
                    },

                    #endregion

                    #region import

                    {
                        MessageAction.ContactsImportedFromCSV, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ImportActionType",
                                ActionTextResourceName = "ContactsImportedFromCSV",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsModule"
                            }
                    },
                    {
                        MessageAction.CrmTasksImportedFromCSV, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ImportActionType",
                                ActionTextResourceName = "CrmTasksImportedFromCSV",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },
                    {
                        MessageAction.OpportunitiesImportedFromCSV, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ImportActionType",
                                ActionTextResourceName = "OpportunitiesImportedFromCSV",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.CasesImportedFromCSV, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ImportActionType",
                                ActionTextResourceName = "CasesImportedFromCSV",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },

                    #endregion

                    #region export

                    {
                        MessageAction.ContactsExportedToCsv, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ExportActionType",
                                ActionTextResourceName = "ContactsExportedToCsv",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "ContactsModule"
                            }
                    },
                    {
                        MessageAction.CrmTasksExportedToCsv, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ExportActionType",
                                ActionTextResourceName = "CrmTasksExportedToCsv",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CrmTasksModule"
                            }
                    },
                    {
                        MessageAction.OpportunitiesExportedToCsv, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ExportActionType",
                                ActionTextResourceName = "OpportunitiesExportedToCsv",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "OpportunitiesModule"
                            }
                    },
                    {
                        MessageAction.CasesExportedToCsv, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ExportActionType",
                                ActionTextResourceName = "CasesExportedToCsv",
                                ProductResourceName = "CrmProduct",
                                ModuleResourceName = "CasesModule"
                            }
                    },

                    #endregion
                };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Resources/BlogsResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Community.Modules.Blogs.Core.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class BlogsResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal BlogsResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Community.Modules.Blogs.Core.Resources.BlogsResource", typeof(BlogsResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The corporate blog.
        /// </summary>
        public static string AddonDescriptionResourceKey {
            get {
                return ResourceManager.GetString("AddonDescriptionResourceKey", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Blogs.
        /// </summary>
        public static string AddonName {
            get {
                return ResourceManager.GetString("AddonName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All posts by the author.
        /// </summary>
        public static string AllRecordsOfTheAutor {
            get {
                return ResourceManager.GetString("AllRecordsOfTheAutor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Blogs.
        /// </summary>
        public static string Blogs {
            get {
                return ResourceManager.GetString("Blogs", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The post topic field cannot be empty.
        /// </summary>
        public static string BlogTitleEmptyMessage {
            get {
                return ResourceManager.GetString("BlogTitleEmptyMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string BlogTitleLabel {
            get {
                return ResourceManager.GetString("BlogTitleLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cancel.
        /// </summary>
        public static string CancelButton {
            get {
                return ResourceManager.GetString("CancelButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add comment.
        /// </summary>
        public static string CommentsAddButtonTitle {
            get {
                return ResourceManager.GetString("CommentsAddButtonTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comments.
        /// </summary>
        public static string CommentsTitle {
            get {
                return ResourceManager.GetString("CommentsTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete the post?.
        /// </summary>
        public static string ConfirmRemovePostMessage {
            get {
                return ResourceManager.GetString("ConfirmRemovePostMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Text.
        /// </summary>
        public static string ContentTitle {
            get {
                return ResourceManager.GetString("ContentTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string DeleteBlogLink {
            get {
                return ResourceManager.GetString("DeleteBlogLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string EditBlogLink {
            get {
                return ResourceManager.GetString("EditBlogLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit Post.
        /// </summary>
        public static string EditPostTitle {
            get {
                return ResourceManager.GetString("EditPostTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No blogs have been created yet.
        /// </summary>
        public static string EmptyScreenBlogCaption {
            get {
                return ResourceManager.GetString("EmptyScreenBlogCaption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create the first blog.
        /// </summary>
        public static string EmptyScreenBlogLink {
            get {
                return ResourceManager.GetString("EmptyScreenBlogLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create your own page to share the interesting information, thoughts and experiences with others, express your opinions, get feedback from the users&apos; comments..
        /// </summary>
        public static string EmptyScreenBlogText {
            get {
                return ResourceManager.GetString("EmptyScreenBlogText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to View pages with the interesting information, other users&apos; thoughts and experiences, express your opinions, get feedback from the users&apos; comments..
        /// </summary>
        public static string EmptyScreenBlogTextVisitor {
            get {
                return ResourceManager.GetString("EmptyScreenBlogTextVisitor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the needed tags separating them with commas.
        /// </summary>
        public static string EnterTagsMessage {
            get {
                return ResourceManager.GetString("EnterTagsMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close.
        /// </summary>
        public static string HideButton {
            get {
                return ResourceManager.GetString("HideButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new post.
        /// </summary>
        public static string NewPost {
            get {
                return ResourceManager.GetString("NewPost", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Publish.
        /// </summary>
        public static string PostButton {
            get {
                return ResourceManager.GetString("PostButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Author.
        /// </summary>
        public static string PostedTitle {
            get {
                return ResourceManager.GetString("PostedTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Preview.
        /// </summary>
        public static string PreviewButton {
            get {
                return ResourceManager.GetString("PreviewButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Read more.
        /// </summary>
        public static string ReadMoreLink {
            get {
                return ResourceManager.GetString("ReadMoreLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Search in blogs.
        /// </summary>
        public static string SearchDefaultString {
            get {
                return ResourceManager.GetString("SearchDefaultString", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show on page.
        /// </summary>
        public static string ShowOnPage {
            get {
                return ResourceManager.GetString("ShowOnPage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subscribe to all user&apos;s posts .
        /// </summary>
        public static string SubscribeOnAuthorAction {
            get {
                return ResourceManager.GetString("SubscribeOnAuthorAction", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The subscription allows you to track new user posts in blogs.
        /// </summary>
        public static string SubscribeOnAuthorDescription {
            get {
                return ResourceManager.GetString("SubscribeOnAuthorDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New user posts.
        /// </summary>
        public static string SubscribeOnAuthorTitle {
            get {
                return ResourceManager.GetString("SubscribeOnAuthorTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subscribe to post comments.
        /// </summary>
        public static string SubscribeOnNewCommentsAction {
            get {
                return ResourceManager.GetString("SubscribeOnNewCommentsAction", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The subscription allows you to track new post comments.
        /// </summary>
        public static string SubscribeOnNewCommentsDescription {
            get {
                return ResourceManager.GetString("SubscribeOnNewCommentsDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Post comments.
        /// </summary>
        public static string SubscribeOnNewCommentsTitle {
            get {
                return ResourceManager.GetString("SubscribeOnNewCommentsTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subscribe to all posts.
        /// </summary>
        public static string SubscribeOnNewPostAction {
            get {
                return ResourceManager.GetString("SubscribeOnNewPostAction", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The subscription allows you to track new posts in blogs.
        /// </summary>
        public static string SubscribeOnNewPostDescription {
            get {
                return ResourceManager.GetString("SubscribeOnNewPostDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New blog posts.
        /// </summary>
        public static string SubscribeOnNewPostTitle {
            get {
                return ResourceManager.GetString("SubscribeOnNewPostTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tags.
        /// </summary>
        public static string TagsTitle {
            get {
                return ResourceManager.GetString("TagsTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select the text you want to be hidden from the feed pages and the blog list page and click the &quot;Text Cut&quot; button..
        /// </summary>
        public static string TeamlabCutText {
            get {
                return ResourceManager.GetString("TeamlabCutText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Text Cut.
        /// </summary>
        public static string TeamlabCutTitle {
            get {
                return ResourceManager.GetString("TeamlabCutTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Total.
        /// </summary>
        public static string TotalPages {
            get {
                return ResourceManager.GetString("TotalPages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unsubscribe from user&apos;s posts.
        /// </summary>
        public static string UnSubscribeOnAuthorAction {
            get {
                return ResourceManager.GetString("UnSubscribeOnAuthorAction", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unsubscribe from post comments.
        /// </summary>
        public static string UnSubscribeOnNewCommentsAction {
            get {
                return ResourceManager.GetString("UnSubscribeOnNewCommentsAction", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unsubscribe from all posts.
        /// </summary>
        public static string UnSubscribeOnNewPostAction {
            get {
                return ResourceManager.GetString("UnSubscribeOnNewPostAction", resourceCulture);
            }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/WellKnownPorts.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net
{
    /// <summary>
    /// This class provides well known TCP/UDP service ports.
    /// </summary>
    public class WellKnownPorts
    {
        #region Members

        /// <summary>
        /// DNS protocol.
        /// </summary>
        public static readonly int DNS = 53;

        /// <summary>
        /// FTP - control (command) port.
        /// </summary>
        public static readonly int FTP_Control = 21;

        /// <summary>
        /// FTP over SSL protocol.
        /// </summary>
        public static readonly int FTP_Control_SSL = 990;

        /// <summary>
        /// FTP - data port.
        /// </summary>
        public static readonly int FTP_Data = 20;

        /// <summary>
        /// HTTP protocol.
        /// </summary>
        public static readonly int HTTP = 80;

        /// <summary>
        /// HTTPS protocol.
        /// </summary>
        public static readonly int HTTPS = 443;

        /// <summary>
        /// IMAP4 protocol.
        /// </summary>
        public static readonly int IMAP4 = 143;

        /// <summary>
        /// IMAP4 over SSL protocol.
        /// </summary>
        public static readonly int IMAP4_SSL = 993;

        /// <summary>
        /// NNTP (Network News Transfer Protocol)  protocol.
        /// </summary>
        public static readonly int NNTP = 119;

        /// <summary>
        /// NTP (Network Time Protocol) protocol.
        /// </summary>
        public static readonly int NTP = 123;

        /// <summary>
        /// POP3 protocol.
        /// </summary>
        public static readonly int POP3 = 110;

        /// <summary>
        /// POP3 over SSL protocol.
        /// </summary>
        public static readonly int POP3_SSL = 995;

        /// <summary>
        /// SMTP protocol.
        /// </summary>
        public static readonly int SMTP = 25;

        /// <summary>
        /// SMTP over SSL protocol.
        /// </summary>
        public static readonly int SMTP_SSL = 465;

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/mail.printpage.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.printPage = (function($) {
    var conversationId,
        messageId,
        showImagesIds,
        showQuotesIds,
        sortAsc,
        showAll;

    var viewTmpl = 'message-print-tmpl';

    var $html;
    var $pageContent;
    var $view;
    var $title;

    function init(conversation, id, simIds, squIds, asc, displayAll) {
        showImagesIds = simIds;
        showQuotesIds = squIds;
        sortAsc = asc;
        showAll = displayAll;

        initElements();

        if (conversation) {
            conversationId = id;
            getConversation(conversationId, function(messages) {
                if (!sortAsc) {
                    messages.reverse();
                }

                renderView(messages);
                printView();
            });
        } else {
            messageId = id;
            getMessage(messageId, function(message) {
                renderView([message]);
                printView();
            });
        }
    }

    function initElements() {
        $html = $('html');
        $pageContent = $('#studioPageContent .page-content .mainContainerClass');
        $title = $html.find('title');
    }

    function getMessage(id, cb) {
        return serviceManager.getMessage(id, false, {}, {
            success: function (params, message) {

                //set up images
                var loadImages = false;
                var showImages = showImagesIds.indexOf(message.id.toString()) != -1;
                var senderAddress = ASC.Mail.Utility.ParseAddress(message.from).email;
                if (trustedAddresses.isTrusted(senderAddress) || showImages) {
                    loadImages = true;
                }

                var res = ASC.Mail.Sanitizer.Sanitize(message.htmlBody, {
                    urlProxyHandler: ASC.Mail.Constants.PROXY_HTTP_URL,
                    needProxyHttp: ASC.Mail.Constants.NEED_PROXY_HTTP_URL,
                    loadImages: loadImages
                });

                message.htmlBody = res.html;
                message.contentIsBlocked = res.imagesBlocked;
                message.sanitized = res.sanitized;

                messagePage.preprocessMessages(null, [message]);
                cb(message);
            },
            error: function() {
                showErrorMessage();
            }
        });
    }

    function getConversation(id, cb) {
        return serviceManager.getConversation(id, true, {}, {
            success: function (params, messages) {

                for (var i = 0, n = messages.length; i < n; i++) {
                    var message = messages[i];

                    //set up images
                    var loadImages = showAll || false;

                    if (!showAll) {
                        var showImages = showImagesIds.indexOf(message.id.toString()) != -1;
                        var senderAddress = ASC.Mail.Utility.ParseAddress(message.from).email;
                        if (trustedAddresses.isTrusted(senderAddress) || showImages) {
                            loadImages = true;
                        }
                    }

                    var res = ASC.Mail.Sanitizer.Sanitize(message.htmlBody, {
                        urlProxyHandler: ASC.Mail.Constants.PROXY_HTTP_URL,
                        needProxyHttp: ASC.Mail.Constants.NEED_PROXY_HTTP_URL,
                        loadImages: loadImages
                    });

                    message.htmlBody = res.html;
                    message.contentIsBlocked = res.imagesBlocked;
                    message.sanitized = res.sanitized;
                }

                messagePage.preprocessMessages(null, messages);
                cb(messages);
            },
            error: function() {
                showErrorMessage();
            }
        });
    }

    function renderView(messages) {
        $title.text(messages[0].subject || MailScriptResource.NoSubject);

        for (var i = 0; i < messages.length; i++) {
            messages[i].printedHtmlBody = getMessageBodyForPrint(messages[i]);
        }

        $view = $.tmpl(viewTmpl, { messages: messages }, {
            fileSizeToStr: AttachmentManager.GetSizeString,
            cutFileName: AttachmentManager.CutFileName,
            getFileNameWithoutExt: AttachmentManager.GetFileName,
            getFileExtension: AttachmentManager.GetFileExtension
        });

        hideLoader();
        $pageContent.append($view);
    }

    function getMessageBodyForPrint(message) {
        var $body = $('<div/>').html(message.htmlBody);

        // remove br tags from the end
        var $lastEl = $body.children(':last-child');
        $lastEl.prevUntil(':not(br)').remove();
        if ($lastEl.is('br')) {
            $lastEl.remove();
        }

        //set up quotes
        var showQuotes = showQuotesIds.indexOf(message.id.toString()) != -1;
        if (!showQuotes) {
            var $quote = $body.find('div.gmail_quote:first, div.yahoo_quoted:first, blockquote:first, div:has(hr#stopSpelling):last');
            $quote.after('<div class="quote-hidden-msg">' + MailScriptResource.QuotedTextHiddenMsg + '</div>');
            $quote.hide();
        }

        return $body.html();
    }

    function printView() {
        setTimeout(function() {
            window.print();
        }, 300);
    }

    function hideLoader() {
        $('#firstLoader').remove();
    }

    function showErrorMessage() {
        toastr.error(ASC.Resources.Master.ResourceJS.CommonJSErrorMsg);
    }

    return {
        init: init
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Utils/Import/CSV/ImportDeals.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

using ASC.Core.Users;
using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.CRM.Core.Entities;
using ASC.Web.CRM.Resources;

using LumenWorks.Framework.IO.Csv;

using Newtonsoft.Json.Linq;

#endregion

namespace ASC.Web.CRM.Classes
{
    public partial class ImportDataOperation
    {

        private void ImportOpportunityData(DaoFactory _daoFactory)
        {
            var allUsers = ASC.Core.CoreContext.UserManager.GetUsers(EmployeeStatus.All).ToList();

            using (var CSVFileStream = _dataStore.GetReadStream("temp", _CSVFileURI))
            using (CsvReader csv = ImportFromCSV.CreateCsvReaderInstance(CSVFileStream, _importSettings))
            {
                int currentIndex = 0;

                var customFieldDao = _daoFactory.CustomFieldDao;
                var contactDao = _daoFactory.ContactDao;
                var tagDao = _daoFactory.TagDao;
                var dealDao = _daoFactory.DealDao;
                var dealMilestoneDao = _daoFactory.DealMilestoneDao;

                var findedTags = new Dictionary<int, List<String>>();
                var findedCustomField = new List<CustomField>();
                var findedDeals = new List<Deal>();
                var findedDealMembers = new Dictionary<int, List<int>>();

                var dealMilestones = dealMilestoneDao.GetAll();

                while (csv.ReadNextRecord())
                {
                    _columns = csv.GetCurrentRowFields(false);

                    var obj = new Deal();

                    obj.ID = currentIndex;

                    obj.Title = GetPropertyValue("title");

                    if (String.IsNullOrEmpty(obj.Title)) continue;

                    obj.Description = GetPropertyValue("description");

                    var csvResponsibleValue = GetPropertyValue("responsible");
                    var responsible = allUsers.Where(n => n.DisplayUserName().Equals(csvResponsibleValue)).FirstOrDefault();

                    if (responsible != null)
                        obj.ResponsibleID = responsible.ID;
                    else
                        obj.ResponsibleID = Constants.LostUser.ID;

                    DateTime actualCloseDate;

                    DateTime expectedCloseDate;

                    if (DateTime.TryParse(GetPropertyValue("actual_close_date"), out actualCloseDate))
                        obj.ActualCloseDate = actualCloseDate;

                    if (DateTime.TryParse(GetPropertyValue("expected_close_date"), out expectedCloseDate))
                        obj.ExpectedCloseDate = expectedCloseDate;

                    var currency = CurrencyProvider.Get(GetPropertyValue("bid_currency"));

                    if (currency != null)
                        obj.BidCurrency = currency.Abbreviation;
                    else
                        obj.BidCurrency = Global.TenantSettings.DefaultCurrency.Abbreviation;

                    decimal bidValue;

                    var bidValueStr = GetPropertyValue("bid_amount");

                    if (Decimal.TryParse(bidValueStr, NumberStyles.Number, CultureInfo.InvariantCulture, out bidValue))
                        obj.BidValue = bidValue;
                    else
                        obj.BidValue = 0;


                    var bidTypeStr = GetPropertyValue("bid_type");

                    BidType bidType = BidType.FixedBid;

                    if (!String.IsNullOrEmpty(bidTypeStr))
                    {
                        if (String.Compare(CRMDealResource.BidType_FixedBid, bidTypeStr, true) == 0)
                            bidType = BidType.FixedBid;
                        else if (String.Compare(CRMDealResource.BidType_PerDay, bidTypeStr, true) == 0)
                            bidType = BidType.PerDay;
                        else if (String.Compare(CRMDealResource.BidType_PerHour, bidTypeStr, true) == 0)
                            bidType = BidType.PerHour;
                        else if (String.Compare(CRMDealResource.BidType_PerMonth, bidTypeStr, true) == 0)
                            bidType = BidType.PerMonth;
                        else if (String.Compare(CRMDealResource.BidType_PerWeek, bidTypeStr, true) == 0)
                            bidType = BidType.PerWeek;
                        else if (String.Compare(CRMDealResource.BidType_PerYear, bidTypeStr, true) == 0)
                            bidType = BidType.PerYear;
                    }

                    obj.BidType = bidType;

                    if (obj.BidType != BidType.FixedBid)
                    {
                        int perPeriodValue;

                        if (int.TryParse(GetPropertyValue("per_period_value"), out perPeriodValue))
                            obj.PerPeriodValue = perPeriodValue;
                    }

                    int probabilityOfWinning;

                    if (int.TryParse(GetPropertyValue("probability_of_winning"), out probabilityOfWinning))
                        obj.DealMilestoneProbability = probabilityOfWinning;

                    var dealMilestoneTitle = GetPropertyValue("deal_milestone");

                    var tag = GetPropertyValue("tag");


                    if (!String.IsNullOrEmpty(tag))
                    {
                        var tagList = tag.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                        tagList.AddRange(_importSettings.Tags);
                        tagList = tagList.Distinct().ToList();
                        findedTags.Add(obj.ID, tagList);
                    }
                    else if (_importSettings.Tags.Count != 0)
                    {
                        findedTags.Add(obj.ID, _importSettings.Tags);
                    }


                    if (String.IsNullOrEmpty(dealMilestoneTitle))
                        obj.DealMilestoneID = dealMilestones[0].ID;
                    else
                    {
                        var dealMilestone = dealMilestones.Find(item => String.Compare(item.Title, dealMilestoneTitle, true) == 0);

                        if (dealMilestone == null)
                            obj.DealMilestoneID = dealMilestones[0].ID;
                        else
                            obj.DealMilestoneID = dealMilestone.ID;
                    }

                    var contactName = GetPropertyValue("client");

                    var localMembersDeal = new List<int>();

                    if (!String.IsNullOrEmpty(contactName))
                    {
                        var contacts = contactDao.GetContactsByName(contactName, true);

                        if (contacts.Count > 0)
                        {
                            obj.ContactID = contacts[0].ID;
                            localMembersDeal.Add(obj.ContactID);
                        }
                        else
                        {
                            contacts = contactDao.GetContactsByName(contactName, false);
                            if (contacts.Count > 0)
                            {
                                obj.ContactID = contacts[0].ID;
                                localMembersDeal.Add(obj.ContactID);
                            }
                        }


                    }

                    var members = GetPropertyValue("member");

                    if (!String.IsNullOrEmpty(members))
                    {
                        var membersList = members.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                        foreach (var item in membersList)
                        {
                            var findedMember = contactDao.GetContactsByName(item, true);

                            if (findedMember.Count > 0)
                            {
                                localMembersDeal.Add(findedMember[0].ID);
                            }
                            else
                            {
                                findedMember = _daoFactory.ContactDao.GetContactsByName(item, false);
                                if (findedMember.Count > 0)
                                {
                                    localMembersDeal.Add(findedMember[0].ID);
                                }
                            }
                        }
                    }

                    if (localMembersDeal.Count > 0)
                        findedDealMembers.Add(obj.ID, localMembersDeal);


                    foreach (JProperty jToken in _importSettings.ColumnMapping.Children())
                    {
                        var propertyValue = GetPropertyValue(jToken.Name);

                        if (String.IsNullOrEmpty(propertyValue)) continue;

                        if (!jToken.Name.StartsWith("customField_")) continue;

                        var fieldID = Convert.ToInt32(jToken.Name.Split(new[] { '_' })[1]);
                        var field = customFieldDao.GetFieldDescription(fieldID);

                        if (field != null)
                        {
                            findedCustomField.Add(new CustomField
                            {
                                EntityID = obj.ID,
                                EntityType = EntityType.Opportunity,
                                ID = fieldID,
                                Value = field.FieldType == CustomFieldType.CheckBox ? (propertyValue == "on" || propertyValue == "true" ? "true" : "false") : propertyValue
                            });
                        }
                    }

                    Percentage += 1.0 * 100 / (ImportFromCSV.MaxRoxCount * 2);

                    if (ImportDataCache.CheckCancelFlag(EntityType.Opportunity))
                    {
                        ImportDataCache.ResetAll(EntityType.Opportunity);

                        throw new OperationCanceledException();
                    }

                    ImportDataCache.Insert(EntityType.Opportunity, (ImportDataOperation)Clone());



                    findedDeals.Add(obj);

                    if (currentIndex + 1 > ImportFromCSV.MaxRoxCount) break;

                    currentIndex++;

                }


                Percentage = 50;

                if (ImportDataCache.CheckCancelFlag(EntityType.Opportunity))
                {
                    ImportDataCache.ResetAll(EntityType.Opportunity);

                    throw new OperationCanceledException();
                }

                ImportDataCache.Insert(EntityType.Opportunity, (ImportDataOperation)Clone());

                var newDealIDs = dealDao.SaveDealList(findedDeals);
                findedDeals.ForEach(d => d.ID = newDealIDs[d.ID]);

                Percentage += 12.5;

                if (ImportDataCache.CheckCancelFlag(EntityType.Opportunity))
                {
                    ImportDataCache.ResetAll(EntityType.Opportunity);

                    throw new OperationCanceledException();
                }

                ImportDataCache.Insert(EntityType.Opportunity, (ImportDataOperation)Clone());

                findedCustomField.ForEach(item => item.EntityID = newDealIDs[item.EntityID]);

                customFieldDao.SaveList(findedCustomField);

                Percentage += 12.5;

                if (ImportDataCache.CheckCancelFlag(EntityType.Opportunity))
                {
                    ImportDataCache.ResetAll(EntityType.Opportunity);

                    throw new OperationCanceledException();
                }

                ImportDataCache.Insert(EntityType.Opportunity, (ImportDataOperation)Clone());

                foreach (var findedDealMemberKey in findedDealMembers.Keys)
                {
                    dealDao.SetMembers(newDealIDs[findedDealMemberKey], findedDealMembers[findedDealMemberKey].ToArray());
                }

                Percentage += 12.5;

                if (ImportDataCache.CheckCancelFlag(EntityType.Opportunity))
                {
                    ImportDataCache.ResetAll(EntityType.Opportunity);

                    throw new OperationCanceledException();
                }

                ImportDataCache.Insert(EntityType.Opportunity, (ImportDataOperation)Clone());

                foreach (var findedTagKey in findedTags.Keys)
                {
                    tagDao.SetTagToEntity(EntityType.Opportunity, newDealIDs[findedTagKey], findedTags[findedTagKey].ToArray());
                }

                if (_importSettings.IsPrivate)
                    findedDeals.ForEach(dealItem => CRMSecurity.SetAccessTo(dealItem, _importSettings.AccessList));

                Percentage += 12.5;

                if (ImportDataCache.CheckCancelFlag(EntityType.Opportunity))
                {
                    ImportDataCache.ResetAll(EntityType.Opportunity);

                    throw new OperationCanceledException();
                }

                ImportDataCache.Insert(EntityType.Opportunity, (ImportDataOperation)Clone());

            }

            Complete();
        }

    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Data/DbPostDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;

using ASC.Blogs.Core.Domain;
using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Tenants;

namespace ASC.Blogs.Core.Data
{
    public class DbPostDao : DbDao, IPostDao
    {
        public DbPostDao(DbManager db, int tenant) : base(db, tenant) { }

        #region IPostDao

        private Exp GetWhere(Guid? id, long? blogId, Guid? userId, string tag)
        {
            var where = Exp.Empty;
            if (id.HasValue) where &= Exp.Eq("id", id.Value.ToString());
            if (blogId.HasValue) where &= Exp.Eq("blog_id", blogId.Value);
            if (userId.HasValue) where &= Exp.Eq("created_by", userId.Value.ToString());
            if (tag != null) where &= Exp.In("id", Query("blogs_tags").Select("post_id").Where("name", tag));
            return where;
        }

        public int GetCount(Guid? id, long? blogId, Guid? userId)
        {
            return GetCount(id, blogId, userId, null);
        }

        public int GetCount(Guid? id, long? blogId, Guid? userId, string tag)
        {
            var where = GetWhere(id, blogId, userId, tag);
            var query = Query("blogs_posts").SelectCount().Where(where);
            return Db.ExecuteScalar<int>(query);
        }

        public List<Post> Select(Guid? id, long? blogId, Guid? userId, string tag, bool withContent, bool asc, int? from, int? count, bool fillTags, bool withCommentsCount)
        {
            var where = GetWhere(id, blogId, userId, tag);
            var query = Query("blogs_posts")
                .Select("id", "title", "created_by", "created_when", "blog_id", "post_id")
                .Where(where);

            if (withContent) query.Select("content");
            if (count.HasValue) query.SetMaxResults(count.Value);
            if (from.HasValue) query.SetFirstResult(from.Value);

            query.OrderBy("created_when", asc);

            var posts = Db.ExecuteList<Post>(query, r => RowMappers.ToPost(r, withContent));

            if (posts.Count > 0)
            {
                var pids = posts.ConvertAll(p => p.ID.ToString());
                var postQ = Query("blogs_posts").Select("id").Where(where).OrderBy("created_when", asc);
                if (count.HasValue) postQ.SetMaxResults(count.Value);
                if (from.HasValue) postQ.SetFirstResult(from.Value);
                var postsFilter = Exp.In("post_id", pids);

                if (fillTags)
                {
                    var tagQuery = Query("blogs_tags").Where(postsFilter).Select("name", "post_id");
                    var tlist = Db.ExecuteList<Tag>(tagQuery, RowMappers.ToTag);
                    foreach (var post in posts)
                    {
                        post.TagList = tlist.FindAll(t => t.PostId == post.ID);
                    }
                }
            }
            return posts;
        }

        public List<Post> Select(Guid? id, long? blogId, Guid? userId, bool withContent, bool asc, int? from, int? count, bool fillTags, bool withCommentsCount)
        {
            return Select(id, blogId, userId, null, withContent, true, null, null, fillTags, withCommentsCount);
        }

        public List<Post> Select(Guid? id, long? blogId, Guid? userId, bool withContent, bool fillTags, bool withCommentsCount)
        {
            return Select(id, blogId, userId, withContent, true, null, null, fillTags, withCommentsCount);
        }


        public List<int> SearchPostsByWord(string word)
        {
            var q1 = Query("blogs_posts")
                .Select("post_id")
                .Where(Exp.Like("lower(title)", word, SqlLike.StartWith) | Exp.Like("lower(title)", " " + word) | Exp.Like("lower(content)", word, SqlLike.StartWith) | Exp.Like("lower(content)", " " + word));

            var q2 = new SqlQuery("blogs_tags t")
                .InnerJoin("blogs_posts p", Exp.EqColumns("t.Tenant", "p.Tenant") & Exp.EqColumns("t.post_id", "p.id"))
                .Select("p.post_id")
                .Where("t.Tenant", Tenant)
                .Where(Exp.Like("lower(name)", word, SqlLike.StartWith) | Exp.Like("lower(name)", " " + word));

            return Db
                    .ExecuteList(q1.Union(q2))
                    .ConvertAll(row => Convert.ToInt32(row[0]));
        }

        public List<Tag> SelectTags(Guid? postId)
        {
            var query = Query("blogs_tags").Select("name", "post_id");
            if (postId.HasValue) query.Where("post_id", postId.Value.ToString());
            return Db.ExecuteList<Tag>(query, RowMappers.ToTag);
        }

        public List<string> GetTags(string like, int limit)
        {
            var query = Query("blogs_tags").Select("name").Distinct();
            query.Where(Exp.Like("name", like, SqlLike.StartWith)).SetMaxResults(limit);
            return Db.ExecuteList<string>(query, RowMappers.ToString);
        }

        public List<Post> GetPosts(List<int> ids, bool withContent, bool withTags)
        {
            var postIds = ids.ConvertAll(id => id.ToString(CultureInfo.InvariantCulture));
            var select = Query("blogs_posts")
                .Select("id", "title", "created_by", "created_when", "blog_id", "post_id")
                .Where(Exp.In("post_id", postIds));

            if (withContent) select.Select("content");

            var posts = Db.ExecuteList(select, r => RowMappers.ToPost(r, withContent));

            if (posts.Count > 0)
            {
                if (withTags)
                {
                    var tagQuery = Query("blogs_tags").Where(Exp.In("post_id", postIds)).Select("name", "post_id");
                    var tlist = Db.ExecuteList(tagQuery, RowMappers.ToTag);
                    foreach (var post in posts)
                    {
                        post.TagList = tlist.FindAll(t => t.PostId == post.ID);
                    }
                }
            }

            return posts;
        }

        public List<Post> GetPosts(List<Guid> ids, bool withContent, bool withTags)
        {
            var postIds = ids.ConvertAll(id => id.ToString());
            var select = Query("blogs_posts")
                .Select("id", "title", "created_by", "created_when", "blog_id", "post_id")
                .Where(Exp.In("id", postIds));

            if (withContent) select.Select("content");

            var posts = Db.ExecuteList<Post>(select, r => RowMappers.ToPost(r, withContent));

            if (posts.Count > 0)
            {
                if (withTags)
                {
                    var tagQuery = Query("blogs_tags").Where(Exp.In("post_id", postIds)).Select("name", "post_id");
                    var tlist = Db.ExecuteList<Tag>(tagQuery, RowMappers.ToTag);
                    foreach (var post in posts)
                    {
                        post.TagList = tlist.FindAll(t => t.PostId == post.ID);
                    }
                }
            }

            return posts;
        }

        public void SavePost(Post post)
        {
            var isInsert = false;
            if (post.ID == Guid.Empty)
            {
                post.ID = Guid.NewGuid();
                isInsert = true;
            }

            using (var tx = Db.BeginTransaction())
            {
                var tagsForSave = new List<Tag>(post.TagList);
                var tagsForDelete = new List<Tag>();
                if (!isInsert)
                {
                    var savedTags = SelectTags(post.ID);
                    tagsForDelete.AddRange(savedTags);
                    tagsForDelete.RemoveAll(_1 => tagsForSave.Exists(_2 => String.Equals(_1.Content, _2.Content, StringComparison.CurrentCultureIgnoreCase)));
                    tagsForSave.RemoveAll(_1 => savedTags.Exists(_2 => String.Equals(_1.Content, _2.Content, StringComparison.CurrentCultureIgnoreCase)));
                }

                if (tagsForDelete.Count > 0)
                {
                    var deleteq = Delete("blogs_tags")
                        .Where("post_id", post.ID.ToString())
                        .Where(Exp.In("name", tagsForDelete.ConvertAll(_ => (object)_.Content)));

                    Db.ExecuteNonQuery(deleteq);
                }

                if (tagsForSave.Count > 0)
                {
                    foreach (var tag in tagsForSave)
                    {
                        var insertq = Insert("blogs_tags")
                            .InColumns("name", "post_id")
                            .Values(tag.Content, post.ID.ToString());
                        Db.ExecuteNonQuery(insertq);
                    }
                }

                var queryi = Insert("blogs_posts")
                    .InColumnValue("post_id", post.AutoIncrementID)
                    .InColumnValue("id", post.ID.ToString())
                    .InColumnValue("title", post.Title)
                    .InColumnValue("content", post.Content)
                    .InColumnValue("created_by", post.UserID.ToString())
                    .InColumnValue("created_when", TenantUtil.DateTimeToUtc(post.Datetime))
                    .InColumnValue("blog_id", post.BlogId)
                    .Identity(1, 0, true);

                post.AutoIncrementID = Db.ExecuteScalar<int>(queryi);

                tx.Commit();
            }
        }

        public void DeletePost(Guid postId)
        {
            using (var tx = Db.BeginTransaction())
            {
                Db.ExecuteNonQuery(Delete("blogs_posts").Where("id", postId.ToString()));
                Db.ExecuteNonQuery(Delete("blogs_comments").Where("post_id", postId.ToString()));
                Db.ExecuteNonQuery(Delete("blogs_tags").Where("post_id", postId.ToString()));
                Db.ExecuteNonQuery(Delete("blogs_reviewposts").Where("post_id", postId.ToString()));

                tx.Commit();
            }
        }

        public List<Comment> GetComments(Guid postId)
        {
            var query = Query("blogs_comments")
                .Select("id", "post_id", "parent_id", "content", "created_by", "created_when", "inactive")
                .Where("post_id", postId.ToString())
                .OrderBy("created_when", true);

            return Db.ExecuteList<Comment>(query, RowMappers.ToComment);
        }

        public Comment GetCommentById(Guid commentId)
        {
            var select = Query("blogs_comments")
                .Select("id", "post_id", "parent_id", "content", "created_by", "created_when", "inactive")
                .Where("id", commentId.ToString());

            var list = Db.ExecuteList<Comment>(select, RowMappers.ToComment);
            return list.Count > 0 ? list[0] : null;
        }

        public void SaveComment(Comment comment)
        {
            var isInsert = (comment.ID == Guid.Empty);
            if (isInsert) comment.ID = Guid.NewGuid();

            var query = Insert("blogs_comments")
                .InColumns("id", "post_id", "parent_id", "content", "created_by", "created_when", "inactive")
                .Values(comment.ID, comment.PostId, comment.ParentId, comment.Content, comment.UserID.ToString(), TenantUtil.DateTimeToUtc(comment.Datetime), comment.Inactive ? 1 : 0);

            using (var tx = Db.BeginTransaction())
            {
                Db.ExecuteNonQuery(query);

                if (isInsert)
                {
                    var update = Update("blogs_posts")
                        .Set("LastCommentId", comment.ID.ToString())
                        .Where("id", comment.PostId.ToString());

                    Db.ExecuteNonQuery(update);
                }

                tx.Commit();
            }
        }

        public List<TagStat> GetTagStat(int? top)
        {
            var query = Query("blogs_tags")
                        .Select("name", "count(*) as cnt")
                        .OrderBy("cnt", false)
                        .GroupBy("name");

            if (top.HasValue) query.SetMaxResults(top.Value);

            var result = Db.ExecuteList(query, (r => new TagStat { Name = (string)r[0], Count = Convert.ToInt32(r[1]) }));

            return result;
        }

        public List<int> GetCommentsCount(List<Guid> postsIds)
        {
            var select = Query("blogs_comments")
                .Select("post_id", "count(*)")
                .Where(Exp.In("post_id", postsIds.ConvertAll(id => id.ToString())))
                .Where(Exp.Like("inactive", "0"))
                .GroupBy("post_id");

            var list = Db.ExecuteList(select);

            var result = new List<int>(postsIds.Count);
            for (var i = 0; i < postsIds.Count; i++)
            {
                var finded = list.Find(row => new Guid(row[0].ToString()) == postsIds[i]);
                result.Add(finded == null ? 0 : Convert.ToInt32(finded[1]));
            }
            return result;
        }

        public void SavePostReview(Guid userId, Guid postId, DateTime datetime)
        {
            var insert = Insert("blogs_reviewposts")
                .InColumns("post_id", "reviewed_by", "timestamp")
                .Values(postId.ToString(), userId.ToString(), TenantUtil.DateTimeToUtc(datetime));
            Db.ExecuteNonQuery(insert);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/IndexEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using ASC.Common.Logging;
using ASC.ElasticSearch;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Data.Search;

namespace ASC.Mail.Core.Engine
{
    public class IndexEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        private ILog Log { get; set; }

        public IndexEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.IndexEngine");
        }

        public bool IsIndexAvailable()
        {
            if (!FactoryIndexer<MailWrapper>.Support)
            {
                Log.Info("[SKIP INDEX] IsIndexAvailable->FactoryIndexer<MailWrapper>.Support == false");
                return false;
            }

            if (!FactoryIndexer.CheckState(false))
            {
                Log.Info("[SKIP INDEX] IsIndexAvailable->FactoryIndexer.CheckState(false) == false");
                return false;
            }

            return true;
        }

        public void Add<T>(T data) where T : Wrapper, new()
        {
            var typeParameterType = typeof(T);

            try
            {
                if (data == null)
                    throw new ArgumentNullException("data");

                if (!IsIndexAvailable())
                    return;

                FactoryIndexer<T>.Index(data);

                Log.InfoFormat("IndexEngine->Add<{0}>(mail Id = {1}) success", typeParameterType, data == null ? -1 : data.Id);
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("IndexEngine->Add<{0}>(mail Id = {1}) error: {2}", typeParameterType, data == null ? -1 : data.Id, ex.ToString());
            }
        }

        public void Update(List<MailWrapper> mails, UpdateAction action, Expression<Func<MailWrapper, IList>> fields)
        {
            try
            {
                if (mails == null || !mails.Any())
                    throw new ArgumentNullException("mails");

                if (!IsIndexAvailable())
                    return;

                mails.ForEach(x => FactoryIndexer<MailWrapper>.Update(x, action, fields));
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("IndexEngine->Update(count = {0}) error: {1}", mails == null ? 0 : mails.Count,
                    ex.ToString());
            }
        }

        public void Update(MailWrapper data, Expression<Func<Selector<MailWrapper>, Selector<MailWrapper>>> expression,
            UpdateAction action, Expression<Func<MailWrapper, IList>> fields)
        {
            try
            {
                if (data == null)
                    throw new ArgumentNullException("data");

                if (expression == null)
                    throw new ArgumentNullException("expression");

                if (!IsIndexAvailable())
                    return;

                FactoryIndexer<MailWrapper>.Update(data, expression, action, fields);
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("IndexEngine->Update() error: {0}", ex.ToString());
            }
        }

        public void Update(MailWrapper data, Expression<Func<Selector<MailWrapper>, Selector<MailWrapper>>> expression,
            params Expression<Func<MailWrapper, object>>[] fields)
        {
            try
            {
                if (data == null)
                    throw new ArgumentNullException("data");

                if (expression == null)
                    throw new ArgumentNullException("expression");

                if (!IsIndexAvailable())
                    return;

                FactoryIndexer<MailWrapper>.Update(data, expression, true, fields);
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("IndexEngine->Update() error: {0}", ex.ToString());
            }
        }

        public void Update<T>(List<T> list, params Expression<Func<T, object>>[] fields) where T : Wrapper, new()
        {
            try
            {
                if (list == null || !list.Any())
                    throw new ArgumentNullException("list");

                if (!IsIndexAvailable())
                    return;

                list.ForEach(x => FactoryIndexer<T>.Update(x, true, fields));
            }
            catch (Exception ex)
            {
                var typeParameterType = typeof(T);

                Log.ErrorFormat("IndexEngine->Update<{0}>(mail Id = {1}) error: {2}", typeParameterType, list == null ? 0 : list.Count, ex.ToString());
            }
        }

        public void Remove(List<int> ids, int tenant, Guid user)
        {
            try
            {
                if (ids == null || !ids.Any())
                    throw new ArgumentNullException("ids");

                if (!IsIndexAvailable())
                    return;

                ids.ForEach(id =>
                    FactoryIndexer<MailWrapper>.Delete(
                        r => new Selector<MailWrapper>()
                            .Where(m => m.Id, id)
                            .Where(e => e.UserId, user)
                            .Where(e => e.TenantId, tenant)));
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("IndexEngine->Remove(count = {0}) error: {1}", ids == null ? 0 : ids.Count, ex.ToString());
            }
        }

        public void Remove(MailBoxData mailBox)
        {
            try
            {
                if (mailBox == null)
                    throw new ArgumentNullException("mailBox");

                if (!IsIndexAvailable())
                    return;

                var selector = new Selector<MailWrapper>()
                    .Where(m => m.MailboxId, mailBox.MailBoxId)
                    .Where(e => e.UserId, new Guid(mailBox.UserId))
                    .Where(e => e.TenantId, mailBox.TenantId);

                FactoryIndexer<MailWrapper>.Delete(r => selector);
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("IndexEngine->Remove(mailboxId = {0}) error: {1}", mailBox == null ? -1 : mailBox.MailBoxId, ex.ToString());
            }
        }

        public void RemoveContacts(List<int> ids, int tenant, Guid user)
        {
            try
            {
                if (ids == null || !ids.Any())
                    throw new ArgumentNullException("ids");

                if (!IsIndexAvailable())
                    return;

                FactoryIndexer<MailContactWrapper>.Delete(
                    r => new Selector<MailContactWrapper>()
                        .In(s => s.Id, ids.ToArray())
                        .Where(e => e.User, user)
                        .Where(e => e.TenantId, tenant));
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("IndexEngine->RemoveContacts(count = {0}) error: {1}", ids == null ? 0 : ids.Count, ex.ToString());
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Classes/ReportTransformer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using ASC.Projects.Core.Domain.Reports;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Projects.Resources;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Projects.Classes
{
    static class ReportTransformer
    {
        public static string Transform(this Report report, IList<object[]> reportData, ReportViewType view, int templateID)
        {
            var xml = new StringBuilder();

            if (reportData.Count != 0)
            {
                xml = xml.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
                   .Append("<reportResult>");
                foreach (var row in reportData)
                {
                    xml.Append("<r ");
                    for (var i = 0; i < row.Length; i++)
                    {
                        xml.AppendFormat("c{0}=\"{1}\" ", i, ToString(row[i], view));
                    }
                    xml.Append("/>");
                }
                xml.Append("</reportResult>");
            }
            else
            {
                xml = xml.Append(string.Format("<div class='noContentBlock'>{0}</div>", ProjectsCommonResource.NoData));
            }

            return report.Transform(xml.ToString(), view, templateID);
        }

        public static string Transform(this Report report, string xml, ReportViewType view, int templateID)
        {
            if (view == ReportViewType.Xml)
            {
                return Encoding.UTF8.GetString(Encoding.Convert(Encoding.Unicode, Encoding.UTF8, Encoding.Unicode.GetBytes(xml)));
            }
            if (view == ReportViewType.EMail)
            {
                xml = report.Transform(xml, ReportViewType.Html, templateID);
            }

            var xslt = report.GetXslTransform(view);
            if (xslt == null) throw new InvalidOperationException("Xslt not found for type " + report.ReportType + " and view " + view);

            using (var reader = XmlReader.Create(new StringReader(xml)))
            using (var writer = new StringWriter())
            using (XmlWriter.Create(writer, new XmlWriterSettings { Encoding = Encoding.UTF8 }))
            {
                xslt.Transform(reader, GetXslParameters(report, view, templateID), writer);
                return writer.ToString();
            }
        }


        private static string ToString(object value, ReportViewType view)
        {
            if (value == null) return null;
            if (value is Enum) return ((Enum)value).ToString("d");
            if (value is DateTime) return ((DateTime)value).ToString("o");
            if (value is float) return ((float) value).ToString(CultureInfo.InvariantCulture);

            value = value.ToString()
                         .Replace("&", "&amp;")
                         .Replace("<", "&lt;")
                         .Replace(">", "&gt;")
                         .Replace("\"", "&quot;");
            if (view == ReportViewType.Csv && (value as string).Contains(","))
                value = string.Format("&quot;{0}&quot;", value);

            return value.ToString();
        }

        private static XslCompiledTransform GetXslTransform(this Report report, ReportViewType viewType)
        {
            var viewTypeStr = viewType.ToString().ToLower();
            return GetXslTransform(string.Format("{0}_{1}.{2}.xsl", report.ReportType, report.Filter.ViewType, viewTypeStr)) ??
                GetXslTransform(string.Format("{0}.{1}.xsl", report.ReportType, viewTypeStr)) ??
                GetXslTransform(string.Format("{0}.xsl", viewTypeStr));
        }

        public static XslCompiledTransform GetXslTransform(string fileName)
        {
            var transform = new XslCompiledTransform();
            var assembly = Assembly.GetExecutingAssembly();
            var path = Path.GetDirectoryName(assembly.Location);
            if ("bin".Equals(Path.GetFileName(path), StringComparison.InvariantCultureIgnoreCase) && File.Exists(fileName))
            {
                    transform.Load(fileName);
                    return transform;
            }

            using (var stream = assembly.GetManifestResourceStream("ASC.Web.Projects.templates." + fileName))
            {
                if (stream != null)
                {
                    using (var xmlReader = XmlReader.Create(stream))
                    {
                        transform.Load(xmlReader);
                        return transform;
                    }
                }
            }
            return null;
        }

        private static XsltArgumentList GetXslParameters(this Report report, ReportViewType view, int templateID)
        {
            var parameters = new XsltArgumentList();
            var columns = report.GetColumns(view, templateID);
            var logo = string.IsNullOrEmpty(SetupInfo.MainLogoMailTmplURL) ? CommonLinkUtility.GetFullAbsolutePath(TenantLogoManager.GetLogoDark(true)) : SetupInfo.MainLogoMailTmplURL;
            var logoText = TenantWhiteLabelSettings.Load().LogoText;

            for (var i = 0; i < columns.Count; i++)
            {
                parameters.AddParam("p" + i, string.Empty, columns[i]);
            }

            parameters.AddParam("p" + columns.Count, string.Empty, Global.ReportCsvDelimiter.Value);
            parameters.AddParam("logo", string.Empty, logo);
            parameters.AddParam("logoText", string.Empty, logoText);

            return parameters;
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Autoreply/Utility/StringExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Autoreply.Utility
{
    public static class StringExtensions
    {
        public static string TrimStart(this string str, string trimStr)
        {
            if (string.IsNullOrEmpty(str))
                return str;

            while (str.StartsWith(trimStr))
            {
                str = str.Remove(0, trimStr.Length);
            }

            return str;
        }

        public static string TrimEnd(this string str, string trimStr)
        {
            if (string.IsNullOrEmpty(str))
                return str;

            while (str.EndsWith(trimStr))
            {
                str = str.Remove(str.Length - trimStr.Length);
            }

            return str;
        }

        public static string Trim(this string str, string trimStr)
        {
            return str.TrimStart(trimStr).TrimEnd(trimStr);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/UserTopics.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using AjaxPro;

using ASC.Core;
using ASC.Core.Users;
using ASC.Forum;
using ASC.Web.Community.Modules.Forum.Resources;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio;
using ASC.Web.Studio.Controls.Common;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Forum;
using ASC.Web.UserControls.Forum.Common;

namespace ASC.Web.Community.Forum
{
    [AjaxNamespace("SearchResult")]
    public partial class UserTopics : MainPage
    {
        protected bool _isFind;
        private Guid _userID;

        protected void Page_Load(object sender, EventArgs e)
        {
            ForumManager.Instance.SetCurrentPage(ForumPage.Search);

            int currentPageNumber;
            if (!int.TryParse(Request["p"], out currentPageNumber))
                currentPageNumber = 1;

            if (currentPageNumber <= 0)
                currentPageNumber = 1;

            var findTopicList = new List<Topic>();
            var topicCount = 0;

            if (!String.IsNullOrEmpty(Request["uid"]))
            {
                try
                {
                    _userID = new Guid(Request["uid"]);
                }
                catch
                {
                    _userID = Guid.Empty;
                }

                if (_userID != Guid.Empty)
                {
                    findTopicList = ForumDataProvider.SearchTopicsByUser(TenantProvider.CurrentTenantID, _userID, currentPageNumber, ForumManager.Settings.TopicCountOnPage, out topicCount);
                }
            }

            if (findTopicList.Count > 0)
            {
                _isFind = true;

                var i = 0;
                foreach (var topic in findTopicList)
                {
                    var topicControl = (TopicControl)LoadControl(ForumManager.Settings.UserControlsVirtualPath + "/TopicControl.ascx");
                    topicControl.SettingsID = ForumManager.Settings.ID;
                    topicControl.Topic = topic;
                    topicControl.IsShowThreadName = true;
                    topicControl.IsEven = (i % 2 == 0);
                    topicListHolder.Controls.Add(topicControl);
                    i++;
                }

                #region navigators

                var pageNavigator = new PageNavigator
                {
                    CurrentPageNumber = currentPageNumber,
                    EntryCountOnPage = ForumManager.Settings.TopicCountOnPage,
                    VisiblePageCount = 5,
                    EntryCount = topicCount,
                    PageUrl = "usertopics.aspx?uid=" + _userID.ToString()
                };

                bottomPageNavigatorHolder.Controls.Add(pageNavigator);

                #endregion
            }
            else
            {
                var emptyScreenControl = new EmptyScreenControl
                {
                    ImgSrc = WebImageSupplier.GetAbsoluteWebPath("forums_icon.png", ForumManager.Settings.ModuleID),
                    Header = ForumResource.EmptyScreenSearchCaption,
                    Describe = ForumResource.EmptyScreenSearchText,
                };

                topicListHolder.Controls.Add(emptyScreenControl);
            }

            //bread crumbs
            (Master as ForumMasterPage).CurrentPageCaption = CoreContext.UserManager.GetUsers(_userID).DisplayUserName(false);

            Title = HeaderStringHelper.GetPageTitle((Master as ForumMasterPage).CurrentPageCaption);
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/ProjectApi.Comments.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.Exceptions;
using ASC.Api.Projects.Wrappers;
using ASC.Api.Utils;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Core.Users;
using ASC.Web.Studio.UserControls.Common.Comments;
using ASC.Web.Studio.Utility.HtmlUtility;

namespace ASC.Api.Projects
{
    public partial class ProjectApi
    {
        #region comments

        ///<summary>
        ///Returns the information about the comment with the ID specified in the request
        ///</summary>
        ///<short>
        ///Get comment
        ///</short>
        ///<category>Comments</category>
        ///<param name="commentid">Comment ID</param>
        ///<returns>Comment</returns>        
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"comment/{commentid}")]
        public CommentWrapper GetComment(Guid commentid)
        {
            var comment = EngineFactory.CommentEngine.GetByID(commentid).NotFoundIfNull();
            var entity = EngineFactory.CommentEngine.GetEntityByTargetUniqId(comment).NotFoundIfNull();

            return new CommentWrapper(this, comment, entity);
        }

        /////<summary>
        /////Updates the seleted comment using the comment text specified in the request
        /////</summary>
        /////<short>
        /////Update comment
        /////</short>
        /////<category>Comments</category>
        /////<param name="commentid">comment ID</param>
        /////<param name="content">comment text</param>
        /////<returns>Comment</returns>
        /////<exception cref="ItemNotFoundException"></exception>
        /////<example>
        /////<![CDATA[
        /////Sending data in application/json:
        /////
        /////{
        /////    text:"My comment text",
        /////    
        /////}
        /////
        /////Sending data in application/x-www-form-urlencoded
        /////content=My%20comment%20text
        /////]]>
        /////</example>
        //[Update(@"comment/{commentid}")]
        //public CommentWrapper UpdateComments(Guid commentid, string content)
        //{
        //    var comment = EngineFactory.CommentEngine.GetByID(commentid).NotFoundIfNull();
        //    comment.Content = Update.IfNotEquals(comment.Content, content);

        //    string type;
        //    comment = SaveComment(comment, out type);

        //    return new CommentWrapper(comment);
        //}

        ///<summary>
        ///Get preview
        ///</summary>
        ///<short>
        ///Get preview
        ///</short>
        ///<category>Comments</category>
        ///<param name="htmltext">html to create preview</param>
        ///<param name="commentid">guid of editing comment or empty string if comment is new</param>
        [Create(@"comment/preview")]
        public CommentInfo GetProjectCommentPreview(string htmltext, string commentid)
        {
            ProjectSecurity.DemandAuthentication();

            var commentEngine = EngineFactory.CommentEngine;

            Comment comment;
            if (!string.IsNullOrEmpty(commentid))
            {
                comment = commentEngine.GetByID(new Guid(commentid));
                comment.Content = htmltext;
            }
            else
            {
                comment = new Comment
                {
                    Content = htmltext,
                    CreateOn = TenantUtil.DateTimeNow(),
                    CreateBy = SecurityContext.CurrentAccount.ID
                };
            }

            var creator = EngineFactory.ParticipantEngine.GetByID(comment.CreateBy).UserInfo;
            var info = new CommentInfo
            {
                CommentID = comment.OldGuidId.ToString(),
                UserID = comment.CreateBy,
                TimeStamp = comment.CreateOn,
                TimeStampStr = comment.CreateOn.Ago(),
                UserPost = creator.Title,
                Inactive = comment.Inactive,
                CommentBody = HtmlUtility.GetFull(comment.Content),
                UserFullName = DisplayUserSettings.GetFullUserName(creator),
                UserProfileLink = creator.GetUserProfilePageURL(),
                UserAvatarPath = creator.GetBigPhotoURL()
            };

            return info;
        }

        ///<summary>
        ///Remove comment with the id specified in the request
        ///</summary>
        ///<short>Remove comment</short>
        ///<section>Comments</section>
        ///<param name="commentid">Comment ID</param>
        ///<returns>Comment id</returns>
        ///<category>Comments</category>
        [Delete("comment/{commentid}")]
        public string RemoveProjectComment(string commentid)
        {
            var commentEngine = EngineFactory.CommentEngine;

            var comment = commentEngine.GetByID(new Guid(commentid)).NotFoundIfNull();
            comment.Inactive = true;

            var entity = commentEngine.GetEntityByTargetUniqId(comment);
            if (entity == null) return "";

            ProjectSecurity.DemandEditComment(entity.Project, comment);

            commentEngine.SaveOrUpdate(comment);
            MessageService.Send(Request, MessageAction.TaskCommentDeleted, MessageTarget.Create(comment.ID), entity.Project.Title, entity.Title);

            return commentid;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parentcommentid"></param>
        /// <param name="entityid"></param>
        /// <param name="content"></param>
        /// <param name="type"></param>
        /// <category>Comments</category>
        /// <returns></returns>
        [Create("comment")]
        public CommentInfo AddProjectComment(string parentcommentid, int entityid, string content, string type)
        {
            if (string.IsNullOrEmpty(type) || !(new List<string> { "message", "task" }).Contains(type.ToLower()))
                throw new ArgumentException();

            var isMessageComment = type.ToLower().Equals("message");
            var comment = isMessageComment
                ? new Comment { Content = content, TargetUniqID = ProjectEntity.BuildUniqId<Message>(entityid) }
                : new Comment { Content = content, TargetUniqID = ProjectEntity.BuildUniqId<Task>(entityid) };


            if (!string.IsNullOrEmpty(parentcommentid))
                comment.Parent = new Guid(parentcommentid);

            var commentEngine = EngineFactory.CommentEngine;
            var entity = commentEngine.GetEntityByTargetUniqId(comment).NotFoundIfNull();

            comment = commentEngine.SaveOrUpdateComment(entity, comment);

            MessageService.Send(Request, isMessageComment ? MessageAction.DiscussionCommentCreated : MessageAction.TaskCommentCreated, MessageTarget.Create(comment.ID), entity.Project.Title, entity.Title);

            return GetCommentInfo(null, comment, entity);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="commentid"></param>
        /// <param name="content"></param>
        ///<category>Comments</category>
        /// <returns></returns>
        [Update("comment/{commentid}")]
        public string UpdateComment(string commentid, string content)
        {
            var commentEngine = EngineFactory.CommentEngine;
            var comment = commentEngine.GetByID(new Guid(commentid));
            comment.Content = content;

            var entity = commentEngine.GetEntityByTargetUniqId(comment);
            if (entity == null) throw new Exception("Access denied.");

            commentEngine.SaveOrUpdateComment(entity, comment);

            MessageService.Send(Request, MessageAction.TaskCommentUpdated, MessageTarget.Create(comment.ID), entity.Project.Title, entity.Title);

            return HtmlUtility.GetFull(content);
        }

        internal CommentInfo GetCommentInfo(IEnumerable<Comment> allComments, Comment comment, ProjectEntity entity)
        {
            var creator = EngineFactory.ParticipantEngine.GetByID(comment.CreateBy).UserInfo;
            var oCommentInfo = new CommentInfo
            {
                TimeStamp = comment.CreateOn,
                TimeStampStr = comment.CreateOn.Ago(),
                CommentBody = HtmlUtility.GetFull(comment.Content),
                CommentID = comment.OldGuidId.ToString(),
                UserID = comment.CreateBy,
                UserFullName = creator.DisplayUserName(),
                UserProfileLink = creator.GetUserProfilePageURL(),
                Inactive = comment.Inactive,
                IsEditPermissions = ProjectSecurity.CanEditComment(entity, comment),
                IsResponsePermissions = ProjectSecurity.CanCreateComment(entity),
                IsRead = true,
                UserAvatarPath = creator.GetBigPhotoURL(),
                UserPost = creator.Title,
                CommentList = new List<CommentInfo>()
            };

            if (allComments != null)
                foreach (var com in allComments.Where(com => com.Parent == comment.OldGuidId))
                {
                    oCommentInfo.CommentList.Add(GetCommentInfo(allComments, com, entity));
                }

            return oCommentInfo;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Security/PersonalBlogSecObject.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Blogs.Core.Domain;
using ASC.Common.Security;
using ASC.Common.Security.Authorizing;
using ASC.Core.Users;

namespace ASC.Blogs.Core.Security
{
    public class PersonalBlogSecObject : SecurityObjectId, ISecurityObject
    {
        private readonly UserInfo blogOwner;

        public PersonalBlogSecObject()
            : base((int)BlogType.Personal, typeof(BlogType))
        {

        }

        public PersonalBlogSecObject(UserInfo blogOwner)
            : this()
        {

            this.blogOwner = blogOwner;
        }

        public override string ToString()
        {
            return "personal blog";
        }

        #region ISecurityObjectProvider Members

        public bool InheritSupported
        {
            get { return false; }
        }

        public bool ObjectRolesSupported
        {
            get { return blogOwner != null; }
        }

        public ISecurityObjectId InheritFrom(ISecurityObjectId objectId)
        {
            throw new NotImplementedException();
        }

        public IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext)
        {
            var roles = new List<IRole>();
            if (blogOwner != null && blogOwner.ID.Equals(account.ID))
            {
                roles.Add(ASC.Common.Security.Authorizing.Constants.Owner);
            }
            return roles;
        }

        #endregion
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/DNS/Client/DNS_rr_MX.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Dns.Client
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// MX record class.
    /// </summary>
    [Serializable]
    public class DNS_rr_MX : DNS_rr_base, IComparable
    {
        #region Members

        private readonly string m_Host = "";
        private readonly int m_Preference;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="preference">MX record preference.</param>
        /// <param name="host">Mail host dns name.</param>
        /// <param name="ttl">TTL value.</param>
        public DNS_rr_MX(int preference, string host, int ttl) : base(QTYPE.MX, ttl)
        {
            m_Preference = preference;
            m_Host = host;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets mail host dns name.
        /// </summary>
        public string Host
        {
            get { return m_Host; }
        }

        /// <summary>
        /// Gets MX record preference. The lower number is the higher priority server.
        /// </summary>
        public int Preference
        {
            get { return m_Preference; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses resource record from reply data.
        /// </summary>
        /// <param name="reply">DNS server reply data.</param>
        /// <param name="offset">Current offset in reply data.</param>
        /// <param name="rdLength">Resource record data length.</param>
        /// <param name="ttl">Time to live in seconds.</param>
        public static DNS_rr_MX Parse(byte[] reply, ref int offset, int rdLength, int ttl)
        {
            /* RFC 1035	3.3.9. MX RDATA format

			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                  PREFERENCE                   |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			/                   EXCHANGE                    /
			/                                               /
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

			where:

			PREFERENCE      
				A 16 bit integer which specifies the preference given to
				this RR among others at the same owner.  Lower values
                are preferred.

			EXCHANGE 
			    A <domain-name> which specifies a host willing to act as
                a mail exchange for the owner name. 
			*/

            int pref = reply[offset++] << 8 | reply[offset++];

            string name = "";
            if (Dns_Client.GetQName(reply, ref offset, ref name))
            {
                return new DNS_rr_MX(pref, name, ttl);
            }
            else
            {
                throw new ArgumentException("Invalid MX resource record data !");
            }
        }

        /// <summary>
        /// Compares the current instance with another object of the same type. 
        /// </summary>
        /// <param name="obj">An object to compare with this instance. </param>
        /// <returns>Returns 0 if two objects are equal, returns negative value if this object is less,
        /// returns positive value if this object is grater.</returns>
        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            if (!(obj is DNS_rr_MX))
            {
                throw new ArgumentException("Argument obj is not MX_Record !");
            }

            DNS_rr_MX mx = (DNS_rr_MX) obj;
            if (Preference > mx.Preference)
            {
                return 1;
            }
            else if (Preference < mx.Preference)
            {
                return -1;
            }
            else
            {
                return 0;
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/ThirdParty/Login.Master.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

namespace ASC.Web.Studio.ThirdParty
{
    public partial class Login : MasterPage
    {
        private const string CallbackSuccessJavascript =
            "function snd(){{try{{window.opener.OAuthCallback(\"{0}\");}}catch(err){{alert(err);}}window.close();}} window.onload = snd;";

        private const string CallbackErrorJavascript =
            "function snd(){{try{{window.opener.OAuthError(\"{0}\");}}catch(err){{alert(err);}}window.close();}} window.onload = snd;";

        protected override void OnInit(EventArgs e)
        {
            HttpContext.Current.PushRewritenUri();
            base.OnInit(e);
        }

        public void SubmitCode(string code)
        {
            var urlRedirect = Request["redirect"];
            if (!string.IsNullOrEmpty(urlRedirect))
            {
                Response.Redirect(AppendCode(urlRedirect, code), true);
            }

            Page.ClientScript.RegisterClientScriptBlock(GetType(), "posttoparent",
                                                        String.Format(CallbackSuccessJavascript, code.Replace("\"", "\\\"")), true);
        }

        public void SubmitError(string error)
        {
            var urlRedirect = Request["redirect"];
            if (!string.IsNullOrEmpty(urlRedirect))
            {
                Response.Redirect(AppendCode(urlRedirect, null, error), true);
            }

            Page.ClientScript.RegisterClientScriptBlock(GetType(), "posterrortoparent",
                                                        String.Format(CallbackErrorJavascript, error.Replace("\"", "\\\"")), true);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
        }

        private static string AppendCode(string url, string code = null, string error = null)
        {
            url += (url.Contains("#") ? "&" : "#")
                   + (string.IsNullOrEmpty(error)
                          ? (string.IsNullOrEmpty(code)
                                 ? string.Empty
                                 : "code=" + HttpUtility.UrlEncode(code))
                          : ("error/" + HttpUtility.UrlEncode(error)));

            return url;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Expressions/Attachment/ConcreteMessageAttachmentsExp.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao.Expressions.Attachment
{
    public class ConcreteMessageAttachmentsExp : UserAttachmentsExp
    {
        private readonly int _mailId;
        private readonly List<int> _attachIds;
        private readonly bool? _onlyEmbedded;

        public ConcreteMessageAttachmentsExp(int mailId, int tenant, string user, List<int> attachIds = null,
            bool? isRemoved = false, bool? onlyEmbedded = false)
            : base(tenant, user, isRemoved)
        {
            _mailId = mailId;
            _attachIds = attachIds;
            _onlyEmbedded = onlyEmbedded;
        }

        public override Exp GetExpression()
        {
            var exp = base.GetExpression();

            exp = exp & Exp.Eq(AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME), _mailId);

            if (_attachIds != null && _attachIds.Any())
            {
                exp = exp & Exp.In(AttachmentTable.Columns.Id.Prefix(AttachmentTable.TABLE_NAME), _attachIds);
            }

            if (!_onlyEmbedded.HasValue)
                return exp;

            if (_onlyEmbedded.Value)
            {
                exp = exp &
                      !Exp.Eq(AttachmentTable.Columns.ContentId.Prefix(AttachmentTable.TABLE_NAME),
                          null);
            }
            else
            {
                exp = exp &
                      Exp.Eq(AttachmentTable.Columns.ContentId.Prefix(AttachmentTable.TABLE_NAME),
                          null);
            }

            return exp;
        }
    }
}

<|start_filename|>common/ASC.Common/Notify/Messages/NoticeMessage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Notify.Model;
using ASC.Notify.Patterns;
using ASC.Notify.Recipients;

namespace ASC.Notify.Messages
{
    [Serializable]
    public class NoticeMessage : INoticeMessage
    {
        [NonSerialized]
        private readonly List<ITagValue> arguments = new List<ITagValue>();

        [NonSerialized]
        private IPattern pattern;

        public NoticeMessage()
        {
        }

        public NoticeMessage(IDirectRecipient recipient, INotifyAction action, string objectID)
        {
            if (recipient == null) throw new ArgumentNullException("recipient");
            Recipient = recipient;
            Action = action;
            ObjectID = objectID;
        }

        public NoticeMessage(IDirectRecipient recipient, INotifyAction action, string objectID, IPattern pattern)
        {
            if (recipient == null) throw new ArgumentNullException("recipient");
            if (pattern == null) throw new ArgumentNullException("pattern");
            Recipient = recipient;
            Action = action;
            Pattern = pattern;
            ObjectID = objectID;
            ContentType = pattern.ContentType;
        }

        public NoticeMessage(IDirectRecipient recipient, string subject, string body, string contentType)
        {
            if (recipient == null) throw new ArgumentNullException("recipient");
            if (body == null) throw new ArgumentNullException("body");
            Recipient = recipient;
            Subject = subject;
            Body = body;
            ContentType = contentType;
        }

        public string ObjectID { get; private set; }

        public IDirectRecipient Recipient { get; private set; }

        public IPattern Pattern
        {
            get { return pattern; }
            internal set { pattern = value; }
        }

        public INotifyAction Action { get; private set; }

        public ITagValue[] Arguments
        {
            get { return arguments.ToArray(); }
        }

        public void AddArgument(params ITagValue[] tagValues)
        {
            if (tagValues == null) throw new ArgumentNullException("tagValues");
            Array.ForEach(tagValues,
                tagValue =>
                {
                    if (!arguments.Exists(tv => Equals(tv.Tag, tagValue.Tag)))
                    {
                        arguments.Add(tagValue);
                    }
                });
        }

        public ITagValue GetArgument(string tag)
        {
            return arguments.Find(r => r.Tag == tag);
        }

        public string Subject { get; set; }

        public string Body { get; set; }

        public string ContentType { get; internal set; }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/skins/default/layout-media.css<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


@media (min-width: 1200px) {
    body {
        overflow: hidden;
    }

    .studio-container {
        height: 100vh;
        height: calc(var(--vh, 1vh) * 100);
    }

    nav {
        height: calc(100vh - 98px);
        height: calc(var(--vh, 1vh) * 100 - 98px);
        display: grid;
    }

    nav.with-chat {
        height: calc(100vh - 112px);
        height: calc(var(--vh, 1vh) * 100 - 112px);
    }

    main {
        height: calc(100vh - 74px);
        height: calc(var(--vh, 1vh) * 100 - 74px);
        display: grid;
    }

    aside {
        height: calc(100vh - 74px);
        height: calc(var(--vh, 1vh) * 100 - 74px);
    }

    .nav-content {
        overflow: hidden;
    }

    .nav-content.webkit-scrollbar::-webkit-scrollbar-track { background: transparent; }

    .nav-content:hover {
        overflow-y: scroll;
        margin-right: -16px;
        scrollbar-width: thin;
        scrollbar-color: #BFBFBF transparent;
    }

    .nav-content #treeViewContainer {
        overflow: hidden;
    }

    .page-content {
        padding-right: 8px;
        margin-right: -24px;
        overflow-y: scroll;
        overflow-x: auto;
        scrollbar-width: thin;
        scrollbar-color: #BFBFBF transparent;
    }

    .page-content.webkit-scrollbar::-webkit-scrollbar-track { background: transparent; }

    @-moz-document url-prefix() {
        .nav-content:hover {
            margin-right: -16px;
            padding-right: 8px;
        }
        .page-content {
            margin-right: -16px;
            padding-right: 8px;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/Monitoring/PortsChecker.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    [ManagementControl(ManagementType.Monitoring, Location)]
    [AjaxNamespace("PortsCheckerAjax")]
    public partial class PortsChecker : UserControl
    {
        public const string Location = "~/UserControls/Management/Monitoring/PortsChecker.ascx";

        protected static readonly List<Port> Ports = new List<Port>
            {
                new Port {Name = "HTTP", Number = 80, AllowClosedForIncomingRequests = false},
                new Port {Name = "HTTPS", Number = 443, AllowClosedForIncomingRequests = false},
                new Port {Name = "SMTP", Number = 25},
                new Port {Name = "SMTPS", Number = 465},
                new Port {Name = "IMAP", Number = 143},
                new Port {Name = "IMAPS", Number = 993},
                new Port {Name = "POP3", Number = 110},
                new Port {Name = "POP3S", Number = 995}
            };

        protected string HelpLink { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            AjaxPro.Utility.RegisterTypeForAjax(GetType(), Page);
            Page.RegisterBodyScripts("~/UserControls/Management/Monitoring/js/portschecker.js")
                .RegisterStyle("~/UserControls/Management/Monitoring/css/monitoring.less");

            HelpLink = CommonLinkUtility.GetHelpLink();
        }

        [AjaxMethod]
        public List<object> GetPortStatusList()
        {
            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
            return Ports
                .Select(port =>
                    {
                        PortStatus status = GetPortStatus(port);
                        return new { name = port.Name, number = port.Number, status = status, statusDescription = GetStatusDescription(status) };
                    })
                .Cast<object>()
                .ToList();
        }

        private PortStatus GetPortStatus(Port port)
        {
            if (!port.AllowClosedForOutgoingRequests && IsClosedForOutgoingRequests(port.Number))
                return PortStatus.Closed;

            if (!port.AllowClosedForIncomingRequests && IsClosedForIncomingRequests(port.Number))
                return PortStatus.Closed;

            return PortStatus.Open;
        }

        private bool IsClosedForOutgoingRequests(int portNumber)
        {
            return !TryConnect("portquiz.net", portNumber);
        }

        private bool IsClosedForIncomingRequests(int portNumber)
        {
            return !TryConnect(CoreContext.TenantManager.GetCurrentTenant().TenantDomain, portNumber);
        }

        private bool TryConnect(string host, int port)
        {
            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socket.Connect(host, port);
                return socket.Connected;
            }
            catch
            {
                return false;
            }
            finally
            {
                socket.Close();
            }
        }

        protected string GetStatusDescription(PortStatus status)
        {
            return MonitoringResource.ResourceManager.GetString("PortStatus" + status) ?? status.ToString();
        }

        protected enum PortStatus
        {
            Open,
            Closed
        }

        protected class Port
        {
            public string Name { get; set; }
            public int Number { get; set; }
            public bool AllowClosedForIncomingRequests { get; set; }
            public bool AllowClosedForOutgoingRequests { get; set; }

            public Port()
            {
                AllowClosedForIncomingRequests = true;
                AllowClosedForOutgoingRequests = false;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Resources/CRMVoipResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.CRM.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class CRMVoipResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal CRMVoipResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.CRM.Resources.CRMVoipResource", typeof(CRMVoipResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add operator.
        /// </summary>
        public static string AddOperatorBtn {
            get {
                return ResourceManager.GetString("AddOperatorBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add operators.
        /// </summary>
        public static string AddOperatorsBtn {
            get {
                return ResourceManager.GetString("AddOperatorsBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add ringtone.
        /// </summary>
        public static string AddRingtoneBtn {
            get {
                return ResourceManager.GetString("AddRingtoneBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Alias.
        /// </summary>
        public static string Alias {
            get {
                return ResourceManager.GetString("Alias", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Alias{1} helps identify the number with some word or phrase (e.g. support, sales, etc.). It will be visible in the virtual number list..
        /// </summary>
        public static string AliasDscrMsg {
            get {
                return ResourceManager.GetString("AliasDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter a name for the number.
        /// </summary>
        public static string AliasPlaceholder {
            get {
                return ResourceManager.GetString("AliasPlaceholder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Buy phone number.
        /// </summary>
        public static string BuyNumberBtn {
            get {
                return ResourceManager.GetString("BuyNumberBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Number purchase.
        /// </summary>
        public static string BuyNumberHeader {
            get {
                return ResourceManager.GetString("BuyNumberHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Call.
        /// </summary>
        public static string Call {
            get {
                return ResourceManager.GetString("Call", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Agent.
        /// </summary>
        public static string CallAgent {
            get {
                return ResourceManager.GetString("CallAgent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Client.
        /// </summary>
        public static string CallClient {
            get {
                return ResourceManager.GetString("CallClient", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cost.
        /// </summary>
        public static string CallCost {
            get {
                return ResourceManager.GetString("CallCost", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Date/Time.
        /// </summary>
        public static string CallDatetime {
            get {
                return ResourceManager.GetString("CallDatetime", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Duration.
        /// </summary>
        public static string CallDuration {
            get {
                return ResourceManager.GetString("CallDuration", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Type.
        /// </summary>
        public static string CallType {
            get {
                return ResourceManager.GetString("CallType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Waiting Time.
        /// </summary>
        public static string CallWaitingTime {
            get {
                return ResourceManager.GetString("CallWaitingTime", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cancel.
        /// </summary>
        public static string CancelBtn {
            get {
                return ResourceManager.GetString("CancelBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string DeleteBtn {
            get {
                return ResourceManager.GetString("DeleteBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The number will be saved to Twilio, but will be unavailable for the current portal.
        /// </summary>
        public static string DeleteNumberBody {
            get {
                return ResourceManager.GetString("DeleteNumberBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete number.
        /// </summary>
        public static string DeleteNumberBtn {
            get {
                return ResourceManager.GetString("DeleteNumberBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete number.
        /// </summary>
        public static string DeleteNumberHeader {
            get {
                return ResourceManager.GetString("DeleteNumberHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete rigntone.
        /// </summary>
        public static string DeleteRingtoneBtn {
            get {
                return ResourceManager.GetString("DeleteRingtoneBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string EditBtn {
            get {
                return ResourceManager.GetString("EditBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Buy a new IP phone number to add it to the ONLYOFFICE portal. Once added you can use this phone number with portal CRM..
        /// </summary>
        public static string EmptyScreenNumberDescription1 {
            get {
                return ResourceManager.GetString("EmptyScreenNumberDescription1", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Note: the phone numbers you already have at Twilio website cannot be transferred to the portal..
        /// </summary>
        public static string EmptyScreenNumberDescription2 {
            get {
                return ResourceManager.GetString("EmptyScreenNumberDescription2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No IP telephony numbers have been added yet.
        /// </summary>
        public static string EmptyScreenNumberHeader {
            get {
                return ResourceManager.GetString("EmptyScreenNumberHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to General settings.
        /// </summary>
        public static string GeneralSettings {
            get {
                return ResourceManager.GetString("GeneralSettings", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Greeting ringtones.
        /// </summary>
        public static string GreetingRingtones {
            get {
                return ResourceManager.GetString("GreetingRingtones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Incoming call queue{1} shows the number of the incoming calls assigned to the currently available operators. If the number of incoming calls exceed the queue, they will be redirected to the voice mail service..
        /// </summary>
        public static string IncomingCallsQueueDscrMsg {
            get {
                return ResourceManager.GetString("IncomingCallsQueueDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incoming call queue length.
        /// </summary>
        public static string IncomingCallsQueueSize {
            get {
                return ResourceManager.GetString("IncomingCallsQueueSize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Once linked, all the calls will be processed by the current portal..
        /// </summary>
        public static string LinkNumberBody {
            get {
                return ResourceManager.GetString("LinkNumberBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Link purchased number.
        /// </summary>
        public static string LinkNumberBtn {
            get {
                return ResourceManager.GetString("LinkNumberBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Number linking.
        /// </summary>
        public static string LinkNumberHeader {
            get {
                return ResourceManager.GetString("LinkNumberHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The number is successfully linked.
        /// </summary>
        public static string LinkNumberSuccessMsg {
            get {
                return ResourceManager.GetString("LinkNumberSuccessMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The upload is in progress, please wait.
        /// </summary>
        public static string LoadingMsg {
            get {
                return ResourceManager.GetString("LoadingMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No available numbers unfortunately, please try again later..
        /// </summary>
        public static string NoAvailableNumbersMsg {
            get {
                return ResourceManager.GetString("NoAvailableNumbersMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You do not have any numbers so far..
        /// </summary>
        public static string NoExistingNumbersMsg {
            get {
                return ResourceManager.GetString("NoExistingNumbersMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You do not have any numbers. They can be purchased {0}here{1}..
        /// </summary>
        public static string NoNumbersMsg {
            get {
                return ResourceManager.GetString("NoNumbersMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such numbers could be found.
        /// </summary>
        public static string NoSearchingNumbersMsg {
            get {
                return ResourceManager.GetString("NoSearchingNumbersMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Number operators.
        /// </summary>
        public static string NumberOperators {
            get {
                return ResourceManager.GetString("NumberOperators", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can set them {0}here{1}..
        /// </summary>
        public static string NumbersCountDscrMsg {
            get {
                return ResourceManager.GetString("NumbersCountDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Numbers you currently have.
        /// </summary>
        public static string NumbersCountMsg {
            get {
                return ResourceManager.GetString("NumbersCountMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Operator.
        /// </summary>
        public static string Operator {
            get {
                return ResourceManager.GetString("Operator", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Operator pause.
        /// </summary>
        public static string OperatorPause {
            get {
                return ResourceManager.GetString("OperatorPause", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Disabled.
        /// </summary>
        public static string OperatorPauseDisabled {
            get {
                return ResourceManager.GetString("OperatorPauseDisabled", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Operator pause{1} allows the operator have some time before accepting calls again. This can be used to take some notes on the previous call, etc..
        /// </summary>
        public static string OperatorPauseDscrMsg {
            get {
                return ResourceManager.GetString("OperatorPauseDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enabled.
        /// </summary>
        public static string OperatorPauseEnabled {
            get {
                return ResourceManager.GetString("OperatorPauseEnabled", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Outgoing calls.
        /// </summary>
        public static string OutgoingCalls {
            get {
                return ResourceManager.GetString("OutgoingCalls", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Queue ringtones.
        /// </summary>
        public static string QueueRingtones {
            get {
                return ResourceManager.GetString("QueueRingtones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Quick setup.
        /// </summary>
        public static string QuickTuning {
            get {
                return ResourceManager.GetString("QuickTuning", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Quick setup{1} is used to quickly enable or disable the outgoing calls, call recording for the number as well as set up working hours when the number will be available to the clients..
        /// </summary>
        public static string QuickTuningDscrMsg {
            get {
                return ResourceManager.GetString("QuickTuningDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Call recording.
        /// </summary>
        public static string RecordingCalls {
            get {
                return ResourceManager.GetString("RecordingCalls", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The conversation recordings are saved in the WAV format. Your browser does not support audio file playback with this format, i.e. you will not be able to listen to these recordings..
        /// </summary>
        public static string RecordingsCallsPlayNotSupportedMsg {
            get {
                return ResourceManager.GetString("RecordingsCallsPlayNotSupportedMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The list of the browsers which support this function can be found {0}here{1}.
        /// </summary>
        public static string RecordingsCallsPlayNotSupportedTipMsg {
            get {
                return ResourceManager.GetString("RecordingsCallsPlayNotSupportedTipMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ringtone list.
        /// </summary>
        public static string RingtonesList {
            get {
                return ResourceManager.GetString("RingtonesList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ringtone setup.
        /// </summary>
        public static string RingtonesTuning {
            get {
                return ResourceManager.GetString("RingtonesTuning", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Ringtone setup{1} is used to view and edit the ringtones currently assigned to various phone operations..
        /// </summary>
        public static string RingtonesTuningDscrMsg {
            get {
                return ResourceManager.GetString("RingtonesTuningDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Uploaded ringtone recommendations{1}: The file size must not exceed 5 MB. Supported formats: MP3..
        /// </summary>
        public static string RingtonesUploadingRecomendationsMsg {
            get {
                return ResourceManager.GetString("RingtonesUploadingRecomendationsMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Search.
        /// </summary>
        public static string SearchLabel {
            get {
                return ResourceManager.GetString("SearchLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Number setup.
        /// </summary>
        public static string TuningNumber {
            get {
                return ResourceManager.GetString("TuningNumber", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not specified.
        /// </summary>
        public static string UnspecifiedOption {
            get {
                return ResourceManager.GetString("UnspecifiedOption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Update settings.
        /// </summary>
        public static string UpdateSettingsBtn {
            get {
                return ResourceManager.GetString("UpdateSettingsBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Virtual numbers.
        /// </summary>
        public static string VirtualNumbers {
            get {
                return ResourceManager.GetString("VirtualNumbers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Virtual numbers and operators.
        /// </summary>
        public static string VirtualNumbersAndOperators {
            get {
                return ResourceManager.GetString("VirtualNumbersAndOperators", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Virtual numbers{1} are used to communicate with your CRM clients with the help of VoIP phones provided by Twilio..
        /// </summary>
        public static string VirtualNumbersDscrMsg {
            get {
                return ResourceManager.GetString("VirtualNumbersDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Voice mail.
        /// </summary>
        public static string Voicemail {
            get {
                return ResourceManager.GetString("Voicemail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Voice mail ringtones.
        /// </summary>
        public static string VoicemailRingtones {
            get {
                return ResourceManager.GetString("VoicemailRingtones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to VoIP.
        /// </summary>
        public static string VoipModuleDescription {
            get {
                return ResourceManager.GetString("VoipModuleDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to VoIP.
        /// </summary>
        public static string VoipModuleTitle {
            get {
                return ResourceManager.GetString("VoipModuleTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Waiting ringtones.
        /// </summary>
        public static string WaitingRingtones {
            get {
                return ResourceManager.GetString("WaitingRingtones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Waiting timeout.
        /// </summary>
        public static string WaitingTimeout {
            get {
                return ResourceManager.GetString("WaitingTimeout", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 10 minutes.
        /// </summary>
        public static string WaitingTimeout10Minutes {
            get {
                return ResourceManager.GetString("WaitingTimeout10Minutes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 15 minutes.
        /// </summary>
        public static string WaitingTimeout15Minutes {
            get {
                return ResourceManager.GetString("WaitingTimeout15Minutes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 5 minutes.
        /// </summary>
        public static string WaitingTimeout5Minutes {
            get {
                return ResourceManager.GetString("WaitingTimeout5Minutes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Waiting timeout{1} shows the time during which the customer will wait for the operator answer. When this time is exceeded, the call will be redirected to the voice mail service..
        /// </summary>
        public static string WaitingTimeoutDscrMsg {
            get {
                return ResourceManager.GetString("WaitingTimeoutDscrMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Working hours.
        /// </summary>
        public static string WorkingHours {
            get {
                return ResourceManager.GetString("WorkingHours", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect interval.
        /// </summary>
        public static string WorkingHoursFormatErrorMsg {
            get {
                return ResourceManager.GetString("WorkingHoursFormatErrorMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the time in the ##:## format.
        /// </summary>
        public static string WorkingHoursFormatTip {
            get {
                return ResourceManager.GetString("WorkingHoursFormatTip", resourceCulture);
            }
        }
    }
}


<|start_filename|>module/ASC.Feed/FeedMin.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Core.Users;

namespace ASC.Feed
{
    public class FeedMinUser
    {
        public UserInfo UserInfo { get; set; }
    }

    public class FeedMin
    {
        public string Id { get; set; }

        public Guid AuthorId { get; set; }

        public FeedMinUser Author { get; set; }

        public DateTime CreatedDate { get; set; }

        public DateTime ModifiedDate { get; set; }

        public string Product { get; set; }

        public string Item { get; set; }

        public string Title { get; set; }

        public string ItemUrl { get; set; }

        public string Description { get; set; }

        public string AdditionalInfo { get; set; }

        public string AdditionalInfo2 { get; set; }

        public string Module { get; set; }

        public string ExtraLocation { get; set; }

        public IEnumerable<FeedComment> Comments { get; set; }

        public class FeedComment
        {
            public Guid AuthorId { get; set; }

            public FeedMinUser Author { get; set; }

            public string Description { get; set; }

            public DateTime Date { get; set; }


            public FeedMin ToFeedMin()
            {
                return new FeedMin { Author = Author, Title = Description, CreatedDate = Date, ModifiedDate = Date };
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Dao/TimeSpendDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Tenants;

using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Web.Projects;

namespace ASC.Projects.Data.DAO
{
    class TimeSpendDao : BaseDao, ITimeSpendDao
    {
        private readonly string[] columns = { "id", "note", "date", "hours", "relative_task_id", "person_id", "project_id", "create_on", "create_by",
            "payment_status", "status_changed" };
        private readonly Converter<object[], TimeSpend> converter;

        public TimeSpendDao(int tenantID) : base(tenantID)
        {
            converter = ToTimeSpend;
        }

        public List<TimeSpend> GetByFilter(TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            var query = CreateQuery();

            if (filter.Max != 0 && !filter.Max.Equals(int.MaxValue))
            {
                query.SetFirstResult((int)filter.Offset);
                query.SetMaxResults((int)filter.Max * 2);
            }

            if (!string.IsNullOrEmpty(filter.SortBy))
            {
                var sortColumns = filter.SortColumns["TimeSpend"];
                sortColumns.Remove(filter.SortBy);

                query.OrderBy("t." + filter.SortBy, filter.SortOrder);

                foreach (var sort in sortColumns.Keys)
                {
                    query.OrderBy("t." + sort, sortColumns[sort]);
                }
            }

            query = CreateQueryFilter(query, filter, isAdmin, checkAccess);

            return Db.ExecuteList(query).ConvertAll(converter);
        }

        public int GetByFilterCount(TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            var query = new SqlQuery(TimeTrackingTable + " t")
                          .InnerJoin(TasksTable + " pt",
                                Exp.EqColumns("t.tenant_id", "pt.tenant_id") &
                                Exp.EqColumns("t.relative_task_id", "pt.id"))
                          .Select("t.id")
                          .Where("t.tenant_id", Tenant);


            query = CreateQueryFilter(query, filter, isAdmin, checkAccess);

            var queryCount = new SqlQuery().SelectCount().From(query, "t1");

            return Db.ExecuteScalar<int>(queryCount);
        }

        public float GetByFilterTotal(TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            var query = new SqlQuery(TimeTrackingTable + " t")
                        .InnerJoin(TasksTable + " pt",
                                Exp.EqColumns("t.tenant_id", "pt.tenant_id") &
                                Exp.EqColumns("t.relative_task_id", "pt.id"))
                          .Select("t.hours")
                          .Where("t.tenant_id", Tenant);

            query = CreateQueryFilter(query, filter, isAdmin, checkAccess);

            var queryCount = new SqlQuery().SelectSum("hours").From(query, "t1");

            return Db.ExecuteScalar<float>(queryCount);
        }

        private SqlQuery CreateQueryFilter(SqlQuery query, TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            if (filter.MyProjects || filter.MyMilestones)
            {
                query.InnerJoin(ParticipantTable + " ppp", Exp.EqColumns("t.project_id", "ppp.project_id") & Exp.Eq("ppp.removed", false) & Exp.EqColumns("t.tenant_id", "ppp.tenant"));
                query.Where("ppp.participant_id", CurrentUserID);
            }

            if (filter.ProjectIds.Count != 0)
            {
                query.Where(Exp.In("t.project_id", filter.ProjectIds));
            }
            else
            {
                if (ProjectsCommonSettings.Load().HideEntitiesInPausedProjects)
                {
                    if (!checkAccess && isAdmin)
                    {
                        query.InnerJoin(ProjectsTable + " p", Exp.EqColumns("t.tenant_id", "p.tenant_id") & Exp.EqColumns("t.project_id", "p.id"));
                    }
                    query.Where(!Exp.Eq("p.status", ProjectStatus.Paused));
                }
            }

            if (filter.Milestone.HasValue || filter.MyMilestones)
            {
                query.InnerJoin(MilestonesTable + " pm", Exp.EqColumns("pm.tenant_id", "t.tenant_id") & Exp.EqColumns("pm.project_id", "t.project_id"));
                query.Where(Exp.EqColumns("pt.milestone_id", "pm.id"));

                if (filter.Milestone.HasValue)
                {
                    query.Where("pm.id", filter.Milestone);
                }
                else if (filter.MyMilestones)
                {
                    query.Where(Exp.Gt("pm.id", 0));
                }
            }

            if (filter.TagId != 0)
            {
                if (filter.TagId == -1)
                {
                    query.LeftOuterJoin(ProjectTagTable + " ptag", Exp.EqColumns("ptag.project_id", "t.project_id"));
                    query.Where("ptag.tag_id", null);
                }
                else
                {
                    query.InnerJoin(ProjectTagTable + " ptag", Exp.EqColumns("ptag.project_id", "t.project_id"));
                    query.Where("ptag.tag_id", filter.TagId);
                }
            }


            if (filter.UserId != Guid.Empty)
            {
                query.Where("t.person_id", filter.UserId);
            }


            if (filter.DepartmentId != Guid.Empty)
            {
                query.InnerJoin("core_usergroup cug", Exp.Eq("cug.removed", false) & Exp.EqColumns("cug.userid", "t.person_id") & Exp.EqColumns("cug.tenant", "t.tenant_id"));
                query.Where("cug.groupid", filter.DepartmentId);
            }

            var minDate = DateTime.MinValue;
            var maxDate = DateTime.MaxValue;

            if (!filter.FromDate.Equals(minDate) && !filter.FromDate.Equals(maxDate) &&
                !filter.ToDate.Equals(minDate) && !filter.ToDate.Equals(maxDate))
            {
                query.Where(Exp.Between("t.date", filter.FromDate, filter.ToDate));
            }

            if (filter.PaymentStatuses.Any())
            {
                query.Where(Exp.In("payment_status", filter.PaymentStatuses));
            }

            if (!string.IsNullOrEmpty(filter.SearchText))
            {
                query.Where(Exp.Like("t.note", filter.SearchText, SqlLike.AnyWhere) | Exp.Like("pt.title", filter.SearchText, SqlLike.AnyWhere));
            }

            if (checkAccess)
            {
                query.InnerJoin(ProjectsTable + " p", Exp.EqColumns("p.tenant_id", "t.tenant_id") & Exp.EqColumns("p.id", "t.project_id"));
                query.Where(Exp.Eq("p.private", false));
            }
            else if (!isAdmin)
            {
                query.InnerJoin(ProjectsTable + " p", Exp.EqColumns("p.tenant_id", "t.tenant_id") & Exp.EqColumns("p.id", "t.project_id"));

                if (!(filter.MyProjects || filter.MyMilestones))
                {
                    query.LeftOuterJoin(ParticipantTable + " ppp", Exp.Eq("ppp.participant_id", CurrentUserID) & Exp.EqColumns("ppp.project_id", "t.project_id") & Exp.EqColumns("ppp.tenant", "t.tenant_id"));
                }

                var isInTeam = !Exp.Eq("ppp.security", null) & Exp.Eq("ppp.removed", false);
                var canReadTasks = !Exp.Eq("security & " + (int)ProjectTeamSecurity.Tasks, (int)ProjectTeamSecurity.Tasks);
                var canReadMilestones = Exp.Eq("pt.milestone_id", 0) | !Exp.Eq("security & " + (int)ProjectTeamSecurity.Milestone, (int)ProjectTeamSecurity.Milestone);
                var responsible = Exp.Exists(new SqlQuery("projects_tasks_responsible ptr")
                        .Select("ptr.responsible_id")
                        .Where(Exp.EqColumns("pt.id", "ptr.task_id") &
                        Exp.EqColumns("ptr.tenant_id", "pt.tenant_id") &
                        Exp.Eq("ptr.responsible_id", CurrentUserID)));

                query.Where(Exp.Eq("p.private", false) | isInTeam & (responsible | canReadTasks & canReadMilestones));
            }

            query.GroupBy("t.id");

            return query;
        }

        public List<TimeSpend> GetByProject(int projectId)
        {
            return Db.ExecuteList(CreateQuery().Where("t.project_id", projectId).OrderBy("date", false)).ConvertAll(converter);
        }

        public List<TimeSpend> GetByTask(int taskId)
        {
            return Db.ExecuteList(CreateQuery().Where("t.relative_task_id", taskId).OrderBy("date", false)).ConvertAll(converter);
        }

        public TimeSpend GetById(int id)
        {
            return Db.ExecuteList(CreateQuery().Where("t.id", id))
                            .ConvertAll(converter)
                            .SingleOrDefault();
        }

        public TimeSpend Save(TimeSpend timeSpend)
        {
            timeSpend.Date = TenantUtil.DateTimeToUtc(timeSpend.Date);
            timeSpend.StatusChangedOn = TenantUtil.DateTimeToUtc(timeSpend.StatusChangedOn);

            var insert = Insert(TimeTrackingTable)
                .InColumnValue("id", timeSpend.ID)
                .InColumnValue("note", timeSpend.Note)
                .InColumnValue("date", timeSpend.Date)
                .InColumnValue("hours", timeSpend.Hours)
                .InColumnValue("relative_task_id", timeSpend.Task.ID)
                .InColumnValue("person_id", timeSpend.Person.ToString())
                .InColumnValue("project_id", timeSpend.Task.Project.ID)
                .InColumnValue("create_on", timeSpend.CreateOn)
                .InColumnValue("create_by", CurrentUserID)
                .InColumnValue("payment_status", timeSpend.PaymentStatus)
                .InColumnValue("status_changed", timeSpend.StatusChangedOn)
                .Identity(1, 0, true);

            timeSpend.ID = Db.ExecuteScalar<int>(insert);

            return timeSpend;
        }

        public void Delete(int id)
        {
            Db.ExecuteNonQuery(Delete(TimeTrackingTable).Where("id", id));
        }

        private SqlQuery CreateQuery()
        {
            return new SqlQuery(TimeTrackingTable + " t")
                .InnerJoin(TasksTable + " pt", Exp.EqColumns("t.tenant_id", "pt.tenant_id") & Exp.EqColumns("t.relative_task_id", "pt.id"))
                .Select(columns.Select(c => "t." + c).ToArray())
                .Where("t.tenant_id", Tenant);
        }

        private static TimeSpend ToTimeSpend(IList<object> r)
        {
            return new TimeSpend
            {
                ID = Convert.ToInt32(r[0]),
                Note = (string)r[1],
                Date = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[2])),
                Hours = Convert.ToSingle(r[3]),
                Task = new Task { ID = Convert.ToInt32(r[4]) },
                Person = ToGuid(r[5]),
                CreateOn = r[7] != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[7])) : default(DateTime),
                CreateBy = r[8] != null ? ToGuid(r[8]) : ToGuid(r[5]),
                PaymentStatus = (PaymentStatus)r[9],
                StatusChangedOn = r[10] != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[10])) : default(DateTime)
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Dao/SubtaskDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

using ASC.Collections;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Tenants;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;

namespace ASC.Projects.Data.DAO
{
    internal class CachedSubtaskDao : SubtaskDao
    {
        private readonly HttpRequestDictionary<Subtask> _subtaskCache = new HttpRequestDictionary<Subtask>("subtask");

        public CachedSubtaskDao(int tenantID) : base(tenantID)
        {
        }

        public override void Delete(int id)
        {
            ResetCache(id);
            base.Delete(id);
        }

        public override Subtask GetById(int id)
        {
            return _subtaskCache.Get(id.ToString(CultureInfo.InvariantCulture), () => GetBaseById(id));
        }

        private Subtask GetBaseById(int id)
        {
            return base.GetById(id);
        }

        public override Subtask Save(Subtask subtask)
        {
            if (subtask != null)
            {
                ResetCache(subtask.ID);
            }
            return base.Save(subtask);
        }

        private void ResetCache(int subtaskId)
        {
            _subtaskCache.Reset(subtaskId.ToString(CultureInfo.InvariantCulture));
        }
    }

    class SubtaskDao : BaseDao, ISubtaskDao
    {
        private readonly Converter<object[], Subtask> converter;

        public SubtaskDao(int tenantID) : base(tenantID)
        {
            converter = ToSubTask;
        }

        public List<Subtask> GetSubtasks(int taskid)
        {
            return Db.ExecuteList(CreateQuery().Where("task_id", taskid)).ConvertAll(converter);
        }

        public void GetSubtasksForTasks(ref List<Task> tasks)
        {
            var taskIds = tasks.Select(t => t.ID).ToArray();
            var subtasks = Db.ExecuteList(CreateQuery().Where(Exp.In("task_id", taskIds)))//bug: there may be too large set of tasks
                .ConvertAll(converter);

            tasks = tasks.GroupJoin(subtasks, task => task.ID, subtask => subtask.Task, (task, subtaskCol) =>
                        {
                            task.SubTasks.AddRange(subtaskCol.ToList());
                            return task;
                        }).ToList();
        }

        public List<Subtask> GetSubtasks(Exp where)
        {
            return Db.ExecuteList(CreateQuery().Where(where)).ConvertAll(converter);
        }

        public virtual Subtask GetById(int id)
        {
            return Db.ExecuteList(CreateQuery().Where("id", id)).ConvertAll(converter).SingleOrDefault();
        }

        public List<Subtask> GetById(ICollection<int> ids)
        {
            return Db.ExecuteList(CreateQuery().Where(Exp.In("id", ids.ToArray()))).ConvertAll(converter);
        }

        public List<Subtask> GetUpdates(DateTime from, DateTime to)
        {
            return Db.ExecuteList(CreateQuery().Select("status_changed")
                                                .Where(Exp.Between("create_on", from, to) |
                                                    Exp.Between("last_modified_on", from, to) |
                                                    Exp.Between("status_changed", from, to)))
                            .ConvertAll(x =>
                                            {
                                                var st = ToSubTask(x);
                                                st.StatusChangedOn = Convert.ToDateTime(x.Last());
                                                return st;
                                            }).ToList();
        }

        public List<Subtask> GetByResponsible(Guid id, TaskStatus? status = null)
        {
            var query = CreateQuery().Where("responsible_id", id);

            if (status.HasValue)
            {
                query.Where("status", status.Value);
            }

            return Db.ExecuteList(query).ConvertAll(converter);
        }

        public int GetSubtaskCount(int taskid, params TaskStatus[] statuses)
        {
            var query = Query(SubtasksTable)
                .SelectCount()
                .Where("task_id", taskid);
            if (statuses != null && 0 < statuses.Length)
            {
                query.Where(Exp.In("status", statuses));
            }
            return Db.ExecuteScalar<int>(query);
        }

        public virtual Subtask Save(Subtask subtask)
        {
            var insert = Insert(SubtasksTable)
                .InColumnValue("id", subtask.ID)
                .InColumnValue("task_id", subtask.Task)
                .InColumnValue("title", subtask.Title)
                .InColumnValue("responsible_id", subtask.Responsible.ToString())
                .InColumnValue("status", subtask.Status)
                .InColumnValue("create_by", subtask.CreateBy.ToString())
                .InColumnValue("create_on", TenantUtil.DateTimeToUtc(subtask.CreateOn))
                .InColumnValue("last_modified_by", subtask.LastModifiedBy.ToString())
                .InColumnValue("last_modified_on", TenantUtil.DateTimeToUtc(subtask.LastModifiedOn))
                .InColumnValue("status_changed", TenantUtil.DateTimeToUtc(subtask.StatusChangedOn))
                .Identity(1, 0, true);

            subtask.ID = Db.ExecuteScalar<int>(insert);
            return subtask;
        }

        public void CloseAllSubtasks(Task task)
        {
            Db.ExecuteNonQuery(
                Update(SubtasksTable)
                    .Set("status", TaskStatus.Closed)
                    .Set("last_modified_by", CurrentUserID)
                    .Set("last_modified_on", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()))
                    .Set("status_changed", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()))
                    .Where("status", TaskStatus.Open)
                    .Where("task_id", task.ID));
        }

        public virtual void Delete(int id)
        {
            Db.ExecuteNonQuery(Delete(SubtasksTable).Where("id", id));
        }

        private SqlQuery CreateQuery()
        {
            return new SqlQuery(SubtasksTable)
                .Select("id", "title", "responsible_id", "status", "create_by", "create_on", "last_modified_by", "last_modified_on", "task_id")
                .OrderBy("status", true)
                .OrderBy("(case status when 1 then create_on else status_changed end)", true)
                .Where("tenant_id", Tenant);
        }

        private static Subtask ToSubTask(IList<object> r)
        {
            return new Subtask
            {
                ID = Convert.ToInt32(r[0]),
                Title = (string)r[1],
                Responsible = ToGuid(r[2]),
                Status = (TaskStatus)Convert.ToInt32(r[3]),
                CreateBy = ToGuid(r[4]),
                CreateOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[5])),
                LastModifiedBy = ToGuid(r[6]),
                LastModifiedOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[7])),
                Task = Convert.ToInt32(r[8])
            };
        }
    }
}


<|start_filename|>common/ASC.Data.Storage/StaticUploader.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;

using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Common.Threading.Progress;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Data.Storage.Configuration;

namespace ASC.Data.Storage
{
    public class StaticUploader
    {
        private static readonly TaskScheduler Scheduler;
        private static readonly CancellationTokenSource TokenSource;

        private static readonly ICache Cache;
        private static readonly object Locker;

        static StaticUploader()
        {
            Scheduler = new LimitedConcurrencyLevelTaskScheduler(4);
            Cache = AscCache.Memory;
            Locker = new object();
            TokenSource = new CancellationTokenSource();
        }

        public static string UploadFile(string relativePath, string mappedPath, Action<string> onComplete = null)
        {
            if (TokenSource.Token.IsCancellationRequested) return null;
            if (!CanUpload()) return null;
            if (!File.Exists(mappedPath)) return null;

            var tenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId;
            UploadOperation uploadOperation;
            var key = GetCacheKey(tenantId.ToString(), relativePath);

            lock (Locker)
            {
                uploadOperation = Cache.Get<UploadOperation>(key);
                if (uploadOperation != null)
                {
                    return !string.IsNullOrEmpty(uploadOperation.Result) ? uploadOperation.Result : string.Empty;
                }

                uploadOperation = new UploadOperation(tenantId, relativePath, mappedPath);
                Cache.Insert(key, uploadOperation, DateTime.MaxValue);
            }

            uploadOperation.DoJob();
            if (onComplete != null)
            {
                onComplete(uploadOperation.Result);
            }

            return uploadOperation.Result;
        }

        public static Task<string> UploadFileAsync(string relativePath, string mappedPath, Action<string> onComplete = null)
        {
            var tenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId;
            var task = new Task<string>(() =>
            {
                CoreContext.TenantManager.SetCurrentTenant(tenantId);
                return UploadFile(relativePath, mappedPath, onComplete);
            }, TaskCreationOptions.LongRunning);

            task.ConfigureAwait(false);

            task.Start(Scheduler);

            return task;
        }

        public static async void UploadDir(string relativePath, string mappedPath)
        {
            if (!CanUpload()) return;
            if (!Directory.Exists(mappedPath)) return;

            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var key = typeof(UploadOperationProgress).FullName + tenant.TenantId;
            UploadOperationProgress uploadOperation;

            lock (Locker)
            {
                uploadOperation = Cache.Get<UploadOperationProgress>(key);
                if (uploadOperation != null) return;

                uploadOperation = new UploadOperationProgress(relativePath, mappedPath);
                Cache.Insert(key, uploadOperation, DateTime.MaxValue);
            }


            tenant.SetStatus(TenantStatus.Migrating);
            CoreContext.TenantManager.SaveTenant(tenant);

            await uploadOperation.RunJobAsync();

            tenant.SetStatus(Core.Tenants.TenantStatus.Active);
            CoreContext.TenantManager.SaveTenant(tenant);
        }

        public static bool CanUpload()
        {
            var current = CdnStorageSettings.Load().DataStoreConsumer;
            if (current == null || !current.IsSet || (string.IsNullOrEmpty(current["cnamessl"]) && string.IsNullOrEmpty(current["cname"])))
            {
                return false;
            }

            return true;
        }

        public static void Stop()
        {
            TokenSource.Cancel();
        }

        public static UploadOperationProgress GetProgress(int tenantId)
        {
            lock (Locker)
            {
                var key = typeof(UploadOperationProgress).FullName + tenantId;
                return Cache.Get<UploadOperationProgress>(key);
            }
        }

        private static string GetCacheKey(string tenantId, string path)
        {
            return typeof(UploadOperation).FullName + tenantId + path;
        }
    }

    public class UploadOperation
    {
        private static readonly ILog Log = LogManager.GetLogger("ASC");
        private readonly int tenantId;
        private readonly string path;
        private readonly string mappedPath;
        public string Result { get; private set; }

        public UploadOperation(int tenantId, string path, string mappedPath)
        {
            this.tenantId = tenantId;
            this.path = path.TrimStart('/');
            this.mappedPath = mappedPath;
            Result = string.Empty;
        }

        public string DoJob()
        {
            try
            {
                var tenant = CoreContext.TenantManager.GetTenant(tenantId);
                CoreContext.TenantManager.SetCurrentTenant(tenant);
                SecurityContext.AuthenticateMe(tenant.OwnerId);

                var dataStore = CdnStorageSettings.Load().DataStore;

                if (File.Exists(mappedPath))
                {
                    if (!dataStore.IsFile(path))
                    {
                        using (var stream = File.OpenRead(mappedPath))
                        {
                            dataStore.Save(path, stream);
                        }
                    }

                    Result = dataStore.GetInternalUri("", path, TimeSpan.Zero, null).AbsoluteUri.ToLower();
                    LogManager.GetLogger("ASC").DebugFormat("UploadFile {0}", Result);
                    return Result;
                }
            }
            catch (Exception e)
            {
                Log.Error(e);
            }
            return null;
        }
    }

    [DataContract]
    public class UploadOperationProgress : ProgressBase
    {
        private readonly string relativePath;
        private readonly string mappedPath;
        private readonly IEnumerable<string> directoryFiles;

        public UploadOperationProgress(string relativePath, string mappedPath)
        {
            this.relativePath = relativePath;
            this.mappedPath = mappedPath;

            var extensions = ".png|.jpeg|.jpg|.gif|.ico|.swf|.mp3|.ogg|.eot|.svg|.ttf|.woff|.woff2|.css|.less|.js";
            var extensionsArray = extensions.Split('|');

            directoryFiles = Directory.GetFiles(mappedPath, "*", SearchOption.AllDirectories)
                .Where(r => extensionsArray.Contains(Path.GetExtension(r)))
                .ToList();

            StepCount = directoryFiles.Count();
        }

        protected override async Task DoJobAsync()
        {
            var tasks = new List<Task>();
            foreach (var file in directoryFiles)
            {
                var filePath = file.Substring(mappedPath.TrimEnd('/').Length);
                tasks.Add(StaticUploader.UploadFileAsync(Path.Combine(relativePath, filePath), file, (res) => StepDone()));
            }

            await Task.WhenAll(tasks);
        }

        protected override void DoJob()
        {
            foreach (var file in directoryFiles)
            {
                var filePath = file.Substring(mappedPath.TrimEnd('/').Length);
                StaticUploader.UploadFileAsync(Path.Combine(relativePath, filePath), file, (res) => StepDone()).Wait();
            }
        }
    }
}


<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Utils/PostfixPasswordEncryptor.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Mail.Server.Exceptions;

namespace ASC.Mail.Server.Utils
{
    public enum HashType { Md5 = 1 }

    public class PostfixPasswordEncryptor
    {
        public static string EncryptString(HashType ht, string str, string salt = null)
        {
            switch (ht)
            {
                case HashType.Md5:
                    var md5 = SaltMd5.Init(str, salt);
                    return md5.ToBfFormat();
            }
            throw new PostfixEncryptorException("This hash type doesn't implemented.");
        }
    }

    internal class SaltMd5
    {
        private SaltMd5()
        {
        }

        private bool _isCalculated;
        private const int SALT_LENGTH = 8;
        private const string REQUIRED_MD5_SALT_PREFIX = "$1$";

        private string _stringToHash;
        private string _salt;
        private string _hash;


        public static SaltMd5 Init(string stringToHash, string salt)
        {
            if (salt != null && !salt.StartsWith(REQUIRED_MD5_SALT_PREFIX))
                throw new ArgumentException("Invalid salt format. Should be $1$********");

            var hash = new SaltMd5 { _stringToHash = stringToHash, _salt = salt };
            return hash;
        }

        //http://pentestmonkey.net/cheat-sheet/john-the-ripper-hash-formats
        public string ToBfFormat()
        {
            if (!_isCalculated) CalculateCryptMd5();
            return _hash;
        }

        private void CalculateCryptMd5()
        {
            var saltInString = _salt == null ? GenerateRandomString() : _salt.Substring(REQUIRED_MD5_SALT_PREFIX.Length).Replace('$', ',');
            _hash = Md5Crypt.crypt(_stringToHash, saltInString);
            _isCalculated = true;
        }


        private static string GenerateRandomString()
        {
            const string chars = "23456789abcdefghjkmnpqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
            var t = new Random();
            var randomString = "";
            for (var i = 0; i < SALT_LENGTH; i++)
                randomString += chars[t.Next(0, chars.Length - 1)];

            return randomString;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Projects/Wrappers/SearchWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

using ASC.Projects.Engine;

namespace ASC.Api.Projects.Wrappers
{
    [DataContract(Name = "search", Namespace = "")]
    public class SearchWrapper
    {
        [DataMember(Order = 10)]
        public SearchItemWrapper Item { get; set; }

        [DataMember(Order = 14)]
        public SearchItemWrapper Owner { get; set; }


        private SearchWrapper()
        {
        }

        public SearchWrapper(SearchItem searchItem)
        {
            Item = new SearchItemWrapper(searchItem);
            if (searchItem.Container != null)
            {
                Owner = new SearchItemWrapper(searchItem.Container);
            }
        }


        public static SearchWrapper GetSample()
        {
            return new SearchWrapper
            {
                Item = SearchItemWrapper.GetSample()
            };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_MVGroupHFCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// Implements same multi value header fields group. Group can contain one type header fields only.
    /// This is class is used by Via:,Route:, ... .
    /// </summary>
    public class SIP_MVGroupHFCollection<T> where T : SIP_t_Value, new()
    {
        #region Members

        private readonly string m_FieldName = "";
        private readonly List<SIP_MultiValueHF<T>> m_pFields;
        private readonly SIP_Message m_pMessage;

        #endregion

        #region Properties

        /// <summary>
        /// Gets header field name what this group holds.
        /// </summary>
        public string FieldName
        {
            get { return m_FieldName; }
        }

        /// <summary>
        /// Gets number of header fields in this group.
        /// </summary>
        public int Count
        {
            get { return m_pFields.Count; }
        }

        /// <summary>
        /// Gets header fields what are in this group.
        /// </summary>
        public SIP_MultiValueHF<T>[] HeaderFields
        {
            get { return m_pFields.ToArray(); }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner message that owns this group.</param>
        /// <param name="fieldName">Header field name what group holds.</param>
        public SIP_MVGroupHFCollection(SIP_Message owner, string fieldName)
        {
            m_pMessage = owner;
            m_FieldName = fieldName;

            m_pFields = new List<SIP_MultiValueHF<T>>();

            Refresh();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Add new header field on the top of the whole header.
        /// </summary>
        /// <param name="value">Header field value.</param>
        public void AddToTop(string value)
        {
            m_pMessage.Header.Insert(0, m_FieldName, value);
            Refresh();
        }

        /// <summary>
        /// Add new header field on the bottom of the whole header.
        /// </summary>
        /// <param name="value">Header field value.</param>
        public void Add(string value)
        {
            m_pMessage.Header.Add(m_FieldName, value);
            Refresh();
        }

        /// <summary>
        /// Removes all specified header fields with their values.
        /// </summary>
        public void RemoveAll()
        {
            m_pMessage.Header.RemoveAll(m_FieldName);
            m_pFields.Clear();
        }

        /// <summary>
        /// Gets top most header field first value. 
        /// </summary>
        public T GetTopMostValue()
        {
            if (m_pFields.Count > 0)
            {
                return m_pFields[0].Values[0];
            }

            return null;
        }

        /// <summary>
        /// Removes top most header field first value. If value is the last value, 
        /// the whole header field will be removed.
        /// </summary>
        public void RemoveTopMostValue()
        {
            if (m_pFields.Count > 0)
            {
                SIP_MultiValueHF<T> h = m_pFields[0];
                if (h.Count > 1)
                {
                    h.Remove(0);
                }
                else
                {
                    m_pMessage.Header.Remove(m_pFields[0]);
                    m_pFields.Remove(m_pFields[0]);
                }
            }
        }

        /// <summary>
        /// Removes last value. If value is the last value n header field, the whole header field will be removed.
        /// </summary>
        public void RemoveLastValue()
        {
            SIP_MultiValueHF<T> h = m_pFields[m_pFields.Count - 1];
            if (h.Count > 1)
            {
                h.Remove(h.Count - 1);
            }
            else
            {
                m_pMessage.Header.Remove(m_pFields[0]);
                m_pFields.Remove(h);
            }
        }

        /// <summary>
        /// Gets all header field values.
        /// </summary>
        /// <returns></returns>
        public T[] GetAllValues()
        {
            List<T> retVal = new List<T>();
            foreach (SIP_MultiValueHF<T> h in m_pFields)
            {
                foreach (SIP_t_Value v in h.Values)
                {
                    retVal.Add((T) v);
                }
            }

            return retVal.ToArray();
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Refreshes header fields in group from actual header.
        /// </summary>
        private void Refresh()
        {
            m_pFields.Clear();

            foreach (SIP_HeaderField h in m_pMessage.Header)
            {
                if (h.Name.ToLower() == m_FieldName.ToLower())
                {
                    m_pFields.Add((SIP_MultiValueHF<T>) h);
                }
            }
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/TasksConfig.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;

namespace ASC.Mail.Data.Contracts
{
    public class TasksConfig
    {
        public enum AggregateModeType
        {
            All,
            External,
            Internal
        };

        public TimeSpan CheckTimerInterval { get; set; }
        public TimeSpan ActiveInterval { get; set; }
        public List<string> WorkOnUsersOnly { get; set; }
        public AggregateModeType AggregateMode { get; set; }
        public bool EnableSignalr { get; set; }
        public int ChunkOfPop3Uidl { get; set; }
        public int MaxMessagesPerSession { get; set; }
        public int MaxTasksAtOnce { get; set; }
        public TimeSpan OverdueAccountDelay { get; set; }
        public TimeSpan QuotaEndedDelay { get; set; }
        public TimeSpan TenantCachingPeriod { get; set; }
        public TimeSpan QueueLifetime { get; set; }
        public double InactiveMailboxesRatio { get; set; }
        public TimeSpan AuthErrorWarningTimeout { get; set; }
        public TimeSpan AuthErrorDisableMailboxTimeout { get; set; }
        public int TenantOverdueDays { get; set; }
        public long TenantMinQuotaBalance { get; set; }
        public bool SaveOriginalMessage { get; set; }
        public Dictionary<string, int> ImapFlags { get; set; }
        public string[] SkipImapFlags { get; set; }
        public Dictionary<string, Dictionary<string, MailBoxData.MailboxInfo>> SpecialDomainFolders { get; set; }
        public Dictionary<string, int> DefaultFolders { get; set; }
        public string DefaultApiSchema { get; set; }
        public TimeSpan TaskLifetime { get; set; }
        public bool SslCertificateErrorsPermit { get; set; }
        public int TcpTimeout { get; set; }
        public string ProtocolLogPath { get; set; }
        public bool CollectStatistics { get; set; }

        public bool UseDump { get; set; }

        public static readonly TasksConfig Default = new TasksConfig
        {
            CheckTimerInterval = TimeSpan.FromSeconds(10),
            ActiveInterval = TimeSpan.FromSeconds(90),
            WorkOnUsersOnly = new List<string>(),
            AggregateMode = AggregateModeType.All,
            EnableSignalr = false,
            ChunkOfPop3Uidl = 100,
            MaxMessagesPerSession = 10,
            MaxTasksAtOnce = 10,
            OverdueAccountDelay = TimeSpan.FromSeconds(600),
            QuotaEndedDelay = TimeSpan.FromSeconds(600),
            TenantCachingPeriod = TimeSpan.FromSeconds(86400), // 1 day
            QueueLifetime = TimeSpan.FromSeconds(30),
            InactiveMailboxesRatio = 25,
            AuthErrorWarningTimeout = TimeSpan.FromHours(1),
            AuthErrorDisableMailboxTimeout = TimeSpan.FromDays(3),
            TenantOverdueDays = 10,
            TenantMinQuotaBalance = 26214400,
            SaveOriginalMessage = false,
            ImapFlags = new Dictionary<string, int>(),
            SkipImapFlags = new string[] { },
            SpecialDomainFolders = new Dictionary<string, Dictionary<string, MailBoxData.MailboxInfo>>(),
            DefaultFolders = new Dictionary<string, int>(),
            DefaultApiSchema = Uri.UriSchemeHttp,
            TaskLifetime = TimeSpan.FromSeconds(300),
            SslCertificateErrorsPermit = false,
            TcpTimeout = 30000,
            ProtocolLogPath = "",
            CollectStatistics = true,
            UseDump = false
        };

        public static TasksConfig FromConfig
        {
            get
            {
                var config = Default;

                if (ConfigurationManagerExtension.AppSettings["mail.check-work-timer-seconds"] != null)
                {
                    config.CheckTimerInterval = TimeSpan.FromSeconds(
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.check-work-timer-seconds"]));
                }

                if (ConfigurationManagerExtension.AppSettings["mail.activity-timeout-seconds"] != null)
                {
                    config.ActiveInterval = TimeSpan.FromSeconds(
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.activity-timeout-seconds"]));
                }

                Guid userId;
                if (ConfigurationManagerExtension.AppSettings["mail.one-user-mode"] != null &&
                    Guid.TryParse(ConfigurationManagerExtension.AppSettings["mail.one-user-mode"], out userId))
                {
                    config.WorkOnUsersOnly.Add(ConfigurationManagerExtension.AppSettings["mail.one-user-mode"]);
                }

                if (ConfigurationManagerExtension.AppSettings["mail.aggregate-mode"] != null)
                {
                    AggregateModeType aggregateMode;

                    switch (ConfigurationManagerExtension.AppSettings["mail.aggregate-mode"])
                    {
                        case "external":
                            aggregateMode = AggregateModeType.External;
                            break;
                        case "internal":
                            aggregateMode = AggregateModeType.Internal;
                            break;
                        default:
                            aggregateMode = AggregateModeType.All;
                            break;
                    }

                    config.AggregateMode = aggregateMode;
                }

                if (ConfigurationManagerExtension.AppSettings["web.enable-signalr"] != null)
                {
                    config.EnableSignalr = Convert.ToBoolean(ConfigurationManagerExtension.AppSettings["web.enable-signalr"]);
                }

                if (ConfigurationManagerExtension.AppSettings["mail.check-pop3-uidl-chunk"] != null)
                {
                    config.ChunkOfPop3Uidl =
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.check-pop3-uidl-chunk"]);

                    if (config.ChunkOfPop3Uidl < 1 || config.ChunkOfPop3Uidl > 100)
                        config.ChunkOfPop3Uidl = 100;
                }

                if (ConfigurationManagerExtension.AppSettings["mail.max-messages-per-mailbox"] != null)
                {
                    config.MaxMessagesPerSession =
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.max-messages-per-mailbox"]);

                    if (config.MaxMessagesPerSession < 1)
                        config.MaxMessagesPerSession = -1;
                }

                if (ConfigurationManagerExtension.AppSettings["mail.max-tasks-count"] != null)
                {
                    config.MaxTasksAtOnce = Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.max-tasks-count"]);

                    if (config.MaxTasksAtOnce < 1)
                        config.MaxTasksAtOnce = 1;
                }

                if (ConfigurationManagerExtension.AppSettings["mail.overdue-account-delay-seconds"] != null)
                {
                    config.OverdueAccountDelay = TimeSpan.FromSeconds(
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.overdue-account-delay-seconds"]));
                }

                if (ConfigurationManagerExtension.AppSettings["mail.quota-ended-delay-seconds"] != null)
                {
                    config.QuotaEndedDelay = TimeSpan.FromSeconds(
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.quota-ended-delay-seconds"]));
                }

                if (ConfigurationManagerExtension.AppSettings["mail.tenant-cache-lifetime-seconds"] != null)
                {
                    config.TenantCachingPeriod = TimeSpan.FromSeconds(
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.tenant-cache-lifetime-seconds"]));
                }

                if (ConfigurationManagerExtension.AppSettings["mail.queue-lifetime-seconds"] != null)
                {
                    config.QueueLifetime =
                        TimeSpan.FromSeconds(
                            Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.queue-lifetime-seconds"]));
                }

                if (ConfigurationManagerExtension.AppSettings["mail.inactive-mailboxes-ratio"] != null)
                {
                    config.InactiveMailboxesRatio =
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.inactive-mailboxes-ratio"]);

                    if (config.InactiveMailboxesRatio < 0)
                        config.InactiveMailboxesRatio = 0;
                    if (config.InactiveMailboxesRatio > 100)
                        config.InactiveMailboxesRatio = 100;
                }

                config.AuthErrorWarningTimeout = Defines.AuthErrorWarningTimeout;
                config.AuthErrorDisableMailboxTimeout = Defines.AuthErrorDisableTimeout;

                if (ConfigurationManagerExtension.AppSettings["mail.tenant-overdue-days"] != null)
                {
                    config.TenantOverdueDays =
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.tenant-overdue-days"]);
                }

                if (ConfigurationManagerExtension.AppSettings["mail.tenant-min-quota-balance"] != null)
                {
                    config.TenantMinQuotaBalance =
                        Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.tenant-min-quota-balance"]);
                }

                config.SaveOriginalMessage = Defines.SaveOriginalMessage;

                config.DefaultApiSchema = Defines.DefaultApiSchema;

                if (ConfigurationManagerExtension.AppSettings["mail.task-process-lifetime-seconds"] != null)
                {
                    config.TaskLifetime =
                        TimeSpan.FromSeconds(
                            Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.task-process-lifetime-seconds"]));
                }

                config.SslCertificateErrorsPermit = Defines.SslCertificatesErrorPermit;

                config.TcpTimeout = Default.TcpTimeout;

                if (ConfigurationManagerExtension.AppSettings["mail.protocol-log-path"] != null)
                {
                    config.ProtocolLogPath = ConfigurationManagerExtension.AppSettings["mail.protocol-log-path"] ?? "";
                }

                if (ConfigurationManagerExtension.AppSettings["mail.collect-statistics"] != null)
                {
                    config.CollectStatistics = Convert.ToBoolean(ConfigurationManagerExtension.AppSettings["mail.collect-statistics"] ?? "true");
                }

                if (ConfigurationManagerExtension.AppSettings["mail.use-damp"] != null)
                {
                    config.UseDump = Convert.ToBoolean(ConfigurationManagerExtension.AppSettings["mail.use-damp"] ?? "false");
                }

                return config;
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/SmallChat/SmallChat.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Data.Storage;

namespace ASC.Web.Studio.UserControls.Common.SmallChat
{
    public partial class SmallChat : UserControl
    {
        public static string Location
        {
            get
            {
                return "~/UserControls/Common/SmallChat/SmallChat.ascx";
            }
        }

        public static string SoundPath { get; private set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            SoundPath = WebPath.GetPath("UserControls/Common/SmallChat/css/sounds/chat");

            Page
                .RegisterStyle(
                    "~/UserControls/Common/SmallChat/css/smallchat.css",
                    "~/UserControls/Common/SmallChat/css/jquery.cssemoticons.css")
                .RegisterBodyScripts(
                    "~/js/third-party/jquery/jquery.linkify.js",
                    "~/js/third-party/jquery/noty/jquery.noty.js",
                    "~/js/third-party/jquery/jquery.cssemoticons.js",
                    "~/js/third-party/autosize.js",
                    "~/UserControls/Common/SmallChat/js/smallchat.js");
        }
    }
}

<|start_filename|>module/ASC.Socket.IO/app/hubs/voipListPhones.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


const VoipPhone = require('./voipPhone.js');

class ListVoipPhone {
    constructor() {
        this.phones = [];
    }

    addPhone(numberId) {
        const existingPhone = this.phones.find((item) => item.numberId === numberId);
        if (!existingPhone) {
            this.phones.push(new VoipPhone(numberId));
        }
    }

    getPhone(numberId) {
        return this.phones.find((item) => item.numberId === numberId);
    }

    addOrUpdateAgent(numberId, agent) {
        const phone = this.getPhone(numberId);
        if (!phone) return;
        phone.addOrUpdateAgent(agent);
    }

    removeAgent(numberId, agentId) {
        const phone = this.getPhone(numberId);
        if (!phone) return;
        phone.removeAgent(agentId);
    }

    anyCalls(numberId) {
        const phone = this.getPhone(numberId);
        if (!phone) return false;
        return phone.anyCalls();
    }

    dequeueCall(numberId) {
        const phone = this.getPhone(numberId);
        if (!phone) return "";
        return phone.dequeueCall();
    }

    removeCall(numberId, callId) {
        const phone = this.getPhone(numberId);
        if (!phone) return;
        phone.removeCall(callId);
    }

    enqueue(numberId, callId, agent) {
        const phone = this.getPhone(numberId);
        if (!phone) return "";
        return phone.enqueue(callId, agent);
    }

    onlineAgents(numberId) {
        const phone = this.getPhone(numberId);
        if (!phone) return [];
        return phone.onlineAgents();
    }

    getStatus(numberId, agentId) {
        const phone = this.getPhone(numberId);
        if (!phone) return 2;
        return phone.getAgentStatus(agentId);
    }

    getAgent(numberId, contactResponsibles) {
        const phone = this.getPhone(numberId);
        if (!phone) return null;
        return phone.getAgent(contactResponsibles);
    }
}

module.exports = ListVoipPhone;

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Common/Subscriber.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;

using AjaxPro;

using ASC.Core;
using ASC.Notify.Model;
using ASC.Notify.Recipients;
using ASC.Web.Community.Modules.Blogs.Core.Resources;
using ASC.Web.Community.Resources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Community.Blogs
{
    [AjaxNamespace("Subscriber")]
    public class Subscriber
    {
        private readonly ISubscriptionProvider _subscriptionProvider;
        private readonly IRecipientProvider _recipientProvider;

        public IDirectRecipient IAmAsRecipient
        {
            get { return (IDirectRecipient)_recipientProvider.GetRecipient(SecurityContext.CurrentAccount.ID.ToString()); }
        }


        public Subscriber()
        {
            var engine = BasePage.GetEngine();
            _subscriptionProvider = engine.NotifySource.GetSubscriptionProvider();
            _recipientProvider = engine.NotifySource.GetRecipientsProvider();
        }

        #region Comments

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse SubscribeOnComments(Guid postID, int statusNotify)
        {
            var resp = new AjaxResponse();
            try
            {
                if (statusNotify == 1)
                {
                    _subscriptionProvider.Subscribe(
                        ASC.Blogs.Core.Constants.NewComment,
                        postID.ToString(),
                        IAmAsRecipient
                        );


                    resp.rs1 = "1";
                    resp.rs2 = RenderCommentsSubscription(false, postID);
                }
                else
                {

                    _subscriptionProvider.UnSubscribe(
                        ASC.Blogs.Core.Constants.NewComment,
                        postID.ToString(),
                        IAmAsRecipient
                        );

                    resp.rs1 = "1";
                    resp.rs2 = RenderCommentsSubscription(true, postID);
                }
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs2 = HttpUtility.HtmlEncode(e.Message);
            }

            return resp;
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse SubscribeOnBlogComments(Guid postID, int statusNotify)
        {
            var resp = new AjaxResponse();
            try
            {
                if (statusNotify == 1)
                {
                    _subscriptionProvider.Subscribe(
                        ASC.Blogs.Core.Constants.NewComment,
                        postID.ToString(),
                        IAmAsRecipient
                        );


                    resp.rs1 = "0";
                    resp.rs2 = RenderCommentsSubscriptionLink(false, postID);
                    resp.rs3 = String.Format("({0})", CommunityResource.Subscribed.ToLower());
                }
                else
                {

                    _subscriptionProvider.UnSubscribe(
                        ASC.Blogs.Core.Constants.NewComment,
                        postID.ToString(),
                        IAmAsRecipient
                        );

                    resp.rs1 = "1";
                    resp.rs2 = RenderCommentsSubscriptionLink(true, postID);
                    resp.rs3 = "";
                }
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs2 = HttpUtility.HtmlEncode(e.Message);
            }

            return resp;
        }

        public string RenderCommentsSubscription(bool isSubscribe, Guid postID)
        {
            var sb = new StringBuilder();

            sb.Append("<div id=\"blogs_subcribeOnCommentsBox\">");

            sb.AppendFormat("<a class='linkAction' title='{3}' href=\"#\" onclick=\"BlogSubscriber.SubscribeOnComments('{0}', {1}); return false;\">{2}</a>",
                            postID,
                            (isSubscribe ? 1 : 0),
                            (!isSubscribe ? BlogsResource.UnSubscribeOnNewCommentsAction : BlogsResource.SubscribeOnNewCommentsAction),
                            BlogsResource.SubscribeOnNewCommentsDescription);

            sb.Append("</div>");
            return sb.ToString();
        }

        public string RenderCommentsSubscriptionLink(bool isSubscribe, Guid postID)
        {
            var sb = new StringBuilder();

            sb.AppendFormat("<a id=\"statusSubscribe\" class=\"" + (!isSubscribe ? "subscribed" : "unsubscribed") + " follow-status\" title=\"{2}\" href=\"#\" onclick=\"BlogSubscriber.SubscribeOnBlogComments('{0}', {1}, this); return false;\"></a>",
                            postID,
                            (isSubscribe ? 1 : 0),
                            (!isSubscribe ? BlogsResource.UnSubscribeOnNewCommentsAction : BlogsResource.SubscribeOnNewCommentsAction)
                );

            return sb.ToString();
        }

        public bool IsCommentsSubscribe(Guid postID)
        {
            return
                _subscriptionProvider.IsSubscribed(
                    ASC.Blogs.Core.Constants.NewComment,
                    IAmAsRecipient,
                    postID.ToString());
        }


        #endregion

        #region PersonalBlog

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse SubscribeOnPersonalBlog(Guid userID, int statusNotify)
        {
            var resp = new AjaxResponse();
            try
            {
                if (statusNotify == 1)
                {
                    _subscriptionProvider.Subscribe(
                        ASC.Blogs.Core.Constants.NewPostByAuthor,
                        userID.ToString(),
                        IAmAsRecipient
                        );


                    resp.rs1 = "1";
                    resp.rs2 = RenderPersonalBlogSubscription(false, userID);
                }
                else
                {
                    _subscriptionProvider.UnSubscribe(
                        ASC.Blogs.Core.Constants.NewPostByAuthor,
                        userID.ToString(),
                        IAmAsRecipient
                        );

                    resp.rs1 = "1";
                    resp.rs2 = RenderPersonalBlogSubscription(true, userID);
                }
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs2 = HttpUtility.HtmlEncode(e.Message);
            }

            return resp;
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse SubscribePersonalBlog(Guid userID, int statusNotify)
        {
            var resp = new AjaxResponse();
            try
            {
                if (statusNotify == 1)
                {
                    _subscriptionProvider.Subscribe(
                        ASC.Blogs.Core.Constants.NewPostByAuthor,
                        userID.ToString(),
                        IAmAsRecipient
                        );


                    resp.rs1 = "1";
                    resp.rs2 = RenderPersonalBlogSubscriptionLink(false, userID);
                }
                else
                {
                    _subscriptionProvider.UnSubscribe(
                        ASC.Blogs.Core.Constants.NewPostByAuthor,
                        userID.ToString(),
                        IAmAsRecipient
                        );

                    resp.rs1 = "1";
                    resp.rs2 = RenderPersonalBlogSubscriptionLink(true, userID);
                }
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs2 = HttpUtility.HtmlEncode(e.Message);
            }

            return resp;
        }

        public string RenderPersonalBlogSubscription(bool isSubscribe, Guid userID)
        {
            var sb = new StringBuilder();

            sb.Append("<div id=\"blogs_subcribeOnPersonalBlogBox\">");
            sb.AppendFormat("<a class='linkAction' title='{3}' href=\"#\" onclick=\"BlogSubscriber.SubscribeOnPersonalBlog('{0}', {1}); return false;\">{2}</a>",
                            userID,
                            (isSubscribe ? 1 : 0),
                            (!isSubscribe ? BlogsResource.UnSubscribeOnAuthorAction : BlogsResource.SubscribeOnAuthorAction),
                            BlogsResource.SubscribeOnAuthorDescription);
            sb.Append("</div>");

            return sb.ToString();
        }

        public string RenderPersonalBlogSubscriptionLink(bool isSubscribe, Guid userID)
        {
            var sb = new StringBuilder();

            sb.AppendFormat("<li><a class='dropdown-item' title='{3}' href=\"#\" onclick=\"BlogSubscriber.SubscribePersonalBlog('{0}', {1}, this); return false;\">{2}</a></li>",
                            userID,
                            (isSubscribe ? 1 : 0),
                            (!isSubscribe ? BlogsResource.UnSubscribeOnAuthorAction : BlogsResource.SubscribeOnAuthorAction),
                            BlogsResource.SubscribeOnAuthorDescription);

            return sb.ToString();
        }

        public bool IsPersonalBlogSubscribe(Guid userID)
        {
            return
                _subscriptionProvider.IsSubscribed(
                    ASC.Blogs.Core.Constants.NewPostByAuthor,
                    IAmAsRecipient,
                    userID.ToString());
        }


        #endregion

        #region NewPosts

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse SubscribeOnNewPosts(int statusNotify)
        {
            var resp = new AjaxResponse();
            try
            {
                if (statusNotify == 1)
                {
                    _subscriptionProvider.Subscribe(
                        ASC.Blogs.Core.Constants.NewPost,
                        null,
                        IAmAsRecipient
                        );


                    resp.rs1 = "1";
                    resp.rs2 = RenderNewPostsSubscription(false);
                }
                else
                {
                    _subscriptionProvider.UnSubscribe(
                        ASC.Blogs.Core.Constants.NewPost,
                        null,
                        IAmAsRecipient
                        );

                    resp.rs1 = "1";
                    resp.rs2 = RenderNewPostsSubscription(true);
                }
            }
            catch (Exception e)
            {
                resp.rs1 = "0";
                resp.rs2 = HttpUtility.HtmlEncode(e.Message);
            }

            return resp;
        }


        public string RenderNewPostsSubscription(bool isSubscribe)
        {
            var sb = new StringBuilder();

            sb.Append("<div id=\"blogs_subcribeOnNewPostsBox\">");
            sb.AppendFormat("<a class='linkAction' title='{2}' href=\"#\" onclick=\"BlogSubscriber.SubscribeOnNewPosts({0}); return false;\">{1}</a>",
                            (isSubscribe ? 1 : 0),
                            (!isSubscribe ? BlogsResource.UnSubscribeOnNewPostAction : BlogsResource.SubscribeOnNewPostAction),
                            BlogsResource.SubscribeOnNewPostDescription);
            sb.Append("</div>");

            return sb.ToString();
        }

        public bool IsNewPostsSubscribe()
        {
            return
                _subscriptionProvider.IsSubscribed(
                    ASC.Blogs.Core.Constants.NewPost,
                    IAmAsRecipient,
                    null);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Api/ASC.Specific/ASCBasicAuthorization.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Net;
using System.Text;
using System.Web;

using ASC.Api.Interfaces;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Security.Cryptography;

namespace ASC.Specific
{
    public class AscBasicTestAuthorization : AscBasicAuthorization
    {
        protected override void Authentificate(string username, string password)
        {
            //set tennant to 0 for testing
            CoreContext.TenantManager.SetCurrentTenant(0);
            base.Authentificate(username, password);
        }
    }

    public class AscBasicAuthorization : IApiAuthorization
    {
        private readonly ILog log;


        public AscBasicAuthorization()
        {

        }

        public AscBasicAuthorization(ILog log)
        {
            this.log = log;
        }


        public bool Authorize(HttpContextBase context)
        {
            if (!SecurityContext.IsAuthenticated)
            {
                try
                {
                    //Try basic
                    var authorization = context.Request.Headers["Authorization"];
                    if (string.IsNullOrEmpty(authorization))
                    {
                        return false;
                    }
                    authorization = authorization.Trim();
                    if (authorization.IndexOf(',') != -1)
                        authorization = authorization.Substring(0, authorization.IndexOf(',')).Trim();

                    if (authorization.IndexOf("Basic", 0) != 0)
                    {
                        return false;
                    }

                    // cut the word "basic" and decode from base64
                    // get "username:password"
                    var tempConverted = Convert.FromBase64String(authorization.Substring(6));
                    var user = new ASCIIEncoding().GetString(tempConverted);

                    // get "username"
                    // get "password"
                    var usernamePassword = user.Split(new[] { ':' });
                    var username = usernamePassword[0];
                    var password = <PASSWORD>[1];
                    log.DebugFormat("Basic Authorizing {0}", username);
                    Authentificate(username, password);
                }
                catch (Exception) { }
            }
            return SecurityContext.IsAuthenticated;
        }

        protected virtual void Authentificate(string username, string password)
        {
            var u = CoreContext.UserManager.GetUserByEmail(username) ?? CoreContext.UserManager.GetUserByUserName(username) ?? CoreContext.UserManager.GetUsers(new Guid(username));
            if (!Core.Users.Constants.LostUser.Equals(u))
            {
                var passwordHash = PasswordHasher.GetClientPassword(password);
                SecurityContext.AuthenticateMe(u.Email, passwordHash);
            }
        }

        public bool OnAuthorizationFailed(HttpContextBase context)
        {
            if (!string.IsNullOrEmpty(context.Request.Headers["Authorization"]))
            {
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Response.StatusDescription = HttpStatusCode.Unauthorized.ToString();
                string realm = String.Format("Basic Realm=\"{0}\"", context.Request.GetUrlRewriter().Host);
                context.Response.AppendHeader("WWW-Authenticate", realm);
                return true;
            }
            return false;
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Users/UserPhotoThumbnailManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace ASC.Web.Core.Users
{
    public class UserPhotoThumbnailManager
    {
        public static List<ThumbnailItem> SaveThumbnails(int x, int y, int width, int height, Guid userId)
        {
            return SaveThumbnails(new UserPhotoThumbnailSettings(x, y, width, height), userId);
        }

        public static List<ThumbnailItem> SaveThumbnails(Point point, Size size, Guid userId)
        {
            return SaveThumbnails(new UserPhotoThumbnailSettings(point, size), userId);
        }

        public static List<ThumbnailItem> SaveThumbnails(UserPhotoThumbnailSettings thumbnailSettings, Guid userId)
        {
            if (thumbnailSettings.Size.IsEmpty) return null;

            var thumbnailsData = new ThumbnailsData(userId);

            var resultBitmaps = new List<ThumbnailItem>();

            var img = thumbnailsData.MainImgBitmap;

            if (img == null) return null;

            foreach (var thumbnail in thumbnailsData.ThumbnailList)
            {
                thumbnail.Bitmap = GetBitmap(img, thumbnail.Size, thumbnailSettings);

                resultBitmaps.Add(thumbnail);
            }

            thumbnailsData.Save(resultBitmaps);

            thumbnailSettings.SaveForUser(userId);

            return thumbnailsData.ThumbnailList;
        }

        public static Bitmap GetBitmap(Image mainImg, Size size, UserPhotoThumbnailSettings thumbnailSettings, InterpolationMode interpolationMode = InterpolationMode.HighQualityBicubic)
        {
            var thumbnailBitmap = new Bitmap(size.Width, size.Height);

            var scaleX = size.Width / (1.0 * thumbnailSettings.Size.Width);
            var scaleY = size.Height / (1.0 * thumbnailSettings.Size.Height);

            var rect = new Rectangle(-(int)(scaleX * (1.0 * thumbnailSettings.Point.X)),
                                     -(int)(scaleY * (1.0 * thumbnailSettings.Point.Y)),
                                     (int)(scaleX * mainImg.Width),
                                     (int)(scaleY * mainImg.Height));

            using (var graphic = Graphics.FromImage(thumbnailBitmap))
            {
                graphic.InterpolationMode = interpolationMode;
                graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphic.SmoothingMode = SmoothingMode.HighQuality;
                graphic.CompositingMode = CompositingMode.SourceCopy;
                graphic.CompositingQuality = CompositingQuality.HighQuality;

                using (var wrapMode = new System.Drawing.Imaging.ImageAttributes())
                {
                    wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                    graphic.DrawImage(mainImg, rect, 0, 0, mainImg.Width, mainImg.Height, GraphicsUnit.Pixel, wrapMode);
                }
            }

            return thumbnailBitmap;
        }
    }

    public class ThumbnailItem
    {
        public Size Size { get; set; }
        public string ImgUrl { get; set; }
        public Bitmap Bitmap { get; set; }
    }

    public class ThumbnailsData
    {
        private Guid UserId { get; set; }

        public ThumbnailsData(Guid userId)
        {
            UserId = userId;
        }

        public Bitmap MainImgBitmap
        {
            get { return UserPhotoManager.GetPhotoBitmap(UserId); }
        }

        public string MainImgUrl
        {
            get { return UserPhotoManager.GetPhotoAbsoluteWebPath(UserId); }
        }

        public List<ThumbnailItem> ThumbnailList
        {
            get
            {
                return new List<ThumbnailItem>
                    {
                        new ThumbnailItem
                            {
                                Size = UserPhotoManager.RetinaFotoSize,
                                ImgUrl = UserPhotoManager.GetRetinaPhotoURL(UserId)
                            },
                        new ThumbnailItem
                            {
                                Size = UserPhotoManager.MaxFotoSize,
                                ImgUrl = UserPhotoManager.GetMaxPhotoURL(UserId)
                            },
                        new ThumbnailItem
                            {
                                Size = UserPhotoManager.BigFotoSize,
                                ImgUrl = UserPhotoManager.GetBigPhotoURL(UserId)
                            },
                        new ThumbnailItem
                            {
                                Size = UserPhotoManager.MediumFotoSize,
                                ImgUrl = UserPhotoManager.GetMediumPhotoURL(UserId)
                            },
                        new ThumbnailItem
                            {
                                Size = UserPhotoManager.SmallFotoSize,
                                ImgUrl = UserPhotoManager.GetSmallPhotoURL(UserId)
                            }
                    };
            }
        }

        public void Save(List<ThumbnailItem> bitmaps)
        {
            foreach (var item in bitmaps)
                UserPhotoManager.SaveThumbnail(UserId, item.Bitmap, MainImgBitmap.RawFormat);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Classes/NotifyHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Threading;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Notify.Cron;
using ASC.Notify.Messages;
using ASC.Notify.Patterns;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain.Reports;
using ASC.Projects.Core.Services.NotifyService;
using ASC.Projects.Engine;
using ASC.Web.Core.Files;
using ASC.Web.Files.Services.DocumentService;
using ASC.Web.Projects.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Utility;

using Autofac;

namespace ASC.Web.Projects.Classes
{
    public class NotifyHelper
    {
        private static readonly ILog logger;

        static NotifyHelper()
        {
            logger = LogManager.GetLogger("ASC.Web.Projects.Reports");
        }

        public static void SendAutoReminderAboutTask(DateTime state)
        {
            try
            {
                var now = DateTime.UtcNow;
                List<object[]> tasks;

                using (var scope = DIHelper.Resolve(Tenant.DEFAULT_TENANT))
                {
                    var daoFactory = scope.Resolve<IDaoFactory>();
                    tasks = daoFactory.TaskDao.GetTasksForReminder(now);
                }

                foreach (var r in tasks)
                {
                    var tenant = CoreContext.TenantManager.GetTenant((int)r[0]);
                    if (tenant == null ||
                        tenant.Status != TenantStatus.Active ||
                        TariffState.NotPaid <= CoreContext.PaymentManager.GetTariff(tenant.TenantId).State)
                    {
                        continue;
                    }

                    var localTime = TenantUtil.DateTimeFromUtc(tenant.TimeZone, now);
                    if (!TimeToSendReminderAboutTask(localTime)) continue;

                    var deadline = (DateTime)r[2];
                    if (deadline.Date != localTime.Date) continue;

                    try
                    {
                        CoreContext.TenantManager.SetCurrentTenant(tenant);
                        SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);
                        using (var scope = DIHelper.Resolve())
                        {
                            var engineFactory = scope.Resolve<EngineFactory>();
                            var t = engineFactory.TaskEngine.GetByID((int)r[1]);
                            if (t == null) continue;

                            foreach (var responsible in t.Responsibles)
                            {
                                var user = CoreContext.UserManager.GetUsers(t.CreateBy);
                                if (!Constants.LostUser.Equals(user) && user.Status == EmployeeStatus.Active)
                                {
                                    SecurityContext.AuthenticateMe(user.ID);

                                    Thread.CurrentThread.CurrentCulture = user.GetCulture();
                                    Thread.CurrentThread.CurrentUICulture = user.GetCulture();

                                    NotifyClient.Instance.SendReminderAboutTaskDeadline(new List<Guid> { responsible }, t);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.Error("SendAutoReminderAboutTask", ex);
                    }
                }
            }
            catch (Exception ex)
            {
                logger.Error("SendAutoReminderAboutTask", ex);
            }
        }

        private static bool TimeToSendReminderAboutTask(DateTime currentTime)
        {
            var hourToSend = 7;
            if (!string.IsNullOrEmpty(ConfigurationManagerExtension.AppSettings["remindertime"]))
            {
                int hour;
                if (int.TryParse(ConfigurationManagerExtension.AppSettings["remindertime"], out hour))
                {
                    hourToSend = hour;
                }
            }
            return currentTime.Hour == hourToSend;
        }

        public static void SendAutoReports(DateTime datetime)
        {
            try
            {
                var now = DateTime.UtcNow.Date.AddHours(DateTime.UtcNow.Hour);

                List<ReportTemplate> templates;

                using (var scope = DIHelper.Resolve(Tenant.DEFAULT_TENANT))
                {
                    var daoFactory = scope.Resolve<IDaoFactory>();
                    templates = daoFactory.ReportDao.GetAutoTemplates();
                }

                foreach (var tGrouped in templates.GroupBy(r => r.Tenant))
                {
                    try
                    {
                        SendByTenant(now, tGrouped);
                    }
                    catch (Exception e)
                    {
                        LogManager.GetLogger("ASC").Error("SendByTenant", e);
                    }

                }
            }
            catch (Exception ex)
            {
                logger.Error("SendAutoReports", ex);
            }
        }

        public static void SendMsgMilestoneDeadline(DateTime scheduleDate)
        {
            var date = DateTime.UtcNow.AddDays(2);

            List<object[]> milestones;

            using (var scope = DIHelper.Resolve(Tenant.DEFAULT_TENANT))
            {
                var daoFactory = scope.Resolve<IDaoFactory>();
                milestones = daoFactory.MilestoneDao.GetInfoForReminder(date);
            }

            foreach (var r in milestones)
            {
                var tenant = CoreContext.TenantManager.GetTenant((int)r[0]);
                if (tenant == null ||
                    tenant.Status != TenantStatus.Active ||
                    TariffState.NotPaid <= CoreContext.PaymentManager.GetTariff(tenant.TenantId).State)
                {
                    continue;
                }

                var localTime = TenantUtil.DateTimeFromUtc(tenant.TimeZone, date);
                if (localTime.Date == ((DateTime)r[2]).Date)
                {
                    try
                    {
                        CoreContext.TenantManager.SetCurrentTenant(tenant);
                        SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);
                        using (var scope = DIHelper.Resolve())
                        {
                            var m = scope.Resolve<IDaoFactory>().MilestoneDao.GetById((int)r[1]);
                            if (m != null)
                            {
                                var sender = !m.Responsible.Equals(Guid.Empty) ? m.Responsible : m.Project.Responsible;
                                var user = CoreContext.UserManager.GetUsers(sender);
                                if (!Constants.LostUser.Equals(user) && user.Status == EmployeeStatus.Active)
                                {
                                    SecurityContext.AuthenticateMe(user.ID);

                                    Thread.CurrentThread.CurrentCulture = user.GetCulture();
                                    Thread.CurrentThread.CurrentUICulture = user.GetCulture();

                                    NotifyClient.Instance.SendMilestoneDeadline(sender, m);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        logger.Error("SendMsgMilestoneDeadline, tenant: " + tenant.TenantDomain, ex);
                    }
                }
            }
        }

        private static void SendByTenant(DateTime now, IGrouping<int, ReportTemplate> tGrouped)
        {
            var tenant = CoreContext.TenantManager.GetTenant(tGrouped.Key);
            if (tenant == null || tenant.Status != TenantStatus.Active || CoreContext.PaymentManager.GetTariff(tenant.TenantId).State >= TariffState.NotPaid) return;

            CoreContext.TenantManager.SetCurrentTenant(tenant);
            DocbuilderReportsUtility.Terminate(ReportOrigin.ProjectsAuto);

            var timeZone = CoreContext.TenantManager.GetCurrentTenant().TimeZone;

            foreach (var t in tGrouped)
            {
                try
                {
                    SendReport(now, timeZone, t);
                }
                catch (System.Security.SecurityException se)
                {
                    logger.Error("SendAutoReports", se);
                }
                catch (Exception ex)
                {
                    logger.ErrorFormat("TemplateId: {0}, Temaplate: {1}\r\n{2}", t.Id, t.Filter.ToXml(), ex);
                }
            }
        }

        private static void SendReport(DateTime now, TimeZoneInfo timeZone, ReportTemplate t)
        {
            var cron = new CronExpression(t.Cron) { TimeZone = timeZone };
            var date = cron.GetTimeAfter(now.AddTicks(-1));

            LogManager.GetLogger("ASC.Web.Projects.Reports").DebugFormat("Find auto report: {0} - {1}, now: {2}, date: {3}", t.Name, t.Cron, now, date);
            if (date != now) return;

            var user = CoreContext.UserManager.GetUsers(t.CreateBy);
            if (user.ID == Constants.LostUser.ID || user.Status != EmployeeStatus.Active) return;

            SecurityContext.AuthenticateMe(user.ID);

            Thread.CurrentThread.CurrentCulture = user.GetCulture();
            Thread.CurrentThread.CurrentUICulture = user.GetCulture();

            var message = new NoticeMessage(user, HttpUtility.HtmlDecode(t.Name), "", "html");
            message.AddArgument(new TagValue(CommonTags.SendFrom, CoreContext.TenantManager.GetCurrentTenant().Name));
            message.AddArgument(new TagValue(CommonTags.Priority, 1));

            ReportState state;
            var template = t;
            var result = Report.TryCreateReportFromTemplate(t, (s, u) =>
            {
                try
                {
                    if (string.IsNullOrEmpty(s.Exception))
                    {
                        template.SaveDocbuilderReport(s, u);
                    }

                    SendWhenGenerated(s, user);
                }
                catch (Exception e)
                {
                    logger.Error(e);
                }
            }, message, out state, true);

            if (!result)
            {
                SendWhenGenerated(state, user);
            }
        }

        private static void SendWhenGenerated(ReportState state, UserInfo user)
        {
            try
            {
                Thread.CurrentThread.CurrentCulture = user.GetCulture();
                Thread.CurrentThread.CurrentUICulture = user.GetCulture();

                var message = (NoticeMessage)state.Obj;

                message.Body = !string.IsNullOrEmpty(state.Exception) ? state.Exception : string.Format(Resources.ReportResource.AutoGeneratedReportMail, message.Subject, CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.GetFileWebEditorUrl(state.FileId)));

                WorkContext.NotifyContext.DispatchEngine.Dispatch(message, "email.sender");

                logger.DebugFormat("Send auto report: {0} to {1}, tenant: {2}", message.Subject, SecurityContext.CurrentAccount.ID, TenantProvider.CurrentTenantID);
            }
            catch (Exception e)
            {
                logger.Error("SendWhenGenerated", e);
            }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/IMAP_Envelope.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP
{
    #region usings

    using System;
    using System.Collections;
    using System.Text;
    using Mime;
    using MIME;

    #endregion

    /// <summary>
    /// IMAP ENVELOPE STRUCTURE (date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, and message-id).
    ///  Defined in RFC 3501 7.4.2.
    /// </summary>
    public class IMAP_Envelope
    {
        #region Members

        private MailboxAddress[] m_Bcc;
        private MailboxAddress[] m_Cc;
        private DateTime m_Date = DateTime.MinValue;
        private MailboxAddress[] m_From;
        private string m_InReplyTo;
        private string m_MessageID;
        private MailboxAddress[] m_ReplyTo;
        private MailboxAddress m_Sender;
        private string m_Subject;
        private MailboxAddress[] m_To;

        #endregion

        #region Properties

        /// <summary>
        /// Gets header field "<b>Date:</b>" value. Returns DateTime.MinValue if no date or date parsing fails.
        /// </summary>
        public DateTime Date
        {
            get { return m_Date; }
        }

        /// <summary>
        /// Gets header field "<b>Subject:</b>" value. Returns null if value isn't set.
        /// </summary>
        public string Subject
        {
            get { return m_Subject; }
        }

        /// <summary>
        /// Gets header field "<b>From:</b>" value. Returns null if value isn't set.
        /// </summary>
        public MailboxAddress[] From
        {
            get { return m_From; }
        }

        /// <summary>
        /// Gets header field "<b>Sender:</b>" value. Returns null if value isn't set.
        /// </summary>
        public MailboxAddress Sender
        {
            get { return m_Sender; }
        }

        /// <summary>
        /// Gets header field "<b>Reply-To:</b>" value. Returns null if value isn't set.
        /// </summary>
        public MailboxAddress[] ReplyTo
        {
            get { return m_ReplyTo; }
        }

        /// <summary>
        /// Gets header field "<b>To:</b>" value. Returns null if value isn't set.
        /// </summary>
        public MailboxAddress[] To
        {
            get { return m_To; }
        }

        /// <summary>
        /// Gets header field "<b>Cc:</b>" value. Returns null if value isn't set.
        /// </summary>
        public MailboxAddress[] Cc
        {
            get { return m_Cc; }
        }

        /// <summary>
        /// Gets header field "<b>Bcc:</b>" value. Returns null if value isn't set.
        /// </summary>
        public MailboxAddress[] Bcc
        {
            get { return m_Bcc; }
        }

        /// <summary>
        /// Gets header field "<b>In-Reply-To:</b>" value. Returns null if value isn't set.
        /// </summary>
        public string InReplyTo
        {
            get { return m_InReplyTo; }
        }

        /// <summary>
        /// Gets header field "<b>Message-ID:</b>" value. Returns null if value isn't set.
        /// </summary>
        public string MessageID
        {
            get { return m_MessageID; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Construct secified mime entity ENVELOPE string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <returns></returns>
        public static string ConstructEnvelope(MimeEntity entity)
        {
            /* RFC 3501 7.4.2
				ENVELOPE
					A parenthesized list that describes the envelope structure of a
					message.  This is computed by the server by parsing the
					[RFC-2822] header into the component parts, defaulting various
					fields as necessary.

					The fields of the envelope structure are in the following
					order: date, subject, from, sender, reply-to, to, cc, bcc,
					in-reply-to, and message-id.  The date, subject, in-reply-to,
					and message-id fields are strings.  The from, sender, reply-to,
					to, cc, and bcc fields are parenthesized lists of address
					structures.

					An address structure is a parenthesized list that describes an
					electronic mail address.  The fields of an address structure
					are in the following order: personal name, [SMTP]
					at-domain-list (source route), mailbox name, and host name.

					[RFC-2822] group syntax is indicated by a special form of
					address structure in which the host name field is NIL.  If the
					mailbox name field is also NIL, this is an end of group marker
					(semi-colon in RFC 822 syntax).  If the mailbox name field is
					non-NIL, this is a start of group marker, and the mailbox name
					field holds the group name phrase.

					If the Date, Subject, In-Reply-To, and Message-ID header lines
					are absent in the [RFC-2822] header, the corresponding member
					of the envelope is NIL; if these header lines are present but
					empty the corresponding member of the envelope is the empty
					string.
					
						Note: some servers may return a NIL envelope member in the
						"present but empty" case.  Clients SHOULD treat NIL and
						empty string as identical.

						Note: [RFC-2822] requires that all messages have a valid
						Date header.  Therefore, the date member in the envelope can
						not be NIL or the empty string.

						Note: [RFC-2822] requires that the In-Reply-To and
						Message-ID headers, if present, have non-empty content.
						Therefore, the in-reply-to and message-id members in the
						envelope can not be the empty string.

					If the From, To, cc, and bcc header lines are absent in the
					[RFC-2822] header, or are present but empty, the corresponding
					member of the envelope is NIL.

					If the Sender or Reply-To lines are absent in the [RFC-2822]
					header, or are present but empty, the server sets the
					corresponding member of the envelope to be the same value as
					the from member (the client is not expected to know to do
					this).

						Note: [RFC-2822] requires that all messages have a valid
						From header.  Therefore, the from, sender, and reply-to
						members in the envelope can not be NIL.
		 
					ENVELOPE ("date" "subject" from sender reply-to to cc bcc "in-reply-to" "messageID")
			*/

            // NOTE: all header fields and parameters must in ENCODED form !!!

            StringBuilder retVal = new StringBuilder();
            retVal.Append("(");

            // date
            if (entity.Header.Contains("Date:"))
            {
                retVal.Append(TextUtils.QuoteString(MimeUtils.DateTimeToRfc2822(entity.Date)));
            }
            else
            {
                retVal.Append("NIL");
            }

            // subject
            if (entity.Subject != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.Subject)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // from
            if (entity.From != null && entity.From.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // sender	
            //	NOTE: There is confusing part, according rfc 2822 Sender: is MailboxAddress and not AddressList.
            if (entity.Sender != null)
            {
                retVal.Append(" (");

                retVal.Append(ConstructAddress(entity.Sender));

                retVal.Append(")");
            }
            else if (entity.From != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // reply-to
            if (entity.ReplyTo != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.ReplyTo));
            }
            else if (entity.From != null)
            {
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // to
            if (entity.To != null && entity.To.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.To));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // cc
            if (entity.Cc != null && entity.Cc.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.Cc));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // bcc
            if (entity.Bcc != null && entity.Bcc.Count > 0)
            {
                retVal.Append(" " + ConstructAddresses(entity.Bcc));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // in-reply-to			
            if (entity.InReplyTo != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.InReplyTo)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            // message-id
            if (entity.MessageID != null)
            {
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.MessageID)));
            }
            else
            {
                retVal.Append(" NIL");
            }

            retVal.Append(")");

            return retVal.ToString();
        }

        /// <summary>
        /// Parses ENVELOPE from IMAP envelope string.
        /// </summary>
        /// <param name="envelopeString">Envelope string.</param>
        public void Parse(string envelopeString)
        {
            if (envelopeString.StartsWith("("))
            {
                envelopeString = envelopeString.Substring(1);
            }
            if (envelopeString.EndsWith(")"))
            {
                envelopeString = envelopeString.Substring(0, envelopeString.Length - 1);
            }

            string word = "";
            StringReader r = new StringReader(envelopeString);

            #region Date

            // Date
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_Date = DateTime.MinValue;
            }
            else
            {
                try
                {
                    m_Date = MimeUtils.ParseDate(word);
                }
                catch
                {
                    // Failed to parse date, return minimum.
                    m_Date = DateTime.MinValue;
                }
            }

            #endregion

            #region Subject

            // Subject
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_Subject = null;
            }
            else
            {
                m_Subject = MIME_Encoding_EncodedWord.DecodeS(word);
            }

            #endregion

            #region From

            // From
            m_From = ParseAddresses(r);

            #endregion

            #region Sender

            // Sender
            //	NOTE: There is confusing part, according rfc 2822 Sender: is MailboxAddress and not AddressList.
            MailboxAddress[] sender = ParseAddresses(r);
            if (sender != null && sender.Length > 0)
            {
                m_Sender = sender[0];
            }
            else
            {
                m_Sender = null;
            }

            #endregion

            #region ReplyTo

            // ReplyTo
            m_ReplyTo = ParseAddresses(r);

            #endregion

            #region To

            // To
            m_To = ParseAddresses(r);

            #endregion

            #region Cc

            // Cc
            m_Cc = ParseAddresses(r);

            #endregion

            #region Bcc

            // Bcc
            m_Bcc = ParseAddresses(r);

            #endregion

            #region InReplyTo

            // InReplyTo
            r.ReadToFirstChar();
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_InReplyTo = null;
            }
            else
            {
                m_InReplyTo = word;
            }

            #endregion

            #region MessageID

            // MessageID
            r.ReadToFirstChar();
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("Invalid IMAP ENVELOPE structure !");
            }
            if (word.ToUpper() == "NIL")
            {
                m_MessageID = null;
            }
            else
            {
                m_MessageID = word;
            }

            #endregion
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Constructs ENVELOPE addresses structure.
        /// </summary>
        /// <param name="addressList">Address list.</param>
        /// <returns></returns>
        private static string ConstructAddresses(AddressList addressList)
        {
            StringBuilder retVal = new StringBuilder();
            retVal.Append("(");

            foreach (MailboxAddress address in addressList.Mailboxes)
            {
                retVal.Append(ConstructAddress(address));
            }

            retVal.Append(")");

            return retVal.ToString();
        }

        /// <summary>
        /// Constructs ENVELOPE address structure.
        /// </summary>
        /// <param name="address">Mailbox address.</param>
        /// <returns></returns>
        private static string ConstructAddress(MailboxAddress address)
        {
            /* An address structure is a parenthesized list that describes an
			   electronic mail address.  The fields of an address structure
			   are in the following order: personal name, [SMTP]
			   at-domain-list (source route), mailbox name, and host name.
			*/

            // NOTE: all header fields and parameters must in ENCODED form !!!

            StringBuilder retVal = new StringBuilder();
            retVal.Append("(");

            // personal name
            retVal.Append(TextUtils.QuoteString(MimeUtils.EncodeHeaderField(address.DisplayName)));

            // source route, always NIL (not used nowdays)
            retVal.Append(" NIL");

            // mailbox name
            retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(address.LocalPart)));

            // host name
            retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(address.Domain)));

            retVal.Append(")");

            return retVal.ToString();
        }

        /// <summary>
        /// Parses addresses from IMAP ENVELOPE addresses structure.
        /// </summary>
        /// <param name="r"></param>
        /// <returns></returns>
        private MailboxAddress[] ParseAddresses(StringReader r)
        {
            r.ReadToFirstChar();
            if (r.StartsWith("NIL", false))
            {
                // Remove NIL
                r.ReadSpecifiedLength("NIL".Length);

                return null;
            }
            else
            {
                r.ReadToFirstChar();

                // This must be ((address)[*(address)])
                if (!r.StartsWith("("))
                {
                    throw new Exception("Invalid IMAP ENVELOPE structure !");
                }
                else
                {
                    // Read addresses
                    string addressesString = r.ReadParenthesized();

                    ArrayList addresses = new ArrayList();
                    StringReader rAddresses = new StringReader(addressesString.Trim());
                    // Now we have (address)[*(address)], read addresses
                    while (rAddresses.StartsWith("("))
                    {
                        addresses.Add(ParseAddress(rAddresses.ReadParenthesized()));

                        rAddresses.ReadToFirstChar();
                    }

                    MailboxAddress[] retVal = new MailboxAddress[addresses.Count];
                    addresses.CopyTo(retVal);

                    return retVal;
                }
            }
        }

        /// <summary>
        /// Parses address from IMAP ENVELOPE address structure.
        /// </summary>
        /// <param name="addressString">Address structure string.</param>
        /// <returns></returns>
        private MailboxAddress ParseAddress(string addressString)
        {
            /* RFC 3501 7.4.2 ENVELOPE
				An address structure is a parenthesized list that describes an
				electronic mail address.  The fields of an address structure
				are in the following order: personal name, [SMTP]
				at-domain-list (source route), mailbox name, and host name.
			*/

            StringReader r = new StringReader(addressString.Trim());
            string personalName = "";
            string emailAddress = "";

            // personal name
            if (r.StartsWith("NIL", false))
            {
                // Remove NIL
                r.ReadSpecifiedLength("NIL".Length);
            }
            else
            {
                personalName = MIME_Encoding_EncodedWord.DecodeS(r.ReadWord());
            }

            // source route, always NIL (not used nowdays)
            r.ReadWord();

            // mailbox name
            if (r.StartsWith("NIL", false))
            {
                // Remove NIL
                r.ReadSpecifiedLength("NIL".Length);
            }
            else
            {
                emailAddress = r.ReadWord() + "@";
            }

            // host name
            if (r.StartsWith("NIL", false))
            {
                // Remove NIL
                r.ReadSpecifiedLength("NIL".Length);
            }
            else
            {
                emailAddress += r.ReadWord();
            }

            return new MailboxAddress(personalName, emailAddress);
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Resources/TaskResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Projects.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class TaskResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal TaskResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Projects.Resources.TaskResource", typeof(TaskResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Accept Task.
        /// </summary>
        public static string Accept {
            get {
                return ResourceManager.GetString("Accept", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Accept.
        /// </summary>
        public static string AcceptSubtask {
            get {
                return ResourceManager.GetString("AcceptSubtask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add.
        /// </summary>
        public static string Add {
            get {
                return ResourceManager.GetString("Add", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add the first task.
        /// </summary>
        public static string AddFirstTask {
            get {
                return ResourceManager.GetString("AddFirstTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add new subtask.
        /// </summary>
        public static string AddNewSubtask {
            get {
                return ResourceManager.GetString("AddNewSubtask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add new task.
        /// </summary>
        public static string AddNewTask {
            get {
                return ResourceManager.GetString("AddNewTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add subtask.
        /// </summary>
        public static string AddSubtask {
            get {
                return ResourceManager.GetString("AddSubtask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add new task.
        /// </summary>
        public static string AddTask {
            get {
                return ResourceManager.GetString("AddTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All Tasks.
        /// </summary>
        public static string AllTasks {
            get {
                return ResourceManager.GetString("AllTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Assigned to.
        /// </summary>
        public static string AssignedTo {
            get {
                return ResourceManager.GetString("AssignedTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The best way is to return and close subtasks manually, then retry to close the task.
        /// </summary>
        public static string BetterToReturn {
            get {
                return ResourceManager.GetString("BetterToReturn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The best way is to return and close subtasks manually, then retry to close tasks.
        /// </summary>
        public static string BetterToReturnTasks {
            get {
                return ResourceManager.GetString("BetterToReturnTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Responsible.
        /// </summary>
        public static string ByResponsible {
            get {
                return ResourceManager.GetString("ByResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Change Status.
        /// </summary>
        public static string ChangeStatus {
            get {
                return ResourceManager.GetString("ChangeStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose link type.
        /// </summary>
        public static string ChooseLinkType {
            get {
                return ResourceManager.GetString("ChooseLinkType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose the project.
        /// </summary>
        public static string ChooseProject {
            get {
                return ResourceManager.GetString("ChooseProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose task.
        /// </summary>
        public static string ChooseTaskForLink {
            get {
                return ResourceManager.GetString("ChooseTaskForLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string Closed {
            get {
                return ResourceManager.GetString("Closed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed by.
        /// </summary>
        public static string ClosedBy {
            get {
                return ResourceManager.GetString("ClosedBy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closing Date.
        /// </summary>
        public static string ClosingDate {
            get {
                return ResourceManager.GetString("ClosingDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closing Tasks.
        /// </summary>
        public static string ClosingTasks {
            get {
                return ResourceManager.GetString("ClosingTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closing the Task.
        /// </summary>
        public static string ClosingTheTask {
            get {
                return ResourceManager.GetString("ClosingTheTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No comments for this task could be found..
        /// </summary>
        public static string CommentsEmptyScreen_Describe {
            get {
                return ResourceManager.GetString("CommentsEmptyScreen_Describe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No comments found.
        /// </summary>
        public static string CommentsEmptyScreen_Header {
            get {
                return ResourceManager.GetString("CommentsEmptyScreen_Header", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Copy task.
        /// </summary>
        public static string CopyTaskHeader {
            get {
                return ResourceManager.GetString("CopyTaskHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Created by.
        /// </summary>
        public static string CreatedBy {
            get {
                return ResourceManager.GetString("CreatedBy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new link.
        /// </summary>
        public static string CreateNewLink {
            get {
                return ResourceManager.GetString("CreateNewLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creation Date.
        /// </summary>
        public static string CreatingDate {
            get {
                return ResourceManager.GetString("CreatingDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Due date.
        /// </summary>
        public static string DeadLine {
            get {
                return ResourceManager.GetString("DeadLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No tasks matching your filter can be displayed in this section..
        /// </summary>
        public static string DescrEmptyListTaskFilter {
            get {
                return ResourceManager.GetString("DescrEmptyListTaskFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Description.
        /// </summary>
        public static string Description {
            get {
                return ResourceManager.GetString("Description", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each task must have a title.
        /// </summary>
        public static string EachTaskMustHaveTitle {
            get {
                return ResourceManager.GetString("EachTaskMustHaveTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string Edit {
            get {
                return ResourceManager.GetString("Edit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit task.
        /// </summary>
        public static string EditTask {
            get {
                return ResourceManager.GetString("EditTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close all subtasks, then close task.
        /// </summary>
        public static string EndAllSubtasksCloseTask {
            get {
                return ResourceManager.GetString("EndAllSubtasksCloseTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close all subtasks, then close tasks.
        /// </summary>
        public static string EndAllSubtasksCloseTasks {
            get {
                return ResourceManager.GetString("EndAllSubtasksCloseTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Due Date.
        /// </summary>
        public static string EndDate {
            get {
                return ResourceManager.GetString("EndDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Error creating a new link.
        /// </summary>
        public static string ErrorCreateNewLink {
            get {
                return ResourceManager.GetString("ErrorCreateNewLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Follow the task.
        /// </summary>
        public static string FollowTask {
            get {
                return ResourceManager.GetString("FollowTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to the task.
        /// </summary>
        public static string GoToTheTask {
            get {
                return ResourceManager.GetString("GoToTheTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to High.
        /// </summary>
        public static string HighPriority {
            get {
                return ResourceManager.GetString("HighPriority", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Notify responsible.
        /// </summary>
        public static string MessageResponsible {
            get {
                return ResourceManager.GetString("MessageResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The message was sent successfully.
        /// </summary>
        public static string MessageSend {
            get {
                return ResourceManager.GetString("MessageSend", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone.
        /// </summary>
        public static string Milestone {
            get {
                return ResourceManager.GetString("Milestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move tasks to another Milestone.
        /// </summary>
        public static string MoveTasksToAnotherMilestone {
            get {
                return ResourceManager.GetString("MoveTasksToAnotherMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move to milestone.
        /// </summary>
        public static string MoveTasksToMilestone {
            get {
                return ResourceManager.GetString("MoveTasksToMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move task to another Milestone.
        /// </summary>
        public static string MoveTaskToAnotherMilestone {
            get {
                return ResourceManager.GetString("MoveTaskToAnotherMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move to milestone.
        /// </summary>
        public static string MoveToMilestone {
            get {
                return ResourceManager.GetString("MoveToMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to none.
        /// </summary>
        public static string None {
            get {
                return ResourceManager.GetString("None", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nobody.
        /// </summary>
        public static string NoResponsible {
            get {
                return ResourceManager.GetString("NoResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no tasks matching this filter.
        /// </summary>
        public static string NoTasks {
            get {
                return ResourceManager.GetString("NoTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No tasks have been created yet.
        /// </summary>
        public static string NoTasksCreated {
            get {
                return ResourceManager.GetString("NoTasksCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string Open {
            get {
                return ResourceManager.GetString("Open", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Priority.
        /// </summary>
        public static string Priority {
            get {
                return ResourceManager.GetString("Priority", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Project.
        /// </summary>
        public static string Project {
            get {
                return ResourceManager.GetString("Project", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invalid link. Please, make sure that the start and due date are correct..
        /// </summary>
        public static string RelatedLinkInvalid {
            get {
                return ResourceManager.GetString("RelatedLinkInvalid", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Related tasks.
        /// </summary>
        public static string RelatedTask {
            get {
                return ResourceManager.GetString("RelatedTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Interval between start date and end date of two tasks.
        /// </summary>
        public static string RelatedTaskIntervalDesc {
            get {
                return ResourceManager.GetString("RelatedTaskIntervalDesc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no other tasks linked to this task..
        /// </summary>
        public static string RelatedTasksEmptyScreen_Describe {
            get {
                return ResourceManager.GetString("RelatedTasksEmptyScreen_Describe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No linked tasks found.
        /// </summary>
        public static string RelatedTasksEmptyScreen_Header {
            get {
                return ResourceManager.GetString("RelatedTasksEmptyScreen_Header", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete task.
        /// </summary>
        public static string RemoveTask {
            get {
                return ResourceManager.GetString("RemoveTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete this task? .
        /// </summary>
        public static string RemoveTaskPopup {
            get {
                return ResourceManager.GetString("RemoveTaskPopup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete tasks.
        /// </summary>
        public static string RemoveTasks {
            get {
                return ResourceManager.GetString("RemoveTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete this tasks?.
        /// </summary>
        public static string RemoveTasksPopup {
            get {
                return ResourceManager.GetString("RemoveTasksPopup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Responsible users.
        /// </summary>
        public static string Responsibles {
            get {
                return ResourceManager.GetString("Responsibles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show tasks without responsible.
        /// </summary>
        public static string ShowTasksWithoutResponsible {
            get {
                return ResourceManager.GetString("ShowTasksWithoutResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subtask.
        /// </summary>
        public static string Subtask {
            get {
                return ResourceManager.GetString("Subtask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subtasks.
        /// </summary>
        public static string Subtasks {
            get {
                return ResourceManager.GetString("Subtasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No subtasks have been created for this task..
        /// </summary>
        public static string SubtasksEmptyScreen_Describe {
            get {
                return ResourceManager.GetString("SubtasksEmptyScreen_Describe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No subtasks found.
        /// </summary>
        public static string SubtasksEmptyScreen_Header {
            get {
                return ResourceManager.GetString("SubtasksEmptyScreen_Header", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task.
        /// </summary>
        public static string Task {
            get {
                return ResourceManager.GetString("Task", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Description.
        /// </summary>
        public static string TaskDescription {
            get {
                return ResourceManager.GetString("TaskDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Created by.
        /// </summary>
        public static string TaskProducer {
            get {
                return ResourceManager.GetString("TaskProducer", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Assigned to.
        /// </summary>
        public static string TaskResponsible {
            get {
                return ResourceManager.GetString("TaskResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks.
        /// </summary>
        public static string Tasks {
            get {
                return ResourceManager.GetString("Tasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks Count.
        /// </summary>
        public static string TasksCount {
            get {
                return ResourceManager.GetString("TasksCount", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks help the manager distribute all the work evenly among the project participants, set responsible ones for various parts of the project. Start adding tasks, get them done, set who&apos;s responsible, manage team work..
        /// </summary>
        public static string TasksHelpTheManage {
            get {
                return ResourceManager.GetString("TasksHelpTheManage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks help the manager distribute all the work evenly among the project participants, set responsible ones for various parts of the project..
        /// </summary>
        public static string TasksHelpTheManageVisitor {
            get {
                return ResourceManager.GetString("TasksHelpTheManageVisitor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Start date.
        /// </summary>
        public static string TaskStartDate {
            get {
                return ResourceManager.GetString("TaskStartDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string TaskTitle {
            get {
                return ResourceManager.GetString("TaskTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Track time.
        /// </summary>
        public static string TrackTime {
            get {
                return ResourceManager.GetString("TrackTime", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You&apos;re trying to close tasks with open subtasks.
        /// </summary>
        public static string TryingToCloseTasks {
            get {
                return ResourceManager.GetString("TryingToCloseTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You&apos;re trying to close a task with open subtasks.
        /// </summary>
        public static string TryingToCloseTheTask {
            get {
                return ResourceManager.GetString("TryingToCloseTheTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unfollow the task.
        /// </summary>
        public static string UnfollowTask {
            get {
                return ResourceManager.GetString("UnfollowTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unsorted Tasks.
        /// </summary>
        public static string UnsortedTask {
            get {
                return ResourceManager.GetString("UnsortedTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Will be moved to milestone.
        /// </summary>
        public static string WillBeMovedToMilestone {
            get {
                return ResourceManager.GetString("WillBeMovedToMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nobody.
        /// </summary>
        public static string WithoutResponsible {
            get {
                return ResourceManager.GetString("WithoutResponsible", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/SearchEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Web;

using ASC.Common.Logging;
using ASC.Common.Utils;
using ASC.Files.Core;
using ASC.Projects.Core.Domain;
using ASC.Web.Core.Files;
using ASC.Web.Files.Api;
using ASC.Web.Projects.Classes;
using ASC.Web.Projects.Core;

using Autofac;

using IDaoFactory = ASC.Projects.Core.DataInterfaces.IDaoFactory;

namespace ASC.Projects.Engine
{
    [DebuggerDisplay("SearchItem: EntityType = {EntityType}, ID = {ID}, Title = {Title}")]
    public class SearchItem
    {
        public EntityType EntityType { get; private set; }
        public string ItemPath { get; private set; }
        public string ID { get; private set; }
        public string Title { get; private set; }
        public string Description { get; private set; }
        public DateTime CreateOn { get; private set; }
        public SearchItem Container { get; set; }

        public SearchItem(EntityType entityType, string id, string title, DateTime createOn, SearchItem container = null, string desc = "", string itemPath = "")
        {
            Container = container;
            EntityType = entityType;
            ID = id;
            Title = title;
            Description = desc;
            CreateOn = createOn;

            if (!string.IsNullOrEmpty(itemPath))
            {
                ItemPath = ItemPathToAbsolute(itemPath);
            }
            else if (container != null)
            {
                ItemPath = container.ItemPath;
            }
        }

        public SearchItem(ProjectEntity entity)
            : this(entity.EntityType, entity.ID.ToString(CultureInfo.InvariantCulture), entity.Title, entity.CreateOn, new SearchItem(entity.Project), entity.Description, entity.ItemPath)
        {
        }

        public SearchItem(Project entity)
            : this(entity.EntityType, entity.ID.ToString(CultureInfo.InvariantCulture), entity.Title, entity.CreateOn, desc: entity.Description, itemPath: entity.ItemPath)
        {
        }

        public Dictionary<string, object> GetAdditional()
        {
            var result = new Dictionary<string, object>
                             {
                                 { "Type", EntityType },
                                 { "Hint", LocalizedEnumConverter.ConvertToString(EntityType) }
                             };

            if (Container != null)
            {
                result.Add("ContainerValue", Container.Title);
                result.Add("ContainerTitle", LocalizedEnumConverter.ConvertToString(Container.EntityType));
                result.Add("ContainerPath", Container.ItemPath);
            }

            return result;
        }

        private string ItemPathToAbsolute(string itemPath)
        {
            var projectID = ID;
            var container = Container;

            while (true)
            {
                if (container == null) break;

                projectID = container.ID;

                container = container.Container;
            }

            return string.Format(itemPath, VirtualPathUtility.ToAbsolute(PathProvider.BaseVirtualPath), projectID, ID);
        }
    }

    public class SearchEngine
    {
        public IDaoFactory DaoFactory { get; set; }
        public ProjectSecurity ProjectSecurity { get; set; }

        public EngineFactory EngineFactory { get; set; }
        public CommentEngine CommentEngine { get { return EngineFactory.CommentEngine; } }
        public TaskEngine TaskEngine { get { return EngineFactory.TaskEngine; } }

        private readonly List<SearchItem> searchItems;

        public SearchEngine()
        {
            searchItems = new List<SearchItem>();
        }

        public IEnumerable<SearchItem> Search(string searchText, int projectId = 0)
        {
            var queryResult = DaoFactory.SearchDao.Search(searchText, projectId);
            using (var scope = DIHelper.Resolve())
            {
                var projectSecurity = scope.Resolve<ProjectSecurity>();

                foreach (var r in queryResult)
                {
                    switch (r.EntityType)
                    {
                        case EntityType.Project:
                            var project = (Project)r;
                            if (projectSecurity.CanRead(project))
                            {
                                searchItems.Add(new SearchItem(project));
                            }
                            continue;
                        case EntityType.Milestone:
                            var milestone = (Milestone)r;
                            if (projectSecurity.CanRead(milestone))
                            {
                                searchItems.Add(new SearchItem(milestone));
                            }
                            continue;
                        case EntityType.Message:
                            var message = (Message)r;
                            if (projectSecurity.CanRead(message))
                            {
                                searchItems.Add(new SearchItem(message));
                            }
                            continue;
                        case EntityType.Task:
                            var task = (Task)r;
                            if (projectSecurity.CanRead(task))
                            {
                                searchItems.Add(new SearchItem(task));
                            }
                            continue;
                        case EntityType.Comment:
                            var comment = (Comment)r;
                            var entity = CommentEngine.GetEntityByTargetUniqId(comment);
                            if (entity == null) continue;

                            searchItems.Add(new SearchItem(comment.EntityType,
                                comment.ID.ToString(CultureInfo.InvariantCulture), HtmlUtil.GetText(comment.Content),
                                comment.CreateOn, new SearchItem(entity)));
                            continue;
                        case EntityType.SubTask:
                            var subtask = (Subtask)r;
                            var parentTask = TaskEngine.GetByID(subtask.Task);
                            if (parentTask == null) continue;

                            searchItems.Add(new SearchItem(subtask.EntityType,
                                subtask.ID.ToString(CultureInfo.InvariantCulture), subtask.Title, subtask.CreateOn,
                                new SearchItem(parentTask)));
                            continue;
                    }
                }
            }

            try
            {
                // search in files
                var fileEntries = new List<FileEntry>();
                using (var folderDao = FilesIntegration.GetFolderDao())
                using (var fileDao = FilesIntegration.GetFileDao())
                {
                    fileEntries.AddRange(folderDao.Search(searchText, true));
                    fileEntries.AddRange(fileDao.Search(searchText, true));

                    var projectIds = projectId != 0
                                         ? new List<int> { projectId }
                                         : fileEntries.GroupBy(f => f.RootFolderId)
                                               .Select(g => folderDao.GetFolder(g.Key))
                                               .Select(f => f != null ? folderDao.GetBunchObjectID(f.RootFolderId).Split('/').Last() : null)
                                               .Where(s => !string.IsNullOrEmpty(s))
                                               .Select(int.Parse);

                    var rootProject = projectIds.ToDictionary(id => FilesIntegration.RegisterBunch("projects", "project", id.ToString(CultureInfo.InvariantCulture)));
                    fileEntries.RemoveAll(f => !rootProject.ContainsKey(f.RootFolderId));

                    var security = FilesIntegration.GetFileSecurity();
                    fileEntries.RemoveAll(f => !security.CanRead(f));

                    foreach (var f in fileEntries)
                    {
                        var id = rootProject[f.RootFolderId];
                        var project = DaoFactory.ProjectDao.GetById(id);

                        if (ProjectSecurity.CanReadFiles(project))
                        {
                            var itemId = f.FileEntryType == FileEntryType.File
                                             ? FilesLinkUtility.GetFileWebPreviewUrl(f.Title, f.ID)
                                             : Web.Files.Classes.PathProvider.GetFolderUrl((Folder)f, project.ID);
                            searchItems.Add(new SearchItem(EntityType.File, itemId, f.Title, f.CreateOn, new SearchItem(project), itemPath: "{2}"));
                        }
                    }
                }
            }
            catch (Exception err)
            {
                LogManager.GetLogger("ASC").Error(err);
            }
            return searchItems;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/core/asc.mail.utility.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined") {
    ASC = {};
}
if (typeof ASC.Mail === "undefined") {
    ASC.Mail = (function () {
        return {};
    })();
}
if (typeof ASC.Mail.Utility === "undefined") {
    ASC.Mail.Utility = (function () {
        var ResourceJS = ASC.Resources.Master.ResourceJS;
        var parseErrorTypes = {
                None: 0,
                EmptyRecipients: 1,
                IncorrectEmail: 2
            },
            lastSentMessageId = 0;


        function checkCalendarRequirements() {
            if (!window.ICAL)
                throw "Required ICAL module (~/js/third-party/ical.min.js)";

            if (!window.moment)
                throw "Required moment.js module (~/js/third-party/moment.min.js, ~/js/third-party/moment-timezone.min.js)";

            if (!window.RRule)
                throw "Required moment.js module (~/js/third-party/rrule.js, ~/js/third-party/nlp.js)";
        }

        function getAccounts(params) {
            var d = jq.Deferred();

            if (!params.skipAccountsCheck)
                window.Teamlab.getAccounts(params, { success: d.resolve, error: d.reject });
            else
                d.resolve(params, []);

            return d.promise();
        }

        function checkAccounts(params, accounts) {
            function getDefaultAccount(accs) {
                var def = jq.grep(accs, function (a) { return a.is_default === true }),
                    acc = (def.length > 0 ? def[0] : accs[0]);

                return new ASC.Mail.Address(
                    acc.name,
                    acc.email,
                    true);
            }

            var d = jq.Deferred();

            try {
                if (params.skipAccountsCheck) {
                    d.resolve(params);
                    return d.promise();
                }

                var message = params.message;

                if (accounts.length === 0) {
                    throw "No accounts.";
                }

                if (!message.from) {
                    message.from = getDefaultAccount(accounts);
                } else {
                    var found = jq.grep(accounts, function (a) {
                        return  message.from.EqualsByEmail(a.email);
                    });

                    if (found.length === 0) {
                        if (!params.origCalendarEvent.canNotify)
                            throw "From not found in your accounts.";

                        message.from = getDefaultAccount(accounts);
                    }
                    else if (found.length > 1) {
                        throw "Found more then one account by From.";
                    } else if (!found[0].enabled) {
                        throw "Account is disabled.";
                    }
                }

                d.resolve(params);

            } catch (e) {
                d.reject(params, e);
            }

            return d.promise();
        }

        function saveDraft(params) {
            var d = jq.Deferred();

            if (params.skipSave) {
                d.resolve(params, { messageUrl: null, saveSkipped: true });
                return d.promise();
            }

            var message = params.message;

            window.Teamlab.saveMailMessage(
                params,
                message,
                {
                    success: d.resolve,
                    error: d.reject
                });

            return d.promise();
        }

        function saveTemplate(params) {
            var d = jq.Deferred();

            if (params.skipSave) {
                d.resolve(params, { messageUrl: null, saveSkipped: true });
                return d.promise();
            }

            var message = params.message;

            window.Teamlab.saveMailTemplate(
                params,
                message,
                {
                    success: d.resolve,
                    error: d.reject
                });

            return d.promise();
        }

        function afterTemplateSave(params, savedMessage) {
            var d = jq.Deferred();

            if (params.skipSave) {
                d.resolve(params, { messageUrl: null, saveSkipped: true });
                return d.promise();
            }

            var message = params.message;
            message.id = savedMessage.id;

            d.resolve(params, { messageUrl: "/addons/mail/#templateitem/" + message.id });

            return d.promise();
        }

        function afterSave(params, savedMessage) {
            var d = jq.Deferred();

            if (params.skipSave) {
                d.resolve(params, { messageUrl: null, saveSkipped: true });
                return d.promise();
            }

            var message = params.message;
            message.id = savedMessage.id;

            d.resolve(params, { messageUrl: "/addons/mail/#draftitem/" + message.id });

            return d.promise();
        }

        function addDocuments(params, saveResult) {
            function addDoc(fileId) {
                var dfd = jq.Deferred();

                var data = {
                    fileId: fileId,
                    version: ""
                };

                window.Teamlab.addMailDocument(
                    {
                        message: message,
                        documentId: fileId,
                        sendImmediately: params.sendImmediately
                    },
                    message.id,
                    data,
                    {
                        success: function (params, attachedDocument) {
                            message.attachments.push(attachedDocument);
                            message.RemoveDocumentAfterSave(params.documentId);
                            dfd.resolve(params, saveResult);
                        },
                        error: dfd.reject
                    });

                return dfd.promise();
            }

            var d = jq.Deferred();

            if (params.skipSave) {
                d.resolve(params, saveResult);
                return d.promise();
            }

            var message = params.message;

            if (message.HasDocumentsForSave()) {
                var documentIds = message.GetDocumentsForSave();

                var addarray = [];
                for (var i = 0, len = documentIds.length; i < len; i++) {
                    var documentId = documentIds[i];
                    addarray.push(addDoc(documentId));
                }

                jq.when.apply(jq, addarray).done(function () {
                    if (!message.HasDocumentsForSave())
                        d.resolve(params, saveResult);
                    else
                        d.reject(params, "Something goes wrong.");
                })
                .fail(d.reject);

            } else {
                d.resolve(params, saveResult);
            }

            return d.promise();
        }

        function sendDraft(params) {
            var d = jq.Deferred();

            if (params.skipSend) {
                d.resolve(params, -1);
                return d.promise();
            }

            var message = params.message;

            window.Teamlab.sendMailMessage(
                params,
                message,
                {
                    success: d.resolve,
                    error: d.reject
                });

            return d.promise();
        }

        function afterSend(params, messageId) {
            var d = jq.Deferred();

            var sendResult = params.skipSend ?
            { messageUrl: null, sendSkipped: true } :
            { messageUrl: "/addons/mail/#conversation/" + messageId };

            var socket = ASC.SocketIO && !ASC.SocketIO.disabled() ? ASC.SocketIO.Factory.counters : null;

            if (!params.skipSend && (!socket || !socket.connected())) {
                var state = 0;
                if (params.method === "REQUEST")
                    state = 1;
                else if (params.method === "REPLY")
                    state = 2;
                else if (params.method === "CANCEL")
                    state = 3;

                lastSentMessageId = messageId;

                setTimeout(function () {
                    ASC.Mail.Utility._showSignalRMailNotification(state);
                }, 3000);
            }

            if (params.method === "REPLY" && !params.skipCalendarImport) {
                Teamlab.importCalendarEventIcs({}, params.calendarId, params.message.calendarIcs, {
                    success: function() {
                        d.resolve(params, sendResult);
                    },
                    error: d.reject,
                    max_request_attempts: 1
                });
            } else {
                d.resolve(params, sendResult);
            }

            return d.promise();
        }

        function getCalendarEventByUid(params) {
            var d = jq.Deferred();

            Teamlab.getCalendarEventByUid(
                params,
                params.calendarEventUid,
                {
                    success: d.resolve,
                    error: d.reject,
                    max_request_attempts: 1
                });

            return d.promise();
        }

        function checkCalendarValid(params, ical) {
            var d = jq.Deferred();

            try {
                params.origCalendarEvent = ical;

                if (!ical || !ical.mergedIcs)
                    throw "Empty ical";

                var jCalData = window.ICAL.parse(ical.mergedIcs);

                var comp = new window.ICAL.Component(jCalData);
                if (comp.name !== "vcalendar")
                    throw "Unsupported ical type (only vcalendar)";

                var vevent = comp.getFirstSubcomponent("vevent");
                if (!vevent)
                    throw "VEVENT not found";

                var event = new window.ICAL.Event(vevent);

                if (event.uid !== params.calendarEventUid) {
                    throw "No found event by calendarEventUid=\"{0}\"".format(params.calendarEventUid);
                }

                var iCalInfo = {
                    comp: comp,
                    vevent: vevent,
                    event: event,
                    organizerAddress: new ASC.Mail.Address(Encoder.htmlDecode(vevent.getFirstProperty("organizer").getParameter("cn") || ""),
                        event.organizer.toLowerCase().replace("mailto:", "")),
                    calendarTimeZone: ical.timeZone
                };

                var rrule = vevent.getFirstPropertyValue("rrule");

                if (rrule !== null) {
                    iCalInfo.recurrence = ASC.Mail.Utility.ToRRuleRfc2445String(rrule);
                }

                if (!ASC.Mail.Utility.IsValidEmail(iCalInfo.organizerAddress.email)) {
                    throw "Organizer email \"{0}\" is invalid".format(iCalInfo.organizerAddress.email, event.organizer);
                }

                iCalInfo.organizerAddress.isValid = true;

                if (!event.attendees ||
                    event.attendees.length === 0)
                    throw "Unable to find attendees";

                switch (params.method) {
                    case "REQUEST":
                    case "REPLY":
                        if (comp.getFirstPropertyValue("method") !== "REQUEST" &&
                            comp.getFirstPropertyValue("method") !== "REPLY" &&
                            comp.getFirstPropertyValue("method") !== "PUBLISH")
                            throw "Allow only REQUEST";
                        break;
                    case "CANCEL":
                        break;

                    default:
                        throw "Unsupported send method \"{0}\"".format(params.method);
                }

                if (params.method === "REPLY") {
                    var curAttendee = jq.grep(event.attendees, function (a) {
                        return ASC.Mail.Utility.IsEqualEmail(a.getFirstValue().toLowerCase().replace("mailto:", ""), params.attendeeEmail);
                    })[0];

                    if (!curAttendee) {
                        throw "Attendee with email \"{0}\" not found".format(params.attendeeEmail);
                    }

                    if (curAttendee.getParameter("partstat") === params.replyDecision) {
                        throw "Attendee with email \"{0}\" already answered \"{1}\"".format(params.attendeeEmail, params.replyDecision);
                    }

                    iCalInfo.currentAttendee = curAttendee;
                    iCalInfo.currentAttendeeAddress = new ASC.Mail.Address(Encoder.htmlDecode(curAttendee.getParameter("cn") || ""),
                        curAttendee.getFirstValue().toLowerCase().replace("mailto:", ""));

                    if (!ASC.Mail.Utility.IsValidEmail(iCalInfo.currentAttendeeAddress.email)) {
                        throw "Attendee email \"{0}\" is invalid".format(iCalInfo.currentAttendeeAddress.email, iCalInfo.currentAttendee);
                    }

                    iCalInfo.currentAttendeeAddress.isValid = true;
                    params.skipSend = iCalInfo.currentAttendeeAddress.EqualsByEmail(iCalInfo.organizerAddress);
                    if (params.skipSend)
                        params.skipSave = true;

                } else if (params.method === "CANCEL" && params.attendeesEmails) {
                    var cancelAttendees = jq.grep(event.attendees, function (a) {
                        var exists = false;
                        for (var i = 0, len = params.attendeesEmails.length; i < len; i++) {
                            if (ASC.Mail.Utility.IsEqualEmail(a.getFirstValue().toLowerCase().replace("mailto:", ""), params.attendeesEmails[i].toLowerCase())) {
                                exists = true;
                                break;
                            }
                        }

                        return exists;
                    });

                    if (!cancelAttendees)
                        throw "Attendees for cancel not found in event.";

                    iCalInfo.cancelAttendees = cancelAttendees;
                }

                d.resolve(params, iCalInfo);

            } catch (e) {
                d.reject(params, e);
            }

            return d.promise();
        }

        function createBoby(params, iCalInfo) {
            window.moment.locale(ASC.Resources.Master.TwoLetterISOLanguageName);

            var start = window.moment(iCalInfo.event.startDate.toJSDate()),
                end = window.moment(iCalInfo.event.endDate.toJSDate()),
                dateStartAllDay = iCalInfo.event.startDate.isDate,
                dateEndAllDay = iCalInfo.event.endDate.isDate,
                dtStart = iCalInfo.calendarTimeZone && !dateStartAllDay ? start.utcOffset(iCalInfo.calendarTimeZone.offset) : start,
                dtEnd = iCalInfo.calendarTimeZone && !dateEndAllDay ? end.utcOffset(iCalInfo.calendarTimeZone.offset) : end;

            if (dateStartAllDay &&
                dateEndAllDay &&
                start.isBefore(end, 'day')) {
                // Correct end date
                end = end.clone().startOf('day').add(-1, 'day');
                dtEnd = end;
            }

            function getMapUrl(location) {
                if (!location)
                    return '';

                return "https://maps.google.com/maps?q={0}".format(location.split(/[,\s]/).join('+'));
            }

            var info = {
                summary: iCalInfo.event.summary,
                location: iCalInfo.event.location,
                allDay: false,
                orgName: iCalInfo.organizerAddress.name,
                orgEmail: iCalInfo.organizerAddress.email,
                mailToHref: "mailto:" + iCalInfo.organizerAddress.email,
                mapUrl: iCalInfo.event.location ? getMapUrl(iCalInfo.event.location) : null,
                description: iCalInfo.event.description
            };

            info.dateEvent = ASC.Mail.Utility.ToCalendarDateString(dtStart, dtEnd, dateStartAllDay, dateEndAllDay);
            if (iCalInfo.recurrence)
                info.rruleText = ASC.Mail.Utility.ToCalendarRRuleString(iCalInfo.recurrence, dtStart);

            switch (params.method) {
                case "REQUEST":
                    info.action = params.isUpdate ?
                        ResourceJS.MailIcsUpdateDescription :
                        ResourceJS.MailIcsRequestDescription.format(
                        (iCalInfo.organizerAddress.name || iCalInfo.organizerAddress.email) ||
                        (iCalInfo.currentAttendeeAddress.name || iCalInfo.currentAttendeeAddress.email));
                    break;
                case "REPLY":
                    var res;
                    switch (params.replyDecision) {
                        case "ACCEPTED":
                            res = ResourceJS.MailIcsReplyYesDescription;
                            break;
                        case "TENTATIVE":
                            res = ResourceJS.MailIcsReplyMaybeDescription;
                            break;
                        case "DECLINED":
                            res = ResourceJS.MailIcsReplyNoDescription;
                            break;
                        default:
                            throw "Unsupported attendee partstart";
                    }
                    info.action = res.format(iCalInfo.currentAttendeeAddress.name ||
                        iCalInfo.currentAttendeeAddress.email);
                    break;
                case "CANCEL":
                    info.action = ResourceJS.MailIcsCancelDescription;
                    break;
                default:
                    break;
            }

            var body = jq("<div/>").html(
                jq.tmpl('template-mailCalendar', info))
                .prop('outerHTML');

            body = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\
                    <html xmlns=\"http://www.w3.org/1999/xhtml\">\
                        <head>\
                            <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\
                            <link href=\"https://fonts.googleapis.com/css?family=Open+Sans:900,800,700,600,500,400,300&subset=latin,cyrillic-ext,cyrillic,latin-ext\" rel=\"stylesheet\" type=\"text/css\" />\
                            <meta name=\"viewport\" content=\"width=device-width\" />\
                        </head>\
                        <body style=\"margin: 0; padding: 0; text-align: center; width: 100%; font-family: 'Open Sans', Tahoma, Arial; font-size: 14px; color: #333;\">" + body + "</body>\
                    </html>";

            return body;
        }

        function createMessageWithCalendarRequest(params, iCalInfo) {
            var d = jq.Deferred(),
            message = new ASC.Mail.Message();

            var toAddresses = [];
            jq.each(iCalInfo.event.attendees, function (i, a) {
                var email = a.getFirstValue().toLowerCase().replace("mailto:", "");
                var name = a.getParameter("cn") || "";
                if (ASC.Mail.Utility.IsValidEmail(email)) {

                    if (iCalInfo.organizerAddress.EqualsByEmail(email))
                        return true; // skip org email

                    var toAddress = new ASC.Mail.Address(name, email, true);

                    if (params.attendeesEmails) {
                        var found = jq.grep(params.attendeesEmails, function (aEmail) {
                            return toAddress.EqualsByEmail(aEmail);
                        });

                        if (found.length === 0)
                            return true; //continue
                    }

                    toAddresses.push(toAddress);
                }
                return true;
            });

            if (toAddresses.length > 0) {
                var fromAddress = iCalInfo.organizerAddress;

                var subject = params.isUpdate ?
                    ResourceJS.MailIcsUpdateSubject.format(iCalInfo.event.summary) :
                    ResourceJS.MailIcsRequestSubject.format(iCalInfo.event.summary);

                message.from = fromAddress;
                message.to = toAddresses;
                message.subject = subject;
                message.body = createBoby(params, iCalInfo);
                message.calendarIcs = iCalInfo.comp.toString();

                d.resolve(message, params);
            } else {
                d.reject(params, "Empty recipients list (toAddresses)");
            }

            return d.promise();
        }

        function createMessageWithCalendarReply(params, iCalInfo) {
            var d = jq.Deferred();
            var message = new ASC.Mail.Message();
            try {
                iCalInfo.comp.updatePropertyWithValue("prodid", "-//Ascensio System//OnlyOffice Calendar//EN");
                iCalInfo.comp.updatePropertyWithValue("method", params.method);

                iCalInfo.currentAttendee.removeParameter("rsvp");
                iCalInfo.currentAttendee.setParameter("partstat", params.replyDecision);

                var t = window.ICAL.Time.now();

                iCalInfo.vevent.updatePropertyWithValue("dtstamp", t);
                iCalInfo.vevent.updatePropertyWithValue("created", t);
                iCalInfo.vevent.updatePropertyWithValue("last-modified", t);

                iCalInfo.vevent.removeAllProperties("attendee");
                iCalInfo.vevent.addProperty(iCalInfo.currentAttendee);

                var toAddress = iCalInfo.organizerAddress;

                var subject;
                switch (params.replyDecision) {
                    case "ACCEPTED":
                        subject = ResourceJS.MailIcsReplyYesDescription;
                        break;
                    case "TENTATIVE":
                        subject = ResourceJS.MailIcsReplyMaybeDescription;
                        break;
                    case "DECLINED":
                        subject = ResourceJS.MailIcsReplyNoDescription;
                        break;
                    default:
                        throw "Unsupported attendee partstart";
                }
                subject = "{0} \"{1}\"".format(
                    subject.format(iCalInfo.currentAttendeeAddress.name ||
                        iCalInfo.currentAttendeeAddress.email),
                    iCalInfo.event.summary);

                var fromAddress = new ASC.Mail.Address(
                    "",
                    params.attendeeEmail,
                    true);

                message.from = fromAddress;
                message.to = [toAddress];
                message.subject = ResourceJS.MailIcsReplySubject.format(subject);
                message.body = createBoby(params, iCalInfo);
                message.calendarIcs = iCalInfo.comp.toString();

                d.resolve(message, params);
            } catch (e) {
                d.reject(params, e);
            }

            return d.promise();
        }

        function createMessageWithCalendarCancel(params, iCalInfo) {
            var d = jq.Deferred();
            var message = new ASC.Mail.Message();

            iCalInfo.comp.updatePropertyWithValue("prodid", "-//Ascensio System//OnlyOffice Calendar//EN");
            iCalInfo.comp.updatePropertyWithValue("method", params.method);
            iCalInfo.comp.updatePropertyWithValue("status", "CANCELLED");

            var toAddresses = [];
            if (iCalInfo.cancelAttendees) {
                iCalInfo.vevent.removeAllProperties("attendee");
                for (var i = 0, len = iCalInfo.cancelAttendees.length; i < len; i++) {
                    iCalInfo.cancelAttendees[i].removeParameter("rsvp");
                    iCalInfo.cancelAttendees[i].setParameter("partstat", "DECLINED");
                    iCalInfo.vevent.addProperty(iCalInfo.cancelAttendees[i]);
                    toAddresses.push(new ASC.Mail.Address(
                                            iCalInfo.cancelAttendees[i].getParameter("cn"),
                                            iCalInfo.cancelAttendees[i].getFirstValue().toLowerCase().replace("mailto:", ""),
                                            true));
                }
            } else {
                jq.each(iCalInfo.event.attendees, function (i, a) {
                    var email = a.getFirstValue().toLowerCase().replace("mailto:", "");
                    var name = a.getParameter("cn") || "";
                    if (ASC.Mail.Utility.IsValidEmail(email)) {
                        toAddresses.push((new ASC.Mail.Address(name, email, true)));
                    }
                });
            }

            var t = window.ICAL.Time.now();

            iCalInfo.vevent.updatePropertyWithValue("dtstamp", t);
            iCalInfo.vevent.updatePropertyWithValue("created", t);
            iCalInfo.vevent.updatePropertyWithValue("last-modified", t);

            var fromAddress = iCalInfo.organizerAddress;

            message.from = fromAddress;
            message.to = toAddresses;
            message.subject = ResourceJS.MailIcsCancelSubject.format(iCalInfo.event.summary);
            message.body = createBoby(params, iCalInfo);
            message.calendarIcs = iCalInfo.comp.toString();

            d.resolve(message, params);

            return d.promise();
        }

        function sendCalendarRequest(params) {
            var d = jq.Deferred();

            try {
                checkCalendarRequirements();

                if (!params.calendarEventUid)
                    throw "Param 'calendarEventUid' value is empty";

                getCalendarEventByUid(params)
                    .then(checkCalendarValid, d.reject)
                    .then(createMessageWithCalendarRequest, d.reject)
                    .then(ASC.Mail.Utility.SendMessage, d.reject)
                    .then(d.resolve, d.reject);

            } catch (e) {
                d.reject(params, e);
            }

            return d.promise();
        }

        function sendCalendarCancel(params) {
            var d = jq.Deferred();

            try {
                checkCalendarRequirements();

                if (!params.calendarEventUid)
                    throw "Param 'calendarEventUid' value is empty";

                getCalendarEventByUid(params)
                    .then(checkCalendarValid, d.reject)
                    .then(createMessageWithCalendarCancel, d.reject)
                    .then(ASC.Mail.Utility.SendMessage, d.reject)
                    .then(d.resolve, d.reject);

            } catch (e) {
                d.reject(params, e);
            }

            return d.promise();
        }

        return {
            ParseErrorTypes: parseErrorTypes,
            /**
             * Parse addresses from string
             * @param {String} str
             * @return {Object} result with array of addresses and array of errors
             */
            ParseAddresses: function (str) {
                var parsedObjs = {
                    addresses: [],
                    errors: []
                };

                if ("string" !== typeof str || str.length === 0) {
                    parsedObjs.errors.push({ message: "Empty recipients", type: parseErrorTypes.EmptyRecipients, errorItem: null });
                    return parsedObjs;
                }

                function contact2Obj(e) {
                    var t = /^"(.*)"\s*<([^>]+)>$/,
                        n = /^(.*)<([^>]+)>$/,
                        i = e.match(t) || e.match(n);
                    return i ? {
                        name: jq.trim(i[1].replace(/\\"/g, '"').replace(/\\\\/g, "\\")),
                        email: jq.trim(i[2])
                    } : {
                        email: e
                    }
                };

                function obj2Contact(e) {
                    var t = undefined;
                    if (e.email) {
                        t = e.email;
                        e.name && (t = '"' + e.name.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '" <' + t + ">");
                    }
                    return t;
                };

                function parseAndAppend(s) {
                    s = obj2Contact(contact2Obj(s));
                    if (!s)
                        return;
                    var parsed = emailAddresses.parseOneAddress(s);
                    if (parsed) {
                        var isValid = true;
                        if (parsed.domain.indexOf(".") === -1 || !/(^((?!-)[a-zA-Z0-9-]{1,63}\.)+[a-zA-Z]{2,63}\.?$)/.test(parsed.domain)) {
                            isValid = false;
                            parsedObjs.errors.push({ message: "Incorrect domain", type: parseErrorTypes.IncorrectEmail, errorItem: s });
                        }

                        if (parsed.domain.indexOf('[') === 0 && parsed.domain.indexOf(']') === parsed.domain.length - 1) {
                            parsedObjs.errors.push({ message: "Domains as ip adress are not suppoted", type: parseErrorTypes.IncorrectEmail, errorItem: s });
                        }

                        if (!/^[\x00-\x7F]+$/.test(punycode.toUnicode(parsed.domain))) {
                            isValid = false;
                            parsedObjs.errors.push({ message: "Punycode domains are not suppoted", type: parseErrorTypes.IncorrectEmail, errorItem: s });
                        }

                        if (!/^[\x00-\x7F]+$/.test(parsed.local) || !/^([a-zA-Z0-9]+)([_\-\.\+][a-zA-Z0-9]+)*$/.test(parsed.local)) {
                            isValid = false;
                            parsedObjs.errors.push({ message: "Incorrect localpart", type: parseErrorTypes.IncorrectEmail, errorItem: s });
                        }

                        if (/\s+/.test(parsed.local) || parsed.local !== parsed.parts.local.tokens) {
                            isValid = false;
                            parsedObjs.errors.push({ message: "Incorrect, localpart contains spaces", type: parseErrorTypes.IncorrectEmail, errorItem: s });
                        }

                        if (/\s+/.test(parsed.domain) || parsed.domain !== parsed.parts.domain.tokens) {
                            isValid = false;
                            parsedObjs.errors.push({ message: "Incorrect, domain contains spaces", type: parseErrorTypes.IncorrectEmail, errorItem: s });
                        }

                        parsedObjs.addresses.push(new ASC.Mail.Address(parsed.name || "", parsed.address, isValid));
                    } else {
                        var invalidEmail = s.trim();
                        if (invalidEmail) {
                            parsedObjs.addresses.push(new ASC.Mail.Address("", invalidEmail, false));
                            parsedObjs.errors.push({ message: "Incorrect email", type: parseErrorTypes.IncorrectEmail, errorItem: s });
                        }
                    }
                }

                var e = str.replace(/[\s,;]*$/, ",");
                for (var t, i = false, o = 0, a = 0, s = e.length; s > a; a += 1) {
                    switch (e.charAt(a)) {
                        case ",":
                        case ";":
                            if (!i) {
                                t = e.substring(o, a);
                                t = jq.trim(t);
                                if (t) {
                                    parseAndAppend(t);
                                }
                                o = a + 1;
                            }
                            break;
                        case '"':
                            "\\" !== e.charAt(a - 1) && '"' !== e.charAt(a + 1) && (i = !i);
                    }
                }
                if (!parsedObjs.addresses.length) {
                    parseAndAppend(e.replace(/,\s*$/, ""));
                }
                return parsedObjs;
            },
            /**
             * Parse address from string
             * @param {String} str
             * @return {ASC.Mail.Address} result
             */
            ParseAddress: function (str) {
                var parsed = ASC.Mail.Utility.ParseAddresses(str);

                if (parsed.errors.length > 0 ||
                    parsed.addresses.length !== 1) {
                    return new ASC.Mail.Address("", str, false);
                }

                return parsed.addresses[0];
            },
            /**
             * Check email validity
             * @param {String}/{ASC.Mail.Address} email
             * @return {Bool} result
             */
            IsValidEmail: function (email, options) {
                options = options || {
                    nameExistance: false
                }

                if (!options.hasOwnProperty('nameExistance')) {
                    options.nameExistance = false;
                }

                var parsed = ASC.Mail.Utility.ParseAddress(email);

                if (!options.nameExistance && parsed.name)
                    return false;
                    

                return parsed.isValid;
            },
            /**
             * Check domain validity
             * @param {String} domain
             * @return {Bool} result
             */
            IsValidDomainName: function (domain) {
                var parsed = emailAddresses.parseOneAddress("test@" + domain);
                return !!parsed && parsed.domain === domain && domain.indexOf(".") !== -1;
            },
            /**
             * Compare emails
             * @param {String}/{ASC.Mail.Address} email1
             * @param {String}/{ASC.Mail.Address} email2
             * @return {Bool} result
             */
            IsEqualEmail: function(email1, email2) {
                var parsed1 = ASC.Mail.Utility.ParseAddress(email1);
                var parsed2 = ASC.Mail.Utility.ParseAddress(email2);

                if (!parsed1.isValid ||
                    !parsed2.isValid) {
                    return false;
                }

                return parsed1.email === parsed2.email;
            },
            /**
             * Save message to Mail Drafts
             * @param {ASC.Mail.Message} message
             * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
             * @return {Object} result with messageUrl;
             */
            SaveMessageInDrafts: function(message, params) {
                var d = jq.Deferred();

                params = params || { skipAccountsCheck: true };

                try {

                    if (!(message instanceof ASC.Mail.Message)) {
                        throw "Unsupported message format";
                    }

                    if (message.body.length > ASC.Resources.Master.MailMaximumMessageBodySize) {
                        throw "Message body exceeded limit";
                    }

                    if (!params.hasOwnProperty("skipAccountsCheck") || !message.from)
                        params.skipAccountsCheck = false;

                    params.message = message;

                    getAccounts(params)
                        .then(checkAccounts, d.reject)
                        .then(saveDraft, d.reject)
                        .then(afterSave, d.reject)
                        .then(addDocuments, d.reject)
                        .then(d.resolve, d.reject);

                } catch (e) {
                    d.reject(params, e);
                }

                return d.promise();
            },
            /**
            * Save message to Mail Templates
            * @param {ASC.Mail.Message} message
            * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
            * @return {Object} result with messageUrl;
            */
            SaveMessageInTemplates: function (message, params) {
                var d = jq.Deferred();

                params = params || { skipAccountsCheck: true };

                try {

                    if (!(message instanceof ASC.Mail.Message)) {
                        throw "Unsupported message format";
                    }

                    if (message.body.length > ASC.Resources.Master.MailMaximumMessageBodySize) {
                        throw "Message body exceeded limit";
                    }

                    if (!params.hasOwnProperty("skipAccountsCheck") || !message.from)
                        params.skipAccountsCheck = false;

                    params.message = message;

                    getAccounts(params)
                        .then(checkAccounts, d.reject)
                        .then(saveTemplate, d.reject)
                        .then(afterTemplateSave, d.reject)
                        .then(addDocuments, d.reject)
                        .then(d.resolve, d.reject);

                } catch (e) {
                    d.reject(params, e);
                }

                return d.promise();
            },
            /**
             * Send message
             * @param {ASC.Mail.Message} message
             * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
             * @return {Object} result with messageUrl;
             */
            SendMessage: function (message, params) {
                function improveAddresses(addresses) {
                    var result = { addresses: [], hasBad: false };

                    if (!addresses || !addresses.length)
                        return result;

                    if (!jq.isArray(addresses) && ("string" === typeof addresses)) {
                        var p = ASC.Mail.Utility.ParseAddresses(addresses);
                        result.addresses = p.addresses;
                        result.hasBad = p.errors.length > 0;
                        return result;
                    }

                    for (var i = 0, len = addresses.length; i < len; i++) {
                        var a = !(addresses[i] instanceof ASC.Mail.Address)
                            ? ASC.Mail.Utility.ParseAddress(addresses[i])
                            : addresses[i];

                        result.addresses.push(a);

                        if (!a.isValid)
                            result.hasBad = true;
                    }

                    return result;
                }

                var d = jq.Deferred();

                params = params || { skipAccountsCheck: true };

                try {

                    if (!(message instanceof ASC.Mail.Message)) {
                        throw "Unsupported message format";
                    }

                    if (!params.hasOwnProperty("skipAccountsCheck") || !message.from)
                        params.skipAccountsCheck = false;

                    var t = improveAddresses(message.to);
                    message.to = t.addresses;

                    if (!message.to.length && !message.cc.length && !message.bcc.length) {
                        throw "To field is empty";
                    } else if (t.hasBad) {
                        throw "To field contains invalid recipients.";
                    }

                    t = improveAddresses(message.cc);
                    message.cc = t.addresses;

                    if (t.hasBad) {
                        throw "Cc field contains invalid recipients.";
                    }

                    t = improveAddresses(message.bcc);
                    message.bcc = t.addresses;

                    if (t.hasBad) {
                        throw "Bcc field contains invalid recipients.";
                    }

                    ASC.Mail.Utility.SaveMessageInDrafts(message, params)
                        .then(sendDraft, d.reject)
                        .then(afterSend, d.reject)
                        .then(d.resolve, d.reject);

                } catch (e) {
                    d.reject(params, e);
                }

                return d.promise();
            },
            /**
             * Send message with Calendar Request
             * @param {Int} calendarId
             * @param {String} calendarEventUid
             * @param {Array} attendeesEmails
             * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
             * @return {Object} result with messageUrl;
             */
            SendCalendarRequest: function (calendarId, calendarEventUid, attendeesEmails, params) {
                params = params || { skipAccountsCheck: true };
                params.calendarId = calendarId || -1;
                params.calendarEventUid = calendarEventUid;
                params.method = "REQUEST";
                params.skipSave = params.skipSave || true;
                if (attendeesEmails)
                    params.attendeesEmails = attendeesEmails;

                return sendCalendarRequest(params);
            },
            /**
             * Send message with Calendar Update
             * @param {Int} calendarId
             * @param {String} calendarEventUid
             * @param {Array} attendeesEmails
             * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
             * @return {Object} result with messageUrl;
             */
            SendCalendarUpdate: function (calendarId, calendarEventUid, attendeesEmails, params) {
                params = params || { skipAccountsCheck: false };
                params.calendarId = calendarId || -1;
                params.calendarEventUid = calendarEventUid;
                params.method = "REQUEST";
                params.isUpdate = true;
                params.skipSave = params.skipSave || true;
                if (attendeesEmails)
                    params.attendeesEmails = attendeesEmails;

                return sendCalendarRequest(params);
            },
            /**
             * Send message with Calendar Reply
             * @param {Int} calendarId
             * @param {String} calendarEventUid
             * @param {String} attendeeEmail
             * @param {String} attendeeDecision (Support only: ACCEPTED/DECLINED/TENTATIVE)
             * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
             * @return {Object} result with messageUrl;
             */
            SendCalendarReply: function (calendarId, calendarEventUid, attendeeEmail, attendeeDecision, params) {
                var d = jq.Deferred();
                params = params || { skipAccountsCheck: true };
                params.calendarId = calendarId || -1;
                params.calendarEventUid = calendarEventUid;
                params.method = "REPLY";
                params.attendeeEmail = attendeeEmail;
                params.replyDecision = attendeeDecision;
                params.skipSave = params.skipSave || true;

                try {
                    checkCalendarRequirements();

                    if (!calendarEventUid)
                        throw "Param 'calendarEventUid' value is empty", calendarEventUid;

                    if (!attendeeEmail)
                        throw "Param 'attendeeEmail' value is empty", attendeeEmail;

                    if (!attendeeDecision)
                        throw "Param 'attendeeDecision' value is empty", attendeeDecision;

                    if (attendeeDecision !== "ACCEPTED" &&
                        attendeeDecision !== "DECLINED" &&
                        attendeeDecision !== "TENTATIVE")
                        throw "Param 'attendeeDecision' value is invalid (ACCEPTED, DECLINED, TENTATIVE)", attendeeDecision;

                    if (!ASC.Mail.Utility.IsValidEmail(attendeeEmail))
                        throw "Param 'attendeeEmail' value is invalid", attendeeEmail;

                    getCalendarEventByUid(params)
                        .then(checkCalendarValid, d.reject)
                        .then(createMessageWithCalendarReply, d.reject)
                        .then(ASC.Mail.Utility.SendMessage, d.reject)
                        .then(d.resolve, d.reject);

                } catch (e) {
                    d.reject(params, e);
                }

                return d.promise();
            },
            /**
             * Send message with Calendar Reply ics
             * @param {String} calendarEventUid
             * @param {String} calendarEventIcs
             * @param {String} attendeeEmail
             * @param {String} attendeeDecision (Support only: ACCEPTED/DECLINED/TENTATIVE)
             * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
             * @return {Object} result with messageUrl;
             */
            SendCalendarReplyIcs: function (calendarEventUid, calendarEventIcs, attendeeEmail, attendeeDecision, params) {
                var d = jq.Deferred();
                params = params || { skipAccountsCheck: true };
                params.calendarId = -1;
                params.calendarEventUid = calendarEventUid;
                params.method = "REPLY";
                params.attendeeEmail = attendeeEmail;
                params.replyDecision = attendeeDecision;
                params.skipSave = params.skipSave || true;
                params.skipCalendarImport = params.skipCalendarImport || true;

                try {
                    checkCalendarRequirements();

                    if (!calendarEventUid)
                        throw "Param 'calendarEventUid' value is empty", calendarEventUid;

                    if (!attendeeEmail)
                        throw "Param 'attendeeEmail' value is empty", attendeeEmail;

                    if (!attendeeDecision)
                        throw "Param 'attendeeDecision' value is empty", attendeeDecision;

                    if (attendeeDecision !== "ACCEPTED" &&
                        attendeeDecision !== "DECLINED" &&
                        attendeeDecision !== "TENTATIVE")
                        throw "Param 'attendeeDecision' value is invalid (ACCEPTED, DECLINED, TENTATIVE)", attendeeDecision;

                    if (!ASC.Mail.Utility.IsValidEmail(attendeeEmail))
                        throw "Param 'attendeeEmail' value is invalid", attendeeEmail;

                    checkCalendarValid(params, { mergedIcs: calendarEventIcs })
                        .then(createMessageWithCalendarReply, d.reject)
                        .then(ASC.Mail.Utility.SendMessage, d.reject)
                        .then(d.resolve, d.reject);

                } catch (e) {
                    d.reject(params, e);
                }

                return d.promise();
            },
            /**
             * Send message with Calendar Cancel
             * @param {Int} calendarId
             * @param {String} calendarEventUid
             * @param {Array} attendeesEmails
             * @param {Object} params (Example: { skipAccountsCheck: true, skipSave: true });
             * @return {Object} result with messageUrl;
             */
            SendCalendarCancel: function (calendarId, calendarEventUid, attendeesEmails, params) {
                params = params || { skipAccountsCheck: true };
                params.calendarId = calendarId || -1;
                params.calendarEventUid = calendarEventUid;
                params.method = "CANCEL";
                params.skipSave = params.skipSave || true;
                if (attendeesEmails)
                    params.attendeesEmails = attendeesEmails;
                return sendCalendarCancel(params);
            },
            _showSignalRMailNotification: function (state) {
                var module = StudioManager.getCurrentModule();
                if (module !== "mail" && module !== "calendar")
                    return;

                switch (state) {
                    case -1:
                        toastr.error(ResourceJS.MailSendMessageError);

                        if (module === "mail" && window.mailAlerts) { // mail hook
                            window.mailAlerts.check(lastSentMessageId > 0 ? { showFailureOnlyMessageId: lastSentMessageId } : {});
                        }
                        break;
                    case 0:
                        toastr.success(ResourceJS.MailSentMessageText);
                        if (module === "mail" && window.mailAlerts) { // mail hook
                            if (!ASC.Resources.Master.Hub.Url ||
                            (jq.connection && jq.connection.hub.state !== jq.connection.connectionState.connected)) {
                                setTimeout(function() {
                                    window.mailAlerts.check(lastSentMessageId > 0 ? { showFailureOnlyMessageId: lastSentMessageId } : {});
                                }, 5000);
                            }
                        }
                        break;
                    case 1:
                        toastr.success(ResourceJS.MailSentIcalRequestText);
                        break;
                    case 2:
                        toastr.success(ResourceJS.MailSentIcalResponseText);
                        break;
                    case 3:
                        toastr.success(ResourceJS.MailSentIcalCancelText);
                        break;
                    default:
                        break;
                }

                if (module === "mail" && window.messagePage) {
                    window.messagePage.refreshMailAfterSent(state);
                }
            },
            /**
             * Convert Moment DateTimes of calendar event to formated string 
             * @param {Moment DateTime} dtStart
             * @param {Moment DateTime} dtEnd
             * @return {String} formated string;
             */
            ToCalendarDateString: function (dtStart, dtEnd, allDayStart, allDayEnd) {
                checkCalendarRequirements();

                var dateEvent;
                var strStart = dtStart.format("ddd, DD MMM YYYY"),
                    strEnd = dtEnd.format("ddd, DD MMM YYYY"),
                    strStartTime = allDayStart ? "" : dtStart.format("LT"),
                    strEndTime = allDayEnd ? "" : dtEnd.format("LT"),
                    strTz = "(UTC{0})".format(dtStart.format("Z"));

                if (dtStart.isSame(dtEnd, 'day')) {
                    if (allDayStart)
                        dateEvent = "{0}, {1}".format(strStart, ResourceJS.MailIcsCalendarAllDayEventLabel);
                    else
                        dateEvent = "{0}, {1} - {2} {3}".format(strStart, strStartTime, strEndTime, strTz);
                } else {
                    if (allDayStart && allDayEnd) {
                        dateEvent = "{0}, {1} - {2}, {1}".format(strStart, ResourceJS.MailIcsCalendarAllDayEventLabel, strEnd);
                    } else if (allDayStart && !allDayEnd) {
                        dateEvent = "{0}, {1} - {2}, {3} {4}".format(strStart, ResourceJS.MailIcsCalendarAllDayEventLabel, strEnd, strEndTime, strTz);
                    } else if (!allDayStart && allDayEnd) {
                        dateEvent = "{0}, {1} {2} - {3}, {4}".format(strStart, strStartTime, strTz, strEnd, ResourceJS.MailIcsCalendarAllDayEventLabel);
                    } else {
                        dateEvent = "{0}, {1} - {2}, {3} {4}".format(strStart, strStartTime, strEnd, strEndTime, strTz);
                    }
                }

                return dateEvent;
            },
            /**
             * Convert RRule of calendar event to user-friedndly string 
             * @param {String} rruleRfc2445
             * @param {Moment DateTime} dtStart
             * @return {String} user-friedndly string;
             */
            ToCalendarRRuleString: function (rruleRfc2445, dtStart, notLocalize) {
                function getText(id) {
                    switch (id.toLowerCase()) {
                        case "every":
                            return ResourceJS.MailIcsRRuleEveryLabel;
                        case "until":
                            return ResourceJS.MailIcsRRuleUntilLabel;
                        case "for":
                            return ResourceJS.MailIcsRRuleForLabel;
                        case "times":
                            return ResourceJS.MailIcsRRuleTimesLabel;
                        case "time":
                            return ResourceJS.MailIcsRRuleTimeLabel;
                        case "(~ approximate)":
                            return "(~ {0})".format(ResourceJS.MailIcsRRuleApproximateLabel);
                        case "hours":
                            return ResourceJS.MailIcsRRuleHoursLabel;
                        case "hour":
                            return ResourceJS.MailIcsRRuleHourLabel;
                        case "weekdays":
                            return ResourceJS.MailIcsRRuleWeekdaysLabel;
                        case "weekday":
                            return ResourceJS.MailIcsRRuleWeekdayLabel;
                        case "days":
                            return ResourceJS.MailIcsRRuleDaysLabel;
                        case "day":
                            return ResourceJS.MailIcsRRuleDayLabel;
                        case "weeks":
                            return ResourceJS.MailIcsRRuleWeeksLabel;
                        case "week":
                            return ResourceJS.MailIcsRRuleWeekLabel;
                        case "months":
                            return ResourceJS.MailIcsRRuleMonthsLabel;
                        case "month":
                            return ResourceJS.MailIcsRRuleMonthLabel;
                        case "years":
                            return ResourceJS.MailIcsRRuleYearsLabel;
                        case "year":
                            return ResourceJS.MailIcsRRuleYearLabel;
                        case "on":
                            return ResourceJS.MailIcsRRuleOnLabel;
                        case "on the":
                            return ResourceJS.MailIcsRRuleOnTheLabel;
                        case "in":
                            return ResourceJS.MailIcsRRuleInLabel;
                        case "at":
                            return ResourceJS.MailIcsRRuleAtLabel;
                        case "the":
                            return ResourceJS.MailIcsRRuleTheLabel;
                        case "and":
                            return ResourceJS.MailIcsRRuleAndLabel;
                        case "or":
                            return ResourceJS.MailIcsRRuleOrLabel;
                        case "last":
                            return ResourceJS.MailIcsRRuleLastLabel;
                        case "st":
                            return ResourceJS.MailIcsRRuleStLabel;
                        case "nd":
                            return ResourceJS.MailIcsRRuleNdLabel;
                        case "rd":
                            return ResourceJS.MailIcsRRuleRdLabel;
                        case "th":
                            return ResourceJS.MailIcsRRuleThLabel;
                        case "rrule error: unable to fully convert this rrule to text":
                            return ResourceJS.MailIcsRRuleParseErrorLabel;
                        default:
                            return id;
                    }
                }

                checkCalendarRequirements();

                if (!dtStart)
                    dtStart = window.moment();

                try {
                    var options = RRule.parseString(rruleRfc2445);
                    options.dtstart = dtStart.toDate();
                    var rule = new RRule(options);

                    var language = {
                        dayNames: ASC.Resources.Master.DayNames,
                        monthNames: ASC.Resources.Master.MonthNames,
                        tokens: {
                            'SKIP': /^[ \r\n\t]+|^\.$/,
                            'number': /^[1-9][0-9]*/,
                            'numberAsText': /^(one|two|three)/i,
                            'every': /^every/i,
                            'day(s)': /^days?/i,
                            'weekday(s)': /^weekdays?/i,
                            'week(s)': /^weeks?/i,
                            'hour(s)': /^hours?/i,
                            'month(s)': /^months?/i,
                            'year(s)': /^years?/i,
                            'on': /^(on|in)/i,
                            'at': /^(at)/i,
                            'the': /^the/i,
                            'first': /^first/i,
                            'second': /^second/i,
                            'third': /^third/i,
                            'nth': /^([1-9][0-9]*)(\.|th|nd|rd|st)/i,
                            'last': /^last/i,
                            'for': /^for/i,
                            'time(s)': /^times?/i,
                            'until': /^(un)?til/i,
                            'monday': /^mo(n(day)?)?/i,
                            'tuesday': /^tu(e(s(day)?)?)?/i,
                            'wednesday': /^we(d(n(esday)?)?)?/i,
                            'thursday': /^th(u(r(sday)?)?)?/i,
                            'friday': /^fr(i(day)?)?/i,
                            'saturday': /^sa(t(urday)?)?/i,
                            'sunday': /^su(n(day)?)?/i,
                            'january': /^jan(uary)?/i,
                            'february': /^feb(ruary)?/i,
                            'march': /^mar(ch)?/i,
                            'april': /^apr(il)?/i,
                            'may': /^may/i,
                            'june': /^june?/i,
                            'july': /^july?/i,
                            'august': /^aug(ust)?/i,
                            'september': /^sep(t(ember)?)?/i,
                            'october': /^oct(ober)?/i,
                            'november': /^nov(ember)?/i,
                            'december': /^dec(ember)?/i,
                            'comma': /^(,\s*|(and|or)\s*)+/i
                        }
                    };

                    return notLocalize ? rule.toText() : rule.toText(getText, language);
                } catch (e) {
                    console.warn(e);
                }

                return "";
            },
            /**
             * Convert ICAL.RRule to Rfc2445 string 
             * @param {ICAL.RRule} rrule
             * @return {String} rruleRfc2445 string;
             */
            ToRRuleRfc2445String: function (rrule) {
                if (typeof (rrule) !== "object" && !rrule.icaltype && rrule.icaltype !== "recur")
                    throw "not supported rrule param";

                var str = "FREQ=" + rrule.freq;
                if (rrule.count) {
                    str += ";COUNT=" + rrule.count;
                }
                if (rrule.interval > 1) {
                    str += ";INTERVAL=" + rrule.interval;
                }
                for (var k in rrule.parts) {
                    if (rrule.parts.hasOwnProperty(k)) {
                        str += ";" + k + "=" + rrule.parts[k];
                    }
                }
                if (rrule.until) {
                    str += ';UNTIL=' + (rrule.until.isDate
                        ? window.moment(rrule.until.toJSDate()).startOf('day')
                        : window.moment(rrule.until.toJSDate()).utc()).format("YYYYMMDD[T]HHmmss[Z]");
                }
                if ('wkst' in rrule && rrule.wkst !== ICAL.Time.DEFAULT_WEEK_START) {
                    str += ';WKST=' + ICAL.Recur.numericDayToIcalDay(rrule.wkst);
                }
                return str;
            },

            GetDraftUrl: function(fileIds) {
                var url = "/addons/mail/#compose";

                if (!fileIds) return url;

                if (!(fileIds instanceof Array)) {
                    fileIds = [fileIds];
                }

                url += "?files={0}".format(encodeURIComponent(JSON.stringify(fileIds)));

                return url;
            },

            ParseMailTo: function (s) {
                try {
                    var r = {};

                    var email = s.match(/mailto:([^\?]*)/);
                    email = email && email[1] ? email[1] : false;

                    var cc = s.match(/cc=([^&]+)/);
                    cc = cc && cc[1] ? cc[1] : false;

                    var bcc = s.match(/bcc=([^&]+)/);
                    bcc = bcc && bcc[1] ? bcc[1] : false;

                    var subject = s.match(/subject=([^&]+)/);
                    subject = subject && subject[1] ? subject[1].replace(/\+/g, ' ') : false;

                    var body = s.match(/body=([^&]+)/);
                    body = body && body[1] ? body[1].replace(/\+/g, ' ') : false;

                    if (email)
                        r['email'] = email;

                    if (cc)
                        r['cc'] = cc;

                    if (bcc)
                        r['bcc'] = bcc;

                    if (subject)
                        r['subject'] = decodeURIComponent(subject);

                    if (body)
                        r['body'] = decodeURIComponent(body);

                    return r;
                } catch (e) {
                    console.log("Failed ParseMailTo", e);
                }

                return null;
            }
        };
    })();
}

if (typeof ASC.Mail.Message === "undefined") {
    ASC.Mail.Message = function () {
        var docIds = [];

        this.id = 0;
        this.from = "";
        this.to = [];
        this.cc = [];
        this.bcc = [];
        this.subject = "";
        this.body = "";
        this.attachments = [];
        this.mimeReplyToId = "";
        this.importance = false;
        this.tags = [];
        this.fileLinksShareMode = 2; // ASC.Files.Constants.AceStatusEnum.Read;
        this.calendarIcs = "";
        this.requestReceipt = false;
        this.requestRead = false;

        this.HasDocumentsForSave = function () {
            return docIds.length > 0;
        };
        this.AddDocumentsForSave = function (documentIds) {
            jq.merge(docIds, documentIds);
        };
        this.GetDocumentsForSave = function () {
            return docIds;
        };
        this.RemoveDocumentAfterSave = function (documentId) {
            var pos = -1, i, len = docIds.length;
            for (i = 0; i < len; i++) {
                var docId = docIds[i];
                if (docId === documentId) {
                    pos = i;
                    break;
                }
            }
            if (pos > -1)
                docIds.splice(pos, 1);
        };
        this.ToData = function () {

            function convertAddress(addr) {
                if (typeof (addr) === "object" &&
                    !(addr instanceof ASC.Mail.Address) &&
                    addr.hasOwnProperty("name") &&
                    addr.hasOwnProperty("email") &&
                    addr.hasOwnProperty("isValid"))
                {
                    addr = new ASC.Mail.Address(addr.name, addr.email, addr.isValid);
                }

                return (addr instanceof ASC.Mail.Address) ?
                    addr.ToString() :
                    addr;
            }

            function convertAddresses(addresses) {
                return addresses.map(convertAddress);
            }

            var json = JSON.stringify(this);
            var data = JSON.parse(json);

            data.from = convertAddress(data.from);
            data.to = convertAddresses(data.to);
            data.cc = convertAddresses(data.cc);
            data.bcc = convertAddresses(data.bcc);

            return data;
        };
    };

    if (typeof ASC.Mail.Address === "undefined") {
        ASC.Mail.Address = function (name, email, isValid) {
            this.name = name || "";
            this.email = email;
            this.isValid = isValid;

            function quote(text) {
                if (!text)
                    return "";

                var quoted = "\"";
                for (var i = 0, len = text.length; i < len; i++) {
                    var t = text[i];
                    if (t === '\\' || t === '"')
                        quoted += '\\';
                    quoted += t;
                }
                quoted += "\"";
                return quoted;
            }

            this.ToString = function(skipQuotes) {
                var s = !this.name
                    ? this.email
                    : !skipQuotes 
                        ? quote(this.name) + " <" + this.email + ">"
                        : this.name + " <" + this.email + ">";
                return s;
            };

            this.Equals = function(addr) {
                if (typeof (addr) === "object" && (addr instanceof ASC.Mail.Address)) {
                    return this === addr;
                }
                else if (typeof (addr) === "string") {
                    var parsed = ASC.Mail.Utility.ParseAddress(addr);
                    return this.email === parsed;
                }

                return false;
            }

            this.EqualsByEmail = function (addr) {
                if (typeof (addr) === "object" && (addr instanceof ASC.Mail.Address)) {
                    return this.email.toLowerCase() === addr.email.toLowerCase();
                }
                else if (typeof (addr) === "string") {
                    var parsed = ASC.Mail.Utility.ParseAddress(addr);
                    return this.email.toLowerCase() === parsed.email.toLowerCase();
                }

                return false;
            }
        }
    };
}

if (typeof ASC.Mail.Sanitizer === "undefined") {
    ASC.Mail.Sanitizer = (function() {
        function checkOptions(options) {
            options = options || {
                urlProxyHandler: "",
                needProxyHttp: false,
                loadImages: true,
                baseHref: window.location.origin
            }

            if (!options.hasOwnProperty("urlProxyHandler") || options.urlProxyHandler.length === 0) {
                options.urlProxyHandler = "";
                options.needProxyHttp = false;
            }

            if (!options.hasOwnProperty("needProxyHttp")) {
                options.needProxyHttp = false;
            }

            if (!options.hasOwnProperty("loadImages")) {
                options.loadImages = true;
            }

            if (!options.hasOwnProperty("baseHref")) {
                options.baseHref = window.location.origin;
            }

            return options;
        }

        // specify the regex to detect external content
        var regex = /(url\("?)(?!data:)/gim;

        /**
         *  Take CSS property-value pairs and proxy URLs in values,
         *  then add the styles to an array of property-value pairs
         */
        function addStyles(output, styles, options) {
            for (var prop = styles.length - 1; prop >= 0; prop--) {
                if (styles[styles[prop]] && options.needProxyHttp) {
                    var url = styles[styles[prop]].replace(regex, '$1' + options.urlProxyHandler);
                    styles[styles[prop]] = url;
                }
                if (styles[styles[prop]]) {
                    output.push(styles[prop] + ':' + styles[styles[prop]] + ';');
                }
            }
        }

        /**
         * Take CSS rules and analyze them, proxy URLs via addStyles(),
         * then create matching CSS text for later application to the DOM
         */
        function addCssRules(output, cssRules, options) {
            for (var index = cssRules.length - 1; index >= 0; index--) {
                var rule = cssRules[index];
                // check for rules with selector
                if (rule.type === 1 && rule.selectorText) {
                    output.push(rule.selectorText + '{');
                    if (rule.style) {
                        addStyles(output, rule.style, options);
                    }
                    output.push('}');
                    // check for @media rules
                } else if (rule.type === rule.MEDIA_RULE) {
                    output.push('@media ' + rule.media.mediaText + '{');
                    addCssRules(output, rule.cssRules, options);
                    output.push('}');
                    // check for @font-face rules
                } else if (rule.type === rule.FONT_FACE_RULE) {
                    output.push('@font-face {');
                    if (rule.style) {
                        addStyles(output, rule.style, options);
                    }
                    output.push('}');
                    // check for @keyframes rules
                } else if (rule.type === rule.KEYFRAMES_RULE) {
                    output.push('@keyframes ' + rule.name + '{');
                    for (var i = rule.cssRules.length - 1; i >= 0; i--) {
                        var frame = rule.cssRules[i];
                        if (frame.type === 8 && frame.keyText) {
                            output.push(frame.keyText + '{');
                            if (frame.style) {
                                addStyles(output, frame.style, options);
                            }
                            output.push('}');
                        }
                    }
                    output.push('}');
                }
            }
        }

        function isForbiddenStyle(styleName, styleValue) {
            styleName = (styleName || "").trim().toLowerCase();
            styleValue = (styleValue || "").trim().toLowerCase();

            switch (styleName) {
                case "position":
                case "left":
                case "top":
                case "right":
                case "bottom":
                    return true;
                case "margin-left":
                case "margin-top":
                case "margin-rigth":
                case "margin-bottom":
                    return styleValue.indexOf("-") !== -1;
                default:
                    return false;
            }
        }

        function sanitize(html, options) {
            checkOptions(options);

            var result = {
                html: html,
                imagesBlocked: false,
                sanitized: false,
                httpProxied: false
            };

            if (!html)
                return result;

            // Proxy a URL in case it's not a Data URI
            function proxyAttribute(url) {
                if (!options.needProxyHttp)
                    return url;

                if (/^data:image\//.test(url)) {
                    return url;
                } else {
                    result.httpProxied = true;
                    return options.urlProxyHandler + encodeURIComponent(url);
                }
            }

            // Add a hook to enforce proxy for leaky CSS rules
            window.DOMPurify.addHook("uponSanitizeElement", function (node, data) {
                if (data.tagName === "style") {
                    var output = [];
                    if (node && node.sheet && node.sheet.cssRules) {
                        addCssRules(output, node.sheet.cssRules, options);
                    }
                    node.textContent = output.join("\n");
                }
                else if (node.className === "MsoNormal") {
                    node.setAttribute("style", "margin: 0cm; margin-bottom: .0001pt");
                }
            });

            window.DOMPurify.addHook("afterSanitizeAttributes", function (node) {
                // set all elements owning target to target=_blank
                if (node.hasOwnProperty("target")) {
                    node.setAttribute("target", "_blank");
                }

                // Check all style attribute values and proxy them
                if (node.hasAttribute("style")) {
                    var styles = node.style;
                    var output = [];
                    for (var prop = styles.length - 1; prop >= 0; prop--) {
                        var styleName = styles[prop],
                            styleValue = node.style[styleName];

                        // we re-write each property-value pair to remove invalid CSS
                        if (styleValue && regex.test(styleValue)) {
                            if (options.needProxyHttp) {
                                var url = styleValue.replace(regex, '$1' + options.urlProxyHandler);
                                result.httpProxied = true;
                                node.style[styleName] = url;
                            }
                        }

                        if (isForbiddenStyle(styleName, styleValue)) {
                            continue;
                        }

                        if (!options.loadImages &&
                        (styleName === "background-image" || styleName === "background")) {
                            styleName = "tl_disabled_" + styleName;
                            result.imagesBlocked = true;
                        }

                        output.push(styleName + ':' + styleValue + ';');
                    }
                    // re-add styles in case any are left
                    if (output.length) {
                        node.setAttribute('style', output.join(""));
                    } else {
                        node.removeAttribute('style');
                    }
                }
                var newSrcVal;
                if (node.hasAttribute("src")) {
                    if (!options.loadImages) {
                        newSrcVal = proxyAttribute(node.getAttribute("src"));

                        if (newSrcVal) {
                            node.removeAttribute("src");
                            node.setAttribute("tl_disabled_src", newSrcVal);
                            result.imagesBlocked = true;

                        }
                    }
                }

                if (node.hasAttribute("background")) {
                    if (!options.loadImages) {
                        newSrcVal = proxyAttribute(node.getAttribute("background"));

                        if (newSrcVal) {
                            node.removeAttribute("background");
                            node.setAttribute("tl_disabled_background", newSrcVal);
                            result.imagesBlocked = true;
                        }
                    }
                }
            });

            var clean = window.DOMPurify.sanitize(html,
            {
                ALLOWED_URI_REGEXP:
                    /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|blob|xmpp|data):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,// eslint-disable-line no-useless-escape
                FORBID_TAGS: ['style', 'input', 'form', 'title', 'iframe', 'meta'],
                FORBID_ATTR: ['srcset', 'action']
            });

            result.html = clean;
            result.sanitized = true;

            window.DOMPurify.removeHook("afterSanitizeAttributes");
            window.DOMPurify.removeHook("uponSanitizeElement");

            return result;
        }

        return {
            Sanitize: function(html, options) {
                try {
                    return sanitize(html, options);
                } catch (e) {
                    var error = "Failed ASC.Mail.Sanitizer.Sanitize: {0}".format(e);
                    console.error(error, e);
                    html = error;
                }
                return {
                    html: html,
                    imagesBlocked: false,
                    sanitized: false,
                    httpProxied: false
                };
            }
        };
    })();
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/News/Code/DAO/IFeedStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

namespace ASC.Web.Community.News.Code.DAO
{
    public interface IFeedStorage : IDisposable
    {
        List<FeedType> GetUsedFeedTypes();


        List<Feed> GetFeeds(FeedType feedType, Guid userId, int count, int offset);

        List<Feed> SearchFeeds(string s, FeedType feedType, Guid userId, int count, int offset);

        long GetFeedsCount(FeedType feedType, Guid userId);

        long SearchFeedsCount(string s, FeedType feedType, Guid userId);

        List<Feed> SearchFeeds(string s);

        Feed GetFeed(long id);

        List<Feed> GetFeedByDate(DateTime from, DateTime to, Guid userId);

        List<FeedComment> GetCommentsByDate(DateTime from, DateTime to);

        Feed SaveFeed(Feed feed, bool isEdit, FeedType poll);

        void RemoveFeed(Feed feed);

        void ReadFeed(long feedId, string reader);

        void PollVote(string userId, ICollection<long> variantIds);


        List<FeedComment> GetFeedComments(long feedId);

        FeedComment GetFeedComment(long commentId);

        void RemoveFeedComment(long commentId);
        FeedComment SaveFeedComment(Feed feed, FeedComment comment);
        void RemoveFeedComment(FeedComment comment);
        void UpdateFeedComment(FeedComment comment);
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Classes/RegisterClientScriptHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web;
using System.Web.UI;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.FederatedLogin.LoginProviders;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.CRM.Configuration;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.Core;

using Newtonsoft.Json;

#endregion

namespace ASC.Web.CRM.Classes
{
    public static class RegisterClientScriptHelper
    {
        private static bool IsTwitterSearchEnabled
        {
            get
            {
                return TwitterLoginProvider.Instance.IsEnabled
                && !string.IsNullOrEmpty(TwitterLoginProvider.TwitterDefaultAccessToken)
                && !string.IsNullOrEmpty(TwitterLoginProvider.TwitterAccessTokenSecret);
            }
        }


        public static void DataCommon(Page page)
        {
        }

        public static void DataUserSelectorListView(BasePage page, String ObjId, Dictionary<Guid, String> SelectedUsers)
        {
            var ids = SelectedUsers != null && SelectedUsers.Count > 0 ? SelectedUsers.Select(i => i.Key).ToArray() : new List<Guid>().ToArray();
            var names = SelectedUsers != null && SelectedUsers.Count > 0 ? SelectedUsers.Select(i => i.Value).ToArray() : new List<string>().ToArray();

            page.RegisterInlineScript(String.Format(" SelectedUsers{0} = {1}; ",
                                                        ObjId,
                                                        JsonConvert.SerializeObject(
                                                            new
                                                            {
                                                                IDs = ids,
                                                                Names = names,
                                                                DeleteImgSrc = WebImageSupplier.GetAbsoluteWebPath("remove_12.png", ProductEntryPoint.ID),
                                                                DeleteImgTitle = CRMCommonResource.DeleteUser,
                                                                CurrentUserID = SecurityContext.CurrentAccount.ID
                                                            })), onReady: false);
        }

        #region Data for History View

        public static void DataHistoryView(BasePage page, List<Guid> UserList)
        {
            page.RegisterInlineScript(String.Format(" var historyView_dateTimeNowShortDateString = '{0}'; ", TenantUtil.DateTimeNow().ToShortDateString()), onReady: false);

            if (UserList != null)
            {
                page.RegisterInlineScript(String.Format(" UserList_HistoryUserSelector = {0}; ", JsonConvert.SerializeObject(UserList)), onReady: false);
            }

            RegisterClientScriptHelper.DataUserSelectorListView(page, "_HistoryUserSelector", null);
        }

        #endregion

        #region Data for Contact Views

        public static void DataListContactTab(BasePage page, Int32 entityID, EntityType entityType)
        {
            page.RegisterInlineScript(String.Format(" var entityData = {0}; ",
                                            JsonConvert.SerializeObject(new
                                            {
                                                id = entityID,
                                                type = entityType.ToString().ToLower()
                                            })), onReady: false);
        }

        public static void DataContactFullCardView(BasePage page, Contact targetContact)
        {
            var daoFactory = page.DaoFactory;

            List<CustomField> data;

            if (targetContact is Company)
                data = daoFactory.CustomFieldDao.GetEntityFields(EntityType.Company, targetContact.ID, false);
            else
                data = daoFactory.CustomFieldDao.GetEntityFields(EntityType.Person, targetContact.ID, false);

            var networks =
                daoFactory.ContactInfoDao.GetList(targetContact.ID, null, null, null)
                    .OrderBy(i => i.IsPrimary).ToList()
                    .ConvertAll(
                        n => new
                        {
                            data = n.Data.HtmlEncode(),
                            infoType = n.InfoType,
                            isPrimary = n.IsPrimary,
                            categoryName = n.CategoryToString(),
                            infoTypeLocalName = n.InfoType.ToLocalizedString()
                        });

            String json;
            using (var stream = new MemoryStream())
            {
                var serializer = new DataContractJsonSerializer(data.GetType());
                serializer.WriteObject(stream, data);
                json = Encoding.UTF8.GetString(stream.ToArray());
            }

            var listItems = daoFactory.ListItemDao.GetItems(ListType.ContactStatus);

            var tags = daoFactory.TagDao.GetEntityTags(EntityType.Contact, targetContact.ID);
            var availableTags = daoFactory.TagDao.GetAllTags(EntityType.Contact).Where(item => !tags.Contains(item));
            var responsibleIDs = CRMSecurity.GetAccessSubjectGuidsTo(targetContact);

            var script = String.Format(@"
                        var customFieldList = {0};
                        var contactNetworks = {1};
                        var sliderListItems = {2};
                        var contactTags = {3};
                        var contactAvailableTags = {4};
                        var contactResponsibleIDs = {5}; ",
                json,
                JsonConvert.SerializeObject(networks),
                JsonConvert.SerializeObject(new
                {
                    id = targetContact.ID,
                    status = targetContact.StatusID,
                    positionsCount = listItems.Count,
                    items = listItems.ConvertAll(n => new
                    {
                        id = n.ID,
                        color = n.Color,
                        title = n.Title.HtmlEncode()
                    })
                }),
                JsonConvert.SerializeObject(tags.ToList().ConvertAll(t => t.HtmlEncode())),
                JsonConvert.SerializeObject(availableTags.ToList().ConvertAll(t => t.HtmlEncode())),
                JsonConvert.SerializeObject(responsibleIDs)
                );

            page.RegisterInlineScript(script, onReady: false);
        }

        public static void DataContactActionView(BasePage page, Contact targetContact, List<CustomField> data, List<ContactInfo> networks)
        {
            var daoFactory = page.DaoFactory;

            var tags = targetContact != null ? daoFactory.TagDao.GetEntityTags(EntityType.Contact, targetContact.ID) : new string[] { };
            var availableTags = daoFactory.TagDao.GetAllTags(EntityType.Contact).Where(item => !tags.Contains(item));

            String json;
            using (var stream = new MemoryStream())
            {
                var serializer = new DataContractJsonSerializer(data.GetType());
                serializer.WriteObject(stream, data);
                json = Encoding.UTF8.GetString(stream.ToArray());
            }

            var listItems = daoFactory.ListItemDao.GetItems(ListType.ContactType);

            var presetCompanyForPersonJson = "";
            if (targetContact != null && targetContact is Person && ((Person)targetContact).CompanyID > 0)
            {
                var company = daoFactory.ContactDao.GetByID(((Person)targetContact).CompanyID);
                if (company == null)
                {
                    LogManager.GetLogger("ASC.CRM").ErrorFormat("Can't find parent company (CompanyID = {0}) for person with ID = {1}", ((Person)targetContact).CompanyID, targetContact.ID);
                }
                else
                {
                    presetCompanyForPersonJson = JsonConvert.SerializeObject(new
                    {
                        id = company.ID,
                        displayName = company.GetTitle().HtmlEncode().ReplaceSingleQuote().Replace(@"\", @"\\"),
                        smallFotoUrl = ContactPhotoManager.GetSmallSizePhoto(company.ID, true)
                    });
                }
            }

            var presetPersonsForCompanyJson = "";
            if (targetContact != null && targetContact is Company)
            {
                var people = daoFactory.ContactDao.GetMembers(targetContact.ID);
                if (people.Count != 0)
                {
                    presetPersonsForCompanyJson = JsonConvert.SerializeObject(people.ConvertAll(item => new
                    {
                        id = item.ID,
                        displayName = item.GetTitle().HtmlEncode().ReplaceSingleQuote().Replace(@"\", @"\\"),
                        smallFotoUrl = ContactPhotoManager.GetSmallSizePhoto(item.ID, false)
                    }));
                }
            }

            var script = String.Format(@"
                                var customFieldList = {0};
                                var contactNetworks = {1};
                                var contactActionTags = {2};
                                var contactActionAvailableTags = {3};
                                var contactAvailableTypes = {4};
                                var presetCompanyForPersonJson = '{5}';
                                var presetPersonsForCompanyJson = '{6}';
                                var twitterSearchEnabled = {7};
                                var contactActionCurrencies = {8};",
                              json,
                              JsonConvert.SerializeObject(networks),
                              JsonConvert.SerializeObject(tags.ToList().ConvertAll(t => t.HtmlEncode())),
                              JsonConvert.SerializeObject(availableTags.ToList().ConvertAll(t => t.HtmlEncode())),
                              JsonConvert.SerializeObject(
                                    listItems.ConvertAll(n => new
                                    {
                                        id = n.ID,
                                        title = n.Title.HtmlEncode()
                                    })),
                              presetCompanyForPersonJson,
                              presetPersonsForCompanyJson,
                              IsTwitterSearchEnabled.ToString().ToLower(),
                              JsonConvert.SerializeObject(CurrencyProvider.GetAll())
                              );

            page.RegisterInlineScript(script, onReady: false);
        }

        #endregion

        #region Data for Task Views

        public static void DataContactDetailsViewForTaskAction(BasePage page, Contact TargetContact)
        {
            var isPrivate = !CRMSecurity.CanAccessTo(TargetContact);
            var contactAccessList = new List<Guid>();
            if (isPrivate)
            {
                contactAccessList = CRMSecurity.GetAccessSubjectTo(TargetContact).Keys.ToList<Guid>();
            }

            page.RegisterInlineScript(String.Format(" var contactForInitTaskActionPanel = {0}; ",
                                                    JsonConvert.SerializeObject(new
                                                    {
                                                        id = TargetContact.ID,
                                                        displayName = TargetContact.GetTitle().HtmlEncode().ReplaceSingleQuote(),
                                                        smallFotoUrl = ContactPhotoManager.GetSmallSizePhoto(TargetContact.ID, TargetContact is Company),
                                                        isPrivate = isPrivate,
                                                        accessList = contactAccessList.ConvertAll(n => new { id = n })
                                                    })), onReady: false);
        }

        #endregion

        #region Data for Cases Views

        public static void DataCasesFullCardView(BasePage page, ASC.CRM.Core.Entities.Cases targetCase)
        {
            var daoFactory = page.DaoFactory;
            var customFieldList = daoFactory.CustomFieldDao.GetEntityFields(EntityType.Case, targetCase.ID, false);
            var tags = daoFactory.TagDao.GetEntityTags(EntityType.Case, targetCase.ID);
            var availableTags = daoFactory.TagDao.GetAllTags(EntityType.Case).Where(item => !tags.Contains(item));
            var responsibleIDs = new List<Guid>();
            if (CRMSecurity.IsPrivate(targetCase))
            {
                responsibleIDs = CRMSecurity.GetAccessSubjectGuidsTo(targetCase);
            }
            var script = String.Format(@"
                                        var caseTags = {0};
                                        var caseAvailableTags = {1};
                                        var caseResponsibleIDs = {2}; ",
                                    JsonConvert.SerializeObject(tags.ToList().ConvertAll(t => t.HtmlEncode())),
                                    JsonConvert.SerializeObject(availableTags.ToList().ConvertAll(t => t.HtmlEncode())),
                                    JsonConvert.SerializeObject(responsibleIDs));

            page.RegisterInlineScript(script, onReady: false);
            page.JsonPublisher(customFieldList, "casesCustomFieldList");
        }

        public static void DataCasesActionView(BasePage page, ASC.CRM.Core.Entities.Cases targetCase)
        {
            var daoFactory = page.DaoFactory;
            var customFieldList = targetCase != null
                ? daoFactory.CustomFieldDao.GetEntityFields(EntityType.Case, targetCase.ID, true)
                : daoFactory.CustomFieldDao.GetFieldsDescription(EntityType.Case);
            var tags = targetCase != null ? daoFactory.TagDao.GetEntityTags(EntityType.Case, targetCase.ID) : new string[] { };
            var availableTags = daoFactory.TagDao.GetAllTags(EntityType.Case).Where(item => !tags.Contains(item));


            var presetContactsJson = "";
            var selectedContacts = new List<Contact>();
            if (targetCase != null)
            {
                selectedContacts = daoFactory.ContactDao.GetContacts(daoFactory.CasesDao.GetMembers(targetCase.ID));
            }
            else
            {
                var URLContactID = UrlParameters.ContactID;
                if (URLContactID != 0)
                {
                    var target = daoFactory.ContactDao.GetByID(URLContactID);
                    if (target != null)
                    {
                        selectedContacts.Add(target);
                    }
                }
            }

            if (selectedContacts.Count > 0)
            {
                presetContactsJson = JsonConvert.SerializeObject(selectedContacts.ConvertAll(item => new
                {
                    id = item.ID,
                    displayName = item.GetTitle().HtmlEncode().ReplaceSingleQuote().Replace(@"\", @"\\"),
                    smallFotoUrl = ContactPhotoManager.GetSmallSizePhoto(item.ID, item is Company)
                }));
            }

            var script = String.Format(@"
                                        var casesActionTags = {0};
                                        var casesActionAvailableTags = {1};
                                        var casesActionSelectedContacts = '{2}'; ",
                                    JsonConvert.SerializeObject(tags.ToList().ConvertAll(t => t.HtmlEncode())),
                                    JsonConvert.SerializeObject(availableTags.ToList().ConvertAll(t => t.HtmlEncode())),
                                    presetContactsJson
                                    );

            page.RegisterInlineScript(script, onReady: false);
            page.JsonPublisher(customFieldList, "casesEditCustomFieldList");
        }

        #endregion

        #region Data for Opportunity Views

        public static void DataDealFullCardView(BasePage page, Deal targetDeal)
        {
            var daoFactory = page.DaoFactory;
            var customFieldList = daoFactory.CustomFieldDao.GetEntityFields(EntityType.Opportunity, targetDeal.ID, false);
            var tags = daoFactory.TagDao.GetEntityTags(EntityType.Opportunity, targetDeal.ID);
            var availableTags = daoFactory.TagDao.GetAllTags(EntityType.Opportunity).Where(item => !tags.Contains(item));

            var responsibleIDs = new List<Guid>();
            if (CRMSecurity.IsPrivate(targetDeal))
            {
                responsibleIDs = CRMSecurity.GetAccessSubjectGuidsTo(targetDeal);
            }

            var script = String.Format(@"
                                            var dealTags = {0};
                                            var dealAvailableTags = {1};
                                            var dealResponsibleIDs = {2}; ",
                                        JsonConvert.SerializeObject(tags.ToList().ConvertAll(t => t.HtmlEncode())),
                                        JsonConvert.SerializeObject(availableTags.ToList().ConvertAll(t => t.HtmlEncode())),
                                        JsonConvert.SerializeObject(responsibleIDs)
                                        );

            page.RegisterInlineScript(script, onReady: false);
            page.JsonPublisher(customFieldList, "customFieldList");
        }

        public static void DataDealActionView(BasePage page, Deal targetDeal)
        {
            var daoFactory = page.DaoFactory;
            var customFieldList = targetDeal != null
               ? daoFactory.CustomFieldDao.GetEntityFields(EntityType.Opportunity, targetDeal.ID, true)
               : daoFactory.CustomFieldDao.GetFieldsDescription(EntityType.Opportunity);

            var dealExcludedIDs = new List<Int32>();
            var dealClientIDs = new List<Int32>();
            var dealMembersIDs = new List<Int32>();

            if (targetDeal != null)
            {
                dealExcludedIDs = daoFactory.DealDao.GetMembers(targetDeal.ID).ToList();
                dealMembersIDs = new List<int>(dealExcludedIDs);
                if (targetDeal.ContactID != 0)
                {
                    dealMembersIDs.Remove(targetDeal.ContactID);
                    dealClientIDs.Add(targetDeal.ContactID);
                }
            }


            var presetClientContactsJson = "";
            var presetMemberContactsJson = "";
            var showMembersPanel = false;
            var selectedContacts = new List<Contact>();
            var hasTargetClient = false;

            if (targetDeal != null && targetDeal.ContactID != 0)
            {
                var contact = daoFactory.ContactDao.GetByID(targetDeal.ContactID);
                if (contact != null)
                {
                    selectedContacts.Add(contact);
                }
            }
            else
            {
                var URLContactID = UrlParameters.ContactID;
                if (URLContactID != 0)
                {
                    var target = daoFactory.ContactDao.GetByID(URLContactID);
                    if (target != null)
                    {
                        selectedContacts.Add(target);
                        hasTargetClient = true;
                    }
                }
            }
            if (selectedContacts.Count > 0)
            {
                presetClientContactsJson = JsonConvert.SerializeObject(selectedContacts.ConvertAll(item => new
                {
                    id = item.ID,
                    displayName = item.GetTitle().HtmlEncode().ReplaceSingleQuote().Replace(@"\", @"\\"),
                    smallFotoUrl = ContactPhotoManager.GetSmallSizePhoto(item.ID, item is Company)
                }));
            }


            selectedContacts = new List<Contact>();
            selectedContacts.AddRange(daoFactory.ContactDao.GetContacts(dealMembersIDs.ToArray()));
            if (selectedContacts.Count > 0)
            {
                showMembersPanel = true;
                presetMemberContactsJson = JsonConvert.SerializeObject(selectedContacts.ConvertAll(item => new
                {
                    id = item.ID,
                    displayName = item.GetTitle().HtmlEncode().ReplaceSingleQuote().Replace(@"\", @"\\"),
                    smallFotoUrl = ContactPhotoManager.GetSmallSizePhoto(item.ID, item is Company)
                }));
            }

            var ResponsibleSelectedUserId = targetDeal == null ?
                                                SecurityContext.CurrentAccount.ID :
                                                (targetDeal.ResponsibleID != Guid.Empty ? targetDeal.ResponsibleID : Guid.Empty);

            var script = String.Format(@"
                                            var presetClientContactsJson = '{0}';
                                            var presetMemberContactsJson = '{1}';
                                            var hasDealTargetClient = {2};
                                            var showMembersPanel = {3};
                                            var dealClientIDs = {4};
                                            var dealMembersIDs = {5};
                                            var responsibleId = '{6}'; ",
                                        presetClientContactsJson,
                                        presetMemberContactsJson,
                                        hasTargetClient.ToString().ToLower(),
                                        showMembersPanel.ToString().ToLower(),
                                        JsonConvert.SerializeObject(dealClientIDs),
                                        JsonConvert.SerializeObject(dealMembersIDs),
                                        ResponsibleSelectedUserId
                                    );

            page.RegisterInlineScript(script, onReady: false);
            page.JsonPublisher(customFieldList, "customFieldList");
            page.JsonPublisher(daoFactory.DealMilestoneDao.GetAll(), "dealMilestones");

            if (targetDeal != null)
            {
                page.JsonPublisher(targetDeal, "targetDeal");
            }
        }

        #endregion

        #region Data for Invoices Views

        public static void DataInvoicesActionView(BasePage page, Invoice targetInvoice)
        {
            var daoFactory = page.DaoFactory;
            var invoiceItems = daoFactory.InvoiceItemDao.GetAll();
            var invoiceItemsJson = JsonConvert.SerializeObject(invoiceItems.ConvertAll(item => new
            {
                id = item.ID,
                title = item.Title,
                stockKeepingUnit = item.StockKeepingUnit,
                description = item.Description,
                price = item.Price,
                stockQuantity = item.StockQuantity,
                trackInventory = item.TrackInventory,
                invoiceTax1ID = item.InvoiceTax1ID,
                invoiceTax2ID = item.InvoiceTax2ID
            }));

            var invoiceTaxes = daoFactory.InvoiceTaxDao.GetAll();
            var invoiceTaxesJson = JsonConvert.SerializeObject(invoiceTaxes.ConvertAll(item => new
            {
                id = item.ID,
                name = item.Name,
                rate = item.Rate,
                description = item.Description
            }));

            var invoiceSettings = Global.TenantSettings.InvoiceSetting ?? InvoiceSetting.DefaultSettings;
            var invoiceSettingsJson = JsonConvert.SerializeObject(new
            {
                autogenerated = invoiceSettings.Autogenerated,
                prefix = invoiceSettings.Prefix,
                number = invoiceSettings.Number,
                terms = invoiceSettings.Terms
            });

            var presetContactsJson = string.Empty;
            var presetContactID = UrlParameters.ContactID;
            if (targetInvoice == null && presetContactID != 0)
            {
                var targetContact = daoFactory.ContactDao.GetByID(presetContactID);
                if (targetContact != null)
                {
                    presetContactsJson = JsonConvert.SerializeObject(new
                    {
                        id = targetContact.ID,
                        displayName = targetContact.GetTitle().HtmlEncode().ReplaceSingleQuote(),
                        smallFotoUrl = ContactPhotoManager.GetSmallSizePhoto(targetContact.ID, targetContact is Company),
                        currencyAbbreviation = targetContact.Currency
                    });
                }
            }

            var currencyRates = daoFactory.CurrencyRateDao.GetAll();
            var currencyRatesJson = JsonConvert.SerializeObject(currencyRates.ConvertAll(item => new
            {
                id = item.ID,
                fromCurrency = item.FromCurrency,
                toCurrency = item.ToCurrency,
                rate = item.Rate
            }));

            var apiServer = new Api.ApiServer();
            const string apiUrlFormat = "{0}crm/contact/{1}/data.json";

            var contactInfoData = string.Empty;
            var consigneeInfoData = string.Empty;

            if (targetInvoice != null)
            {
                if (targetInvoice.ContactID > 0)
                {
                    contactInfoData = apiServer.GetApiResponse(String.Format(apiUrlFormat, SetupInfo.WebApiBaseUrl, targetInvoice.ContactID), "GET");
                }
                if (targetInvoice.ConsigneeID > 0)
                {
                    consigneeInfoData = apiServer.GetApiResponse(String.Format(apiUrlFormat, SetupInfo.WebApiBaseUrl, targetInvoice.ConsigneeID), "GET");
                }
            }
            else if (presetContactID != 0)
            {
                contactInfoData = apiServer.GetApiResponse(String.Format(apiUrlFormat, SetupInfo.WebApiBaseUrl, presetContactID), "GET");
            }

            var apiUrl = String.Format("{0}crm/invoice/{1}.json",
                                       SetupInfo.WebApiBaseUrl,
                                       targetInvoice != null ? targetInvoice.ID.ToString(CultureInfo.InvariantCulture) : "sample");
            var invoiceData = apiServer.GetApiResponse(apiUrl, "GET");

            var script = String.Format(@"
                                        var invoiceItems = '{0}';
                                        var invoiceTaxes = '{1}';
                                        var invoiceSettings = '{2}';
                                        var invoicePresetContact = '{3}';
                                        var currencyRates = '{4}';
                                        var invoiceJsonData = '{5}';",
                                        Global.EncodeTo64(invoiceItemsJson),
                                        Global.EncodeTo64(invoiceTaxesJson),
                                        Global.EncodeTo64(invoiceSettingsJson),
                                        Global.EncodeTo64(presetContactsJson),
                                        Global.EncodeTo64(currencyRatesJson),
                                        targetInvoice != null ? Global.EncodeTo64(targetInvoice.JsonData) : ""
                );

            page.RegisterInlineScript(script, onReady: false);
            page.JsonPublisher(contactInfoData, "invoiceContactInfo");
            page.JsonPublisher(consigneeInfoData, "invoiceConsigneeInfo");
            page.JsonPublisher(invoiceData, "invoice");
        }

        public static void DataInvoicesDetailsView(BasePage page, Invoice targetInvoice)
        {
            if (targetInvoice == null)
                return;

            var script = String.Format(@"var invoiceData = '{0}';", Global.EncodeTo64(targetInvoice.JsonData));

            var apiServer = new Api.ApiServer();
            var apiUrl = String.Format("{0}crm/invoice/{1}.json", SetupInfo.WebApiBaseUrl, targetInvoice.ID);
            var invoice = apiServer.GetApiResponse(apiUrl, "GET");

            page.RegisterInlineScript(script, onReady: false);
            page.JsonPublisher(invoice, "invoice");
        }

        #endregion

        #region Data for Reports Views

        public static void DataReportsView(BasePage page)
        {
            var defaultCurrency = Global.TenantSettings.DefaultCurrency.Abbreviation;

            var currencyRates = page.DaoFactory.CurrencyRateDao.GetAll();

            var currencyRatesJson = JsonConvert.SerializeObject(currencyRates.ConvertAll(item => new
            {
                id = item.ID,
                fromCurrency = item.FromCurrency,
                toCurrency = item.ToCurrency,
                rate = item.Rate
            }));

            var script = String.Format(@"
                                        var defaultCurrency = '{0}';
                                        var currencyRates = '{1}';",
                                        defaultCurrency,
                                        currencyRatesJson
                );

            page.RegisterInlineScript(script, onReady: false);
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/mail.filter.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.MailFilter = (function($) {
    var isInit = false;

    var attachments,
        tags,
        from,
        importance,
        withCalendar,
        page,
        pageSize,
        periodFrom,
        periodTo,
        withinPeriod,
        folder,
        userFolder,
        search,
        sort,
        sortOrder,
        to,
        unread,
        fromDate,
        fromMessage,
        prevFlag;

    var init = function() {
        if (isInit === false) {
            isInit = true;

            attachments = false;
            tags = new Array();
            from = undefined;
            importance = false;
            page = 1;
            pageSize = TMMail.option('MessagesPageSize');
            periodFrom = 0;
            withinPeriod = '';
            periodTo = 0;
            folder = '1';
            search = '';
            sort = 'date';
            sortOrder = 'descending';
            to = undefined;
            unread = undefined;
            fromDate = undefined;
            fromMessage = undefined;
            prevFlag = false;
            withCalendar = false;
            userFolder = null;

            reset();
        }
    };

    var reset = function() {
        resetFolder();
        resetUserFolder();
        resetSearch();
        resetTags();
        resetFrom();
        resetTo();
    };


    /*to*/
    var setTo = function(mailbox) {
        to = mailbox;
    };

    var getTo = function() {
        return to;
    };

    var resetTo = function() {
        to = undefined;
    };

    /*from*/
    var setFrom = function(mailbox) {
        from = mailbox;
    };

    var getFrom = function() {
        return from;
    };

    var resetFrom = function() {
        from = undefined;
    };


    /*tags*/
    var addTag = function(tagid) {
        if (-1 == $.inArray(tagid, tags)) {
            tags.push(tagid);
        }
    };

    var removeTag = function(tagid) {
        tags = $.grep(tags, function(value) {
            return value != tagid;
        });
    };

    var removeAllTags = function() {
        resetTags();
    };

    // toggles tag selection state
    // returns new state: true - selected, false - not selected
    var toggleTag = function(tagid) {
        var res = -1 == $.inArray(tagid, tags);
        if (res) {
            addTag(tagid);
        } else {
            removeTag(tagid);
        }
        return res;
    };

    var getTags = function() {
        var res = tags;
        return res;
    };

    var parseTags = function(tagsParam) {
        var arr = tagsParam.split(',');
        $.each(arr, function(index, value) {
            addTag(value);
        });
    };

    var resetTags = function() {
        tags = new Array();
    };


    /*unread*/
    var setUnread = function(unreadParam) {
        unread = unreadParam;
    };

    var getUnread = function() {
        return unread;
    };


    /*attachments*/
    var getAttachments = function() {
        return attachments;
    };

    var setAttachments = function(attachmentsParam) {
        attachments = attachmentsParam;
    };


    /*period*/
    var getPeriod = function() {
        return {
            from: periodFrom,
            to: periodTo
        };
    };

    var setPeriod = function(period) {
        periodFrom = period.from;
        periodTo = period.to;
    };

    var getPeriodWithin = function() {
        return withinPeriod;
    };

    var setPeriodWithin = function(withinPeriodParam) {
        withinPeriod = withinPeriodParam;
    };

    /*importance*/
    var setImportance = function(importanceParam) {
        importance = importanceParam;
    };

    var getImportance = function() {
        return importance;
    };


    var setWithCalendar = function(withCalendarFlag) {
        withCalendar = withCalendarFlag;
    };

    var getWithCalendar = function () {
        return withCalendar;
    };

    /*primary folder*/
    var setFolder = function(folderParam) {
        folder = folderParam;
    };

    var resetFolder = function() {
        folder = '1';
    };

    var getFolder = function() {
        return folder;
    };

    /*user folder*/
    var setUserFolder = function (userFolderId) {
        userFolder = userFolderId;
    };

    var resetUserFolder = function () {
        userFolder = null;
    };

    var getUserFolder = function () {
        return userFolder;
    };

    /* from date*/
    var setFromDate = function(newFromDate) {
        fromDate = newFromDate;
    };

    var getFromDate = function() {
        return fromDate;
    };

    /* from message*/
    var setFromMessage = function(newFromMessage) {
        fromMessage = newFromMessage;
    };

    var getFromMessage = function() {
        return fromMessage;
    };

    /* prev flag*/
    var setPrevFlag = function(newVal) {
        prevFlag = newVal;
    };

    var getPrevFlag = function() {
        return prevFlag;
    };

    /*search*/
    var setSearch = function(searchfilter) {
        search = searchfilter;
    };

    var getSearch = function() {
        return search;
    };

    var resetSearch = function() {
        search = '';
    };

    /*sort*/
    var setSort = function(sortParam) {
        sort = sortParam;
    };

    var getSort = function() {
        return sort;
    };

    var resetSort = function() {
        sort = 'date';
    };

    var setSortOrder = function(order) {
        sortOrder = order;
    };

    var getSortOrder = function() {
        return sortOrder;
    };

    var resetSortOrder = function() {
        sortOrder = 'descending';
    };


    /*page & page size*/
    var setPage = function (newPage) {
        page = newPage;
    };

    var getPage = function () {
        return page;
    };

    var setPageSize = function(newSize) {
        pageSize = parseInt(newSize);
    };

    var getPageSize = function() {
        return pageSize;
    };

    /*anchor*/
    var fromAnchor = function(folderParam, params) {
        reset();

        var toParam,
            tagsParam,
            importanceParam,
            unreadParam,
            fromParam,
            searchParam,
            attachmentsParam,
            period,
            periodWithin,
            sortParam,
            sortorder,
            pageParam,
            pageSizeParam,
            fromDateParam,
            fromMessageParam,
            prevFlagParam,
            withCalendarParam;

        if (typeof params !== 'undefined') {
            toParam = TMMail.getParamsValue(params, /to=([^\/]+)/);
            tagsParam = TMMail.getParamsValue(params, /tag=([^\/]+)/);
            importanceParam = TMMail.getParamsValue(params, /(importance\/)/);
            unreadParam = TMMail.getParamsValue(params, /unread=([^\/]+)/);
            attachmentsParam = TMMail.getParamsValue(params, /(attachments\/)/);
            fromParam = TMMail.getParamsValue(params, /from=([^\/]+)/);
            pageParam = TMMail.getParamsValue(params, /page=(\d+)/);
            pageSizeParam = TMMail.getParamsValue(params, /page_size=(\d+)/);
            period = TMMail.getParamsValue(params, /period=([^\/]+)/);
            periodWithin = TMMail.getParamsValue(params, /within=([^\/]+)/);
            searchParam = TMMail.getParamsValue(params, /search=([^\/]+)/);
            sortParam = TMMail.getParamsValue(params, /sort=([^\/]+)/);
            sortorder = TMMail.getParamsValue(params, /sortorder=([^\/]+)/);
            fromDateParam = TMMail.getParamsValue(params, /from_date=([^\/]+)/);
            fromMessageParam = TMMail.getParamsValue(params, /from_message=([^\/]+)/);
            prevFlagParam = TMMail.getParamsValue(params, /prev=([^\/]+)/);
            withCalendarParam = TMMail.getParamsValue(params, /(calendar\/)/);
        }

        if (!TMMail.pageIs('userfolder')) {
            var itemId = TMMail.getSysFolderIdByName(folderParam, TMMail.sysfolders.inbox.id);
            setFolder(itemId);
        } else {
            var userFolderId = TMMail.extractUserFolderIdFromAnchor();
            if (userFolderId) {
                setFolder(TMMail.sysfolders.userfolder.id);
                setUserFolder(userFolderId);
            } else {
                setFolder(TMMail.sysfolders.inbox.id);
            }
        }

        if (toParam) {
            setTo(decodeURIComponent(toParam));
        } else {
            resetTo();
        }

        if (fromParam) {
            setFrom(decodeURIComponent(fromParam));
        } else {
            resetFrom();
        }

        if (tagsParam) {
            parseTags(tagsParam);
        }

        if (importanceParam) {
            setImportance(true);
        } else {
            setImportance(false);
        }

        if (attachmentsParam) {
            setAttachments(true);
        } else {
            setAttachments(false);
        }

        if (unreadParam) {
            if ('true' == unreadParam) {
                setUnread(true);
            } else {
                setUnread(false);
            }
        } else {
            setUnread(undefined);
        }

        if (searchParam) {
            setSearch(decodeURIComponent(searchParam));
        } else {
            resetSearch();
        }

        if (sortParam) {
            setSort(sortParam);
        } else {
            resetSort();
        }

        if (sortorder) {
            setSortOrder(sortorder);
        } else {
            resetSortOrder();
        }

        if (period) {
            fromParam = parseInt(period.split(',')[0]);
            toParam = parseInt(period.split(',')[1]);
            setPeriod({ from: fromParam, to: toParam });
            setPeriodWithin('');
        } else if (periodWithin) {
            setPeriodWithin(periodWithin);
            setPeriod({ from: 0, to: 0 });
        } else {
            setPeriod({ from: 0, to: 0 });
            setPeriodWithin('');
        }

        if (fromDateParam) {
            setFromDate(new Date(decodeURI(fromDateParam)));
        } else {
            setFromDate(undefined);
        }

        if (fromMessageParam) {
            setFromMessage(+fromMessageParam);
        } else {
            setFromMessage(undefined);
        }

        if ('true' == prevFlagParam) {
            setPrevFlag(true);
        } else {
            setPrevFlag(false);
        }

        setPage(pageParam ? pageParam : 1);

        if (pageSizeParam) {
            setPageSize(pageSizeParam);
        } else {
            setPageSize(TMMail.option('MessagesPageSize'));
        }

        if (withCalendarParam) {
            setWithCalendar(true);
        } else {
            setWithCalendar(false);
        }

    };

    var toAnchor = function(includePagingInfo, data, skipPrevNext) {
        var res = '/';

        var f = {};
        f.tags = tags;
        f.unread = getUnread();
        f.importance = getImportance();
        f.attachments = getAttachments();
        f.to = getTo();
        f.from = getFrom();
        f.sort_order = getSortOrder();
        f.period = getPeriod();
        f.period_within = getPeriodWithin();
        f.search = getSearch();
        f.page = page;
        f.page_size = pageSize;
        f.from_date = fromDate;
        f.from_message = fromMessage;
        f.prev_flag = prevFlag;
        f.with_calendar = getWithCalendar();

        $.extend(f, data);

        if (0 < f.tags.length) {
            res += 'tag=';
            $.each(f.tags, function(index, value) {
                res += value;
                if (index != f.tags.length - 1) {
                    res += ',';
                }
            });
            res += '/';
        }

        if (undefined !== f.unread) {
            if (f.unread) {
                res += 'unread=true/';
            } else {
                res += 'unread=false/';
            }
        }

        if (f.importance) {
            res += 'importance/';
        }

        if (f.attachments) {
            res += 'attachments/';
        }

        if (f.with_calendar) {
            res += 'calendar/';
        }

        if (f.to) {
            res += 'to=' + encodeURIComponent(f.to) + '/';
        }

        if (f.from) {
            res += 'from=' + encodeURIComponent(f.from) + '/';
        }

        // skip sort order if it has default value
        if (f.sort_order && f.sort_order != 'descending') {
            res += 'sortorder=' + f.sort_order + '/';
        }

        if (f.period.to > 0) {
            var pFrom = window.moment(f.period.from)
                .utcOffset(ASC.Resources.Master.CurrentTenantTimeZone.UtcOffset)
                .startOf('day')
                .valueOf();

            var pTo = window.moment(f.period.to)
                .utcOffset(ASC.Resources.Master.CurrentTenantTimeZone.UtcOffset)
                .startOf('day')
                .add(23, 'hours')
                .add(59, 'minutes')
                .valueOf();

            res += 'period=' + pFrom + ',' + pTo + '/';
        } else if ('' != f.period_within) {
            res += 'within=' + encodeURIComponent(f.period_within) + '/';
        }

        if ('' != f.search) {
            res += 'search=' + encodeURIComponent(f.search) + '/';
        }

        if (includePagingInfo === true) {
            if(!commonSettingsPage.isConversationsEnabled())
                res += 'page=' + f.page + '/';

            res += 'page_size=' + f.page_size + '/';
        }

        if (true === skipPrevNext) {
            return res;
        }

        if (f.from_date) {
            res += 'from_date=' + f.from_date + '/';
        }

        if (f.from_message) {
            res += 'from_message=' + f.from_message + '/';
        }

        if (true === f.prev_flag) {
            res += 'prev=true/';
        }

        return res;
    };

    var anchorHasMarkStatus = function(status, anchor) {
        if (!anchor) {
            anchor = ASC.Controls.AnchorController.getAnchor();
        }
        if (status == 'read' || status == 'unread') {
            return undefined !== TMMail.getParamsValue(anchor, /\/unread=([^\/]+)/);
        }
        if (status == 'important' || status == 'normal') {
            return undefined !== TMMail.getParamsValue(anchor, /\/(importance)/);
        }
        return false;
    };

    var isBlank = function() {
        if (0 < tags.length ||
            to != undefined && 0 < to.length ||
            from != undefined && 0 < from.length ||
            attachments != false ||
            importance != false ||
            periodFrom != 0 ||
            withinPeriod != '' ||
            periodTo != 0 ||
            search != '' ||
            unread != undefined ||
            withCalendar != false) {
            return false;
        }

        return true;
    };

    function toData() {
        var res = {};

        if (getUserFolder()) {
            res.user_folder_id = getUserFolder();
        }

        res.folder = folder;

        if (!commonSettingsPage.isConversationsEnabled())
            res.page = page;
        res.page_size = pageSize;
        if (getUnread() != undefined) {
            res.unread = getUnread();
        }
        if (getAttachments()) {
            res.attachments = true;
        }
        if (getImportance()) {
            res.important = true;
        }
        if (0 != periodFrom && 0 != periodTo) {
            res.period_from = periodFrom;
            res.period_to = periodTo;
        }
        if (getPeriodWithin()) {
            var within = getPeriodWithin();
            var now = moment.utc().utcOffset(ASC.Resources.Master.CurrentTenantTimeZone.UtcOffset),
                today = now.clone().startOf('day');

            switch (within) {
            case "today":
                res.period_from = today.valueOf();
                res.period_to = today.clone().add(23, 'hours').add(59, 'minutes').valueOf();
                break;
            case "yesterday":
                var yesterday = today.clone().add(-1, 'days');
                res.period_from = yesterday.valueOf();
                res.period_to = yesterday.clone().add(23, 'hours').add(59, 'minutes').valueOf();
                break;
            case "lastweek":
                var lastweek = today.clone().add(-7, 'days');
                res.period_from = lastweek.valueOf();
                res.period_to = today.clone().add(23, 'hours').add(59, 'minutes').valueOf();
                break;
            default:
                setPeriodWithin("");
                break;
            }
        }

        if (getFrom()) {
            res.from_address = from;
        }
        if (getTo()) {
            var account = accountsManager.getAccountByAddress(to);
            if (account) {
                res.mailbox_id = account.mailbox_id;

                if (account.is_alias || account.is_group) {
                    res.to_address = to;
                }
            }
        }

        if (getTags().length > 0) {
            res.tags = getTags();
        }
        if (getSearch() != '') {
            res.search = getSearch();
        }
        if (getSort()) {
            res.sort = getSort();
            res.sortorder = getSortOrder();
        }
        if (undefined != fromDate) {
            res.from_date = fromDate;
        }
        if (undefined != fromMessage) {
            res.from_message = fromMessage;
        }
        if (true === prevFlag) {
            res.prev_flag = true;
        }

        if (getWithCalendar()) {
            res.with_calendar = true;
        }

        return res;
    }

    return {
        init: init,

        getUnread: getUnread,
        setUnread: setUnread,

        getAttachments: getAttachments,
        setAttachments: setAttachments,

        getPeriod: getPeriod,
        setPeriod: setPeriod,

        getPeriodWithin: getPeriodWithin,
        setPeriodWithin: setPeriodWithin,

        addTag: addTag,
        removeTag: removeTag,
        removeAllTags: removeAllTags,
        toggleTag: toggleTag,
        getTags: getTags,

        getImportance: getImportance,
        setImportance: setImportance,

        getWithCalendar: getWithCalendar,
        setWithCalendar: setWithCalendar,

        getFolder: getFolder,
        getUserFolder: getUserFolder,

        setSearch: setSearch,
        getSearch: getSearch,

        setTo: setTo,
        getTo: getTo,

        setFrom: setFrom,
        getFrom: getFrom,

        setSort: setSort,
        getSort: getSort,
        setSortOrder: setSortOrder,
        getSortOrder: getSortOrder,

        getPage: getPage,
        setPage: setPage,

        setPageSize: setPageSize,
        getPageSize: getPageSize,

        setFolder: setFolder,
        setUserFolder: setUserFolder,

        setFromDate: setFromDate,
        getFromDate: getFromDate,

        setFromMessage: setFromMessage,
        getFromMessage: getFromMessage,

        setPrevFlag: setPrevFlag,
        getPrevFlag: getPrevFlag,

        fromAnchor: fromAnchor,
        toAnchor: toAnchor,
        toData: toData,

        anchorHasMarkStatus: anchorHasMarkStatus,

        isBlank: isBlank,
        reset: reset
    };
})(jQuery);

<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/Helpers.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Core;
using ASC.Security.Cryptography;

using ConfigurationConstants = ASC.Core.Configuration.Constants;
using UserConstants = ASC.Core.Users.Constants;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal static class Helpers
    {
        private static readonly Guid[] SystemUsers = new[]
            {
                Guid.Empty,
                ConfigurationConstants.CoreSystem.ID,
                ConfigurationConstants.Guest.ID,
                UserConstants.LostUser.ID
            };

        private static readonly Guid[] SystemGroups = new[]
            {
                Guid.Empty,
                UserConstants.LostGroupInfo.ID,
                UserConstants.GroupAdmin.ID,
                UserConstants.GroupEveryone.ID,
                UserConstants.GroupVisitor.ID,
                UserConstants.GroupUser.ID,
                new Guid("{EA942538-E68E-4907-9394-035336EE0BA8}"), //community product
                new Guid("{1e044602-43b5-4d79-82f3-fd6208a11960}"), //projects product
                new Guid("{6743007C-6F95-4d20-8C88-A8601CE5E76D}"), //crm product
                new Guid("{E67BE73D-F9AE-4ce1-8FEC-1880CB518CB4}"), //documents product
                new Guid("{F4D98AFD-D336-4332-8778-3C6945C81EA0}"), //people product
                new Guid("{2A923037-8B2D-487b-9A22-5AC0918ACF3F}"), //mail product
                new Guid("{32D24CB5-7ECE-4606-9C94-19216BA42086}"), //calendar product
                new Guid("{37620AE5-C40B-45ce-855A-39DD7D76A1FA}"), //birthdays product
                new Guid("{BF88953E-3C43-4850-A3FB-B1E43AD53A3E}")  //talk product
            };

        public static bool IsEmptyOrSystemUser(string id)
        {
            Guid g;
            return string.IsNullOrEmpty(id) || Guid.TryParse(id, out g) && SystemUsers.Contains(g);
        }

        public static bool IsEmptyOrSystemGroup(string id)
        {
            Guid g;
            return string.IsNullOrEmpty(id) || Guid.TryParse(id, out g) && SystemGroups.Contains(g);
        }

        public static string CreateHash(string s)
        {
            return !string.IsNullOrEmpty(s) && s.StartsWith("S|") ? InstanceCrypto.Encrypt(Crypto.GetV(s.Substring(2), 1, false)) : s;
        }

        public static string CreateHash2(string s)
        {
            return !string.IsNullOrEmpty(s) ? "S|" + Crypto.GetV(InstanceCrypto.Decrypt(s), 1, true) : s;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Dao/MessageDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

using ASC.Collections;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Tenants;
using ASC.ElasticSearch;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Services.NotifyService;
using ASC.Web.Projects;
using ASC.Web.Projects.Core.Search;

namespace ASC.Projects.Data.DAO
{
    internal class CachedMessageDao : MessageDao
    {
        private readonly HttpRequestDictionary<Message> messageCache = new HttpRequestDictionary<Message>("message");

        public CachedMessageDao(int tenant) : base(tenant)
        {
        }

        public override Message GetById(int id)
        {
            return messageCache.Get(id.ToString(CultureInfo.InvariantCulture), () => GetBaseById(id));
        }

        private Message GetBaseById(int id)
        {
            return base.GetById(id);
        }

        public override Message Save(Message msg)
        {
            if (msg != null)
            {
                ResetCache(msg.ID);
            }
            return base.Save(msg);
        }

        public override void Delete(int id)
        {
            ResetCache(id);
            base.Delete(id);
        }

        private void ResetCache(int messageId)
        {
            messageCache.Reset(messageId.ToString(CultureInfo.InvariantCulture));
        }
    }

    class MessageDao : BaseDao, IMessageDao
    {
        private readonly Converter<object[], Message> converter;

        public MessageDao(int tenant) : base(tenant)
        {
            converter = ToMessage;
        }

        public List<Message> GetAll()
        {
            return Db.ExecuteList(CreateQuery()).ConvertAll(converter);
        }

        public List<Message> GetByProject(int projectId)
        {
            return Db.ExecuteList(CreateQuery().Where("t.project_id", projectId).OrderBy("t.create_on", false))
                .ConvertAll(converter);
        }

        public List<Message> GetMessages(int startIndex, int max)
        {
            var query = CreateQuery()
                .OrderBy("t.create_on", false)
                .SetFirstResult(startIndex)
                .SetMaxResults(max);

            return Db.ExecuteList(query).ConvertAll(converter);
        }

        public List<Message> GetRecentMessages(int offset, int max, params int[] projects)
        {
            var query = CreateQuery()
                .SetFirstResult(offset)
                .OrderBy("t.create_on", false)
                .SetMaxResults(max);
            if (projects != null && 0 < projects.Length)
            {
                query.Where(Exp.In("t.project_id", projects));
            }
            return Db.ExecuteList(query).ConvertAll(converter);
        }

        public List<Message> GetByFilter(TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            var query = CreateQuery();

            if (filter.Max > 0 && filter.Max < 150000)
            {
                query.SetFirstResult((int)filter.Offset);
                query.SetMaxResults((int)filter.Max);
            }

            query.OrderBy("t.status", true);

            if (!string.IsNullOrEmpty(filter.SortBy))
            {
                var sortColumns = filter.SortColumns["Message"];
                sortColumns.Remove(filter.SortBy);

                query.OrderBy(GetSortFilter(filter.SortBy), filter.SortOrder);

                foreach (var sort in sortColumns.Keys)
                {
                    query.OrderBy(GetSortFilter(sort), sortColumns[sort]);
                }
            }

            CreateQueryFilter(query, filter, isAdmin, checkAccess);

            return Db.ExecuteList(query).ConvertAll(converter);
        }

        public int GetByFilterCount(TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            var query = new SqlQuery(MessagesTable + " t")
                .InnerJoin(ProjectsTable + " p", Exp.EqColumns("t.project_id", "p.id") & Exp.EqColumns("t.tenant_id", "p.tenant_id"))
                .Select("t.id")
                .GroupBy("t.id")
                .Where("t.tenant_id", Tenant);

            query = CreateQueryFilter(query, filter, isAdmin, checkAccess);

            var queryCount = new SqlQuery().SelectCount().From(query, "t1");
            return Db.ExecuteScalar<int>(queryCount);
        }

        public List<Tuple<Guid, int, int>> GetByFilterCountForReport(TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            filter = (TaskFilter)filter.Clone();

            var query = new SqlQuery(MessagesTable + " t")
                .InnerJoin(ProjectsTable + " p", Exp.EqColumns("t.project_id", "p.id") & Exp.EqColumns("t.tenant_id", "p.tenant_id"))
                .Select("t.create_by", "t.project_id")
                .Where("t.tenant_id", Tenant)
                .Where(Exp.Between("t.create_on", filter.GetFromDate(), filter.GetToDate()));

            if (filter.HasUserId)
            {
                query.Where(Exp.In("t.create_by", filter.GetUserIds()));
                filter.UserId = Guid.Empty;
                filter.DepartmentId = Guid.Empty;
            }

            query = CreateQueryFilter(query, filter, isAdmin, checkAccess);

            var queryCount = new SqlQuery()
                .SelectCount()
                .Select("t1.create_by", "t1.project_id")
                .GroupBy("create_by", "project_id")
                .From(query, "t1");

            return Db.ExecuteList(queryCount).ConvertAll(b => new Tuple<Guid, int, int>(Guid.Parse((string)b[1]), Convert.ToInt32(b[2]), Convert.ToInt32(b[0]))); ;
        }

        public virtual Message GetById(int id)
        {
            return Db.ExecuteList(CreateQuery().Where("t.id", id))
                .ConvertAll(converter)
                .SingleOrDefault();
        }

        public bool IsExists(int id)
        {
            var count = Db.ExecuteScalar<long>(Query(MessagesTable).SelectCount().Where("id", id));
            return 0 < count;
        }

        public virtual Message Save(Message msg)
        {
            var insert = Insert(MessagesTable)
                .InColumnValue("id", msg.ID)
                .InColumnValue("project_id", msg.Project != null ? msg.Project.ID : 0)
                .InColumnValue("title", msg.Title)
                .InColumnValue("status", msg.Status)
                .InColumnValue("create_by", msg.CreateBy.ToString())
                .InColumnValue("create_on", TenantUtil.DateTimeToUtc(msg.CreateOn))
                .InColumnValue("last_modified_by", msg.LastModifiedBy.ToString())
                .InColumnValue("last_modified_on", TenantUtil.DateTimeToUtc(msg.LastModifiedOn))
                .InColumnValue("content", msg.Description)
                .Identity(1, 0, true);
            msg.ID = Db.ExecuteScalar<int>(insert);
            return msg;
        }

        public virtual void Delete(int id)
        {
            using (var tx = Db.BeginTransaction())
            {
                Db.ExecuteNonQuery(Delete(CommentsTable).Where("target_uniq_id", ProjectEntity.BuildUniqId<Message>(id)));
                Db.ExecuteNonQuery(Delete(MessagesTable).Where("id", id));

                tx.Commit();
            }
        }


        private SqlQuery CreateQuery()
        {
            return new SqlQuery(MessagesTable + " t")
                .InnerJoin(ProjectsTable + " p", Exp.EqColumns("t.project_id", "p.id") & Exp.EqColumns("t.tenant_id", "p.tenant_id"))
                .LeftOuterJoin(CommentsTable + " pc", Exp.EqColumns("pc.target_uniq_id", "concat('Message_', cast(t.id as char))") & Exp.EqColumns("t.tenant_id", "pc.tenant_id"))
                .Select(ProjectDao.ProjectColumns.Select(c => "p." + c).ToArray())
                .Select("t.id", "t.title", "t.status", "t.create_by", "t.create_on", "t.last_modified_by", "t.last_modified_on", "t.content")
                .Select("max(coalesce(pc.create_on, t.create_on)) comments")
                .GroupBy("t.id")
                .Where("t.tenant_id", Tenant);
        }

        private SqlQuery CreateQueryFilter(SqlQuery query, TaskFilter filter, bool isAdmin, bool checkAccess)
        {
            if (filter.Follow)
            {
                IEnumerable<string> objects = NotifySource.Instance.GetSubscriptionProvider().GetSubscriptions(NotifyConstants.Event_NewCommentForMessage, NotifySource.Instance.GetRecipientsProvider().GetRecipient(CurrentUserID.ToString()));

                if (filter.ProjectIds.Count != 0)
                {
                    objects = objects.Where(r => r.Split('_')[2] == filter.ProjectIds[0].ToString(CultureInfo.InvariantCulture));
                }

                var ids = objects.Select(r => r.Split('_')[1]).ToArray();
                query.Where(Exp.In("t.id", ids));
            }

            if (filter.ProjectIds.Count != 0)
            {
                query.Where(Exp.In("t.project_id", filter.ProjectIds));
            }
            else
            {
                if (ProjectsCommonSettings.Load().HideEntitiesInPausedProjects)
                {
                    query.Where(!Exp.Eq("p.status", ProjectStatus.Paused));
                }

                if (filter.MyProjects)
                {
                    query.InnerJoin(ParticipantTable + " ppp", Exp.EqColumns("ppp.tenant", "t.tenant_id") & Exp.EqColumns("p.id", "ppp.project_id") & Exp.Eq("ppp.removed", false));
                    query.Where("ppp.participant_id", CurrentUserID);
                }
            }

            if (filter.TagId != 0)
            {
                if (filter.TagId == -1)
                {
                    query.LeftOuterJoin(ProjectTagTable + " pt", Exp.EqColumns("pt.project_id", "t.project_id"));
                    query.Where("pt.tag_id", null);
                }
                else
                {
                    query.InnerJoin(ProjectTagTable + " pt", Exp.EqColumns("pt.project_id", "t.project_id"));
                    query.Where("pt.tag_id", filter.TagId);
                }
            }

            if (filter.UserId != Guid.Empty)
            {
                query.Where("t.create_by", filter.UserId);
            }

            if (filter.DepartmentId != Guid.Empty)
            {
                query.InnerJoin("core_usergroup cug", Exp.EqColumns("cug.tenant", "t.tenant_id") & Exp.Eq("cug.removed", false) & Exp.EqColumns("cug.userid", "t.create_by"));
                query.Where("cug.groupid", filter.DepartmentId);
            }

            if (!filter.FromDate.Equals(DateTime.MinValue) && !filter.ToDate.Equals(DateTime.MinValue) && !filter.ToDate.Equals(DateTime.MaxValue))
            {
                query.Where(Exp.Between("t.create_on", filter.FromDate, filter.ToDate.AddDays(1)));
            }

            if (filter.MessageStatus.HasValue)
            {
                query.Where("t.status", filter.MessageStatus.Value);
            }

            if (!string.IsNullOrEmpty(filter.SearchText))
            {
                List<int> mIds;
                if (FactoryIndexer<DiscussionsWrapper>.TrySelectIds(s => s.MatchAll(filter.SearchText), out mIds))
                {
                    query.Where(Exp.In("t.id", mIds));
                }
                else
                {
                    query.Where(Exp.Like("t.title", filter.SearchText, SqlLike.AnyWhere));
                }
            }

            if (checkAccess)
            {
                query.Where(Exp.Eq("p.private", false));
            }
            else if (!isAdmin)
            {
                var isInTeam = new SqlQuery(ParticipantTable).Select("security").Where(Exp.EqColumns("p.id", "project_id") & Exp.Eq("removed", false) & Exp.Eq("participant_id", CurrentUserID) & !Exp.Eq("security & " + (int)ProjectTeamSecurity.Messages, (int)ProjectTeamSecurity.Messages));
                query.Where(Exp.Eq("p.private", false) | Exp.Eq("p.responsible_id", CurrentUserID) | (Exp.Eq("p.private", true) & Exp.Exists(isInTeam)));
            }

            return query;
        }

        private static string GetSortFilter(string sortBy)
        {
            if (sortBy != "comments") return "t." + sortBy;

            return "comments";

        }

        private Message ToMessage(object[] r)
        {
            var offset = ProjectDao.ProjectColumns.Length;
            return new Message
            {
                Project = r[0] != null ? ProjectDao.ToProject(r) : null,
                ID = Convert.ToInt32(r[0 + offset]),
                Title = (string)r[1 + offset],
                Status = (MessageStatus)Convert.ToInt32(r[2 + offset]),
                CreateBy = ToGuid(r[3 + offset]),
                CreateOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[4 + offset])),
                LastModifiedBy = ToGuid(r[5 + offset]),
                LastModifiedOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[6 + offset])),
                Description = (string)r[7 + offset]
            };
        }


        public IEnumerable<Message> GetMessages(Exp where)
        {
            return Db.ExecuteList(CreateQuery().Where(where)).ConvertAll(converter);
        }
    }
}


<|start_filename|>module/ASC.Files.Thirdparty/Sharpbox/SharpBoxProviderInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using AppLimit.CloudComputing.SharpBox;
using AppLimit.CloudComputing.SharpBox.Exceptions;
using AppLimit.CloudComputing.SharpBox.StorageProvider;

using ASC.Common.Web;
using ASC.Core;
using ASC.Files.Core;
using ASC.Web.Files.Classes;

namespace ASC.Files.Thirdparty.Sharpbox
{
    public class SharpBoxProviderInfo : IProviderInfo, IDisposable
    {
        public int ID { get; set; }
        public Guid Owner { get; private set; }

        private readonly nSupportedCloudConfigurations _providerKey;
        private readonly AuthData _authData;
        private readonly FolderType _rootFolderType;
        private readonly DateTime _createOn;

        public SharpBoxProviderInfo(int id, string providerKey, string customerTitle, AuthData authData, Guid owner, FolderType rootFolderType, DateTime createOn)
        {
            if (string.IsNullOrEmpty(providerKey))
                throw new ArgumentNullException("providerKey");
            if (string.IsNullOrEmpty(authData.Token) && string.IsNullOrEmpty(authData.Password))
                throw new ArgumentNullException("token", "Both token and password can't be null");
            if (!string.IsNullOrEmpty(authData.Login) && string.IsNullOrEmpty(authData.Password) && string.IsNullOrEmpty(authData.Token))
                throw new ArgumentNullException("password", "Password can't be null");

            ID = id;
            CustomerTitle = customerTitle;
            Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner;

            _providerKey = (nSupportedCloudConfigurations)Enum.Parse(typeof(nSupportedCloudConfigurations), providerKey, true);
            _authData = authData;
            _rootFolderType = rootFolderType;
            _createOn = createOn;
        }

        public void Dispose()
        {
            if (StorageOpened)
            {
                Storage.Close();
            }
        }

        private CloudStorage CreateStorage()
        {
            var prms = new object[] { };
            if (!string.IsNullOrEmpty(_authData.Url))
            {
                var uri = _authData.Url;
                if (Uri.IsWellFormedUriString(uri, UriKind.Relative))
                {
                    uri = Uri.UriSchemeHttp + Uri.SchemeDelimiter + uri;
                }
                prms = new object[] { new Uri(uri) };
            }

            var storage = new CloudStorage();
            var config = CloudStorage.GetCloudConfigurationEasy(_providerKey, prms);
            if (!string.IsNullOrEmpty(_authData.Token))
            {
                if (_providerKey != nSupportedCloudConfigurations.BoxNet)
                {
                    var token = storage.DeserializeSecurityTokenFromBase64(_authData.Token);
                    storage.Open(config, token);
                }
            }
            else
            {
                storage.Open(config, new GenericNetworkCredentials { Password = <PASSWORD>, UserName = _authData.Login });
            }
            return storage;
        }

        internal CloudStorage Storage
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    var key = "__CLOUD_STORAGE" + ID;
                    var wrapper = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                    if (wrapper == null || !wrapper.Storage.IsOpened)
                    {
                        wrapper = new StorageDisposableWrapper(CreateStorage());
                        DisposableHttpContext.Current[key] = wrapper;
                    }
                    return wrapper.Storage;
                }
                return CreateStorage();
            }
        }

        internal bool StorageOpened
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    var key = "__CLOUD_STORAGE" + ID;
                    var wrapper = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                    return wrapper != null && wrapper.Storage.IsOpened;
                }
                return false;
            }
        }

        internal void UpdateTitle(string newtitle)
        {
            CustomerTitle = newtitle;
        }

        public string CustomerTitle { get; private set; }

        public DateTime CreateOn
        {
            get { return _createOn; }
        }

        public object RootFolderId
        {
            get { return "sbox-" + ID; }
        }

        public bool CheckAccess()
        {
            try
            {
                return Storage.GetRoot() != null;
            }
            catch (UnauthorizedAccessException)
            {
                return false;
            }
            catch (SharpBoxException ex)
            {
                Global.Logger.Error("Sharpbox CheckAccess error", ex);
                return false;
            }
        }

        public void InvalidateStorage()
        {
            if (HttpContext.Current != null)
            {
                var key = "__CLOUD_STORAGE" + ID;
                var storage = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                if (storage != null)
                {
                    storage.Dispose();
                }
            }
        }

        public string ProviderKey
        {
            get { return _providerKey.ToString(); }
        }

        public FolderType RootFolderType
        {
            get { return _rootFolderType; }
        }


        class StorageDisposableWrapper : IDisposable
        {
            public CloudStorage Storage { get; private set; }


            public StorageDisposableWrapper(CloudStorage storage)
            {
                Storage = storage;
            }

            public void Dispose()
            {
                if (Storage.IsOpened)
                    Storage.Close();
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/_Obsolete/SIP_Target.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Text;

namespace LumiSoft.Net.SIP.Stack
{
    /// <summary>
    /// This class represents remote SIP target info.
    /// </summary>
    public class SIP_Target
    {
        private SIP_EndPointInfo m_pLocalEndPoint = null;
        private string           m_Transport      = SIP_Transport.UDP;
        private string           m_Host           = "";
        private int              m_Port           = 5060;

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="transport">Transport to use.</param>
        /// <param name="host">Host name or IP.</param>
        /// <param name="port">Host port.</param>
        public SIP_Target(string transport,string host,int port)
        {
            m_Transport = transport;
            m_Host      = host;
            m_Port      = port;
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="destination">Remote destination URI.</param>
        public SIP_Target(SIP_Uri destination) : this(null,destination)
        {            
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="localEP">Local end point to use to connect remote destination.</param>
        /// <param name="destination">Remote destination URI.</param>
        public SIP_Target(SIP_EndPointInfo localEP,SIP_Uri destination)
        {
            m_pLocalEndPoint = localEP;

            if(destination.Param_Transport != null){
                m_Transport = destination.Param_Transport;
            }
            else{
                // If SIPS, use always TLS.
                if(destination.IsSecure){
                    m_Transport = SIP_Transport.TLS;
                }
                else{
                    m_Transport = SIP_Transport.UDP;
                }
            }
            m_Host = destination.Host;
            if(destination.Port != -1){
                m_Port = destination.Port;
            }
            else{
                if(m_Transport == SIP_Transport.TLS){
                    m_Port = 5061;
                }
                else{
                    m_Port = 5060;
                }
            }
        }


        #region Properties Implementation

        /// <summary>
        /// Gets local destination to use to connect remote destination. 
        /// Value null means not specified. NOTE This is used only by UDP.
        /// </summary>
        public SIP_EndPointInfo LocalEndPoint
        {
            get{ return m_pLocalEndPoint; }
        }
        
        /// <summary>
        /// Gets transport to use.
        /// </summary>
        public string Transport
        {
            get{ return m_Transport; }
        }

        /// <summary>
        /// Gets remote host name or IP address.
        /// </summary>
        public string Host
        {
            get{ return m_Host; }
        }

        /// <summary>
        /// Gets remote host port.
        /// </summary>
        public int Port
        {
            get{ return m_Port; }
        }

        #endregion

    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/SingleSignOnSettings/js/singlesignonsettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var SsoSettings = (function () {

    var isInit = false,

        currentSettings = null,
        defaultSettings = null,
        ssoConstants = null,
        spMetadata = null,

        tmpIdpCertificates = [],
        tmpSPCertificates = [],
        tmpCertificate = null,
        tmpCertificateIndex = null,

        $ssoMainContainer = jq(".sso-main-container"),

        $ssoEnableBtn = jq("#ssoEnableBtn"),

        $ssoSPSettingsSpoilerLink = jq("#ssoSPSettingsSpoilerLink"),
        $ssoSPSettingsSpoiler = jq("#ssoSPSettingsSpoiler"),

        $ssoUploadMetadataInput = jq("#ssoUploadMetadataInput"),
        $ssoUploadMetadataBtn = jq("#ssoUploadMetadataBtn"),
        $ssoSelectMetadataBtn = jq("#ssoSelectMetadataBtn"),
        $ssoSelectMetadataInput = jq("#ssoSelectMetadataInput"),

        $ssoSpLoginLabel = jq("#ssoSpLoginLabel"),
        $ssoEntityId = jq("#ssoEntityId"),

        $ssoSignPostRbx = jq("#ssoSignPostRbx"),
        $ssoSignPostUrl = jq("#ssoSignPostUrl"),
        $ssoSignRedirectRbx = jq("#ssoSignRedirectRbx"),
        $ssoSignRedirectUrl = jq("#ssoSignRedirectUrl"),

        $ssoLogoutPostRbx = jq("#ssoLogoutPostRbx"),
        $ssoLogoutPostUrl = jq("#ssoLogoutPostUrl"),
        $ssoLogoutRedirectRbx = jq("#ssoLogoutRedirectRbx"),
        $ssoLogoutRedirectUrl = jq("#ssoLogoutRedirectUrl"),

        $ssoNameIdFormat = jq("#ssoNameIdFormat"),

        $ssoIdPCertificateContainer = jq("#ssoIdPCertificateContainer"),
        $ssoAddIdPCertificateBtn = jq("#ssoAddIdPCertificateBtn"),
        $ssoIdpCertificateSpoilerLink = jq("#ssoIdpCertificateSpoilerLink"),
        $ssoIdpCertificateSpoiler = jq("#ssoIdpCertificateSpoiler"),

        $ssoVerifyAuthResponsesSignCbx = jq("#ssoVerifyAuthResponsesSignCbx"),
        $ssoVerifyLogoutRequestsSignCbx = jq("#ssoVerifyLogoutRequestsSignCbx"),
        $ssoVerifyLogoutResponsesSignCbx = jq("#ssoVerifyLogoutResponsesSignCbx"),
        $ssoDecryptAssertionsCbx = jq("#ssoDecryptAssertionsCbx"),
        $ssoDefaultSignVerifyingAlgorithm = jq("#ssoDefaultSignVerifyingAlgorithm"),
        $ssoDefaultDecryptAlgorithm = jq("#ssoDefaultDecryptAlgorithm"),

        $ssoSPCertificateContainer = jq("#ssoSPCertificateContainer"),
        $ssoAddSPCertificateBtn = jq("#ssoAddSPCertificateBtn"),
        $ssoSpCertificateSpoilerLink = jq("#ssoSpCertificateSpoilerLink"),
        $ssoSpCertificateSpoiler = jq("#ssoSpCertificateSpoiler"),

        $ssoSignAuthRequestsCbx = jq("#ssoSignAuthRequestsCbx"),
        $ssoSignLogoutRequestsCbx = jq("#ssoSignLogoutRequestsCbx"),
        $ssoSignLogoutResponsesCbx = jq("#ssoSignLogoutResponsesCbx"),
        $ssoEncryptAssertionsCbx = jq("#ssoEncryptAssertionsCbx"),
        $ssoSigningAlgorithm = jq("#ssoSigningAlgorithm"),
        $ssoEncryptAlgorithm = jq("#ssoEncryptAlgorithm"),

        $ssoFirstName = jq("#ssoFirstName"),
        $ssoLastName = jq("#ssoLastName"),
        $ssoEmail = jq("#ssoEmail"),
        $ssoLocation = jq("#ssoLocation"),
        $ssoTitle = jq("#ssoTitle"),
        $ssoPhone = jq("#ssoPhone"),

        $ssoSaveBtn = jq("#ssoSaveBtn"),
        $ssoResetBtn = jq("#ssoResetBtn"),

        $ssoSPEntityId = jq("#ssoSPEntityId"),
        $ssoSPConsumerUrl = jq("#ssoSPConsumerUrl"),
        $ssoSPLogoutUrl = jq("#ssoSPLogoutUrl"),

        $ssoDownloadSPMetadataBtn = jq("#ssoDownloadSPMetadataBtn"),

        $ssoIdpCertificateDialog = jq("#ssoIdpCertificateDialog"),
        $ssoIdpPublicCertificate = jq("#ssoIdpPublicCertificate"),
        $ssoIdpCertificateActionType = jq("#ssoIdpCertificateActionType"),
        $ssoIdpCertificateOkBtn = jq("#ssoIdpCertificateOkBtn"),

        $ssoSpCertificateDialog = jq("#ssoSpCertificateDialog"),
        $ssoSpCertificateGenerateBtn = jq("#ssoSpCertificateGenerateBtn"),
        $ssoSpPublicCertificate = jq("#ssoSpPublicCertificate"),
        $ssoSpPrivateKey = jq("#ssoSpPrivateKey"),
        $ssoSpCertificateActionType = jq("#ssoSpCertificateActionType"),
        $ssoSpCertificateOkBtn = jq("#ssoSpCertificateOkBtn"),

        $certificatesTmpl = jq("#certificatesTmpl"),
        $certificateItemTmpl = jq("#certificateItemTmpl"),

        $ssoSettingsInviteDialog = jq("#ssoSettingsInviteDialog"),
        $ssoSettingsTurnOffDialog = jq("#ssoSettingsTurnOffDialog");
        $ssoHideAuthPageCbx = jq("#ssoHideAuthPage");

    function getSettings() {
        var isSignPost = $ssoSignPostRbx.is(":checked");
        var isLogoutPost = $ssoLogoutPostRbx.is(":checked");
        return {
            enableSso: $ssoEnableBtn.hasClass("on"),
            spLoginLabel: $ssoSpLoginLabel.val().trim(),
            idpSettings: {
                entityId: $ssoEntityId.val().trim(),
                ssoUrl: isSignPost ? $ssoSignPostUrl.val().trim() : $ssoSignRedirectUrl.val().trim(),
                ssoBinding: isSignPost ? ssoConstants.SsoBindingType.Saml20HttpPost : ssoConstants.SsoBindingType.Saml20HttpRedirect,
                sloUrl: isLogoutPost ? $ssoLogoutPostUrl.val().trim() : $ssoLogoutRedirectUrl.val().trim(),
                sloBinding: isLogoutPost ? ssoConstants.SsoBindingType.Saml20HttpPost : ssoConstants.SsoBindingType.Saml20HttpRedirect,
                nameIdFormat: $ssoNameIdFormat.val(),
            },
            idpCertificates: tmpIdpCertificates,
            idpCertificateAdvanced: {
                verifyAlgorithm: $ssoDefaultSignVerifyingAlgorithm.val(),
                verifyAuthResponsesSign: $ssoVerifyAuthResponsesSignCbx.is(":checked"),
                verifyLogoutRequestsSign: $ssoVerifyLogoutRequestsSignCbx.is(":checked"),
                verifyLogoutResponsesSign: $ssoVerifyLogoutResponsesSignCbx.is(":checked"),
                decryptAlgorithm: $ssoDefaultDecryptAlgorithm.val(),
                decryptAssertions: $ssoDecryptAssertionsCbx.is(":checked")
            },
            spCertificates: tmpSPCertificates,
            spCertificateAdvanced: {
                decryptAlgorithm: null,
                signingAlgorithm: $ssoSigningAlgorithm.val(),
                signAuthRequests: $ssoSignAuthRequestsCbx.is(":checked"),
                signLogoutRequests: $ssoSignLogoutRequestsCbx.is(":checked"),
                signLogoutResponses: $ssoSignLogoutResponsesCbx.is(":checked"),
                encryptAlgorithm: $ssoEncryptAlgorithm.val(),
                encryptAssertions: $ssoEncryptAssertionsCbx.is(":checked")
            },
            fieldMapping: {
                firstName: $ssoFirstName.val().trim(),
                lastName: $ssoLastName.val().trim(),
                email: $ssoEmail.val().trim(),
                title: $ssoTitle.val().trim(),
                location: $ssoLocation.val().trim(),
                phone: $ssoPhone.val().trim()
            },
            hideAuthPage: $ssoHideAuthPageCbx.is(":checked")
        };
    }

    function init(current, defaults, constants, metadata, error) {
        if (error) {
            toastr.error(error);
            isInit = true;
            jq(window).trigger("rightSideReady", null);
            return;
        }

        if (isInit) return;

        currentSettings = current;
        defaultSettings = defaults;
        ssoConstants = constants;
        spMetadata = metadata;

        tmpIdpCertificates = current.IdpCertificates.slice();
        tmpSPCertificates = current.SpCertificates.slice();


        if (currentSettings.EnableSso) {
            onSettingsChanged();
        }

        $ssoSPSettingsSpoilerLink.on('click', function () {
            spoiler.toggle('#ssoSPSettingsSpoiler', jq(this));
        });
        $ssoIdpCertificateSpoilerLink.on('click', function () {
            spoiler.toggle('#ssoIdpCertificateSpoiler', jq(this), null, ASC.Resources.Master.ResourceJS.SsoHideAdvancedSettings, ASC.Resources.Master.ResourceJS.SsoShowAdvancedSettings);
        });

        $ssoSpCertificateSpoilerLink.on('click', function () {
            spoiler.toggle('#ssoSpCertificateSpoiler', jq(this), null, ASC.Resources.Master.ResourceJS.SsoHideAdvancedSettings, ASC.Resources.Master.ResourceJS.SsoShowAdvancedSettings);
        });

        jq("#ssoSPMetadataSpoilerLink").on('click', function () {
            spoiler.toggle('#ssoSPMetadataSpoiler', jq(this));
        });

        

        $ssoEnableBtn.on("click", onSsoEnabled);

        $ssoSaveBtn.on("click", saveSettings);

        $ssoResetBtn.on("click", resetSettings);

        $ssoUploadMetadataBtn.on("click", loadMetadata);

        $ssoMainContainer.find("input, textarea").on("keyup", onSettingsChanged);

        $ssoMainContainer.find("input[type=radio]").on("click", onRadioBoxChanged);

        $ssoMainContainer.find(".checkBox").on("click", onCheckBoxChanged);

        $ssoNameIdFormat.on("change", onSettingsChanged);

        $ssoDefaultSignVerifyingAlgorithm.on("change", onSettingsChanged);

        $ssoDefaultDecryptAlgorithm.on("change", onSettingsChanged);

        $ssoSigningAlgorithm.on("change", onSettingsChanged);

        $ssoEncryptAlgorithm.on("change", onSettingsChanged);

        $ssoDownloadSPMetadataBtn.on("click", onDownloadSPMetadata);

        $ssoAddIdPCertificateBtn.on("click", function () {
            if (jq(this).hasClass("disable"))
                return;

            showIdpCertificateDialog(null, null);
        });

        $ssoIdpCertificateOkBtn.on("click", addIdpCertificate);

        $ssoIdPCertificateContainer.on("click", ".delete", deleteIdpCertificate);

        $ssoIdPCertificateContainer.on("click", ".edit", editIdpCertificate);

        $ssoAddSPCertificateBtn.on("click", function () {
            if (jq(this).hasClass("disable"))
                return;

            showSpCertificateDialog(null);
        });

        $ssoSpCertificateGenerateBtn.on("click", generateSpCertificate);

        $ssoSpCertificateOkBtn.on("click", addSpCertificate);

        $ssoSPCertificateContainer.on("click", ".delete", deleteSpCertificate);

        $ssoSPCertificateContainer.on("click", ".edit", editSpCertificate);

        $ssoSettingsInviteDialog.on("click", ".sso-settings-ok", function () {
            if (jq(this).hasClass("disable"))
                return;
            LoadingBanner.displayLoading()
            Teamlab.deleteSsoSettings(
                {
                    success: function (res, data) {
                        setDefaultSettings(false);
                        onSsoEnabled();
                        showSuccess(data);
                        onSettingsChanged();
                        closeDialog();
                        LoadingBanner.hideLoading();
                    },
                    error: function (error) {
                        showError(error)
                        onSettingsChanged();
                        closeDialog();
                        LoadingBanner.hideLoading();
                    }
                });
        });
        $ssoSpCertificateDialog.on("click", ".sso-settings-cancel", closeDialog);
        $ssoIdpCertificateDialog.on("click", ".sso-settings-cancel", closeDialog);
        $ssoSettingsInviteDialog.on("click", ".sso-settings-cancel", closeDialog);

        $ssoUploadMetadataInput.on("input propertychange paste change", function () {
            jq(this).toggleClass("error", false);
        });

        $ssoSettingsTurnOffDialog.on("click", ".sso-settings-ok", function () {
            if (jq(this).hasClass("disable"))
                return;

            enableSso(false);
            saveSettings();
            closeDialog();
        });
        $ssoSettingsTurnOffDialog.on("click", ".sso-settings-cancel", closeDialog);

        bindUploader();

        renderIdpCertificates(false);
        renderSpCertificates(false);

        renderSpMetadata();

        bindCopyToClipboard();

        isInit = true;

    }

    function setDefaultSettings(partial) {
        $ssoUploadMetadataInput.val("");

        enableSso(defaultSettings.EnableSso);

        $ssoSpLoginLabel.val(defaultSettings.SpLoginLabel);
        $ssoEntityId.val(defaultSettings.IdpSettings.EntityId);

        if (defaultSettings.IdpSettings.SsoBinding === ssoConstants.SsoBindingType.Saml20HttpPost) {
            $ssoSignPostRbx.click();
            $ssoSignPostUrl.val(defaultSettings.IdpSettings.SsoUrl);
            $ssoSignRedirectUrl.val("");
        } else {
            $ssoSignRedirectRbx.click();
            $ssoSignPostUrl.val("");
            $ssoSignRedirectUrl.val(defaultSettings.IdpSettings.SsoUrl);
        }

        if (defaultSettings.IdpSettings.SloBinding === ssoConstants.SsoBindingType.Saml20HttpPost) {
            $ssoLogoutPostRbx.click();
            $ssoLogoutPostUrl.val(defaultSettings.SloUrl);
            $ssoLogoutRedirectUrl.val("");
        } else {
            $ssoLogoutRedirectRbx.click();
            $ssoLogoutPostUrl.val("");
            $ssoLogoutRedirectUrl.val(defaultSettings.SloUrl);
        }

        $ssoNameIdFormat.val(defaultSettings.IdpSettings.NameIdForma)

        tmpIdpCertificates = defaultSettings.IdpCertificates;

        renderIdpCertificates(false);

        $ssoDefaultSignVerifyingAlgorithm.val(defaultSettings.IdpCertificateAdvanced.VerifyAlgorithm)

        if (defaultSettings.IdpCertificateAdvanced.VerifyAuthResponsesSign)
            $ssoVerifyAuthResponsesSignCbx.prop('checked', true);
        else
            $ssoVerifyAuthResponsesSignCbx.prop('checked', false);

        if (defaultSettings.IdpCertificateAdvanced.VerifyLogoutRequestsSign)
            $ssoVerifyLogoutRequestsSignCbx.prop('checked', true);
        else
            $ssoVerifyLogoutRequestsSignCbx.prop('checked', false);

        if (defaultSettings.IdpCertificateAdvanced.VerifyLogoutResponsesSign)
            $ssoVerifyLogoutResponsesSignCbx.prop('checked', true);
        else
            $ssoVerifyLogoutResponsesSignCbx.prop('checked', false);

        $ssoDefaultDecryptAlgorithm.val(defaultSettings.IdpCertificateAdvanced.DecryptAlgorithm)

        if (defaultSettings.IdpCertificateAdvanced.DecryptAssertions)
            $ssoDecryptAssertionsCbx.prop('checked', true);
        else
            $ssoDecryptAssertionsCbx.prop('checked', false);

        if (partial) return;
        tmpSPCertificates = defaultSettings.SpCertificates;

        renderSpCertificates(false);
        $ssoSigningAlgorithm.val(defaultSettings.SpCertificateAdvanced.SigningAlgorithm)

        if (defaultSettings.SpCertificateAdvanced.SignAuthRequests)
            $ssoSignAuthRequestsCbx.prop('checked', true);
        else
            $ssoSignAuthRequestsCbx.prop('checked', false);

        if (defaultSettings.SpCertificateAdvanced.SignLogoutRequests)
            $ssoSignLogoutRequestsCbx.prop('checked', true);
        else
            $ssoSignLogoutRequestsCbx.prop('checked', false);

        if (defaultSettings.SpCertificateAdvanced.SignLogoutResponses)
            $ssoSignLogoutResponsesCbx.prop('checked', true);
        else
            $ssoSignLogoutResponsesCbx.prop('checked', false);

        $ssoEncryptAlgorithm.val(defaultSettings.SpCertificateAdvanced.EncryptAlgorithm)

        if (defaultSettings.SpCertificateAdvanced.EncryptAssertions)
            $ssoEncryptAssertionsCbx.prop('checked', true);
        else
            $ssoEncryptAssertionsCbx.prop('checked', false);

        $ssoFirstName.val(defaultSettings.FieldMapping.FirstName);
        $ssoLastName.val(defaultSettings.FieldMapping.LastName);
        $ssoEmail.val(defaultSettings.FieldMapping.Email);
        $ssoTitle.val(defaultSettings.FieldMapping.Title);
        $ssoLocation.val(defaultSettings.FieldMapping.Location);
        $ssoPhone.val(defaultSettings.FieldMapping.Phone);

        if (defaultSettings.HideAuthPage)
            $ssoHideAuthPageCbx.prop('checked', true);
        else
            $ssoHideAuthPageCbx.prop('checked', false);
    }

    function bindCopyToClipboard() {
        var clipboard = new Clipboard('.copyBtn');
        clipboard.on('success', function (e) {
            toastr.success(window.Resource.Copied);
            e.clearSelection();
        });
    }

    function renderSpMetadata() {
        var baseUrl = spMetadata.baseUrl || window.location.origin;

        $ssoSPEntityId.val(baseUrl + spMetadata.EntityId).next(".copyBtn").attr("data-clipboard-text", baseUrl + spMetadata.EntityId);

        $ssoSPConsumerUrl.val(baseUrl + spMetadata.ConsumerUrl).next(".copyBtn").attr("data-clipboard-text", baseUrl + spMetadata.ConsumerUrl);

        $ssoSPLogoutUrl.val(baseUrl + spMetadata.LogoutUrl).next(".copyBtn").attr("data-clipboard-text", baseUrl + spMetadata.LogoutUrl);

        $ssoDownloadSPMetadataBtn.attr("data-href", baseUrl + spMetadata.MetadataUrl);
    }

    function getPropValue(obj, propName) {
        var value = "";

        if (!obj) return value;

        if (obj.hasOwnProperty(propName))
            return obj[propName];

        if (obj.hasOwnProperty("binding") && obj.hasOwnProperty("location") && obj["binding"] == propName)
            return obj["location"];

        if (Array.isArray(obj)) {
            obj.forEach(function (item) {
                if (item.hasOwnProperty(propName)) {
                    value = item[propName];
                    return;
                }

                if (item.hasOwnProperty("binding") && item.hasOwnProperty("location") && item["binding"] == propName) {
                    value = item["location"]
                    return;
                }
            });
        }

        return value;
    }

    function fillFieldsByMetadata(res) {

        setDefaultSettings(true);
        enableSso(true);

        var metadata = res.meta ? res.meta : res.responseJSON.meta;

        var value;

        if (metadata.entityID)
            $ssoEntityId.val(metadata.entityID || "");

        if (metadata.singleSignOnService) {
            value = getPropValue(metadata.singleSignOnService, ssoConstants.SsoBindingType.Saml20HttpPost);
            if (value) {
                $ssoSignPostUrl.val(value);
                $ssoSignPostRbx.click();
            }

            value = getPropValue(metadata.singleSignOnService, ssoConstants.SsoBindingType.Saml20HttpRedirect);
            if (value) {
                $ssoSignRedirectUrl.val(value);
                $ssoSignRedirectRbx.click();
            }
        }

        if (metadata.singleLogoutService) {
            value = getPropValue(metadata.singleLogoutService, ssoConstants.SsoBindingType.Saml20HttpPost);

            if (value) {
                $ssoLogoutPostUrl.val(value);
                $ssoLogoutPostRbx.click();
            }

            value = getPropValue(metadata.singleLogoutService, ssoConstants.SsoBindingType.Saml20HttpRedirect);
            if (value) {
                $ssoLogoutRedirectUrl.val(value);
                $ssoLogoutRedirectRbx.click();
            }
        }

        if (metadata.nameIDFormat) {
            if (Array.isArray(metadata.nameIDFormat)) {
                var formats = metadata.nameIDFormat.filter(function (format) {
                    return includePropertyValue(ssoConstants.SsoNameIdFormatType, format);
                });
                if (formats.length) {
                    $ssoNameIdFormat.val(formats[0])
                    //window.Common.selectorListener.set($ssoNameIdFormat, formats[0]);
                }
            } else {
                if (includePropertyValue(ssoConstants.SsoNameIdFormatType, metadata.nameIDFormat)) {
                    $ssoNameIdFormat.val(metadata.nameIDFormat)
                    //window.Common.selectorListener.set($ssoNameIdFormat, metadata.nameIDFormat);
                }
            }
        }

        if (metadata.certificate) {
            var data = [];

            if (metadata.certificate.signing) {
                if (Array.isArray(metadata.certificate.signing)) {
                    metadata.certificate.signing = getUniqueItems(metadata.certificate.signing).reverse();
                    metadata.certificate.signing.forEach(function (signingCrt) {
                        data.push({
                            crt: signingCrt.trim(),
                            key: null,
                            action: ssoConstants.SsoIdpCertificateActionType.Verification
                        });
                    });

                    if (data.length > 1) {
                        window.toastr.warning(ASC.Resources.Master.ResourceJS.SsoCertificateMultipleVerificationError);
                    }
                } else {
                    data.push({
                        crt: metadata.certificate.signing.trim(),
                        key: null,
                        action: ssoConstants.SsoIdpCertificateActionType.Verification
                    });
                }
            }

            Teamlab.ssoValidateCerts({ certs: data },
                function (res) {
                    tmpIdpCertificates = res.responseJSON;
                    renderIdpCertificates(true);
                    onSettingsChanged();
                },
                function (error) {

                    var errorMessage = (error ? error.responseText || error.statusText : null) || ASC.Resources.Master.ResourceJS.OperationFailedError;
                    errorMessage = errorMessage == "Invalid certificate" ? ASC.Resources.Master.ResourceJS.InvalidCertificate : errorMessage

                    window.toastr.error(errorMessage);

                },
                null
            );
        }

        HideRequiredError();
        onSettingsChanged();
    }

    function getUniqueItems(array) {
        return array.filter(function (item, index, array) {
            return array.indexOf(item) == index
        });
    }

    function bindUploader() {

        $ssoSelectMetadataInput.fileupload({
            url: "/" + "sso/uploadmetadata",
            dataType: "json",
            autoUpload: true,
            singleFileUploads: true,
            sequentialUploads: true,
            progress: function () {
                LoadingBanner.displayLoading()
            },
            add: function (e, data) {
                var fileName = data.files[0].name;
                if (getFileExtension(fileName) !== ".xml") {
                    toastr.error(ASC.Resources.Master.ResourceJS.SsoMetadataFileTypeError);
                } else {
                    data.submit().then(fillFieldsByMetadata, function (error) {
                        var errorMessage = (error ? error.responseText || error.statusText : null) || ASC.Resources.Master.ResourceJS.OperationFailedError;

                        if (errorMessage == "Metadata file not transferred") {
                            errorMessage = ASC.Resources.Master.ResourceJS.MetadataFileNotTransferred;
                        } else if (errorMessage == "Incorrect metadata file type. A .xml file is required.") {
                            errorMessage = ASC.Resources.Master.ResourceJS.IncorrectMetadataFileType;
                        } else if (errorMessage == "Invalid metadata xml file") {
                            errorMessage = ASC.Resources.Master.ResourceJS.InvalidMetadataXmlFile;
                        }
                        if (error.status !== 500) {
		                    errorMessage = error.statusText;
		                }

                        window.toastr.error(errorMessage);
                    });
                }
            },
            always: function () {
                LoadingBanner.hideLoading();
            }
        });
    }

    function closeDialog() {
        PopupKeyUpActionProvider.CloseDialog();
    }

    function editSpCertificate() {
        if ($ssoSPCertificateContainer.hasClass("disable")) return;
        var actionType = jq(this).parent().find(".action").text().trim();

        var certificate = jq.grep(tmpSPCertificates, function (_item) {
            var item = setKeysToLowerCase(_item);
            return item.action == actionType;
        })[0];

        showSpCertificateDialog(certificate);
    }

    function prepareCertificateData(data) {
        
        var _data = setKeysToLowerCase(data);
        var res = jq.extend({}, _data);
        var now = new Date();

        if (typeof res.startDate !== "object")
            res.startDate = new Date(res.startDate);

        if (typeof res.expiredDate !== "object")
            res.expiredDate = new Date(res.expiredDate);

        res.valid = (res.startDate < now && res.expiredDate > now);
        res.startDateStr = res.startDate.toLocaleDateString();
        res.expiredDateStr = res.expiredDate.toLocaleDateString();

        return res;
    }

    function renderSpCertificates(changeSpAdvancedSettings) {
        var settings = getSettings();
        enableSpAdvancedSettings(settings.enableSso);
        var array = jq.map(tmpSPCertificates, function (item) {
            return prepareCertificateData(item);
        });

        html = $certificatesTmpl.tmpl({ items: array });
        html.appendTo($ssoSPCertificateContainer.empty());

        if (changeSpAdvancedSettings)
            $ssoSpCertificateSpoiler.find("input[type=checkbox]").prop('checked', false);

        if (!array.length) return;

        if ($ssoSpCertificateSpoiler.hasClass("display-none"))
            $ssoSpCertificateSpoilerLink.click();

        if (!changeSpAdvancedSettings) return;

        array.forEach(function (item) {
            if (item.action == ssoConstants.SsoSpCertificateActionType.Signing) {
                $ssoSignAuthRequestsCbx.prop('checked', true);
                $ssoSignLogoutRequestsCbx.prop('checked', true);
            }
            if (item.action == ssoConstants.SsoSpCertificateActionType.Encrypt) {
                $ssoEncryptAssertionsCbx.prop('checked', true);
            }
            if (item.action == ssoConstants.SsoSpCertificateActionType.SigningAndEncrypt) {
                $ssoSignAuthRequestsCbx.prop('checked', true);
                $ssoSignLogoutRequestsCbx.prop('checked', true);
                $ssoEncryptAssertionsCbx.prop('checked', true);
            }
        });
    }

    function deleteSpCertificate() {

        if ($ssoSPCertificateContainer.hasClass("disable")) return;
        var actionType = jq(this).parent().find(".action").text().trim();

        tmpSPCertificates = jq.grep(tmpSPCertificates, function (_item) {
            var item = setKeysToLowerCase(_item);
            return item.action != actionType;
        });

        renderSpCertificates(true);
        onSettingsChanged();
    }

    function checkSpCertificateExist(actionType) {

        var certificates = jq.grep(tmpSPCertificates, function (_item) {
            var item = setKeysToLowerCase(_item);
            return tmpCertificate ? item.action != tmpCertificate.action : true;
        });

        var exists = jq.grep(certificates, function (_item) {
            var item = setKeysToLowerCase(_item);
            return item.action == ssoConstants.SsoSpCertificateActionType.SigningAndEncrypt;
        });

        if (exists.length) {
            return true;
        }

        if (actionType == ssoConstants.SsoSpCertificateActionType.SigningAndEncrypt && certificates.length) {
            return true;
        }

        exists = jq.grep(certificates, function (item) {
            return item.action == actionType;
        });

        if (exists.length) {
            return true;
        }

        return false;
    }

    function addSpCertificate() {

        HideRequiredError();

        var isValid = true;

        var data = {
            crt: $ssoSpPublicCertificate.val().trim(),
            key: $ssoSpPrivateKey.val().trim(),
            action: $ssoSpCertificateActionType.val()
        };

        if (!data.crt) {
            isValid = false;
            ShowRequiredError($ssoSpPublicCertificate, !isValid, !isValid);
        }

        if (!data.key) {
            isValid = false;
            ShowRequiredError($ssoSpPrivateKey, !isValid, !isValid);
        }

        if (checkSpCertificateExist(data.action)) {
            isValid = false;
            
            window.toastr.error(ASC.Resources.Master.ResourceJS.SsoCertificateActionTypeError);
        }

        if (!isValid) return;

        LoadingBanner.displayLoading()

        Teamlab.ssoValidateCerts({ certs: [data] },
            function (res) {
                if (tmpCertificate) {
                    tmpSPCertificates = jq.grep(tmpSPCertificates, function (_item) {
                        var item = setKeysToLowerCase(_item);
                        return item.action != tmpCertificate.action;
                    });
                }
                
                tmpSPCertificates = tmpSPCertificates.concat(res.responseJSON[0]);
                renderSpCertificates(true);
                onSettingsChanged();
                PopupKeyUpActionProvider.CloseDialog();
            },
            function (error) {

                var errorMessage = (error ? error.responseText || error.statusText : null) || ASC.Resources.Master.ResourceJS.OperationFailedError;
                errorMessage = errorMessage == "Invalid certificate" ? ASC.Resources.Master.ResourceJS.InvalidCertificate : errorMessage

                window.toastr.error(errorMessage);

            },
            function () {
                LoadingBanner.hideLoading();
            }
        );

    }

    function generateSpCertificate() {
        LoadingBanner.displayLoading()
        enableInputs(false, $ssoSpCertificateDialog);

        Teamlab.ssoGenerateCert(
            function (res) {
                if (res) {
                    $ssoSpPublicCertificate.val(res.responseJSON.crt);
                    $ssoSpPrivateKey.val(res.responseJSON.key);
                }

            },
            function (error) {

                var errorMessage = (error ? error.responseText || error.statusText : null) || ASC.Resources.Master.ResourceJS.OperationFailedError;
                errorMessage = errorMessage == "Cannot generate certificate" ? ASC.Resources.Master.ResourceJS.CannotGenerateCertificate : errorMessage

                if (error.status !== 500) {
                    errorMessage = error.statusText;
                }

                window.toastr.error(errorMessage);

            },
            function () {
                LoadingBanner.hideLoading()
                enableInputs(true, $ssoSpCertificateDialog);
            }
        );
    }

    function showSpCertificateDialog(_certificate) {
        if (jq(this).hasClass("disable"))
            return;

        var certificate = _certificate != null && _certificate != undefined ? setKeysToLowerCase(_certificate) : _certificate;

        tmpCertificate = certificate;

        HideRequiredError();

        $ssoSpCertificateDialog.find("input, textarea").attr("disabled", false).val("");
        $ssoSpCertificateDialog.find(".selectBox, .radioBox, .checkBox, .button").removeClass("disable");

        if (certificate) {
            $ssoSpPublicCertificate.val(certificate.crt);
            $ssoSpPrivateKey.val(certificate.key);


            $ssoSpCertificateActionType.val(certificate.action);
            //window.Common.selectorListener.set($ssoSpCertificateActionType, certificate.action); //TODO check

            $ssoSpCertificateDialog.find(".create-caption").addClass("display-none");
            $ssoSpCertificateDialog.find(".edit-caption").removeClass("display-none");
        } else {
            $ssoSpCertificateDialog.find(".create-caption").removeClass("display-none");
            $ssoSpCertificateDialog.find(".edit-caption").addClass("display-none");
        }
        StudioBlockUIManager.blockUI("#ssoSpCertificateDialog", 500);

    }

    function editIdpCertificate() {

        if ($ssoIdPCertificateContainer.hasClass("disable")) return;
        var index = jq(this).parent().index();

        var certificate = jq.grep(tmpIdpCertificates, function (item, i) {
            return i == index;
        })[0];

        showIdpCertificateDialog(certificate, index);
    }

    function onDownloadSPMetadata() {
        if (jq(this).hasClass("disable"))
            return;

        window.open(jq(this).attr("data-href"), "_blank");
    }

    function renderIdpCertificates(changeIdpAdvancedSettings) {
        var settings = getSettings();
        enableIdpAdvancedSettings(settings.enableSso);
        var array = jq.map(tmpIdpCertificates, function (item) {
            return prepareCertificateData(item);
        });

        var html = $certificatesTmpl.tmpl({ items: array });
        html.appendTo($ssoIdPCertificateContainer.empty());

        if (changeIdpAdvancedSettings)
            $ssoIdpCertificateSpoiler.find("input[type=checkbox]").prop('checked', false);

        if (!array.length) return;

        if ($ssoIdpCertificateSpoiler.hasClass("display-none"))
            $ssoIdpCertificateSpoilerLink.click();

        if (!changeIdpAdvancedSettings) return;

        array.forEach(function (item) {
            if (item.action == ssoConstants.SsoIdpCertificateActionType.Verification) {
                $ssoVerifyAuthResponsesSignCbx.prop('checked', true);
                $ssoVerifyLogoutRequestsSignCbx.prop('checked', true);
            }
            if (item.action == ssoConstants.SsoIdpCertificateActionType.Decrypt) {
                $ssoDecryptAssertionsCbx.prop('checked', true);
            }
            if (item.action == ssoConstants.SsoIdpCertificateActionType.VerificationAndDecrypt) {
                $ssoVerifyAuthResponsesSignCbx.prop('checked', true);
                $ssoVerifyLogoutRequestsSignCbx.prop('checked', true);
                $ssoDecryptAssertionsCbx.prop('checked', true);
            }
        });
    }

    function deleteIdpCertificate() {

        if ($ssoIdPCertificateContainer.hasClass("disable")) return;
        var index = jq(this).parent().index();

        tmpIdpCertificates = jq.grep(tmpIdpCertificates, function (item, i) {
            return i != index;
        });

        renderIdpCertificates(true);
        onSettingsChanged();
    }

    function addIdpCertificate() {

        HideRequiredError();
        var isValid = true;

        var data = {
            crt: $ssoIdpPublicCertificate.val().trim(),
            key: null,
            action: ssoConstants.SsoIdpCertificateActionType.Verification 
        };
        if (!data.crt) {
            isValid = false;
            ShowRequiredError($ssoIdpPublicCertificate, !isValid, !isValid);
        }

        if (checkIdpCertificateExist(data.action)) {
            isValid = false;

            window.toastr.error(ASC.Resources.Master.ResourceJS.SsoCertificateActionTypeError);

        }

        if (!isValid) return;

        LoadingBanner.displayLoading()
        Teamlab.ssoValidateCerts({ certs: [data] },
            function (res) {
                if (tmpCertificate) {
                    tmpIdpCertificates[tmpCertificateIndex] = res.responseJSON[0];
                } else {
                    tmpIdpCertificates = tmpIdpCertificates.concat(res.responseJSON[0]);
                }

                renderIdpCertificates(true);
                onSettingsChanged();
                PopupKeyUpActionProvider.CloseDialog();
            },
            function (error) {

                var errorMessage = (error ? error.responseText || error.statusText : null) || ASC.Resources.Master.ResourceJS.OperationFailedError;
                errorMessage = errorMessage == "Invalid certificate" ? ASC.Resources.Master.ResourceJS.InvalidCertificate : errorMessage

                if (error.status !== 500) {
                    errorMessage = error.statusText;
                }

                window.toastr.error(errorMessage);

            },
            function () {
                LoadingBanner.hideLoading();
            }
        );
    }

    function showError(error) {
        window.toastr.error((error ? error.responseText || error.statusText : null) || ASC.Resources.Master.ResourceJS.OperationFailedError);
    }

    function checkIdpCertificateExist(actionType) {

        var certificates = jq.grep(tmpIdpCertificates, function (item) {
            return tmpCertificate ? item.action != tmpCertificate.action : true;
        });

        var exists = jq.grep(certificates, function (item) {
            return item.action == ssoConstants.SsoIdpCertificateActionType.VerificationAndDecrypt;
        });

        if (exists.length) {
            return true;
        }

        if (actionType == ssoConstants.SsoIdpCertificateActionType.VerificationAndDecrypt && certificates.length) {
            return true;
        }

        exists = jq.grep(certificates, function (item) {
            return item.action == actionType;
        });

        if (exists.length) {
            return true;
        }
        if (tmpCertificate) {
            var exists =jq.grep(tmpIdpCertificates, function (item, i) {
                return i != tmpCertificateIndex && item.action == data.action && item.crt == data.crt;
            });

            if (exists.length) {
                return true;
            }
        }

        return false;
    }

    function showIdpCertificateDialog(_certificate, index) {
        if (jq(this).hasClass("disable"))
            return;

        var certificate = _certificate != null && _certificate != undefined ? setKeysToLowerCase(_certificate) : _certificate;

        tmpCertificate = certificate;
        tmpCertificateIndex = index;

        HideRequiredError();
        $ssoIdpCertificateDialog.find("input, textarea").attr("disabled", false).val("");
        $ssoIdpCertificateDialog.find(".selectBox, .radioBox, .checkBox, .button").removeClass("disable");

        if (certificate) {
            $ssoIdpPublicCertificate.val(certificate.crt);
            
            $ssoIdpCertificateDialog.find(".create-caption").addClass("display-none");
            $ssoIdpCertificateDialog.find(".edit-caption").removeClass("display-none");
        } else {
            $ssoIdpCertificateDialog.find(".create-caption").removeClass("display-none");
            $ssoIdpCertificateDialog.find(".edit-caption").addClass("display-none");
        }
        StudioBlockUIManager.blockUI("#ssoIdpCertificateDialog", 500);
    }

    function onCheckBoxChanged() {
        if (jq(this).hasClass("disable")) return;

        onSettingsChanged();
    }

    function onRadioBoxChanged() {
        var $this = jq(this);

        if ($this.hasClass("disable")) return;

        $this.closest(".sso-settings-block").find(".textEdit").addClass("display-none");
        jq("#" + $this.attr("data-value")).removeClass("display-none");

        onSettingsChanged();
    }

    var isValidUrl = function (url) {
        return /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(url);
    }

    function loadMetadata() {
        if (jq(this).hasClass("disable"))
            return;

        var url = $ssoUploadMetadataInput.val().trim();

        if (!url || !isValidUrl(url)) {
            $ssoUploadMetadataInput.toggleClass("error", true);
            return;
        }

        $ssoUploadMetadataInput.toggleClass("error", false);
        LoadingBanner.displayLoading()

        Teamlab.ssoLoadMetadata({ url: url },
            function (res) {
                fillFieldsByMetadata(res);
            },
            function (error) {
                var errorMessage = (error ? error.responseText || error.statusText : null) || ASC.Resources.Master.ResourceJS.OperationFailedError;

                if (error.status !== 500) {
                    errorMessage = error.statusText;
                }
                if (errorMessage == "Metadata file not transferred") {
                    errorMessage = ASC.Resources.Master.ResourceJS.MetadataFileNotTransferred;
                }  else if (errorMessage == "Invalid metadata xml file") {
                    errorMessage = ASC.Resources.Master.ResourceJS.InvalidMetadataXmlFile;
                }

                window.toastr.error(errorMessage);
            },
            function () {
                LoadingBanner.hideLoading();
            }
        );
    }

    function resetSettings() {
        if (jq(this).hasClass("disable"))
            return;

        StudioBlockUIManager.blockUI("#ssoSettingsInviteDialog", 500);
    }

    function saveSettings() {
        if (jq(this).hasClass("disable"))
            return;

        var validSettings = getValidSettings();

        if (!validSettings) {
            enableSaveBtn(false);
            return;
        }
        LoadingBanner.displayLoading()
        Teamlab.saveSsoSettings({},
            { serializeSettings: JSON.stringify(validSettings) },
            {
                success: function (res, data) {
                    showSuccess(data);
                    onSettingsChanged();
                    LoadingBanner.hideLoading();
                },
                error: function (error) {
                    showError(error)
                    onSettingsChanged();
                    LoadingBanner.hideLoading();
                },
            });
    }

    function getValidSettings() {
        HideRequiredError();

        var isValid = true;
        var settings = getSettings();

        if (!settings.spLoginLabel) {
            isValid = false;
            ShowRequiredError($ssoSpLoginLabel, !isValid, !isValid);
        }

        if (!settings.idpSettings.entityId) {
            isValid = false;
            ShowRequiredError($ssoEntityId, !isValid, !isValid);
        }

        if (!settings.idpSettings.ssoUrl) {
            isValid = false;
            ShowRequiredError($ssoSignPostRbx.hasClass("checked") ? $ssoSignPostUrl : $ssoSignRedirectUrl, !isValid, !isValid);
        }

        if (!settings.fieldMapping.firstName) {
            isValid = false;
            ShowRequiredError($ssoFirstName, !isValid, !isValid);
        }

        if (!settings.fieldMapping.lastName) {
            isValid = false;
            ShowRequiredError($ssoLastName, !isValid, !isValid);
        }

        if (!settings.fieldMapping.email) {
            isValid = false;
            ShowRequiredError($ssoEmail, !isValid, !isValid);
        }
        var verificationCertificates = jq.grep(settings.idpCertificates, function (item) {
            return item.action == ssoConstants.SsoIdpCertificateActionType.Verification ||
                item.action == ssoConstants.SsoIdpCertificateActionType.VerificationAndDecrypt;
        });

        if (verificationCertificates.length > 1) {
            isValid = false;
            window.toastr.error(ASC.Resources.Master.ResourceJS.SsoCertificateMultipleVerificationError);
        }

        return isValid ? settings : null;
    }

    function ShowRequiredError(item, withouthScroll, withouthFocus) {
        
        jq("div[class='infoPanel alert']").hide();
        jq("div[class='infoPanel alert']").empty();
        var parentBlock = jq(item).parents(".requiredField");
        jq(parentBlock).addClass("requiredFieldError");

        if (typeof (withouthScroll) == "undefined" || withouthScroll == false) {
            jq.scrollTo(jq(parentBlock).position().top - 50, { speed: 500 });
        }

        if (typeof (withouthFocus) == "undefined" || withouthFocus == false) {
            jq(item).focus();
        }
    }

    function showSuccess(data) {
        currentSettings = data;
        toastr.success(ASC.Resources.Master.ResourceJS.LdapSettingsSuccess);

        if (!currentSettings.enableSso)
            spoiler.toggle("#ssoSPSettingsSpoiler", "#ssoSPSettingsSpoilerLink", false);

        spoiler.toggle("#ssoSPMetadataSpoiler", "#ssoSPMetadataSpoilerLink", currentSettings.enableSso ? true : false);

        // Scroll page to full bottom
        jq("html, body").animate({ scrollTop: jq(document).height() }, 1000);
    }

    function HideRequiredError() {
        jq(".requiredField").removeClass("requiredFieldError");
    }

    function setKeysToLowerCase(object) {

        var _object = new Object;
        Object.keys(object).map(key => {
            _object[key.charAt(0).toLowerCase() + key.slice(1)] = object[key]
        });

        return _object;

    }

    function enableSso(on) {
        $ssoEnableBtn.toggleClass("off", !on).toggleClass("on", on);

        if (on && $ssoSPSettingsSpoiler.hasClass("display-none")) {
            $ssoSPSettingsSpoilerLink.click();
        }

        enableInputs(on);

        HideRequiredError();

        onSettingsChanged();
        enableIdpAdvancedSettings(on);
        enableSpAdvancedSettings(on);
    }

    function enableIdpAdvancedSettings(on) {

        $ssoIdpCertificateSpoiler.find("input[type=checkbox], select").attr("disabled", true);
        $ssoIdPCertificateContainer.addClass("disable");

        if (!on) return;

        $ssoIdPCertificateContainer.removeClass("disable");
        tmpIdpCertificates.forEach(function (item) {

            var _item = setKeysToLowerCase(item);

            if (_item.action == ssoConstants.SsoIdpCertificateActionType.Verification || _item.action == ssoConstants.SsoIdpCertificateActionType.VerificationAndDecrypt) {
                $ssoVerifyAuthResponsesSignCbx.attr("disabled", false);
                $ssoVerifyLogoutRequestsSignCbx.attr("disabled", false);
                $ssoVerifyLogoutResponsesSignCbx.attr("disabled", false);
                $ssoDefaultSignVerifyingAlgorithm.attr("disabled", false);
            }
            if (_item.action == ssoConstants.SsoIdpCertificateActionType.Decrypt || _item.action == ssoConstants.SsoIdpCertificateActionType.VerificationAndDecrypt) {
                $ssoDecryptAssertionsCbx.attr("disabled", false);
                $ssoDefaultDecryptAlgorithm.attr("disabled", false);
            }
        });
    }

    function enableSpAdvancedSettings(on) {
        $ssoSpCertificateSpoiler.find("input[type=checkbox], select").attr("disabled", true);
        $ssoSPCertificateContainer.addClass("disable");
        if (!on) return;

        $ssoSPCertificateContainer.removeClass("disable");
        tmpSPCertificates.forEach(function (item) {

            var _item = setKeysToLowerCase(item);

            if (_item.action == ssoConstants.SsoSpCertificateActionType.Signing || _item.action == ssoConstants.SsoSpCertificateActionType.SigningAndEncrypt) {
                $ssoSignAuthRequestsCbx.attr("disabled", false);
                $ssoSignLogoutRequestsCbx.attr("disabled", false);
                $ssoSignLogoutResponsesCbx.attr("disabled", false);
                $ssoSigningAlgorithm.attr("disabled", false);
            }
            if (_item.action == ssoConstants.SsoSpCertificateActionType.Encrypt || _item.action == ssoConstants.SsoSpCertificateActionType.SigningAndEncrypt) {
                $ssoEncryptAssertionsCbx.attr("disabled", false);
                $ssoEncryptAlgorithm.attr("disabled", false);
            }
        });
    }

    function onSsoEnabled() {
        var $this = jq(this);
        var on = $this.hasClass("off");
        var settings = setKeysToLowerCase(currentSettings);
        if (settings.enableSso) {
            StudioBlockUIManager.blockUI("#ssoSettingsTurnOffDialog", 500);
        }
        else {
            enableSso(on);
        }
    }

    function enableInputs(enabled, parent) {
        parent = parent || $ssoMainContainer;
        parent.find("input:not(.blocked), textarea:not(.blocked), select").attr("disabled", !enabled);
        parent.find(".radioBox, .checkBox, .button:not(.on-off-button)").toggleClass("disable", !enabled);
    }

    function onSettingsChanged() {
        var hasUserChanges = hasChanges();
        var isDefaultSettings = isDefault();
        var settings = getSettings();

        enableSaveBtn(hasUserChanges);
        enableResetBtn(!isDefaultSettings);
        enableDownloadBtn(settings.enableSso && !hasUserChanges && !isDefaultSettings);
    }

    function enableSaveBtn(enabled) {
        $ssoSaveBtn.toggleClass("disable", !enabled);
    }

    function enableResetBtn(enabled) {
        $ssoResetBtn.toggleClass("disable", !enabled);
    }

    function enableDownloadBtn(enabled) {
        $ssoDownloadSPMetadataBtn.toggleClass("disable", !enabled);
    }

    function hasChanges() {
        return !isEqual(currentSettings, getSettings());
    }

    function isDefault() {
        return isEqual(currentSettings, defaultSettings);
    }

    function getFileExtension(fileName) {
        if (!fileName) return "";

        var posExt = fileName.lastIndexOf(".");
        return posExt >= 0 ? fileName.substring(posExt).trim().toLowerCase() : "";
    }

    function isEqual(_a, _b) {
        var a = setKeysToLowerCase(_a);
        var b = setKeysToLowerCase(_b);

        if (a === null || b === null)
            return a === b;

        var aProps = Object.getOwnPropertyNames(a);
        var bProps = Object.getOwnPropertyNames(b);

        if (aProps.length != bProps.length) {
            return false;
        }

        for (var i = 0; i < aProps.length; i++) {
            var propName = aProps[i].charAt(0).toLowerCase() + aProps[i].slice(1);
            if (typeof a[propName] == "object" && a[propName] != null) {
                if (!isEqual(a[propName], b[propName])) {
                    return false;
                }
            } else {
                if (a[propName] !== b[propName]) {
                    return false;
                }
            }
        }

        function showSuccess(data) {
            currentSettings = data;
            
            toastr.success(ASC.Resources.Master.ResourceJS.SsoSettingsSuccess);

            if (!currentSettings.EnableSso)
                window.Common.spoiler.toggle("#ssoSPSettingsSpoiler", "#ssoSPSettingsSpoilerLink", false); //currentSettings.enableSso ? false : true);

            window.Common.spoiler.toggle("#ssoSPMetadataSpoiler", "#ssoSPMetadataSpoilerLink", currentSettings.EnableSso ? true : false);

            // Scroll page to full bottom
            jq("html, body").animate({ scrollTop: jq(document).height() }, 1000);
        }

        return true;
    }

    function includePropertyValue(obj, value) {
        var props = Object.getOwnPropertyNames(obj);

        for (var i = 0; i < props.length; i++) {
            if (obj[props[i]] === value)
                return true;
        }

        return false;
    }

    return {
        init: init
    };

})();

var spoiler = function () {
    var toggle = function (toggleEl, spoilerEl, force, hideLinkText, showLinkText) {
        var el = jq(toggleEl);
        var $this = jq(spoilerEl);
        if (!el)
            return;

        var enabled = typeof force === "boolean" ? force : el.hasClass('display-none');
        var linkText = "";

        if (enabled) {
            el.toggleClass('display-none', false);
            if ($this) {
                linkText = hideLinkText || ASC.Resources.Master.ResourceJS.HideLink;
                $this.text(linkText).prop('title', linkText);
            }
        } else {
            el.toggleClass('display-none', true);
            if ($this) {
                linkText = showLinkText || ASC.Resources.Master.ResourceJS.ShowLink;
                $this.text(linkText).prop('title', linkText);
            }
        }
    };

    return {
        toggle: toggle
    };
}();

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_OptionTags.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    /// <summary>
    /// SIP Option Tags. Defined in RFC 3261 27.1, defined values are in: http://www.iana.org/assignments/sip-parameters.
    /// </summary>
    /// <remarks>
    /// Option tags are used in header fields such as Require, Supported, Proxy-Require, and 
    /// Unsupported in support of SIP compatibility mechanisms for extensions (Section 19.2). 
    /// The option tag itself is a string that is associated with a particular SIP option (that is, an extension).
    /// </remarks>
    public class SIP_OptionTags
    {
        #region Members

        /// <summary>
        /// A UA adding the early-session option tag to a message indicates that it understands the 
        /// early-session content disposition. Defined in rfc 3959.
        /// </summary>
        public const string early_session = "early-session";

        /// <summary>
        /// Extension to allow subscriptions to lists of resources. Defined in rfc 4662.
        /// </summary>
        public const string eventlist = "eventlist";

        /// <summary>
        /// When used with the Supported header, this option tag indicates support for the 
        /// History Information to be captured for requests and returned in subsequent responses. 
        /// This tag is not used in a Proxy-Require or Require header field since support of 
        /// History-Info is optional. Defined in rfc 4244.
        /// </summary>
        public const string histinfo = "histinfo";

        /// <summary>
        /// Support for the SIP Join Header. Defined in rfc 3911.
        /// </summary>
        public const string join = "join";

        /// <summary>
        /// This option tag specifies a User Agent ability of accepting a REFER request without 
        /// establishing an implicit subscription (compared to the default case defined in RFC3515).
        /// Defined in rfc 3911.
        /// </summary>
        public const string norefersub = "norefersub";

        /// <summary>
        /// A SIP UA that supports the Path extension header field includes this option tag as a 
        /// header field value in a Supported header field in all requests generated by that UA. 
        /// Intermediate proxies may use the presence of this option tag in a REGISTER request to
        /// determine whether to offer Path service for for that request. If an intermediate proxy 
        /// requires that the registrar support Path for a request, then it includes this option tag 
        /// as a header field value in a Requires header field in that request. Defined in rfc 3327.
        /// </summary>
        public const string path = "path";

        /// <summary>
        /// An offerer MUST include this tag in  the Require header field if the offer contains 
        /// one or more "mandatory" strength-tags. If all the strength-tags in the description are
        /// "optional" or "none" the offerer MUST include this tag either in a Supported header field or 
        /// in a Require header field. Defined in rfc 3312.
        /// </summary>
        public const string precondition = "precondition";

        /// <summary>
        /// This option tag is used to ensure that a server understands the callee capabilities 
        /// parameters used in the request. Defined in rfc 3840.
        /// </summary>
        public const string pref = "pref";

        /// <summary>
        /// This option tag indicates support for the Privacy mechanism. When used in the 
        /// Proxy-Require header, it indicates that proxy servers do not forward the request unless they 
        /// can provide the requested privacy service. This tag is not used in the Require or 
        /// Supported headers. Proxies remove this option tag before forwarding the request if the desired 
        /// privacy function has been performed. Defined in rfc 3323.
        /// </summary>
        public const string privacy = "privacy";

        /// <summary>
        /// This option tag indicates support for the SIP Replaces header. Defined in rfc 3891.
        /// </summary>
        public const string replaces = "replaces";

        /// <summary>
        /// Indicates or requests support for the resource priority mechanism. Defined in rfc 4412.
        /// </summary>
        public const string resource_priority = "resource-priority";

        /// <summary>
        /// The option-tag sdp-anat is defined for use in the Require and Supported SIP [RFC3261] 
        /// header fields. SIP user agents that place this option-tag in a Supported header field understand 
        /// the ANAT semantics as defined in [RFC4091]. Defined in rfc 4092.
        /// </summary>
        public const string sdp_anat = "sdp-anat";

        /// <summary>
        /// This option tag indicates support for the Security Agreement mechanism. When used in the 
        /// Require, or Proxy-Require headers, it indicates that proxy servers are required to use the Security 
        /// Agreement mechanism.  When used in the Supported header, it indicates that the User Agent Client 
        /// supports the Security Agreement mechanism. When used in the Require header in the 494 (Security Agreement 
        /// Required) or 421 (Extension Required) responses, it indicates that the User Agent Client must use the 
        /// Security Agreement Mechanism. Defined in rfc 3329.
        /// </summary>
        public const string sec_agree = "sec-agree";

        /// <summary>
        /// This option tag is used to identify the target dialog header field extension.  When used in a 
        /// Require header field, it implies that the recipient needs to support the Target-Dialog header field. 
        /// When used in a Supported header field, it implies that the sender of the message supports it. 
        /// Defined in rfc 4538.
        /// </summary>
        public const string tdialog = "tdialog";

        /// <summary>
        /// This option tag is for support of the session timer extension. Inclusion in a Supported 
        /// header field in a request or response indicates that the UA is capable of performing 
        /// refreshes according to that specification.  Inclusion in a Require header in a request 
        /// means that the UAS must understand the session timer extension to process the request.  
        /// Inclusion in a Require header field in a response indicates that the UAC must look for the 
        /// Session-Expires header field in the response, and process accordingly. Defined in rfc 4028.
        /// </summary>
        public const string timer = "timer";

        /// <summary>
        /// This option tag is for reliability of provisional responses. When present in a 
        /// Supported header, it indicates that the UA can send or receive reliable provisional
        /// responses. When present in a Require header in a request it indicates that the UAS MUST 
        /// send all provisional responses reliably. When present in a Require header in a
        /// reliable provisional response, it indicates that the response is to be sent reliably.
        /// Defined in rfc 3262.
        /// </summary>
        public const string x100rel = "100rel";

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Common/FileUploader.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;

using ASC.Web.Studio.Core;

namespace ASC.Web.CRM.Controls.Common
{
    public partial class FileUploader : BaseUserControl
    {
        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Common/FileUploader.ascx"); }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterBodyScripts("~/js/uploader/jquery.fileupload.js");
            Page.RegisterBodyScripts("~/js/uploader/jquery.fileuploadmanager.js");

            RegisterScript();
        }

        private void RegisterScript()
        {
            var sb = new StringBuilder();
            sb.AppendFormat(" var uploadFileSizeLimit = \"{0}\"; ", SetupInfo.MaxUploadSize);
            Page.RegisterInlineScript(sb.ToString(), onReady: false);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Test/SearchTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;

using ASC.ElasticSearch;
using ASC.Projects.Core.Domain;
using ASC.Web.Projects.Core.Search;

namespace ASC.Web.Projects.Test
{
    using ASC.Core;

    using NUnit.Framework;

    [TestFixture]
    [TestOf(typeof(SearchTest))]
    public class SearchTest : BaseTest
    {
        private List<Project> Projects { get; set; }

        [OneTimeSetUp]
        public void Setup()
        {
            Projects = new List<Project>
            {
                CreateProject("Project for testing search фёдор", "Description"),
                CreateProject("Another Project for testing search фёдор", "Another Description")
            };
        }

        [TestCaseSource(typeof(SearchCaseData), "TestCases", new object[] { "Search Project all by " })]
        public void ProjectAll(string searchText)
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }
        }

        //[Test]
        //public void ProjectSpecial()
        //{
        //    var projectsSpecial = new List<Project>
        //    {
        //        CreateProject("<EMAIL>", "abc"),
        //        CreateProject("<EMAIL>", "abc")
        //    };

        //    List<int> result;
        //    FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll("<EMAIL>"), out result);

        //    CollectionAssert.IsNotEmpty(result);
        //    Assert.AreEqual(result.Count, 1);
        //    Assert.AreEqual(result[0], projectsSpecial[0].ID);

        //    FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll("test"), out result);

        //    foreach (var prj in projectsSpecial)
        //    {
        //        CollectionAssert.Contains(result, prj.ID);
        //    }

        //    projectsSpecial.ForEach(DeleteProject);
        //}

        [TestCaseSource(typeof(SearchCaseData), "TestCases", new object[] { "Search Project all in " })]
        public void ProjectAllIn(string searchText)
        {
            List<int> result;
            var prj = Projects[0].ID;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText).In(r => r.Id, new[] { prj }), out result);

            Assert.AreEqual(result[0], prj);

            var prj2 = Projects[1].ID;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText).In(r => r.Id, new[] { prj, prj2 }), out result);

            Assert.AreEqual(result.Count, 2);
        }

        [TestCaseSource(typeof(SearchCaseData), "TestCases", new object[] { "Search Project multi by " })]
        public void ProjectMulti(string searchText)
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Match(r => new object[] { r.Title, r.Description }, searchText), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }
        }

        [TestCaseSource(typeof(SearchCaseData), "TestCases", new object[] { "Search Project or by " })]
        public void ProjectOr(string searchText)
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Or(r => r.Match(k => k.Title, searchText), r => r.Match(k => k.Description, searchText)), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }
        }

        [TestCaseSource(typeof(SearchCaseData), "TestCases", new object[] { "Search Project or by " })]
        public void ProjectNot(string searchText)
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Not(r => r.Match(k => k.Title, searchText + "1")).MatchAll(searchText), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }
        }

        [Test]
        public void ProjectMultiProps()
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Match(r => r.Title, "Project").Match(r => r.Description, "Description"), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }
        }

        [TestCaseSource(typeof(SearchCaseData), "WildCardTestCases", new object[] { "Search Project wildcard by " })]
        public void ProjectWildCard(string searchText)
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Or(r => r.Match(a => a.Title, searchText), r => r.Match(a => a.Description, searchText)), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }

        }

        [TestCaseSource(typeof(SearchCaseData), "TestCases", new object[] { "Search Project exactly by " })]
        public void ProjectExactly(string searchText)
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Or(r => r.Match(a => a.Title, "\"" + searchText + "\""), r => r.Match(a => a.Description, "\"" + searchText + "\"")), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll("\"" + searchText + "\""), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }
        }

        [Test]
        public void ProjectPhrase()
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Match(r => r.Title, "\"Project for\""), out result);

            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Match(r => r.Title, "\"for search\""), out result);
            CollectionAssert.IsEmpty(result);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Match(r => r.Title, "for search"), out result);
            foreach (var prj in Projects)
            {
                CollectionAssert.Contains(result, prj.ID);
            }
        }

        //[Test]
        //public void ProjectTag()
        //{
        //    var proj = CreateProject("TQDAZCBGT", "");

        //    TagEngine.SetProjectTags(proj.ID, "tag123,tag1234");

        //    var tag = TagEngine.GetProjectTags(proj.ID);

        //    FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper
        //    {
        //        Id = proj.ID,
        //        TagsWrapper = tag.Keys.Select(r => new TagsWrapper
        //        {
        //            TagId = r
        //        }).ToList()
        //    }, true, r => r.TagsWrapper);

        //    var proj1 = CreateProject("UYTRHGF", "");

        //    TagEngine.SetProjectTags(proj1.ID, "tag123");

        //    tag = TagEngine.GetProjectTags(proj1.ID);

        //    FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper
        //    {
        //        Id = proj1.ID,
        //        TagsWrapper = tag.Keys.Select(r => new TagsWrapper
        //        {
        //            TagId = r
        //        }).ToList()
        //    }, true, r => r.TagsWrapper);

        //    var proj2 = CreateProject("RFVTGB", "");

        //    TagEngine.SetProjectTags(proj2.ID, "tag5432");

        //    tag = TagEngine.GetProjectTags(proj2.ID);

        //    FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper
        //    {
        //        Id = proj2.ID,
        //        TagsWrapper = tag.Keys.Select(r => new TagsWrapper
        //        {
        //            TagId = r
        //        }).ToList()
        //    }, true, r => r.TagsWrapper);

        //    FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper
        //    {
        //        TagsWrapper = tag.Keys.Select(r => new TagsWrapper
        //        {
        //            TagId = r
        //        }).ToList()
        //    },
        //    r => r.In(a => a.Id, new[] { proj.ID, proj1.ID }),
        //    UpdateAction.Add,
        //    r => r.TagsWrapper);

        //    List<int> result;
        //    //FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.Nested(w=> w.In(r => r.TagsWrapper.Select(t=> t.TagId), new[] {tag.Keys.First() })), out result);
        //    FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.In(r => r.TagsWrapper.Select(t => t.TagId), new[] { tag.Keys.First() }), out result);

        //    CollectionAssert.IsNotEmpty(result);
        //    Assert.AreEqual(result.Count, 3);

        //    tag = TagEngine.GetProjectTags(proj.ID);

        //    FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.InAll(r => r.TagsWrapper.Select(b => b.TagId), tag.Select(r => r.Key).ToArray()), out result);

        //    CollectionAssert.IsNotEmpty(result);
        //    Assert.AreEqual(result.Count, 1);
        //    Assert.AreEqual(proj.ID, result[0]);

        //    DeleteProject(proj);
        //    DeleteProject(proj1);
        //    DeleteProject(proj2);
        //}

        [TestCaseSource(typeof(SearchCaseData), "TestCases", new object[] { "Search Project sort " })]
        public void ProjectSort(string searchText)
        {
            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText).Sort(a => a.Id, false), out result);

            Assert.Greater(result[0], result[1]);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText).Sort(a => a.LastModifiedOn, true), out result);

            Assert.Greater(result[1], result[0]);
        }

        [Test(Description = "Search Project update ")]
        public void ProjectUpdate()
        {
            var searchText = "ABCDEF";
            var proj = CreateProject(searchText, "Description");

            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);

            Assert.AreEqual(result[0], proj.ID);

            FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper { Id = proj.ID, Title = "QWERTY" }, true, r => r.Title);
            FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper { Id = proj.ID, LastModifiedOn = DateTime.UtcNow }, true, r => r.LastModifiedOn);
            FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper { Id = proj.ID, TenantId = 10 }, true, r => r.TenantId);
            FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper { Id = proj.ID, TenantId = 5, Title = "Tenant" }, true, r => r.TenantId, r => r.Title);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);
            CollectionAssert.IsEmpty(result);

            DeleteProject(proj);
        }

        [Test(Description = "Search Project update by query")]
        public void ProjectUpdateByQuery()
        {
            var searchText = "ABCDEF";
            var proj1 = CreateProject(searchText, "Description");
            var proj2 = CreateProject(searchText, "Description");
            var proj3 = CreateProject(searchText, "Description");

            List<int> result;
            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);

            Assert.AreEqual(result.Count, 3);

            var newTitle = "QWERTY";
            FactoryIndexer<ProjectsWrapper>.Update(new ProjectsWrapper { Title = "QWERTY" }, r => r.In(t => t.Id, new[] { proj1.ID, proj2.ID }), true, r => r.Title);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(newTitle), out result);
            Assert.AreEqual(result.Count, 2);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);
            Assert.AreEqual(result[0], proj3.ID);

            DeleteProject(proj1);
            DeleteProject(proj2);
            DeleteProject(proj3);
        }

        //[Test(Description = "Delete by id ")]
        //public async System.Threading.Tasks.Task ProjectDeleteById()
        //{
        //    var searchText = "ABCDEF";
        //    var proj = CreateProject(searchText, "Description");

        //    List<int> result;
        //    var tenant = CoreContext.TenantManager.GetCurrentTenant();
        //    await FactoryIndexer<ProjectsWrapper>.DeleteAsync(proj.ID);
        //    FactoryIndexer<ProjectsWrapper>.Flush();
        //    await System.Threading.Tasks.Task.Delay(1000);

        //    CoreContext.TenantManager.SetCurrentTenant(tenant.TenantId);
        //    SecurityContext.AuthenticateMe(tenant.OwnerId);

        //    FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);
        //    CollectionAssert.IsEmpty(result);

        //    Delete(proj);

        //    FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll("Another"), out result);
        //    CollectionAssert.IsNotEmpty(result);
        //}

        [Test(Description = "Delete by query ")]
        public void ProjectDeleteByQuery()
        {
            var searchText = "QAZWSX";
            var proj = CreateProject(searchText, "Description");

            List<int> result;
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            FactoryIndexer<ProjectsWrapper>.Delete(r => r.Match(a => a.Title, searchText));

            CoreContext.TenantManager.SetCurrentTenant(tenant.TenantId);
            SecurityContext.AuthenticateMe(tenant.OwnerId);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);
            CollectionAssert.IsEmpty(result);

            Delete(proj);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll("Another"), out result);
            CollectionAssert.IsNotEmpty(result);
        }

        [Test(Description = "Delete ")]
        public void ProjectDelete()
        {
            var searchText = "WER<PASSWORD>";
            var proj = CreateProject(searchText, "Description");

            List<int> result;

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);
            CollectionAssert.IsNotEmpty(result);

            DeleteProject(proj);

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);
            CollectionAssert.IsEmpty(result);
        }

        [TestCaseSource(typeof(SearchCaseData), "SpecTestCases", new object[] { "Search Project spec " })]
        public void ProjectSpec(string spec)
        {
            var searchText = "ABC" + spec + "BCD";
            var proj = CreateProject(searchText, "Description");

            List<int> result;

            FactoryIndexer<ProjectsWrapper>.TrySelectIds(s => s.MatchAll(searchText), out result);
            CollectionAssert.IsNotEmpty(result);
            Assert.AreEqual(proj.ID, result[0]);

            DeleteProject(proj);
        }

        //[Test(Description = "Subtask ")]
        //public void TaskWithSubstasks()
        //{
        //    var searchText = "qaz<PASSWORD>";
        //    var task = CreateTask(searchText, "Description");

        //    CreateTask("subtask", "Description");
        //    task.SubTasks = new List<Subtask>();
        //    for (var i = 0; i < 3; i++)
        //    {
        //        task.SubTasks.Add(SubtaskEngine.SaveOrUpdate(new Subtask {Title = "subtask" + i}, task));
        //    }

        //    FactoryIndexer<TasksWrapper>.Update(task, true, r=> r.Subtasks);

        //    List<int> result;

        //    FactoryIndexer<TasksWrapper>.TrySelectIds(s => s.Match(r=> r.Subtasks.Select(q=> q.Title) ,"subtask"), out result);
        //    CollectionAssert.IsNotEmpty(result);


        //    FactoryIndexer<TasksWrapper>.TrySelectIds(s => s.MatchAll("subtask"), out result);
        //    CollectionAssert.IsNotEmpty(result);
        //}

        [OneTimeTearDown]
        public void TearDown()
        {
            foreach (var project in Projects)
            {
                DeleteProject(project);
            }
        }

        private Project CreateProject(string title, string description)
        {
            var newProject = GenerateProject(SecurityContext.CurrentAccount.ID);

            newProject.Title = title;
            newProject.Description = description;

            SaveOrUpdate(newProject);

            FactoryIndexer<ProjectsWrapper>.Index(newProject);

            return newProject;
        }

        private Task CreateTask(string title, string description)
        {
            var newTask = GenerateTask();

            newTask.Title = title;
            newTask.Description = description;

            SaveOrUpdate(newTask);

            FactoryIndexer<TasksWrapper>.Index(newTask);

            return newTask;
        }

        private void DeleteProject(Project project)
        {
            Delete(project);
            FactoryIndexer<ProjectsWrapper>.Delete(project);
        }
    }

    public class SearchCaseData
    {
        public static IEnumerable TestCases(string action)
        {
            yield return new TestCaseData("Project").SetName(action + " Project");
            yield return new TestCaseData("for").SetName(action + " for");
            yield return new TestCaseData("testing").SetName(action + " testing");
            yield return new TestCaseData("search").SetName(action + " search");
            yield return new TestCaseData("Description").SetName(action + " Description");
            yield return new TestCaseData("pRoJeCt").SetName(action + " pRoJeCt");
            yield return new TestCaseData("фёдор").SetName(action + " фёдор");
            yield return new TestCaseData("федор").SetName(action + " федор");
        }

        public static IEnumerable WildCardTestCases(string action)
        {
            yield return new TestCaseData("Pr*").SetName(action + " Project");
            yield return new TestCaseData("*Pr*").SetName(action + " *Pr*");
            yield return new TestCaseData("fo*").SetName(action + " for");
            yield return new TestCaseData("*esting").SetName(action + " testing");
            yield return new TestCaseData("*rch").SetName(action + " search");
            yield return new TestCaseData("Desc?iption").SetName(action + " Description");
        }
        public static IEnumerable SpecTestCases(string action)
        {
            yield return new TestCaseData("-").SetName(action + " -");
            yield return new TestCaseData("=").SetName(action + " =");
            yield return new TestCaseData("+").SetName(action + " +");
            yield return new TestCaseData(";").SetName(action + " ;");
            yield return new TestCaseData("/").SetName(action + " /");
            yield return new TestCaseData("\\").SetName(action + " \\");
            yield return new TestCaseData("|").SetName(action + " |");
            yield return new TestCaseData("№").SetName(action + " №");
            yield return new TestCaseData("&").SetName(action + " &");
            yield return new TestCaseData("#").SetName(action + " #");
            yield return new TestCaseData("^").SetName(action + " ^");
            yield return new TestCaseData("<>").SetName(action + " <>");
            yield return new TestCaseData("()").SetName(action + " ()");
            yield return new TestCaseData("[]").SetName(action + " []");
            yield return new TestCaseData("{}").SetName(action + " {}");
            yield return new TestCaseData("$").SetName(action + " $");
            yield return new TestCaseData("%").SetName(action + " %");
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Masters/MasterResources/MasterLocalizationResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Web;

using ASC.Core;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;

using Microsoft.Ajax.Utilities;

namespace ASC.Web.Studio.Masters.MasterResources
{
    public class MasterLocalizationResources : ClientScriptLocalization
    {
        private static string GetDatepikerDateFormat(string s)
        {
            return s
                .Replace("yyyy", "yy")
                .Replace("yy", "yy")
                .Replace("MMMM", "MM")
                .Replace("MMM", "M")
                .Replace("MM", "mm")
                .Replace("M", "mm")
                .Replace("dddd", "DD")
                .Replace("ddd", "D")
                .Replace("dd", "11")
                .Replace("d", "dd")
                .Replace("11", "dd")
                .Replace("'", "")
                ;
        }

        protected override string BaseNamespace
        {
            get { return "ASC.Resources.Master"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            var dateTimeFormat = Thread.CurrentThread.CurrentCulture.DateTimeFormat;

            return new List<KeyValuePair<string, object>>(5)
            {
                RegisterResourceSet("ResourceJS", ResourceJS.ResourceManager),
                RegisterResourceSet("FeedResource", FeedResource.ResourceManager),
                RegisterResourceSet("ChatResource", ChatResource.ResourceManager),
                RegisterResourceSet("UserControlsCommonResource", UserControlsCommonResource.ResourceManager),
                RegisterObject(
                    new
                    {
                        TemplateResource = new
                        {
                            Resource.Administrator,
                            Resource.Owner,
                            Resource.Comments,
                            Resource.AddNewCommentButton,
                            Resource.PublishButton,
                            Resource.PreviewButton,
                            Resource.CancelButton,
                            Resource.AddButton,
                            Resource.CloseButton,
                            Resource.AnswerButton,
                            Resource.EditButton,
                            Resource.DeleteButton,
                            Resource.CommentWasRemoved,
                            Resource.AssociateAccountConnected,
                            Resource.AssociateAccountNotConnected,
                            Resource.AssociateAccountDisconnect,
                            Resource.AssociateAccountConnect,
                            Resource.MailIcsCalendarWhenLabel,
                            Resource.MailIcsCalendarRecurrenceLabel,
                            Resource.MailIcsCalendarWhereLabel,
                            Resource.MailIcsCalendarMapLabel,
                            Resource.MailIcsCalendarNoLocationLabel,
                            Resource.MailIcsCalendarWhoLabel,
                            Resource.MailIcsCalendarDescriptionLabel,
                            Resource.MailIcsCalendarOrganizerLabel,
                            Resource.MailAutoGeneratedText,
                            Resource.ClearFilterButton,
                            Resource.Show,
                            Resource.Hide,
                            Resource.DrnToday,
                            Resource.DrnTomorrow,
                            Resource.In,
                            Yet2 = DateTimeExtension.Yet(2),
                            Yet3 = DateTimeExtension.Yet(3),
                            AllRightsReservedText = (CoreContext.Configuration.CustomMode ? CustomModeResource.AllRightsReservedCustomMode : Resource.AllRightsReservedText).FormatInvariant(DateTime.UtcNow.Year),
                            Resource.LdapUsersListLockTitle,
                            Resource.LdapUserEditCanOnlyAdminTitle,
                            Resource.LdapSettingsSuccess,
                            Resource.Browser,
                            Resource.SsoUsersListLockTitle,
                            Resource.SsoUserEditCanOnlyAdminTitle,
                            Resource.TfaAppShowBackupCodesNote,
                            Resource.TfaAppShowBackupCodesDescription,
                            Resource.PrintButton,
                            Resource.RequestNewButton,
                            Resource.Choose
                        },

                        DatePattern = dateTimeFormat.ShortDatePattern.Replace("'", ""),
                        TimePattern = dateTimeFormat.ShortTimePattern,
                        DateTimePattern = dateTimeFormat.FullDateTimePattern.Replace("'", ""),
                        DatePatternJQ = DateTimeExtension.DateMaskForJQuery,
                        //.Replace(" ", string.Empty) -  remove because, crash date in datepicker on czech language (bug 21954)
                        DatepickerDatePattern = GetDatepikerDateFormat(dateTimeFormat.ShortDatePattern),
                        DatepickerTimePattern = GetDatepikerDateFormat(dateTimeFormat.ShortTimePattern),
                        DatepickerDateTimePattern = GetDatepikerDateFormat(dateTimeFormat.FullDateTimePattern),
                        FirstDay = (int) dateTimeFormat.FirstDayOfWeek,
                        DayNames = dateTimeFormat.AbbreviatedDayNames,
                        DayNamesFull = dateTimeFormat.DayNames,
                        MonthNames = Thread.CurrentThread.CurrentUICulture.DateTimeFormat.AbbreviatedMonthGenitiveNames,
                        MonthNamesFull = Thread.CurrentThread.CurrentUICulture.DateTimeFormat.MonthNames,
                        Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName,
                        CurrentCultureName = Thread.CurrentThread.CurrentCulture.Name.ToLowerInvariant(),
                        CurrentCulture = CultureInfo.CurrentCulture.Name,
                        Resource.FileSizePostfix,
                        Resource.AccessRightsAccessToProduct,
                        Resource.AccessRightsDisabledProduct,
                        Resource.EmailAndPasswordIncorrectEmail,
                        Resource.EmailIsAvailable,
                        Resource.EmailOnDomainIsNotCreated,
                        Resource.NoMailServerDomainsMsg,
                        Resource.EmailAndPasswordCopiedToClipboard,
                        Resource.CopyToClipboard
                    })
            };
        }
    }

    public class MasterCustomResources : ClientScriptCustom
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Resources.Master"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            return new List<KeyValuePair<string, object>>(1)
                   {
                       RegisterObject(
                       new
                            {
                                Admin = CustomNamingPeople.Substitute<Resource>("Administrator"),
                                User = CustomNamingPeople.Substitute<Resource>("User"),
                                Guest = CustomNamingPeople.Substitute<Resource>("Guest"),
                                Department = CustomNamingPeople.Substitute<Resource>("Department"),
                                ConfirmRemoveUser = CustomNamingPeople.Substitute<Resource>("DeleteUserConfirmation").HtmlEncode(),
                                ConfirmRemoveDepartment = CustomNamingPeople.Substitute<Resource>("DeleteDepartmentConfirmation").HtmlEncode(),
                                AddDepartmentHeader = CustomNamingPeople.Substitute<Resource>("AddDepartmentDlgTitle").HtmlEncode(),
                                EditDepartmentHeader = CustomNamingPeople.Substitute<Resource>("DepEditHeader").HtmlEncode(),
                                EmployeeAllDepartments = CustomNamingPeople.Substitute<Resource>("EmployeeAllDepartments").HtmlEncode(),
                                AddEmployees = CustomNamingPeople.Substitute<UserControlsCommonResource>("AddEmployees").HtmlEncode(),
                                AccessRightsAddUser = CustomNamingPeople.Substitute<Resource>("AccessRightsAddUser").HtmlEncode(),
                                AccessRightsAddGroup = CustomNamingPeople.Substitute<Resource>("AccessRightsAddGroup").HtmlEncode(),
                                AccessRightsAllUsers = CustomNamingPeople.Substitute<Resource>("AccessRightsAllUsers"),
                                AccessRightsUsersFromList = CustomNamingPeople.Substitute<Resource>("AccessRightsUsersFromList"),
                                AccessRightsEmptyUserList = CustomNamingPeople.Substitute<Resource>("AccessRightsEmptyUserList"),
                                ChooseUser = CustomNamingPeople.Substitute<Resource>("ChooseUser"),
                                ErrorEmailAlreadyExists = CustomNamingPeople.Substitute<Resource>("ErrorEmailAlreadyExists")
                            })
                   };
        }
    }
}

<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Models/ServiceStatus.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.HealthCheck.Resources;

namespace ASC.HealthCheck.Models
{
    public enum ServiceStatus
    {
        NotFound,
        Running,
        Stopped,
        StartPending,
        StopPending
    }

    public static class ServiceStatusExtention
    {
        public static string GetStringStatus(this ServiceStatus serviceEnum)
        {
            switch (serviceEnum)
            {
                case ServiceStatus.Running:
                    return HealthCheckResource.StatusServiceWork;
                case ServiceStatus.Stopped:
                    return HealthCheckResource.StatusServiceStoped;
                case ServiceStatus.StartPending:
                    return HealthCheckResource.StatusServiceStartWorking;
                case ServiceStatus.StopPending:
                    return HealthCheckResource.ServiceStillNotStoped;
                case ServiceStatus.NotFound:
                    return HealthCheckResource.ServiceNotFound;
                default:
                    return "";
            }
        }
        public static string GetMessageStatus(this ServiceStatus serviceEnum)
        {
            switch (serviceEnum)
            {
                case ServiceStatus.Running:
                    return HealthCheckResource.ServiceWorks;
                case ServiceStatus.Stopped:
                    return HealthCheckResource.ServiceStop;
                case ServiceStatus.StartPending:
                    return HealthCheckResource.ServiceStillNotStarted;
                case ServiceStatus.StopPending:
                    return HealthCheckResource.ServiceStillNotStoped;
                case ServiceStatus.NotFound:
                    return HealthCheckResource.StatusServiceError;
                default:
                    return "";
            }
        }
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/PortalTaskBase.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

using ASC.Common.Data;
using ASC.Common.Logging;
using ASC.Data.Backup.Tasks.Modules;
using ASC.Data.Storage;

namespace ASC.Data.Backup.Tasks
{
    public class ProgressChangedEventArgs : EventArgs
    {
        public int Progress { get; private set; }

        public ProgressChangedEventArgs(int progress)
        {
            Progress = progress;
        }
    }

    public abstract class PortalTaskBase
    {
        protected const int TasksLimit = 10;
        protected readonly List<ModuleName> IgnoredModules = new List<ModuleName>();
        protected readonly List<string> IgnoredTables = new List<string>(); //todo: add using to backup and transfer tasks

        protected ILog Logger;

        public int Progress { get; private set; }

        public int TenantId { get; private set; }
        public string ConfigPath { get; private set; }

        public bool ProcessStorage { get; set; }

        protected PortalTaskBase(ILog logger, int tenantId, string configPath)
        {
            Logger = logger ?? LogManager.GetLogger("ASC");
            TenantId = tenantId;
            ConfigPath = configPath;
            ProcessStorage = true;
        }

        public void IgnoreModule(ModuleName moduleName)
        {
            if (!IgnoredModules.Contains(moduleName))
                IgnoredModules.Add(moduleName);
        }

        public void IgnoreTable(string tableName)
        {
            if (!IgnoredTables.Contains(tableName))
                IgnoredTables.Add(tableName);
        }

        public abstract void RunJob();

        internal virtual IEnumerable<IModuleSpecifics> GetModulesToProcess()
        {
            return ModuleProvider.AllModules.Where(module => !IgnoredModules.Contains(module.ModuleName));
        }

        protected IEnumerable<BackupFileInfo> GetFilesToProcess(int tenantId)
        {
            var files = new List<BackupFileInfo>();
            foreach (var module in StorageFactory.GetModuleList(ConfigPath).Where(IsStorageModuleAllowed))
            {
                var store = StorageFactory.GetStorage(ConfigPath, tenantId.ToString(), module);
                var domains = StorageFactory.GetDomainList(ConfigPath, module).ToArray();

                foreach (var domain in domains)
                {
                    files.AddRange(
                        store.ListFilesRelative(domain, "\\", "*.*", true)
                        .Select(path => new BackupFileInfo(domain, module, path, tenantId)));
                }

                files.AddRange(
                    store.ListFilesRelative(string.Empty, "\\", "*.*", true)
                         .Where(path => domains.All(domain => !path.Contains(domain + "/")))
                         .Select(path => new BackupFileInfo(string.Empty, module, path, tenantId)));
            }

            return files.Distinct();
        }

        protected bool IsStorageModuleAllowed(string storageModuleName)
        {
            var allowedStorageModules = new List<string>
                {
                    "forum",
                    "photo",
                    "bookmarking",
                    "wiki",
                    "files",
                    "crm",
                    "projects",
                    "logo",
                    "fckuploaders",
                    "talk",
                    "mailaggregator",
                    "whitelabel",
                    "customnavigation",
                    "userPhotos"
                };

            if (!allowedStorageModules.Contains(storageModuleName))
                return false;

            IModuleSpecifics moduleSpecifics = ModuleProvider.GetByStorageModule(storageModuleName);
            return moduleSpecifics == null || !IgnoredModules.Contains(moduleSpecifics.ModuleName);
        }

        #region Progress

        public event EventHandler<ProgressChangedEventArgs> ProgressChanged;

        private int stepsCount = 1;
        private volatile int stepsCompleted;

        protected void SetStepsCount(int value)
        {
            if (value <= 0)
            {
                throw new ArgumentOutOfRangeException("value");
            }
            stepsCount = value;
            Logger.Debug("Steps: " + stepsCount);
        }

        protected void SetStepCompleted(int increment = 1)
        {
            if (stepsCount == 1)
            {
                return;
            }
            if (stepsCompleted == stepsCount)
            {
                throw new InvalidOperationException("All steps completed.");
            }
            stepsCompleted += increment;
            SetProgress(100 * stepsCompleted / stepsCount);
        }

        protected void SetCurrentStepProgress(int value)
        {
            if (value < 0 || value > 100)
            {
                throw new ArgumentOutOfRangeException("value");
            }
            if (value == 100)
            {
                SetStepCompleted();
            }
            else
            {
                SetProgress((100 * stepsCompleted + value) / stepsCount);
            }
        }

        protected void SetProgress(int value)
        {
            if (value < 0 || value > 100)
            {
                throw new ArgumentOutOfRangeException("value");
            }
            if (Progress != value)
            {
                Progress = value;
                OnProgressChanged(new ProgressChangedEventArgs(value));
            }
        }

        protected virtual void OnProgressChanged(ProgressChangedEventArgs eventArgs)
        {
            var handler = ProgressChanged;
            if (handler != null)
            {
                handler(this, eventArgs);
            }
        }

        #endregion

        protected Dictionary<string, string> ParseConnectionString(string connectionString)
        {
            var result = new Dictionary<string, string>();

            var parsed = connectionString.Split(';');

            foreach (var p in parsed)
            {
                if (string.IsNullOrEmpty(p.Trim())) continue;
                var keyValue = p.Split('=');
                result.Add(keyValue[0].ToLowerInvariant(), keyValue[1]);
            }

            return result;
        }

        protected async Task RunMysqlFile(Stream stream, string delimiter = ";")
        {
            using (var dbManager = new DbManager("default", 100000))
            using (var tr = dbManager.BeginTransaction())
            {
                if (stream == null) return;

                using (var reader = new StreamReader(stream, Encoding.UTF8))
                {
                    string commandText;

                    if (delimiter != null)
                    {
                        while ((commandText = await reader.ReadLineAsync()) != null)
                        {
                            while (!commandText.EndsWith(delimiter))
                            {
                                var newline = await reader.ReadLineAsync();
                                if (newline == null)
                                {
                                    break;
                                }
                                commandText += newline;
                            }

                            try
                            {
                                await dbManager.ExecuteNonQueryAsync(commandText, null);
                            }
                            catch (Exception e)
                            {
                                Logger.Error("Restore", e);
                            }
                        }
                    }
                    else
                    {
                        commandText = await reader.ReadToEndAsync();

                        try
                        {
                            await dbManager.ExecuteNonQueryAsync(commandText, null);
                        }
                        catch (Exception e)
                        {
                            Logger.Error("Restore", e);
                        }
                    }
                }

                tr.Commit();
            }
        }
        protected async Task RunMysqlProcedure(Stream stream)
        {
            using (var dbManager = new DbManager("default", 100000))
            {
                if (stream == null) return;

                string commandText;
                string delimiter;

                using (var reader = new StreamReader(stream, Encoding.UTF8))
                {
                    var data = await reader.ReadLineAsync();
                    var re = new Regex(@"DELIMITER (\S+)");
                    var match = re.Match(data);

                    if (match.Success)
                    {
                        delimiter = match.Groups[1].Value;
                    }
                    else
                    {
                        return;
                    }

                    while ((commandText = await reader.ReadLineAsync()) != null)
                    {
                        while (!commandText.EndsWith(delimiter))
                        {
                            var newline = await reader.ReadLineAsync();
                            if (newline == null)
                            {
                                break;
                            }
                            commandText += newline;
                        }

                        try
                        {
                            commandText = commandText.Replace(delimiter, "").Trim();
                            if (!commandText.StartsWith("DELIMITER"))
                            {
                                await dbManager.ExecuteNonQueryAsync(commandText, null);
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.Error("Restore", e);
                        }
                    }
                }
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/HttpHandlers/SearchHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;

using ASC.Common.Utils;
using ASC.Files.Core;
using ASC.Web.Core.Files;
using ASC.Web.Core.ModuleManagement.Common;
using ASC.Web.Core.Utility;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Helpers;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Utils;
using ASC.Web.Studio.Core;

namespace ASC.Web.Files.Configuration
{
    public class SearchHandler : BaseSearchHandlerEx
    {
        public override Guid ProductID
        {
            get { return ProductEntryPoint.ID; }
        }

        public override ImageOptions Logo
        {
            get { return new ImageOptions { ImageFileName = "common_search_icon.png" }; }
        }

        public override Guid ModuleID
        {
            get { return ProductID; }
        }

        public override string SearchName
        {
            get { return FilesCommonResource.Search; }
        }

        public IEnumerable<File> SearchFiles(string text)
        {
            var security = Global.GetFilesSecurity();
            using (var fileDao = Global.DaoFactory.GetFileDao())
            {
                return fileDao.Search(text).Where(security.CanRead);
            }
        }

        public IEnumerable<Folder> SearchFolders(string text)
        {
            var security = Global.GetFilesSecurity();
            IEnumerable<Folder> result;
            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                result = folderDao.Search(text).Where(security.CanRead);

                if (ThirdpartyConfiguration.SupportInclusion
                    && FilesSettings.EnableThirdParty)
                {
                    var id = Global.FolderMy;
                    if (!Equals(id, 0))
                    {
                        var folderMy = folderDao.GetFolder(id);
                        result = result.Concat(EntryManager.GetThirpartyFolders(folderMy, text));
                    }

                    id = Global.FolderCommon;
                    var folderCommon = folderDao.GetFolder(id);
                    result = result.Concat(EntryManager.GetThirpartyFolders(folderCommon, text));
                }
            }

            return result;
        }

        public override SearchResultItem[] Search(string text)
        {
            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                var result = SearchFiles(text)
                    .Select(r => new SearchResultItem
                    {
                        Name = r.Title ?? string.Empty,
                        Description = string.Empty,
                        URL = FilesLinkUtility.GetFileWebPreviewUrl(r.Title, r.ID),
                        Date = r.ModifiedOn,
                        Additional = new Dictionary<string, object>
                                {
                                    { "Author", r.CreateByString.HtmlEncode() },
                                    { "Path", FolderPathBuilder(EntryManager.GetBreadCrumbs(r.FolderID, folderDao)) },
                                    { "Size", FileSizeComment.FilesSizeToString(r.ContentLength) }
                                }
                    }
                    );

                var resultFolder = SearchFolders(text)
                    .Select(f =>
                            new SearchResultItem
                            {
                                Name = f.Title ?? string.Empty,
                                Description = String.Empty,
                                URL = PathProvider.GetFolderUrl(f),
                                Date = f.ModifiedOn,
                                Additional = new Dictionary<string, object>
                                        {
                                            { "Author", f.CreateByString.HtmlEncode() },
                                            { "Path", FolderPathBuilder(EntryManager.GetBreadCrumbs(f.ID, folderDao)) },
                                            { "IsFolder", true }
                                        }
                            });

                return result.Concat(resultFolder).ToArray();
            }
        }

        public override IItemControl Control
        {
            get { return new ResultsView(); }
        }

        private static String FolderPathBuilder(IEnumerable<Folder> folders)
        {
            var titles = folders.Select(f => f.Title).ToList();
            const string separator = " \\ ";
            return 4 < titles.Count
                       ? string.Join(separator, new[] { titles.First(), "...", titles.ElementAt(titles.Count - 2), titles.Last() })
                       : string.Join(separator, titles.ToArray());
        }
    }

    public sealed class ResultsView : ItemSearchControl
    {
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "tableBase");
            writer.AddAttribute("cellspacing", "0");
            writer.AddAttribute("cellpadding", "8");
            writer.RenderBeginTag(HtmlTextWriterTag.Table);

            writer.RenderBeginTag(HtmlTextWriterTag.Tbody);

            foreach (var srGroup in Items.GetRange(0, (MaxCount < Items.Count) ? MaxCount : Items.Count))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, "search-result-item");
                writer.RenderBeginTag(HtmlTextWriterTag.Tr);

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "borderBase left-column gray-text");
                writer.RenderBeginTag(HtmlTextWriterTag.Td);

                var typeTitle = srGroup.Additional.ContainsKey("IsFolder") && srGroup.Additional["IsFolder"].Equals(true) ? FilesCommonResource.Folder : FilesCommonResource.File;

                writer.AddAttribute(HtmlTextWriterAttribute.Title, typeTitle);
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write(typeTitle);
                writer.RenderEndTag();
                writer.RenderEndTag();

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "borderBase center-column");
                writer.RenderBeginTag(HtmlTextWriterTag.Td);

                writer.AddAttribute(HtmlTextWriterAttribute.Href, srGroup.URL);
                writer.AddAttribute(HtmlTextWriterAttribute.Title, srGroup.Name);
                writer.AddAttribute(HtmlTextWriterAttribute.Class, "link bold");
                writer.RenderBeginTag(HtmlTextWriterTag.A);
                writer.Write(HtmlUtil.SearchTextHighlight(Text, srGroup.Name.HtmlEncode()));
                writer.RenderEndTag();

                writer.WriteBreak();

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "text-medium-describe");
                writer.RenderBeginTag(HtmlTextWriterTag.Div);

                if (srGroup.Additional.ContainsKey("Author"))
                {
                    writer.Write("{0} {1}", FilesCommonResource.Author, srGroup.Additional["Author"]);
                }
                writer.AddAttribute(HtmlTextWriterAttribute.Class, "splitter");
                writer.RenderBeginTag(HtmlTextWriterTag.Span);
                writer.Write("|");
                writer.RenderEndTag();

                writer.Write("{0} {1}", FilesCommonResource.TitleUploaded, srGroup.Date);

                if (srGroup.Additional.ContainsKey("Size"))
                {
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "separator");
                    writer.RenderBeginTag(HtmlTextWriterTag.Span);
                    writer.Write("|");
                    writer.RenderEndTag();
                    writer.Write("{0} {1}", FilesCommonResource.Size, srGroup.Additional["Size"]);
                }
                writer.RenderEndTag();

                writer.RenderEndTag();

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "borderBase right-column gray-text");
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write(srGroup.Additional["Path"]);
                writer.RenderEndTag();
                writer.RenderEndTag();

                writer.RenderEndTag();
            }

            writer.RenderEndTag();
            writer.RenderEndTag();
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Stack/SIP_UA_Registration.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Stack
{
    #region usings

    using System;
    using System.Net;
    using System.Timers;
    using Message;

    #endregion

    /// <summary>
    /// This class represent SIP UA registration.
    /// </summary>
    public class SIP_UA_Registration
    {
        #region Events

        /// <summary>
        /// This event is raised when registration has disposed.
        /// </summary>
        public event EventHandler Disposed = null;

        /// <summary>
        /// This event is raised when REGISTER/un-REGISTER has failed.
        /// </summary>
        public event EventHandler<SIP_ResponseReceivedEventArgs> Error = null;

        /// <summary>
        /// This event is raised when REGISTER has completed successfully.
        /// </summary>
        public event EventHandler Registered = null;

        /// <summary>
        /// This event is raised when registration state has changed.
        /// </summary>
        public event EventHandler StateChanged = null;

        /// <summary>
        /// This event is raised when un-REGISTER has completed successfully.
        /// </summary>
        public event EventHandler Unregistered = null;

        #endregion

        #region Members

        private readonly string m_AOR = "";
        private readonly AbsoluteUri m_pContact;
        private readonly SIP_Uri m_pServer;
        private readonly int m_RefreshInterval = 300;
        private bool m_AutoDispose;
        private bool m_AutoRefresh = true;
        private bool m_IsDisposed;
        private SIP_Flow m_pFlow;
        private SIP_RequestSender m_pRegisterSender;
        private SIP_Stack m_pStack;
        private TimerEx m_pTimer;
        private SIP_RequestSender m_pUnregisterSender;
        private SIP_UA_RegistrationState m_State = SIP_UA_RegistrationState.Unregistered;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stack">Owner SIP stack.</param>
        /// <param name="server">Registrar server URI. For example: sip:domain.com.</param>
        /// <param name="aor">Address of record. For example: <EMAIL>.</param>
        /// <param name="contact">Contact URI.</param>
        /// <param name="expires">Gets after how many seconds reigisration expires.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>ua</b>,<b>server</b>,<b>transport</b>,<b>aor</b> or <b>contact</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments contains invalid value.</exception>
        internal SIP_UA_Registration(SIP_Stack stack,
                                     SIP_Uri server,
                                     string aor,
                                     AbsoluteUri contact,
                                     int expires)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }
            if (server == null)
            {
                throw new ArgumentNullException("server");
            }
            if (aor == null)
            {
                throw new ArgumentNullException("aor");
            }
            if (aor == string.Empty)
            {
                throw new ArgumentException("Argument 'aor' value must be specified.");
            }
            if (contact == null)
            {
                throw new ArgumentNullException("contact");
            }

            m_pStack = stack;
            m_pServer = server;
            m_AOR = aor;
            m_pContact = contact;
            m_RefreshInterval = expires;

            m_pTimer = new TimerEx((m_RefreshInterval - 15)*1000);
            m_pTimer.AutoReset = false;
            m_pTimer.Elapsed += m_pTimer_Elapsed;
            m_pTimer.Enabled = false;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets registration address of record.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public string AOR
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_AOR;
            }
        }

        /// <summary>
        /// If true and contact is different than received or rport, received and rport is used as contact.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public bool AutoFixContact
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                // TODO:

                return false;
            }
        }

        /// <summary>
        /// Gets registration contact URI.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public AbsoluteUri Contact
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pContact;
            }
        }

        /// <summary>
        /// Gets after how many seconds contact expires.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public int Expires
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return 3600;
            }
        }

        /// <summary>
        /// Gets if this object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get { return m_IsDisposed; }
        }

        /// <summary>
        /// Gets registration state.
        /// </summary>
        public SIP_UA_RegistrationState State
        {
            get { return m_State; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            m_IsDisposed = true;

            m_pStack = null;
            m_pTimer.Dispose();
            m_pTimer = null;

            SetState(SIP_UA_RegistrationState.Disposed);
            OnDisposed();

            Registered = null;
            Unregistered = null;
            Error = null;
            Disposed = null;
        }

        /// <summary>
        /// Starts registering.
        /// </summary>
        /// <param name="autoRefresh">If true, registration takes care of refreshing itself to registrar server.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public void BeginRegister(bool autoRefresh)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            // Fix ME: Stack not running, try register on next step.
            // In ideal solution we need to start registering when stack starts.
            if (!m_pStack.IsRunning)
            {
                m_pTimer.Enabled = true;
                return;
            }

            m_AutoRefresh = autoRefresh;
            SetState(SIP_UA_RegistrationState.Registering);

            /* RFC 3261 10.1 Constructing the REGISTER Request.
                Request-URI: The Request-URI names the domain of the location service for which the registration is meant (for example,
                             "sip:chicago.com").  The "userinfo" and "@" components of the SIP URI MUST NOT be present.
            */

            SIP_Request register = m_pStack.CreateRequest(SIP_Methods.REGISTER,
                                                          new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR),
                                                          new SIP_t_NameAddress(m_pServer.Scheme + ":" + m_AOR));
            register.RequestLine.Uri =
                SIP_Uri.Parse(m_pServer.Scheme + ":" + m_AOR.Substring(m_AOR.IndexOf('@') + 1));
            register.Route.Add(m_pServer.ToString());
            register.Contact.Add("<" + Contact + ">;expires=" + m_RefreshInterval);

            m_pRegisterSender = m_pStack.CreateRequestSender(register, m_pFlow);
            m_pRegisterSender.ResponseReceived += m_pRegisterSender_ResponseReceived;
            m_pRegisterSender.Start();
        }

        /// <summary>
        /// Starts unregistering.
        /// </summary>
        /// <param name="dispose">If true, registration will be disposed after unregister.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        public void BeginUnregister(bool dispose)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            m_AutoDispose = dispose;

            // Stop register timer, otherwise we may get register and unregister race condition.
            m_pTimer.Enabled = false;

            if (m_State == SIP_UA_RegistrationState.Registered)
            {
                /* RFC 3261 10.1 Constructing the REGISTER Request.
                    Request-URI: The Request-URI names the domain of the location service for which the registration is meant (for example,
                                 "sip:chicago.com").  The "userinfo" and "@" components of the SIP URI MUST NOT be present.
                */

                SIP_Request unregister = m_pStack.CreateRequest(SIP_Methods.REGISTER,
                                                                new SIP_t_NameAddress(m_pServer.Scheme + ":" +
                                                                                      m_AOR),
                                                                new SIP_t_NameAddress(m_pServer.Scheme + ":" +
                                                                                      m_AOR));
                unregister.RequestLine.Uri =
                    SIP_Uri.Parse(m_pServer.Scheme + ":" + m_AOR.Substring(m_AOR.IndexOf('@') + 1));
                unregister.Route.Add(m_pServer.ToString());
                unregister.Contact.Add("<" + Contact + ">;expires=0");

                m_pUnregisterSender = m_pStack.CreateRequestSender(unregister, m_pFlow);
                m_pUnregisterSender.ResponseReceived += m_pUnregisterSender_ResponseReceived;
                m_pUnregisterSender.Start();
            }
            else
            {
                SetState(SIP_UA_RegistrationState.Unregistered);
                OnUnregistered();

                if (m_AutoDispose)
                {
                    Dispose();
                }

                m_pUnregisterSender = null;
            }
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// This method is raised when registration needs to refresh server registration.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (m_pStack.IsRunning)
            {
                BeginRegister(m_AutoRefresh);
            }
        }

        /// <summary>
        /// This method is called when REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pRegisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            m_pFlow = e.ClientTransaction.Flow;

            if (e.Response.StatusCodeType == SIP_StatusCodeType.Success)
            {
                SetState(SIP_UA_RegistrationState.Registered);

                OnRegistered();

                m_pFlow.SendKeepAlives = true;
            }
            else
            {
                SetState(SIP_UA_RegistrationState.Error);

                OnError(e);
            }

            // REMOVE ME:
            if (AutoFixContact && (m_pContact is SIP_Uri))
            {
                // If Via: received or rport paramter won't match to our sent-by, use received and rport to construct new contact value.

                SIP_Uri cContact = ((SIP_Uri) m_pContact);
                IPAddress cContactIP = Net_Utils.IsIPAddress(cContact.Host)
                                           ? IPAddress.Parse(cContact.Host)
                                           : null;
                SIP_t_ViaParm via = e.Response.Via.GetTopMostValue();
                if (via != null && cContactIP != null)
                {
                    IPEndPoint ep = new IPEndPoint(via.Received != null ? via.Received : cContactIP,
                                                   via.RPort > 0 ? via.RPort : cContact.Port);
                    if (!cContactIP.Equals(ep.Address) || cContact.Port != via.RPort)
                    {
                        // Unregister old contact.
                        BeginUnregister(false);

                        // Fix contact.
                        cContact.Host = ep.Address.ToString();
                        cContact.Port = ep.Port;

                        m_pRegisterSender.Dispose();
                        m_pRegisterSender = null;

                        BeginRegister(m_AutoRefresh);

                        return;
                    }
                }
            }

            if (m_AutoRefresh)
            {
                // Set registration refresh timer.
                m_pTimer.Enabled = true;
            }

            m_pRegisterSender.Dispose();
            m_pRegisterSender = null;
        }

        /// <summary>
        /// This method is called when un-REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pUnregisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            SetState(SIP_UA_RegistrationState.Unregistered);
            OnUnregistered();

            if (m_AutoDispose)
            {
                Dispose();
            }

            m_pUnregisterSender = null;
        }

        /// <summary>
        /// Changes current registration state.
        /// </summary>
        /// <param name="newState">New registration state.</param>
        private void SetState(SIP_UA_RegistrationState newState)
        {
            m_State = newState;

            OnStateChanged();
        }

        /// <summary>
        /// Raises event <b>StateChanged</b>.
        /// </summary>
        private void OnStateChanged()
        {
            if (StateChanged != null)
            {
                StateChanged(this, new EventArgs());
            }
        }

        /// <summary>
        /// Raises event <b>Registered</b>.
        /// </summary>
        private void OnRegistered()
        {
            if (Registered != null)
            {
                Registered(this, new EventArgs());
            }
        }

        /// <summary>
        /// Raises event <b>Unregistered</b>.
        /// </summary>
        private void OnUnregistered()
        {
            if (Unregistered != null)
            {
                Unregistered(this, new EventArgs());
            }
        }

        /// <summary>
        /// Raises event <b>Error</b>.
        /// </summary>
        /// <param name="e">Event data.</param>
        private void OnError(SIP_ResponseReceivedEventArgs e)
        {
            if (Error != null)
            {
                Error(this, e);
            }
        }

        /// <summary>
        /// Raises event <b>Disposed</b>.
        /// </summary>
        private void OnDisposed()
        {
            if (Disposed != null)
            {
                Disposed(this, new EventArgs());
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Data/DbDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Data;

using ASC.Common.Data;
using ASC.Common.Data.Sql;

#endregion

namespace ASC.Blogs.Core.Data
{
    public class DbDao
    {
        private readonly DbManager db;


        protected DbDao(DbManager db, int tenant)
        {
            if (db == null) throw new ArgumentNullException("db");

            this.db = db;
            Tenant = tenant;
        }

        public int Tenant { get; private set; }

        public DbManager Db { get { return db; } }

        public IDbConnection OpenConnection()
        {
            return db.Connection;
        }

        protected SqlQuery Query(string table)
        {
            return new SqlQuery(table).Where(GetTenantColumnName(table), Tenant);
        }

        protected SqlUpdate Update(string table)
        {
            return new SqlUpdate(table).Where(GetTenantColumnName(table), Tenant);
        }

        protected SqlDelete Delete(string table)
        {
            return new SqlDelete(table).Where(GetTenantColumnName(table), Tenant);
        }

        protected SqlInsert Insert(string table)
        {
            return new SqlInsert(table, true).InColumns(TenantColumnName).Values(Tenant);
        }

        protected string TenantColumnName { get { return "Tenant"; } }

        protected string GetTenantColumnName(string table)
        {
            return String.Format("{0}.{1}", table, TenantColumnName);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/HttpHandlers/FilesUploader.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.Threading;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Mail.Core;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Exceptions;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Utils;
using ASC.Web.Mail.Resources;
using ASC.Web.Studio.Controls.FileUploader;
using ASC.Web.Studio.Controls.FileUploader.HttpModule;

namespace ASC.Web.Mail.HttpHandlers
{
    public class FilesUploader : FileUploadHandler
    {
        private static int TenantId
        {
            get { return CoreContext.TenantManager.GetCurrentTenant().TenantId; }
        }

        private static string Username
        {
            get { return SecurityContext.CurrentAccount.ID.ToString(); }
        }

        private static CultureInfo CurrentCulture
        {
            get
            {
                var u = CoreContext.UserManager.GetUsers(new Guid(Username));

                var culture = !string.IsNullOrEmpty(u.CultureName) ? u.GetCulture() : CoreContext.TenantManager.GetCurrentTenant().GetCulture();

                return culture;
            }
        }

        public override FileUploadResult ProcessUpload(HttpContext context)
        {
            var log = LogManager.GetLogger("ASC.Mail.FilesUploader");

            string message;

            var fileName = string.Empty;

            MailAttachmentData mailAttachmentData = null;

            try
            {
                if (!FileToUpload.HasFilesToUpload(context))
                    throw new Exception(MailScriptResource.AttachmentsBadInputParamsError);

                if (!SecurityContext.IsAuthenticated)
                {
                    throw new HttpException(403, "Access denied.");
                }

                Thread.CurrentThread.CurrentCulture = CurrentCulture;
                Thread.CurrentThread.CurrentUICulture = CurrentCulture;

                var mailId = Convert.ToInt32(context.Request["messageId"]);
                var copyToMy = Convert.ToInt32(context.Request["copyToMy"]);
                var needSaveToTemp = Convert.ToBoolean(context.Request["needSaveToTemp"]);

                if (mailId < 1)
                    throw new AttachmentsException(AttachmentsException.Types.MessageNotFound,
                        "Message not yet saved!");

                var engine = new EngineFactory(TenantId, Username);

                var item = engine.MessageEngine.GetMessage(mailId, new MailMessageData.Options());
                if (item == null)
                    throw new AttachmentsException(AttachmentsException.Types.MessageNotFound, "Message not found.");

                if (string.IsNullOrEmpty(item.StreamId))
                    throw new AttachmentsException(AttachmentsException.Types.BadParams, "Have no stream");

                var postedFile = new FileToUpload(context);

                fileName = context.Request["name"];

                if (string.IsNullOrEmpty(fileName))
                    throw new AttachmentsException(AttachmentsException.Types.BadParams, "Empty name param");

                if (copyToMy == 1)
                {
                    var uploadedFile = FileUploader.Exec(Global.FolderMy.ToString(), fileName,
                        postedFile.ContentLength, postedFile.InputStream, true);

                    return new FileUploadResult
                    {
                        Success = true,
                        FileName = uploadedFile.Title,
                        FileURL = FileShareLink.GetLink(uploadedFile, false),
                        Data = new MailAttachmentData
                        {
                            fileId = Convert.ToInt32(uploadedFile.ID),
                            fileName = uploadedFile.Title,
                            size = uploadedFile.ContentLength,
                            contentType = uploadedFile.ConvertedType,
                            attachedAsLink = true,
                            tenant = TenantId,
                            user = Username
                        }
                    };
                }

                mailAttachmentData = engine.AttachmentEngine
                    .AttachFileToDraft(TenantId, Username, mailId, fileName, postedFile.InputStream,
                        postedFile.ContentLength, null, postedFile.NeedSaveToTemp);

                return new FileUploadResult
                {
                    Success = true,
                    FileName = mailAttachmentData.fileName,
                    FileURL = mailAttachmentData.storedFileUrl,
                    Data = mailAttachmentData
                };
            }
            catch (HttpException he)
            {
                log.Error("FileUpload handler failed", he);

                context.Response.StatusCode = he.GetHttpCode();
                message = he.Message != null
                    ? HttpUtility.HtmlEncode(he.Message)
                    : MailApiErrorsResource.ErrorInternalServer;
            }
            catch (AttachmentsException ex)
            {
                log.Error("FileUpload handler failed", ex);

                switch (ex.ErrorType)
                {
                    case AttachmentsException.Types.BadParams:
                        message = MailScriptResource.AttachmentsBadInputParamsError;
                        break;
                    case AttachmentsException.Types.EmptyFile:
                        message = MailScriptResource.AttachmentsEmptyFileNotSupportedError;
                        break;
                    case AttachmentsException.Types.MessageNotFound:
                        message = MailScriptResource.AttachmentsMessageNotFoundError;
                        break;
                    case AttachmentsException.Types.TotalSizeExceeded:
                        message = MailScriptResource.AttachmentsTotalLimitError;
                        break;
                    case AttachmentsException.Types.DocumentNotFound:
                        message = MailScriptResource.AttachmentsDocumentNotFoundError;
                        break;
                    case AttachmentsException.Types.DocumentAccessDenied:
                        message = MailScriptResource.AttachmentsDocumentAccessDeniedError;
                        break;
                    default:
                        message = MailScriptResource.AttachmentsUnknownError;
                        break;
                }
            }
            catch (TenantQuotaException ex)
            {
                log.Error("FileUpload handler failed", ex);
                message = ex.Message;
            }
            catch (Exception ex)
            {
                log.Error("FileUpload handler failed", ex);
                message = MailScriptResource.AttachmentsUnknownError;
            }

            return new FileUploadResult
            {
                Success = false,
                FileName = fileName,
                Data = mailAttachmentData,
                Message = string.IsNullOrEmpty(message) ? MailApiErrorsResource.ErrorInternalServer : message
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/CurrencyRateDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;

#endregion

namespace ASC.CRM.Core.Dao
{
    public class CurrencyRateDao : AbstractDao
    {
        public CurrencyRateDao(int tenantID)
            : base(tenantID)
        {
        }

        public virtual List<CurrencyRate> GetAll()
        {
            return Db.ExecuteList(GetSqlQuery(null)).ConvertAll(ToCurrencyRate);
        }

        public virtual CurrencyRate GetByID(int id)
        {
            var rates = Db.ExecuteList(GetSqlQuery(Exp.Eq("id", id))).ConvertAll(ToCurrencyRate);

            return rates.Count > 0 ? rates[0] : null;
        }

        public CurrencyRate GetByCurrencies(string fromCurrency, string toCurrency)
        {
            var rates = Db.ExecuteList(GetSqlQuery(Exp.Eq("from_currency", fromCurrency.ToUpper()) & Exp.Eq("to_currency", toCurrency.ToUpper())))
                .ConvertAll(ToCurrencyRate);

            return rates.Count > 0 ? rates[0] : null;
        }

        public int SaveOrUpdate(CurrencyRate currencyRate)
        {
            if (String.IsNullOrEmpty(currencyRate.FromCurrency) || String.IsNullOrEmpty(currencyRate.ToCurrency) || currencyRate.Rate < 0)
                throw new ArgumentException();

            if (currencyRate.ID > 0 && currencyRate.Rate == 0)
                return Delete(currencyRate.ID);

            if (Db.ExecuteScalar<int>(Query("crm_currency_rate").SelectCount().Where(Exp.Eq("id", currencyRate.ID))) == 0)
            {
                var query = Insert("crm_currency_rate")
                    .InColumnValue("id", 0)
                    .InColumnValue("from_currency", currencyRate.FromCurrency.ToUpper())
                    .InColumnValue("to_currency", currencyRate.ToCurrency.ToUpper())
                    .InColumnValue("rate", currencyRate.Rate)
                    .InColumnValue("create_by", SecurityContext.CurrentAccount.ID)
                    .InColumnValue("create_on", DateTime.UtcNow)
                    .InColumnValue("last_modifed_by", SecurityContext.CurrentAccount.ID)
                    .InColumnValue("last_modifed_on", DateTime.UtcNow)
                    .Identity(1, 0, true);

                currencyRate.ID = Db.ExecuteScalar<int>(query);
            }
            else
            {
                Db.ExecuteNonQuery(
                    Update("crm_currency_rate")
                        .Set("from_currency", currencyRate.FromCurrency.ToUpper())
                        .Set("to_currency", currencyRate.ToCurrency.ToUpper())
                        .Set("rate", currencyRate.Rate)
                        .Set("last_modifed_on", DateTime.UtcNow)
                        .Set("last_modifed_by", SecurityContext.CurrentAccount.ID)
                        .Where(Exp.Eq("id", currencyRate.ID)));
            }

            return currencyRate.ID;
        }

        public int Delete(int id)
        {
            if (id <= 0) throw new ArgumentException();

            var sqlQuery = Delete("crm_currency_rate")
                .Where(Exp.Eq("id", id));

            Db.ExecuteNonQuery(sqlQuery);

            return id;
        }

        public List<CurrencyRate> SetCurrencyRates(List<CurrencyRate> rates)
        {
            using (var tx = Db.BeginTransaction())
            {
                Db.ExecuteNonQuery(Delete("crm_currency_rate"));

                foreach (var rate in rates)
                {
                    var query = Insert("crm_currency_rate")
                        .InColumnValue("id", 0)
                        .InColumnValue("from_currency", rate.FromCurrency.ToUpper())
                        .InColumnValue("to_currency", rate.ToCurrency.ToUpper())
                        .InColumnValue("rate", rate.Rate)
                        .InColumnValue("create_by", SecurityContext.CurrentAccount.ID)
                        .InColumnValue("create_on", DateTime.UtcNow)
                        .InColumnValue("last_modifed_by", SecurityContext.CurrentAccount.ID)
                        .InColumnValue("last_modifed_on", DateTime.UtcNow)
                        .Identity(1, 0, true);

                    rate.ID = Db.ExecuteScalar<int>(query);
                }

                tx.Commit();

                return rates;
            }
        }

        private SqlQuery GetSqlQuery(Exp where)
        {
            var sqlQuery = Query("crm_currency_rate")
                .Select("id",
                        "from_currency",
                        "to_currency",
                        "rate");

            if (where != null)
                sqlQuery.Where(where);

            return sqlQuery;
        }

        private static CurrencyRate ToCurrencyRate(object[] row)
        {
            return new CurrencyRate
            {
                ID = Convert.ToInt32(row[0]),
                FromCurrency = Convert.ToString(row[1]),
                ToCurrency = Convert.ToString(row[2]),
                Rate = Convert.ToDecimal(row[3])
            };
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/ProjectBootstrap.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Api.Interfaces;
using ASC.Projects.Engine;
using ASC.Web.Core.Calendars;

namespace ASC.Api.Projects
{
    public class ProjectBootstrap : IApiBootstrapper
    {
        public void Configure()
        {
            FileEngine.RegisterFileSecurityProvider();
            //Register prodjects' calendar events
            CalendarManager.Instance.RegistryCalendarProvider(ProjectApi.GetUserCalendars);
        }
    }
}

<|start_filename|>common/ASC.Data.Storage/ChunkedUploader/CommonChunkedUploadSessionHolder.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using ASC.Common.Logging;
using ASC.Data.Storage;

namespace ASC.Core.ChunkedUploader
{
    public class CommonChunkedUploadSessionHolder
    {
        public static readonly TimeSpan SlidingExpiration = TimeSpan.FromHours(12);

        public IDataStore DataStore { get; set; }
        private string Domain { get; set; }
        private long MaxChunkUploadSize { get; set; }
        private const string StoragePath = "sessions";

        public CommonChunkedUploadSessionHolder(IDataStore dataStore, string domain,
            long maxChunkUploadSize = 10 * 1024 * 1024)
        {
            DataStore = dataStore;
            Domain = domain;
            MaxChunkUploadSize = maxChunkUploadSize;
        }

        public void DeleteExpired()
        {
            // clear old sessions
            try
            {
                DataStore.DeleteExpired(Domain, StoragePath, SlidingExpiration);
            }
            catch (Exception err)
            {
                LogManager.GetLogger("ASC").Error(err);
            }
        }

        public void Store(CommonChunkedUploadSession s)
        {
            using (var stream = s.Serialize())
            {
                DataStore.SavePrivate(Domain, GetPathWithId(s.Id), stream, s.Expired);
            }
        }

        public void Remove(CommonChunkedUploadSession s)
        {
            DataStore.Delete(Domain, GetPathWithId(s.Id));
        }

        public CommonChunkedUploadSession Get(string sessionId)
        {
            using (var stream = DataStore.GetReadStream(Domain, GetPathWithId(sessionId)))
            {
                return CommonChunkedUploadSession.Deserialize(stream);
            }
        }

        public void Init(CommonChunkedUploadSession chunkedUploadSession)
        {
            if (chunkedUploadSession.BytesTotal < MaxChunkUploadSize)
            {
                chunkedUploadSession.UseChunks = false;
                return;
            }

            var tempPath = Guid.NewGuid().ToString();
            var uploadId = DataStore.InitiateChunkedUpload(Domain, tempPath);

            chunkedUploadSession.TempPath = tempPath;
            chunkedUploadSession.UploadId = uploadId;
        }

        public void Finalize(CommonChunkedUploadSession uploadSession)
        {
            var tempPath = uploadSession.TempPath;
            var uploadId = uploadSession.UploadId;
            var eTags = uploadSession.GetItemOrDefault<List<string>>("ETag")
                .Select((x, i) => new KeyValuePair<int, string>(i + 1, x))
                .ToDictionary(x => x.Key, x => x.Value);

            DataStore.FinalizeChunkedUpload(Domain, tempPath, uploadId, eTags);
        }

        public void Move(CommonChunkedUploadSession chunkedUploadSession, string newPath, bool quotaCheckFileSize = true)
        {
            DataStore.Move(Domain, chunkedUploadSession.TempPath, string.Empty, newPath, quotaCheckFileSize);
        }

        public void Abort(CommonChunkedUploadSession uploadSession)
        {
            if (uploadSession.UseChunks)
            {
                var tempPath = uploadSession.TempPath;
                var uploadId = uploadSession.UploadId;

                DataStore.AbortChunkedUpload(Domain, tempPath, uploadId);
            }
            else if (!string.IsNullOrEmpty(uploadSession.ChunksBuffer))
            {
                File.Delete(uploadSession.ChunksBuffer);
            }
        }

        public void UploadChunk(CommonChunkedUploadSession uploadSession, Stream stream, long length)
        {
            var tempPath = uploadSession.TempPath;
            var uploadId = uploadSession.UploadId;
            var chunkNumber = uploadSession.GetItemOrDefault<int>("ChunksUploaded") + 1;

            var eTag = DataStore.UploadChunk(Domain, tempPath, uploadId, stream, MaxChunkUploadSize, chunkNumber, length);

            uploadSession.Items["ChunksUploaded"] = chunkNumber;
            uploadSession.BytesUploaded += length;

            var eTags = uploadSession.GetItemOrDefault<List<string>>("ETag") ?? new List<string>();
            eTags.Add(eTag);
            uploadSession.Items["ETag"] = eTags;
        }

        public Stream UploadSingleChunk(CommonChunkedUploadSession uploadSession, Stream stream, long chunkLength)
        {
            if (uploadSession.BytesTotal == 0)
                uploadSession.BytesTotal = chunkLength;

            if (uploadSession.BytesTotal >= chunkLength)
            {
                //This is hack fixing strange behaviour of plupload in flash mode.

                if (string.IsNullOrEmpty(uploadSession.ChunksBuffer))
                {
                    uploadSession.ChunksBuffer = TempPath.GetTempFileName();
                }

                using (var bufferStream = new FileStream(uploadSession.ChunksBuffer, FileMode.Append))
                {
                    stream.CopyTo(bufferStream);
                }

                uploadSession.BytesUploaded += chunkLength;

                if (uploadSession.BytesTotal == uploadSession.BytesUploaded)
                {
                    return new FileStream(uploadSession.ChunksBuffer, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite,
                        4096, FileOptions.DeleteOnClose);
                }
            }

            return Stream.Null;
        }

        private string GetPathWithId(string id)
        {
            return Path.Combine(StoragePath, id + ".session");
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Sample/Controls/NavigationSidePanel.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Web;
using System.Web.UI;

using ASC.Web.Sample.Classes;

namespace ASC.Web.Sample.Controls
{
    public partial class NavigationSidePanel : UserControl
    {
        public static string Location
        {
            get
            {
                return PathProvider.GetFileStaticRelativePath("NavigationSidePanel.ascx");
            }
        }

        protected string CurrentPage { get; set; }
        protected string ExceptionMessage { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                var page = HttpContext.Current.Request.CurrentExecutionFilePath;

                if (!string.IsNullOrEmpty(page))
                    page = Path.GetFileNameWithoutExtension(page);

                CurrentPage = (page ?? string.Empty).ToLowerInvariant();
            }
            catch (Exception ex)
            {
                ExceptionMessage = ex.Message;
            }
            finally
            {
                if (string.IsNullOrEmpty(CurrentPage))
                    CurrentPage = "default";
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Controls/MailBox/MailBox.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Web.Files.Controls;
using ASC.Web.Mail.Resources;
using ASC.Web.Studio.Core;

namespace ASC.Web.Mail.Controls
{
    public partial class MailBox : UserControl
    {
        public static string Location { get { return "~/addons/mail/Controls/MailBox/MailBox.ascx"; } }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterBodyScripts("~/js/uploader/jquery.fileupload.js",
                                     "~/UserControls/Common/ckeditor/ckeditor-connector.js",
                                     "~/Products/Files/js/common.js",
                                     "~/Products/Files/js/templatemanager.js",
                                     "~/Products/Files/js/servicemanager.js",
                                     "~/Products/Files/js/ui.js",
                                     "~/Products/Files/js/eventhandler.js",
                                     "~/Products/Files/Controls/EmptyFolder/emptyfolder.js",
                                     "~/Products/Files/Controls/FileSelector/fileselector.js",
                                     "~/Products/Files/Controls/Tree/tree.js",
                                     "~/Products/Files/Controls/ConvertFile/confirmconvert.js"
                )
                .RegisterStyle("~/Products/Files/Controls/FileSelector/fileselector.css",
                               "~/Products/Files/Controls/ThirdParty/thirdparty.css",
                               "~/Products/Files/Controls/ContentList/contentlist.css",
                               "~/Products/Files/Controls/EmptyFolder/emptyfolder.css",
                               "~/Products/Files/Controls/Tree/tree.css",
                               "~/Products/Files/Controls/ConvertFile/confirmconvert.css"
                );

            ControlPlaceHolder.Controls.Add(LoadControl(Studio.UserControls.Common.MediaPlayer.Location));

            TagsPageHolder.Controls.Add(LoadControl(TagsPage.Location) as TagsPage);

            OutContentPlaceHolder.Controls.Add(LoadControl(UserFoldersPage.Location) as UserFoldersPage);

            TagsPageHolder.Controls.Add(LoadControl(FiltersPage.Location) as FiltersPage);
            TagsPageHolder.Controls.Add(LoadControl(AccountsPage.Location) as AccountsPage);
            TagsPageHolder.Controls.Add(LoadControl(ContactsPage.Location) as ContactsPage);
            TagsPageHolder.Controls.Add(LoadControl(CommonSettingsPage.Location) as CommonSettingsPage);

            if (Configuration.Settings.IsAdministrationPageAvailable())
                TagsPageHolder.Controls.Add(LoadControl(AdministrationPage.Location) as AdministrationPage);

            var documentsPopup = (DocumentsPopup)LoadControl(DocumentsPopup.Location);
            _phDocUploader.Controls.Add(documentsPopup);

            QuestionPopup.Options.IsPopup = true;

            var fileSelector = (FileSelector)LoadControl(FileSelector.Location);
            fileSelector.DialogTitle = MailResource.SelectFolderDialogTitle;
            fileSelector.OnlyFolder = true;
            fileholder.Controls.Add(fileSelector);

            fileholder.Controls.Add(LoadControl(ConfirmConvert.Location));
        }

        protected String RenderRedirectUpload()
        {
            return string.Format("{0}://{1}:{2}{3}", Request.GetUrlRewriter().Scheme, Request.GetUrlRewriter().Host, Request.GetUrlRewriter().Port, VirtualPathUtility.ToAbsolute("~/") + "fckuploader.ashx?newEditor=true&esid=mail");
        }

        public bool IsMailPrintAvailable()
        {
            return SetupInfo.IsVisibleSettings("MailPrint");
        }
    }
}


<|start_filename|>common/Tests/ASC.Common.Tests/Utils/MimeHeaderUtilsTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#if DEBUG
using ASC.Common.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ASC.Common.Tests.Utils
{
    [TestClass]
    public class MimeHeaderUtilsTest
    {
        [TestMethod]
        public void Encode()
        {
            Assert.AreEqual("=?utf-8?B?0YrRitGK?=", MimeHeaderUtils.EncodeMime("ъъъ"));
            Assert.AreEqual("ddd", MimeHeaderUtils.EncodeMime("ddd"));
        }
    }
}
#endif

<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/CoreModuleSpecifics.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;

using ASC.Core.Billing;
using ASC.Data.Backup.Tasks.Data;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal class CoreModuleSpecifics : ModuleSpecificsBase
    {
        private static readonly Guid ProjectsSourceID = new Guid("6045B68C-2C2E-42db-9E53-C272E814C4AD");
        private static readonly Guid BookmarksSourceID = new Guid("28B10049-DD20-4f54-B986-873BC14CCFC7");
        private static readonly Guid ForumsSourceID = new Guid("853B6EB9-73EE-438d-9B09-8FFEEDF36234");
        private static readonly Guid NewsSourceID = new Guid("6504977C-75AF-4691-9099-084D3DDEEA04");
        private static readonly Guid BlogsSourceID = new Guid("6A598C74-91AE-437d-A5F4-AD339BD11BB2");

        private const string ForumsNewPostInTopicActionID = "new post in topic";
        private const string ForumsNewPostInThreadActionID = "new post in thread";
        private const string NewsNewCommentActionID = "new feed comment";
        private const string BlogsNewCommentActionID = "new comment";

        private const string CrmCompanyAclObjectStart = "ASC.CRM.Core.Entities.Company|";
        private const string CrmPersonAclObjectStart = "ASC.CRM.Core.Entities.Person|";
        private const string CrmDealAclObjectStart = "ASC.CRM.Core.Entities.Deal|";
        private const string CrmCasesAclObjectStart = "ASC.CRM.Core.Entities.Cases|";
        private const string CrmRelationshipEventAclObjectStart = "ASC.CRM.Core.Entities.RelationshipEvent|";
        private const string CalendarCalendarAclObjectStart = "ASC.Api.Calendar.BusinessObjects.Calendar|";
        private const string CalendarEventAclObjectStart = "ASC.Api.Calendar.BusinessObjects.Event|";

        private readonly TableInfo[] _tables = new[]
            {
                new TableInfo("core_acl", "tenant") {InsertMethod = InsertMethod.Ignore},
                new TableInfo("core_subscription", "tenant"),
                new TableInfo("core_subscriptionmethod", "tenant"),
                new TableInfo("core_userphoto", "tenant") {UserIDColumns = new[] {"userid"}},
                new TableInfo("core_usersecurity", "tenant") {UserIDColumns = new[] {"userid"}},
                new TableInfo("core_usergroup", "tenant") {UserIDColumns = new[] {"userid"}},
                new TableInfo("feed_aggregate", "tenant")
                    {
                        InsertMethod = InsertMethod.None,
                        DateColumns = new Dictionary<string, bool> {{"created_date", false}, {"aggregated_date", false}}
                    },
                new TableInfo("feed_readed", "tenant_id")
                    {
                        InsertMethod = InsertMethod.None,
                        DateColumns = new Dictionary<string, bool> {{"timestamp", false}}
                    },
                new TableInfo("feed_users") {InsertMethod = InsertMethod.None},
                new TableInfo("backup_backup", "tenant_id", "id", IdType.Guid),
                new TableInfo("backup_schedule", "tenant_id"),
                new TableInfo("core_settings", "tenant")
            };

        private readonly RelationInfo[] _tableRelations = new[]
            {
                new RelationInfo("core_user", "id", "core_acl", "subject", typeof(TenantsModuleSpecifics)),

                new RelationInfo("core_group", "id", "core_acl", "subject", typeof(TenantsModuleSpecifics)),

                new RelationInfo("core_user", "id", "core_subscription", "recipient", typeof(TenantsModuleSpecifics)),

                new RelationInfo("core_group", "id", "core_subscription", "recipient", typeof(TenantsModuleSpecifics)),

                new RelationInfo("core_user", "id", "core_subscriptionmethod", "recipient", typeof(TenantsModuleSpecifics)),

                new RelationInfo("core_group", "id", "core_subscriptionmethod", "recipient", typeof(TenantsModuleSpecifics)),

                new RelationInfo("core_group", "id", "core_usergroup", "groupid", typeof(TenantsModuleSpecifics),
                                 x => !Helpers.IsEmptyOrSystemGroup(Convert.ToString(x["groupid"]))),

                new RelationInfo("crm_contact", "id", "core_acl", "object", typeof(CrmModuleSpecifics),
                                 x => Convert.ToString(x["object"]).StartsWith(CrmCompanyAclObjectStart) || Convert.ToString(x["object"]).StartsWith(CrmPersonAclObjectStart)),

                new RelationInfo("crm_deal", "id", "core_acl", "object", typeof(CrmModuleSpecifics),
                                 x => Convert.ToString(x["object"]).StartsWith(CrmDealAclObjectStart)),

                new RelationInfo("crm_case", "id", "core_acl", "object", typeof(CrmModuleSpecifics),
                                 x => Convert.ToString(x["object"]).StartsWith(CrmCasesAclObjectStart)),

                new RelationInfo("crm_relationship_event", "id", "core_acl", "object", typeof(CrmModuleSpecifics2),
                                 x => Convert.ToString(x["object"]).StartsWith(CrmRelationshipEventAclObjectStart)),

                new RelationInfo("calendar_calendars", "id", "core_acl", "object", typeof(CalendarModuleSpecifics),
                                 x => Convert.ToString(x["object"]).StartsWith(CalendarCalendarAclObjectStart)),

                new RelationInfo("calendar_events", "id", "core_acl", "object", typeof(CalendarModuleSpecifics),
                                 x => Convert.ToString(x["object"]).StartsWith(CalendarEventAclObjectStart)),

                new RelationInfo("projects_projects", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
                                 x => ValidateSource(ProjectsSourceID, x)),

                new RelationInfo("projects_tasks", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
                                 x => ValidateSource(ProjectsSourceID, x) && Convert.ToString(x["object"]).StartsWith("Task_")),

                new RelationInfo("projects_messages", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
                                 x => ValidateSource(ProjectsSourceID, x) && Convert.ToString(x["object"]).StartsWith("Message_")),

                new RelationInfo("projects_milestones", "id", "core_subscription", "object", typeof(ProjectsModuleSpecifics),
                                 x => ValidateSource(ProjectsSourceID, x) && Convert.ToString(x["object"]).StartsWith("Milestone_")),

                new RelationInfo("bookmarking_bookmark", "ID", "core_subscription", "object", typeof(CommunityModuleSpecifics),
                                 x => ValidateSource(BookmarksSourceID, x) && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),

                new RelationInfo("forum_topic", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
                                 x => ValidateSource(ForumsSourceID, x) && Convert.ToString(x["action"]) == ForumsNewPostInTopicActionID && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),

                new RelationInfo("forum_thread", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
                                 x => ValidateSource(ForumsSourceID, x) && Convert.ToString(x["action"]) == ForumsNewPostInThreadActionID && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),

                new RelationInfo("events_feed", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
                                 x => ValidateSource(NewsSourceID, x) && Convert.ToString(x["action"]) == NewsNewCommentActionID && !string.IsNullOrEmpty(Convert.ToString(x["object"]))),

                new RelationInfo("blogs_posts", "id", "core_subscription", "object", typeof(CommunityModuleSpecifics),
                                 x => ValidateSource(BlogsSourceID, x) && Convert.ToString(x["action"]) == BlogsNewCommentActionID),

                new RelationInfo("core_user", "id", "feed_users", "user_id", typeof(CoreModuleSpecifics)),

                new RelationInfo("files_folder", "id", "backup_backup", "storage_base_path", typeof(FilesModuleSpecifics),
                                 x => IsDocumentsStorageType(Convert.ToString(x["storage_type"]))),

                new RelationInfo("files_file", "id", "backup_backup", "storage_path", typeof(FilesModuleSpecifics),
                                 x => IsDocumentsStorageType(Convert.ToString(x["storage_type"]))),

                new RelationInfo("files_folder", "id", "backup_schedule", "storage_base_path", typeof(FilesModuleSpecifics),
                                 x => IsDocumentsStorageType(Convert.ToString(x["storage_type"]))),
            };

        public override ModuleName ModuleName
        {
            get { return ModuleName.Core; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return _tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return _tableRelations; }
        }

        protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
        {

            if (table.Name == "feed_users")
                return "inner join core_user t1 on t1.id = t.user_id where t1.tenant = " + tenantId;

            if (table.Name == "core_settings")
                return string.Format("where t.{0} = {1} and id not in ('{2}')", table.TenantColumn, tenantId, LicenseReader.CustomerIdKey);

            return base.GetSelectCommandConditionText(tenantId, table);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
        {
            if (table.Name == "core_usergroup" && columnName == "last_modified")
            {
                value = DateTime.UtcNow;
                return true;
            }
            return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
        }

        protected override bool TryPrepareRow(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, DataRowInfo row, out Dictionary<string, object> preparedRow)
        {
            if (table.Name == "core_acl")
            {
                if (int.Parse((string)row["tenant"]) == -1)
                {
                    preparedRow = null;
                    return false;
                }
            }
            return base.TryPrepareRow(dump, connection, columnMapper, table, row, out preparedRow);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
        {
            if (relation.ChildTable == "core_acl" && relation.ChildColumn == "object")
            {
                var valParts = Convert.ToString(value).Split('|');

                var entityId = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, valParts[1]);
                if (entityId == null)
                    return false;

                value = string.Format("{0}|{1}", valParts[0], entityId);
                return true;
            }
            return base.TryPrepareValue(connection, columnMapper, relation, ref value);
        }

        protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
        {
            var relationList = relations.ToList();

            if (relationList.All(x => x.ChildTable == "core_subscription" && x.ChildColumn == "object" && x.ParentTable.StartsWith("projects_")))
            {
                var valParts = Convert.ToString(value).Split('_');

                var projectId = columnMapper.GetMapping("projects_projects", "id", valParts[2]);
                if (projectId == null)
                    return false;

                var firstRelation = relationList.First(x => x.ParentTable != "projects_projects");
                var entityId = columnMapper.GetMapping(firstRelation.ParentTable, firstRelation.ParentColumn, valParts[1]);
                if (entityId == null)
                    return false;

                value = string.Format("{0}_{1}_{2}", valParts[0], entityId, projectId);
                return true;
            }

            if (relationList.All(x => x.ChildTable == "core_subscription" && x.ChildColumn == "recipient")
                || relationList.All(x => x.ChildTable == "core_subscriptionmethod" && x.ChildColumn == "recipient")
                || relationList.All(x => x.ChildTable == "core_acl" && x.ChildColumn == "subject"))
            {
                var strVal = Convert.ToString(value);
                if (Helpers.IsEmptyOrSystemUser(strVal) || Helpers.IsEmptyOrSystemGroup(strVal))
                    return true;

                foreach (var relation in relationList)
                {
                    var mapping = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, value);
                    if (mapping != null)
                    {
                        value = mapping;
                        return true;
                    }
                }
                return false;
            }

            return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relationList, ref value);
        }

        private static bool ValidateSource(Guid expectedValue, DataRowInfo row)
        {
            var source = Convert.ToString(row["source"]);
            try
            {
                return expectedValue == new Guid(source);
            }
            catch
            {
                return false;
            }
        }

        private static bool IsDocumentsStorageType(string strStorageType)
        {
            var storageType = int.Parse(strStorageType);
            return storageType == 0 || storageType == 1;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/MIME/MIME_h_Provider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.MIME
{
    #region usings

    using System;
    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// This class represents MIME headers provider.
    /// </summary>
    public class MIME_h_Provider
    {
        #region Members

        private readonly Dictionary<string, Type> m_pHeadrFields;
        private Type m_pDefaultHeaderField;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets default header field what is used to reperesent unknown header fields.
        /// </summary>
        /// <remarks>This property value value must be based on <see cref="MIME_h"/> class.</remarks>
        /// <exception cref="ArgumentNullException">Is raised when null reference passed.</exception>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public Type DefaultHeaderField
        {
            get { return m_pDefaultHeaderField; }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("DefaultHeaderField");
                }
                if (!value.GetType().IsSubclassOf(typeof (MIME_h)))
                {
                    throw new ArgumentException(
                        "Property 'DefaultHeaderField' value must be based on MIME_h class.");
                }

                m_pDefaultHeaderField = value;
            }
        }

        /// <summary>
        /// Gets header fields parsers collection.
        /// </summary>
        public Dictionary<string, Type> HeaderFields
        {
            get { return m_pHeadrFields; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public MIME_h_Provider()
        {
            m_pDefaultHeaderField = typeof (MIME_h_Unstructured);

            m_pHeadrFields = new Dictionary<string, Type>(StringComparer.CurrentCultureIgnoreCase);
            m_pHeadrFields.Add("content-type", typeof (MIME_h_ContentType));
            m_pHeadrFields.Add("content-disposition", typeof (MIME_h_ContentDisposition)); //BUG: was there
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses specified header field.
        /// </summary>
        /// <param name="field">Header field string (Name: value).</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>field</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public MIME_h Parse(string field)
        {
            if (field == null)
            {
                throw new ArgumentNullException("field");
            }

            MIME_h headerField = null;
            string[] name_value = field.Split(new[] {':'}, 2);
            string name = name_value[0].Trim().ToLowerInvariant();
            if (name == string.Empty)
            {
                throw new ParseException("Invalid header field value '" + field + "'.");
            }
            else
            {
                try
                {
                    if (m_pHeadrFields.ContainsKey(name))
                    {
                        headerField =
                            (MIME_h)
                            m_pHeadrFields[name].GetMethod("Parse").Invoke(null, new object[] {field});
                    }
                    else
                    {
                        headerField =
                            (MIME_h)
                            m_pDefaultHeaderField.GetMethod("Parse").Invoke(null, new object[] {field});
                    }
                }
                catch (Exception x)
                {
                    headerField = new MIME_h_Unparsed(field, x.InnerException);
                }
            }

            return headerField;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/ThirdPartyBanner/ThirdPartyBannerSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;

namespace ASC.Web.Studio.UserControls.Common.ThirdPartyBanner
{
    [Serializable]
    [DataContract]
    public class ThirdPartyBannerSettings : BaseSettings<ThirdPartyBannerSettings>
    {
        [DataMember(Name = "ClosedSetting")]
        public string ClosedSetting { get; set; }

        public override ISettings GetDefault()
        {
            return new ThirdPartyBannerSettings
            {
                ClosedSetting = null,
            };
        }

        public override Guid ID
        {
            get { return new Guid("{B6E9B080-4B14-4C54-95E7-C2E9E87965EB}"); }
        }

        public static bool CheckClosed(string banner)
        {
            return (LoadForCurrentUser().ClosedSetting ?? "").Split('|').Contains(banner);
        }

        public static void Close(string banner)
        {
            var closed = (LoadForCurrentUser().ClosedSetting ?? "").Split('|').ToList();
            if (closed.Contains(banner)) return;
            closed.Add(banner);

            new ThirdPartyBannerSettings { ClosedSetting = string.Join("|", closed.ToArray()) }.SaveForCurrentUser();
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_Directive.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements SIP "directive" value. Defined in RFC 3841.
    /// </summary>
    /// <remarks>
    /// <code>
    /// RFC 3841 Syntax:
    ///     directive          = proxy-directive / cancel-directive / fork-directive / recurse-directive /
    ///                          parallel-directive / queue-directive
    ///     proxy-directive    = "proxy" / "redirect"
    ///     cancel-directive   = "cancel" / "no-cancel"
    ///     fork-directive     = "fork" / "no-fork"
    ///     recurse-directive  = "recurse" / "no-recurse"
    ///     parallel-directive = "parallel" / "sequential"
    ///     queue-directive    = "queue" / "no-queue"
    /// </code>
    /// </remarks>
    public class SIP_t_Directive : SIP_t_Value
    {
        #region DirectiveType enum

        /// <summary>
        /// Proccess directives. Defined in rfc 3841 9.1.
        /// </summary>
        public enum DirectiveType
        {
            /// <summary>
            /// This directive indicates whether the caller would like each server to proxy request. 
            /// </summary>
            Proxy,

            /// <summary>
            /// This directive indicates whether the caller would like each server to redirect request.
            /// </summary>
            Redirect,

            /// <summary>
            /// This directive indicates whether the caller would like each proxy server to send a CANCEL 
            /// request to forked branches.
            /// </summary>
            Cancel,

            /// <summary>
            /// This directive indicates whether the caller would NOT want each proxy server to send a CANCEL 
            /// request to forked branches.
            /// </summary>
            NoCancel,

            /// <summary>
            /// This type of directive indicates whether a proxy should fork a request.
            /// </summary>
            Fork,

            /// <summary>
            /// This type of directive indicates whether a proxy should proxy to only a single address.
            /// The server SHOULD proxy the request to the "best" address (generally the one with the highest q-value).
            /// </summary>
            NoFork,

            /// <summary>
            /// This directive indicates whether a proxy server receiving a 3xx response should send 
            /// requests to the addresses listed in the response.
            /// </summary>
            Recurse,

            /// <summary>
            /// This directive indicates whether a proxy server receiving a 3xx response should forward 
            /// the list of addresses upstream towards the caller.
            /// </summary>
            NoRecurse,

            /// <summary>
            /// This directive indicates whether the caller would like the proxy server to proxy 
            /// the request to all known addresses at once.
            /// </summary>
            Parallel,

            /// <summary>
            /// This directive indicates whether the caller would like the proxy server to go through
            /// all known addresses sequentially, contacting the next address only after it has received 
            /// a non-2xx or non-6xx final response for the previous one.
            /// </summary>
            Sequential,

            /// <summary>
            /// This directive indicates whether if the called party is temporarily unreachable, caller 
            /// wants to have its call queued.
            /// </summary>
            Queue,

            /// <summary>
            /// This directive indicates whether if the called party is temporarily unreachable, caller 
            /// don't want its call to be queued.
            /// </summary>
            NoQueue
        }

        #endregion

        #region Members

        private DirectiveType m_Directive = DirectiveType.Fork;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets directive.
        /// </summary>
        public DirectiveType Directive
        {
            get { return m_Directive; }

            set { m_Directive = value; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "directive" from specified value.
        /// </summary>
        /// <param name="value">SIP "directive" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>value</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "directive" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            /*
                directive          = proxy-directive / cancel-directive / fork-directive / recurse-directive /
                                     parallel-directive / queue-directive
                proxy-directive    = "proxy" / "redirect"
                cancel-directive   = "cancel" / "no-cancel"
                fork-directive     = "fork" / "no-fork"
                recurse-directive  = "recurse" / "no-recurse"
                parallel-directive = "parallel" / "sequential"
                queue-directive    = "queue" / "no-queue"
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // Get Method
            string word = reader.ReadWord();
            if (word == null)
            {
                throw new SIP_ParseException("'directive' value is missing !");
            }
            if (word.ToLower() == "proxy")
            {
                m_Directive = DirectiveType.Proxy;
            }
            else if (word.ToLower() == "redirect")
            {
                m_Directive = DirectiveType.Redirect;
            }
            else if (word.ToLower() == "cancel")
            {
                m_Directive = DirectiveType.Cancel;
            }
            else if (word.ToLower() == "no-cancel")
            {
                m_Directive = DirectiveType.NoCancel;
            }
            else if (word.ToLower() == "fork")
            {
                m_Directive = DirectiveType.Fork;
            }
            else if (word.ToLower() == "no-fork")
            {
                m_Directive = DirectiveType.NoFork;
            }
            else if (word.ToLower() == "recurse")
            {
                m_Directive = DirectiveType.Recurse;
            }
            else if (word.ToLower() == "no-recurse")
            {
                m_Directive = DirectiveType.NoRecurse;
            }
            else if (word.ToLower() == "parallel")
            {
                m_Directive = DirectiveType.Parallel;
            }
            else if (word.ToLower() == "sequential")
            {
                m_Directive = DirectiveType.Sequential;
            }
            else if (word.ToLower() == "queue")
            {
                m_Directive = DirectiveType.Queue;
            }
            else if (word.ToLower() == "no-queue")
            {
                m_Directive = DirectiveType.NoQueue;
            }
            else
            {
                throw new SIP_ParseException("Invalid 'directive' value !");
            }
        }

        /// <summary>
        /// Converts this to valid "directive" value.
        /// </summary>
        /// <returns>Returns "directive" value.</returns>
        public override string ToStringValue()
        {
            /*
                directive          = proxy-directive / cancel-directive / fork-directive / recurse-directive /
                                     parallel-directive / queue-directive
                proxy-directive    = "proxy" / "redirect"
                cancel-directive   = "cancel" / "no-cancel"
                fork-directive     = "fork" / "no-fork"
                recurse-directive  = "recurse" / "no-recurse"
                parallel-directive = "parallel" / "sequential"
                queue-directive    = "queue" / "no-queue"
            */

            if (m_Directive == DirectiveType.Proxy)
            {
                return "proxy";
            }
            else if (m_Directive == DirectiveType.Redirect)
            {
                return "redirect";
            }
            else if (m_Directive == DirectiveType.Cancel)
            {
                return "cancel";
            }
            else if (m_Directive == DirectiveType.NoCancel)
            {
                return "no-cancel";
            }
            else if (m_Directive == DirectiveType.Fork)
            {
                return "fork";
            }
            else if (m_Directive == DirectiveType.NoFork)
            {
                return "no-fork";
            }
            else if (m_Directive == DirectiveType.Recurse)
            {
                return "recurse";
            }
            else if (m_Directive == DirectiveType.NoRecurse)
            {
                return "no-recurse";
            }
            else if (m_Directive == DirectiveType.Parallel)
            {
                return "parallel";
            }
            else if (m_Directive == DirectiveType.Sequential)
            {
                return "sequential";
            }
            else if (m_Directive == DirectiveType.Queue)
            {
                return "queue";
            }
            else if (m_Directive == DirectiveType.NoQueue)
            {
                return "no-queue";
            }
            else
            {
                throw new ArgumentException("Invalid property Directive value, this should never happen !");
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Controls/ConvertFile/confirmconvert.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC.Files.ConfrimConvert = (function () {
    var isInit = false;

    var init = function () {
        if (isInit === false) {
            isInit = true;

            jq(".store-original").change(function () {
                storeOriginalFiles(this);
            });
        }
    };

    var showDialog = function (continueCallback, cancelCallbackString, isForSave) {
        if (jq("#confirmConvert:visible").length > 0) {
            return;
        }

        isForSave = isForSave === true;

        var currentState = jq("#confirmConvert").attr(isForSave ? "data-save" : "data-open");
        if (currentState == "true") {
            if (typeof continueCallback === "function") {
                continueCallback.call();
            }

            return;
        }

        jq("#confirmConvertSave,#confirmConvertSaveDescript").toggle(isForSave);
        jq("#confirmConvertEdit,#confirmConvertEditDescript").toggle(!isForSave);

        jq("#confirmConvertContinue").off("click").on("click", function () {
            jq("#confirmConvertContinue").off("click");
            
            if (jq("#confirmConvertHide").prop("checked")) {
                Teamlab.hideConfirmConvert(isForSave, {
                    success: function () {
                        jq("#confirmConvert").attr(isForSave ? "data-save" : "data-open", true);
                    }
                });
            }

            PopupKeyUpActionProvider.CloseDialogAction = "";
            PopupKeyUpActionProvider.CloseDialog();

            if (typeof continueCallback === "function") {
                continueCallback.call();
            }
        });

        PopupKeyUpActionProvider.CloseDialogAction = cancelCallbackString;
        ASC.Files.UI.blockUI("#confirmConvert", 530);
    };

    var storeOriginalFiles = function (target) {
        var value = jq(target).prop("checked");

        Teamlab.filesStoreOriginal(value, {
            success: function (_, data) {
                ASC.Files.Common.storeOriginal = (data === true);

                jq(".store-original").prop("checked", ASC.Files.Common.storeOriginal);
            },
            error: function (params, error) {
                ASC.Files.UI.displayInfoPanel(error[0], true);
            }
        });
    };

    return {
        init: init,

        showDialog: showDialog
    };
})();

(function ($) {
    $(function () {
        ASC.Files.ConfrimConvert.init();
    });
})(jQuery);

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IO/MultiStream.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IO
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.IO;

    #endregion

    /// <summary>
    /// This class combines multiple stream into one stream for reading.
    /// The most common usage for that stream is when you need to insert some data to the beginning of some stream.
    /// </summary>
    public class MultiStream : Stream
    {
        #region Members

        private bool m_IsDisposed;
        private Queue<Stream> m_pStreams;

        #endregion

        #region Properties

        /// <summary>
        /// Gets a value indicating whether the current stream supports reading.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public override bool CanRead
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                return true;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the current stream supports seeking.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public override bool CanSeek
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                return false;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the current stream supports writing.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public override bool CanWrite
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                return false;
            }
        }

        /// <summary>
        /// Gets the length in bytes of the stream.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="NotSupportedException">Is raised when one of the source streams won't support <b>Length</b> property.</exception>
        public override long Length
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                long length = 0;
                foreach (Stream stream in m_pStreams.ToArray())
                {
                    length += stream.Length;
                }

                return length;
            }
        }

        /// <summary>
        /// Gets or sets the position within the current stream. This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="NotSupportedException">Is raised when this property is accessed.</exception>
        public override long Position
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                throw new NotSupportedException();
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                throw new NotSupportedException();
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public MultiStream()
        {
            m_pStreams = new Queue<Stream>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public new void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }

            m_IsDisposed = true;
            m_pStreams = null;

            base.Dispose();
        }

        /// <summary>
        /// Appends this stream to read queue.
        /// </summary>
        /// <param name="stream">Stream to add.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null.</exception>
        public void AppendStream(Stream stream)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            m_pStreams.Enqueue(stream);
        }

        /// <summary>
        /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public override void Flush()
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("SmartStream");
            }
        }

        /// <summary>
        /// Sets the position within the current stream. This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <param name="offset">A byte offset relative to the <b>origin</b> parameter.</param>
        /// <param name="origin">A value of type SeekOrigin indicating the reference point used to obtain the new position.</param>
        /// <returns>The new position within the current stream.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="NotSupportedException">Is raised when this method is accessed.</exception>
        public override long Seek(long offset, SeekOrigin origin)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("SmartStream");
            }

            throw new NotSupportedException();
        }

        /// <summary>
        /// Sets the length of the current stream. This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <param name="value">The desired length of the current stream in bytes.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="Seek">Is raised when this method is accessed.</exception>
        public override void SetLength(long value)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("SmartStream");
            }

            throw new NotSupportedException();
        }

        /// <summary>
        /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
        /// </summary>
        /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
        /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
        /// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("SmartStream");
            }

            while (true)
            {
                // We have readed all streams data, no data left.
                if (m_pStreams.Count == 0)
                {
                    return 0;
                }
                else
                {
                    int readedCount = m_pStreams.Peek().Read(buffer, offset, count);
                    // We have readed all current stream data.
                    if (readedCount == 0)
                    {
                        // Move to next stream .
                        m_pStreams.Dequeue();

                        // Next while loop will process "read".
                    }
                    else
                    {
                        return readedCount;
                    }
                }
            }
        }

        /// <summary>
        /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written.
        /// This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
        /// <param name="count">The number of bytes to be written to the current stream.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="NotSupportedException">Is raised when this method is accessed.</exception>
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("SmartStream");
            }

            throw new NotSupportedException();
        }

        #endregion
    }
}

<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Infrastructure/WarmingUpper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using log4net;
using RestSharp;
using System.Threading.Tasks;

namespace ASC.HealthCheck.Infrastructure
{
    public class WarmingUpper
    {
        private readonly ILog log = LogManager.GetLogger(typeof(WarmingUpper));
        private const int ApiCount = 5;
        private readonly Task[] tasks = new Task[ApiCount];

        public void WarmingUp(string rootUrl)
        {
            tasks[0] = Task.Run(() => MakeHealthCheckRequest(rootUrl + "api/PortsCheckApi/GetPortList", Method.GET));
            tasks[1] = Task.Run(() => MakeHealthCheckRequest(rootUrl + "api/PortsCheckApi/GetPortStatus", Method.GET));
            tasks[2] = Task.Run(() => MakeHealthCheckRequest(rootUrl + "api/NotifiersApi//GetNotifySettings", Method.GET));
            tasks[3] = Task.Run(() => MakeHealthCheckRequest(rootUrl + "api/NotifiersApi/GetNotifiers", Method.GET));
            tasks[4] = Task.Run(() => MakeHealthCheckRequest(rootUrl + "api/DriveSpaceApi/GetDriveSpace", Method.GET));
            Task.WaitAll(tasks);
            log.Debug("Warming up done.");
        }

        public void MakeHealthCheckRequest(string url, Method method)
        {
            var client = new RestClient(url);
            var request = new RestRequest(method);
            var response = client.Execute(request);
            log.DebugFormat("Request executed {0} , response.Content {1}", url, response.Content);
        }
    }
}


<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Core/Dao/DkimDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Server.Core.Dao.Interfaces;
using ASC.Mail.Server.Core.DbSchema;
using ASC.Mail.Server.Core.DbSchema.Interfaces;
using ASC.Mail.Server.Core.DbSchema.Tables;
using ASC.Mail.Server.Core.Entities;

namespace ASC.Mail.Server.Core.Dao
{
    public class DkimDao : BaseDao, IDkimDao
    {
        protected static ITable table = new MailServerTableFactory().Create<DkimTable>();

        public DkimDao(IDbManager dbManager)
            : base(table, dbManager)
        {
        }

        public int Save(Dkim dkim)
        {
            var query = new SqlInsert(DkimTable.TABLE_NAME, true)
                .InColumnValue(DkimTable.Columns.ID, dkim.Id)
                .InColumnValue(DkimTable.Columns.DOMAIN_NAME, dkim.DomainName)
                .InColumnValue(DkimTable.Columns.SELECTOR, dkim.Selector)
                .InColumnValue(DkimTable.Columns.PRIVATE_KEY, dkim.PrivateKey)
                .InColumnValue(DkimTable.Columns.PUBLIC_KEY, dkim.PublicKey);

            var id = Db.ExecuteScalar<int>(query);

            return id;
        }

        public int Remove(string domain)
        {
            var query = new SqlDelete(DkimTable.TABLE_NAME)
                .Where(DkimTable.Columns.DOMAIN_NAME, domain);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/Wrappers/TaskWrapperFull.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Api.Documents;
using ASC.Projects.Core.Domain;
using ASC.Web.Studio.UserControls.Common.Comments;

namespace ASC.Api.Projects.Wrappers
{
    [DataContract(Name = "task", Namespace = "")]
    public class TaskWrapperFull : TaskWrapper
    {
        [DataMember]
        public List<FileWrapper> Files { get; set; }

        [DataMember]
        public List<CommentInfo> Comments { get; set; }

        [DataMember]
        public int CommentsCount { get; set; }

        [DataMember]
        public bool IsSubscribed { get; set; }

        [DataMember]
        public bool CanEditFiles { get; set; }

        [DataMember]
        public bool CanCreateComment { get; set; }

        [DataMember]
        public ProjectWrapperFull Project { get; set; }

        [DataMember]
        public float TimeSpend { get; set; }

        public TaskWrapperFull(ProjectApiBase projectApiBase, Task task, Milestone milestone, ProjectWrapperFull project, IEnumerable<FileWrapper> files, IEnumerable<CommentInfo> comments, int commentsCount, bool isSubscribed, float timeSpend)
            : base(projectApiBase, task, milestone)
        {
            Files = files.ToList();
            CommentsCount = commentsCount;
            IsSubscribed = isSubscribed;
            Project = project;
            CanEditFiles = projectApiBase.ProjectSecurity.CanEditFiles(task);
            CanCreateComment = projectApiBase.ProjectSecurity.CanCreateComment(task);
            TimeSpend = timeSpend;
            Comments = comments.ToList();
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/HttpHandlers/FileHandler.ashx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.IO;
using System.Web;

using ASC.Common.Logging;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Resources;

#endregion

namespace ASC.Web.CRM.HttpHandlers
{
    public class FileHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            var action = context.Request["action"];

            switch (action)
            {
                case "contactphotoulr":
                    ResponceContactPhotoUrl(context);
                    break;
                case "mailmessage":
                    ResponceMailMessageContent(context);
                    break;
                default:
                    throw new ArgumentException(String.Format("action='{0}' is not defined", action));
            }
        }

        private void ResponceContactPhotoUrl(HttpContext context)
        {
            var contactId = Convert.ToInt32(context.Request["cid"]);
            var isCompany = Convert.ToBoolean(context.Request["isc"]);
            var photoSize = Convert.ToInt32(context.Request["ps"]);

            String photoUrl = String.Empty;

            switch (photoSize)
            {
                case 1:
                    photoUrl = ContactPhotoManager.GetSmallSizePhoto(contactId, isCompany);
                    break;
                case 2:
                    photoUrl = ContactPhotoManager.GetMediumSizePhoto(contactId, isCompany);
                    break;
                case 3:
                    photoUrl = ContactPhotoManager.GetBigSizePhoto(contactId, isCompany);
                    break;
                default:
                    throw new Exception(CRMErrorsResource.ContactPhotoSizeUnknown);
            }

            context.Response.Clear();
            context.Response.Write(photoUrl);

            try
            {
                context.Response.Flush();
                context.Response.SuppressContent = true;
                context.ApplicationInstance.CompleteRequest();
            }
            catch (HttpException ex)
            {
                LogManager.GetLogger("ASC").Error("ResponceContactPhotoUrl", ex);
            }
        }

        private void ResponceMailMessageContent(HttpContext context)
        {
            var messageId = Convert.ToInt32(context.Request["message_id"]);

            var filePath = String.Format("folder_{0}/message_{1}.html", (messageId / 1000 + 1) * 1000, messageId);

            String messageContent = String.Empty;

            using (var streamReader = new StreamReader(Global.GetStore().GetReadStream("mail_messages", filePath)))
            {
                messageContent = streamReader.ReadToEnd();
            }


            context.Response.Clear();
            context.Response.Write(messageContent);
            try
            {
                context.Response.Flush();
                context.Response.SuppressContent = true;
                context.ApplicationInstance.CompleteRequest();
            }
            catch (HttpException ex)
            {
                LogManager.GetLogger("ASC").Error("ResponceMailMessageContent", ex);
            }
        }


        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/contacts/filter/customfilter.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.customFilter = (function ($) {
    var isInit = false;
    var filter;
    var events = $({});

    function init() {
        if (!isInit) {
            isInit = true;

            $('#customFilter').advansedFilter({
                anykey: true,
                anykeytimeout: 1000,
                maxfilters: 0,
                hintDefaultDisable: false,
                sorters: [
                    { id: 'displayName', title: MailScriptResource.FilterByTitle, sortOrder: 'ascending', def: true }
                ],
                filters: []
            }).bind('setfilter', onSetFilter).bind('resetfilter', onResetFilter).bind('resetallfilters', onResetAllFilters);

            // filter object initialization should follow after advanced filter plugin call - because
            // its replace target element with new markup
            filter = $('#customFilter');

            filter.find(".advansed-filter-button").hide();

            events.trigger('ready');
        }
    };

    function onSetFilter(evt, $container, filterItem, value, selectedfilters) {
        events.trigger('set', [filterItem, value, selectedfilters]);
    };

    function onResetFilter(evt, $container, filterItem, selectedfilters) {
        events.trigger('reset', [filterItem, selectedfilters]);
    };

    function onResetAllFilters(evt, $container, filterid, selectedfilters) {
        events.trigger('resetall', [selectedfilters]);
    };

    function show() {
        filter.parent().show();
    };

    function hide() {
        filter.parent().hide();
    };

    function update() {
        filter.advansedFilter('resize');
    };

    function clear() {
        filter.advansedFilter(null);
    };

    function setSearch(text) {
        filter.advansedFilter({ filters: [{ type: 'text', id: 'text', params: { value: text } }]});
    };

    function setSort(sort, order) {
        filter.advansedFilter({ sorters: [{ id: sort, selected: true, dsc: 'descending' === order }]});
    };

    return {
        init: init,

        clear: clear,
        update: update,

        show: show,
        hide: hide,

        setSearch: setSearch,
        setSort: setSort,

        events: events
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Contacts/ContactFullCardView.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Linq;
using System.Text;
using System.Web;

using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Controls.Common;
using ASC.Web.CRM.Resources;


#endregion

namespace ASC.Web.CRM.Controls.Contacts
{
    public partial class ContactFullCardView : BaseUserControl
    {
        #region Properies

        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Contacts/ContactFullCardView.ascx"); }
        }

        public Contact TargetContact { get; set; }

        public Contact TargetCompanyIfPerson { get; set; }

        #endregion

        #region Events

        protected void Page_Load(object sender, EventArgs e)
        {
            TargetCompanyIfPerson = TargetContact is Person && ((Person)TargetContact).CompanyID != 0 ?
                DaoFactory.ContactDao.GetByID(((Person)TargetContact).CompanyID) :
                null;

            RegisterClientScriptHelper.DataContactFullCardView(Page, TargetContact);

            ExecHistoryView();
            RegisterScript();
        }

        #endregion

        #region Methods

        protected void ExecHistoryView()
        {
            var historyViewControl = (HistoryView)LoadControl(HistoryView.Location);

            historyViewControl.TargetContactID = TargetContact.ID;
            historyViewControl.TargetEntityID = 0;
            historyViewControl.TargetEntityType = EntityType.Contact;

            _phHistoryView.Controls.Add(historyViewControl);
        }

        protected string GetMailingHistoryUrl()
        {
            var primaryEmail = DaoFactory.ContactInfoDao.GetList(TargetContact.ID, ContactInfoType.Email, null, true).FirstOrDefault();
            if (primaryEmail == null || string.IsNullOrEmpty(primaryEmail.Data))
            {
                return string.Empty;
            }

            var virtualPath = string.Format("addons/mail/#inbox/from={0}", HttpUtility.UrlEncode(primaryEmail.Data));
            return Studio.Utility.CommonLinkUtility.GetFullAbsolutePath(virtualPath);
        }

        private void RegisterScript()
        {
            var sb = new StringBuilder();


            var additionalContactsCount = 0;
            if (TargetContact is Company)
            {
                var members = DaoFactory.ContactDao.GetMembersIDsAndShareType(TargetContact.ID);
                foreach (var m in members)
                {
                    if (CRMSecurity.CanAccessTo(m.Key, EntityType.Person, m.Value, 0))
                    {
                        additionalContactsCount++;
                    }
                }
            }
            else if (TargetCompanyIfPerson != null && CRMSecurity.CanAccessTo(TargetCompanyIfPerson))
            {
                additionalContactsCount = 1;
            }

            sb.AppendFormat(@"
                    ASC.CRM.ContactFullCardView.init({0},{1},{2},{3},{4},{5},""{6}"",{7},{8});",
                TargetContact.ID,
                (TargetContact is Company).ToString().ToLower(),
                TargetContact is Person ? ((Person)TargetContact).CompanyID : 0,
                Global.TenantSettings.ChangeContactStatusGroupAuto != null ? Global.TenantSettings.ChangeContactStatusGroupAuto.ToString().ToLower() : "null",
                Global.TenantSettings.AddTagToContactGroupAuto != null ? Global.TenantSettings.AddTagToContactGroupAuto.ToString().ToLower() : "null",
                Global.TenantSettings.WriteMailToHistoryAuto.ToString().ToLower(),
                Studio.Core.FileSizeComment.GetFileImageSizeNote(CRMContactResource.ContactPhotoInfo, true),
                additionalContactsCount,
                CRMSecurity.CanEdit(TargetContact).ToString().ToLower()
            );

            Page.RegisterInlineScript(sb.ToString());
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Server/IMAP_eArgs_GetQuota.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP.Server
{
    /// <summary>
    /// Provides data for GetUserQuota event.
    /// </summary>
    public class IMAP_eArgs_GetQuota
    {
        #region Members

        private readonly IMAP_Session m_pSession;

        #endregion

        #region Properties

        /// <summary>
        /// Gets current IMAP session.
        /// </summary>
        public IMAP_Session Session
        {
            get { return m_pSession; }
        }

        /// <summary>
        /// Gets user name.
        /// </summary>
        public string UserName
        {
            get { return m_pSession.UserName; }
        }

        /// <summary>
        /// Gets or sets maximum mailbox size.
        /// </summary>
        public long MaxMailboxSize { get; set; }

        /// <summary>
        /// Gets or sets current mailbox size.
        /// </summary>
        public long MailboxSize { get; set; }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="session">Owner IMAP session.</param>
        public IMAP_eArgs_GetQuota(IMAP_Session session)
        {
            m_pSession = session;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/App_Themes/default/common.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


label .checkbox {
    margin: 0 5px 3px 0;
    vertical-align: middle;
}
.select-action,
.select-action a,
.select-action input,
.select-action span,
.select-action div {
    cursor: default !important;
}
.popup-modal {
    display: none;
}
body .may-row-to,
body .may-drop-to {
    background-color: #fcf6e0;
}
.may-row-to.row-to,
.may-drop-to.drop-to {
    background-color: #F9EEC2;
}
.stick-panel {
    position: fixed;
    top: 0;
    z-index: 255;
}
#fileSidePanelSpacer {
    margin: 0;
}

/*******************************************************************************
    Selector
*******************************************************************************/
#filesSelector {
    background-color: #6CA3BF;
    border: 1px solid #034;
    cursor: default;
    display: block;
    height: 0;
    opacity: 0.3;
    position: absolute;
    width: 0;
    z-index: 254;
}

/*******************************************************************************
    Mobile
*******************************************************************************/
body.mobile div.blockUI.blockOverlay {
    min-width: 1000px;
    width: 100%;
}
/*******************************************************************************
    CreateNewButton - hack for IE7
*******************************************************************************/
*:first-child+html .page-menu .menu-actions .menu-main-button {
    width: 130px;
}

.files-filter {
    display: none;
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Entities/ServerDns.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Mail.Core.Entities
{
    public class ServerDns
    {
        public int Id { get; set; }
        public int Tenant { get; set; }
        public string User { get; set; }
        public int DomainId { get; set; }

        public string DomainCheck { get; set; }

        public string DkimSelector { get; set; }
        public string DkimPrivateKey { get; set; }
        public string DkimPublicKey { get; set; }
        public int DkimTtl { get; set; }
        public bool DkimVerified { get; set; }
        public DateTime? DkimDateChecked { get; set; }

        public string Spf { get; set; }
        public int SpfTtl { get; set; }
        public bool SpfVerified { get; set; }
        public DateTime? SpfDateChecked { get; set; }

        public string Mx { get; set; }
        public int MxTtl { get; set; }
        public bool MxVerified { get; set; }
        public DateTime? MxDateChecked { get; set; }

        public DateTime TimeModified { get; set; }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Controls/Common/NavigationSidePanel.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Core.Users;
using ASC.Projects.Core.Domain;
using ASC.Web.Core.Mobile;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.UserControls.Common.HelpCenter;
using ASC.Web.Studio.UserControls.Common.InviteLink;
using ASC.Web.Studio.UserControls.Common.Support;
using ASC.Web.Studio.UserControls.Common.UserForum;


namespace ASC.Web.Projects.Controls.Common
{
    public partial class NavigationSidePanel : BaseUserControl
    {
        public Project Project { get { return Page.Project; } }

        public List<Project> MyProjects { get; set; }

        protected bool ShowCreateButton { get; set; }

        protected bool IsProjectAdmin { get; set; }

        protected bool IsFullAdmin { get; set; }

        protected bool IsOutsider { get; set; }

        protected bool DisplayAppsBanner;

        protected void Page_Load(object sender, EventArgs e)
        {
            MyProjects = Page.RequestContext.CurrentUserProjects.ToList();

            InitControls();

            IsProjectAdmin = Page.ProjectSecurity.CurrentUserAdministrator;
            IsFullAdmin = Page.Participant.IsFullAdmin;
            IsOutsider = Page.Participant.UserInfo.IsOutsider();
            ShowCreateButton = !Page.Participant.UserInfo.IsOutsider();


            var mobileAppRegistrator = new CachedMobileAppInstallRegistrator(new MobileAppInstallRegistrator());
            var currentUser = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
            var isRegistered = mobileAppRegistrator.IsInstallRegistered(currentUser.Email, null);

            DisplayAppsBanner =
                SetupInfo.DisplayMobappBanner("projects")
                && !CoreContext.Configuration.Standalone
                && !isRegistered;
        }

        private void InitControls()
        {
            if (Page is TMDocs)
            {
                RenderFolderTree();
            }

            var help = (HelpCenter)LoadControl(HelpCenter.Location);
            help.IsSideBar = true;
            HelpHolder.Controls.Add(help);
            SupportHolder.Controls.Add(LoadControl(Support.Location));
            UserForumHolder.Controls.Add(LoadControl(UserForum.Location));
            InviteUserHolder.Controls.Add(LoadControl(InviteLink.Location));
        }

        private void RenderFolderTree()
        {
            var tree = (Files.Controls.TreeBuilder)LoadControl(Files.Controls.TreeBuilder.Location);
            tree.FolderIDCurrentRoot = Files.Classes.Global.FolderProjects;
            placeHolderFolderTree.Controls.Add(tree);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Code/FileDAO.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Tenants;

namespace ASC.Web.UserControls.Wiki.Data
{
    class FileDAO : BaseDao
    {
        public FileDAO(string dbid, int tenant)
            : base(dbid, tenant)
        {
        }


        public List<File> GetFiles(IEnumerable<string> names)
        {
            return GetFiles(names == null ? Exp.Empty : Exp.In("filename", names.ToArray()));
        }

        public List<File> FindFiles(string name)
        {
            if (string.IsNullOrEmpty(name)) return new List<File>();

            return GetFiles(Exp.Like("filename", name, SqlLike.StartWith));
        }

        public File SaveFile(File file)
        {
            if (file == null) throw new ArgumentNullException("file");

            var i = Insert("wiki_files")
                .InColumnValue("filename", file.FileName)
                .InColumnValue("uploadfilename", file.UploadFileName)
                .InColumnValue("version", file.Version)
                .InColumnValue("userid", file.UserID.ToString())
                .InColumnValue("date", TenantUtil.DateTimeToUtc(file.Date))
                .InColumnValue("filelocation", file.FileLocation)
                .InColumnValue("filesize", file.FileSize);

            db.ExecuteNonQuery(i);

            return file;
        }

        public void RemoveFile(string fileName)
        {
            var d1 = Delete("wiki_files").Where("filename", fileName);
            var d2 = Delete("wiki_comments").Where("pagename", fileName);

            db.ExecuteBatch(new[] { d1, d2 });
        }


        private List<File> GetFiles(Exp where)
        {
            var q = Query("wiki_files")
                .Select("filename", "uploadfilename", "version", "userid", "date", "filelocation", "filesize")
                .Where(where)
                .OrderBy("filename", true);

            return db
                .ExecuteList(q)
                .ConvertAll(r => ToFile(r))
                .GroupBy(f => f.FileName)
                .Select(g => g.OrderByDescending(f => f.Version).First())
                .ToList();
        }

        private File ToFile(object[] r)
        {
            return new File
            {
                FileName = (string)r[0],
                UploadFileName = (string)r[1],
                Version = Convert.ToInt32(r[2]),
                UserID = new Guid((string)r[3]),
                Date = TenantUtil.DateTimeFromUtc((DateTime)r[4]),
                FileLocation = (string)r[5],
                FileSize = Convert.ToInt32(r[6]),
                Tenant = this.tenant,
            };
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Employee/GroupWrapperSummary.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Core;
using ASC.Core.Users;

namespace ASC.Api.Employee
{
    [DataContract(Name = "group", Namespace = "")]
    public class GroupWrapperSummary
    {
        public GroupWrapperSummary(GroupInfo group)
        {
            Id = group.ID;
            Name = group.Name;
            Manager = CoreContext.UserManager.GetUsers(CoreContext.UserManager.GetDepartmentManager(group.ID)).UserName;
        }

        protected GroupWrapperSummary()
        {
        }


        [DataMember(Order = 2)]
        public string Name { get; set; }

        [DataMember(Order = 1)]
        public Guid Id { get; set; }

        [DataMember(Order = 9, EmitDefaultValue = true)]
        public string Manager { get; set; }

        public static GroupWrapperSummary GetSample()
        {
            return new GroupWrapperSummary { Id = Guid.Empty, Manager = "Jake.Zazhitski", Name = "Group Name" };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/AUTH/Auth_HttpDigest_NonceManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.AUTH
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Timers;

    #endregion

    /// <summary>
    /// HTTP digest authentication nonce manager.
    /// </summary>
    public class Auth_HttpDigest_NonceManager : IDisposable
    {
        #region Nested type: NonceEntry

        /// <summary>
        /// This class represents nonce entry in active nonces collection.
        /// </summary>
        private class NonceEntry
        {
            #region Members

            private readonly DateTime m_CreateTime;
            private readonly string m_Nonce = "";

            #endregion

            #region Properties

            /// <summary>
            /// Gets nonce value.
            /// </summary>
            public string Nonce
            {
                get { return m_Nonce; }
            }

            /// <summary>
            /// Gets time when this nonce entry was created.
            /// </summary>
            public DateTime CreateTime
            {
                get { return m_CreateTime; }
            }

            #endregion

            #region Constructor

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="nonce"></param>
            public NonceEntry(string nonce)
            {
                m_Nonce = nonce;
                m_CreateTime = DateTime.Now;
            }

            #endregion
        }

        #endregion

        #region Members

        private int m_ExpireTime = 30;
        private List<NonceEntry> m_pNonces;
        private Timer m_pTimer;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets nonce expire time in seconds.
        /// </summary>
        public int ExpireTime
        {
            get { return m_ExpireTime; }

            set
            {
                if (value < 5)
                {
                    throw new ArgumentException("Property ExpireTime value must be >= 5 !");
                }

                m_ExpireTime = value;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public Auth_HttpDigest_NonceManager()
        {
            m_pNonces = new List<NonceEntry>();

            m_pTimer = new Timer(15000);
            m_pTimer.Elapsed += m_pTimer_Elapsed;
            m_pTimer.Enabled = true;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up nay resource being used.
        /// </summary>
        public void Dispose()
        {
            if (m_pNonces == null)
            {
                m_pNonces.Clear();
                m_pNonces = null;
            }

            if (m_pTimer != null)
            {
                m_pTimer.Dispose();
                m_pTimer = null;
            }
        }

        /// <summary>
        /// Creates new nonce and adds it to active nonces collection.
        /// </summary>
        /// <returns>Returns new created nonce.</returns>
        public string CreateNonce()
        {
            string nonce = Guid.NewGuid().ToString().Replace("-", "");
            m_pNonces.Add(new NonceEntry(nonce));

            return nonce;
        }

        /// <summary>
        /// Checks if specified nonce exists in active nonces collection.
        /// </summary>
        /// <param name="nonce">Nonce to check.</param>
        /// <returns>Returns true if nonce exists in active nonces collection, otherwise returns false.</returns>
        public bool NonceExists(string nonce)
        {
            lock (m_pNonces)
            {
                foreach (NonceEntry e in m_pNonces)
                {
                    if (e.Nonce == nonce)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Removes specified nonce from active nonces collection.
        /// </summary>
        /// <param name="nonce">Nonce to remove.</param>
        public void RemoveNonce(string nonce)
        {
            lock (m_pNonces)
            {
                for (int i = 0; i < m_pNonces.Count; i++)
                {
                    if (m_pNonces[i].Nonce == nonce)
                    {
                        m_pNonces.RemoveAt(i);
                        i--;
                    }
                }
            }
        }

        #endregion

        #region Event handlers

        private void m_pTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            RemoveExpiredNonces();
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Removes not used nonces what has expired.
        /// </summary>
        private void RemoveExpiredNonces()
        {
            lock (m_pNonces)
            {
                for (int i = 0; i < m_pNonces.Count; i++)
                {
                    // Nonce expired, remove it.
                    if (m_pNonces[i].CreateTime.AddSeconds(m_ExpireTime) > DateTime.Now)
                    {
                        m_pNonces.RemoveAt(i);
                        i--;
                    }
                }
            }
        }

        #endregion
    }
}

<|start_filename|>module/ASC.ElasticSearch/Core/WrapperWithDoc.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

using ASC.Common.Logging;
using ASC.ElasticSearch.Service;

using Nest;

using Newtonsoft.Json;

namespace ASC.ElasticSearch.Core
{
    public abstract class WrapperWithDoc : Wrapper
    {
        public Document Document { get; set; }

        public static readonly long MaxFileSize = Settings.Default.MaxFileSize;

        protected virtual Task<string> GetDocumentDataAsync()
        {
            return Task.FromResult(GetDocumentData());
        }

        protected virtual string GetDocumentData()
        {
            return "";
        }

        protected abstract Stream GetDocumentStream();
        protected abstract Task<Stream> GetDocumentStreamAsync();

        [Ignore, JsonIgnore]
        public abstract string SettingsTitle { get; }

        internal void InitDocument(bool index)
        {
            Document = new Document
            {
                Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(""))
            };

            try
            {
                if (!index) return;

                var data = GetDocumentData();

                if (!string.IsNullOrEmpty(data))
                {
                    Document.Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(data));
                    return;
                }

                using (var stream = GetDocumentStream())
                {
                    if (stream == null) return;

                    using (var ms = new MemoryStream())
                    {
                        stream.CopyTo(ms);
                        Document.Data = Convert.ToBase64String(ms.GetBuffer());
                    }
                }
            }
            catch (FileNotFoundException e)
            {
                LogManager.GetLogger("ASC.Indexer").Error("InitDocument FileNotFoundException", e);
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC.Indexer").Error("InitDocument", e);
            }
        }

        internal async Task InitDocumentAsync(bool index)
        {
            Document = new Document
            {
                Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(""))
            };

            try
            {
                if (!index) return;

                var data = await GetDocumentDataAsync().ConfigureAwait(false);

                if (!string.IsNullOrEmpty(data))
                {
                    Document.Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(data));
                    return;
                }

                using (var stream = await GetDocumentStreamAsync().ConfigureAwait(false))
                {
                    if (stream == null) return;

                    using (var ms = new MemoryStream())
                    {
                        stream.CopyTo(ms);
                        Document.Data = Convert.ToBase64String(ms.GetBuffer());
                    }
                }
            }
            catch (FileNotFoundException e)
            {
                LogManager.GetLogger("ASC.Indexer").Error("InitDocument FileNotFoundException", e);
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC.Indexer").Error("InitDocument", e);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Users/UserProfile/LoadPhotoControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Core.Users;
using ASC.Web.Core.Users;

namespace ASC.Web.Studio.UserControls.Users.UserProfile
{
    public partial class LoadPhotoControl : UserControl
    {
        public UserInfo User { get; set; }

        protected bool HasAvatar { get; set; }
        protected string MainImgUrl { get; set; }
        protected UserPhotoThumbnailSettings ThumbnailSettings { get; set; }

        protected bool IsLdap { get; set; }

        public static string Location
        {
            get { return "~/UserControls/Users/UserProfile/LoadPhotoControl.ascx"; }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            var defuaultPhoto = UserPhotoManager.GetDefaultPhotoAbsoluteWebPath();

            if (User == null)
            {
                MainImgUrl = defuaultPhoto;
                ThumbnailSettings = UserPhotoThumbnailSettings.LoadForDefaultTenant();
            }
            else
            {
                IsLdap = User.IsLDAP();
                HasAvatar = User.HasAvatar();
                MainImgUrl = UserPhotoManager.GetPhotoAbsoluteWebPath(User.ID);
                ThumbnailSettings = UserPhotoThumbnailSettings.LoadForUser(User.ID);
            }

            Page.RegisterStyle("~/UserControls/Users/UserProfile/css/loadphoto_style.less",
                               "~/UserControls/Users/UserProfile/css/jquery.jcrop.less")
                .RegisterBodyScripts("~/js/uploader/ajaxupload.js",
                                    "~/UserControls/Users/UserProfile/js/loadphoto.js",
                                     "~/UserControls/Users/UserProfile/js/jquery.jcrop.js");

            var script =
                string.Format(
                    "window.ASC.Controls.LoadPhotoImage.init('{0}',[{1},{2}],{{point:{{x:{3},y:{4}}},size:{{width:{5},height:{6}}}}},'{7}', '{8}');",
                    User == null ? "" : User.ID.ToString(),
                    UserPhotoManager.SmallFotoSize.Width,
                    UserPhotoManager.SmallFotoSize.Height,
                    ThumbnailSettings.Point.X,
                    ThumbnailSettings.Point.Y,
                    ThumbnailSettings.Size.Width,
                    ThumbnailSettings.Size.Height,
                    HasAvatar ? MainImgUrl : "",
                    defuaultPhoto);

            Page.RegisterInlineScript(script);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Settings/VoipSettings/VoipQuick.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Web;

using ASC.CRM.Core;
using ASC.VoipService;
using ASC.Web.Core.Files;
using ASC.Web.Core.Utility;
using ASC.Web.Studio;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

using Global = ASC.Web.CRM.Classes.Global;

namespace ASC.Web.CRM.Controls.Settings
{
    public class VoipUploadHandler : IFileUploadHandler
    {
        private const long maxFileSize = 5;

        public FileUploadResult ProcessUpload(HttpContext context)
        {
            if (!VoipNumberData.Allowed || !CRMSecurity.IsAdmin)
                throw CRMSecurity.CreateSecurityException();

            if (context.Request.Files.Count == 0)
            {
                return Error("No files.");
            }

            var file = context.Request.Files[0];

            if (file.ContentLength <= 0 || file.ContentLength > maxFileSize * 1024L * 1024L)
            {
                return Error(Resource.FileSizeMaxExceed);
            }

            try
            {
                var path = file.FileName;

                AudioType audioType;
                if (Enum.TryParse(context.Request["audioType"], true, out audioType))
                {
                    path = Path.Combine(audioType.ToString().ToLower(), path);
                }

                var uri = Global.GetStore().Save("voip", path, file.InputStream, MimeMapping.GetMimeMapping(file.FileName), ContentDispositionUtil.GetHeaderValue(file.FileName, withoutBase: true));
                return Success(new VoipUpload
                {
                    AudioType = audioType,
                    Name = file.FileName,
                    Path = CommonLinkUtility.GetFullAbsolutePath(uri.ToString())
                });
            }
            catch (Exception error)
            {
                return Error(error.Message);
            }
        }

        private static FileUploadResult Success(VoipUpload file)
        {
            return new FileUploadResult
            {
                Success = true,
                Data = file
            };
        }

        private static FileUploadResult Error(string messageFormat, params object[] args)
        {
            return new FileUploadResult
            {
                Success = false,
                Message = string.Format(messageFormat, args)
            };
        }
    }

    public partial class VoipQuick : BaseUserControl
    {
        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Settings/VoIPSettings/VoipQuick.ascx"); }
        }


        protected void Page_Load(object sender, EventArgs e)
        {
            if (!VoipNumberData.Allowed || !CRMSecurity.IsAdmin)
            {
                Response.Redirect(PathProvider.StartURL() + "Settings.aspx?type=voip.common");
            }

            buyNumberContainer.Options.IsPopup = true;
            linkNumberContainer.Options.IsPopup = true;
            deleteNumberContainer.Options.IsPopup = true;
            Page.RegisterBodyScripts("~/js/asc/core/voip.countries.js");
            Page.RegisterBodyScripts(PathProvider.GetFileStaticRelativePath("voip.quick.js"));
        }
    }
}

<|start_filename|>common/ASC.ActiveDirectory/Base/Settings/LdapSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Core;
using ASC.Core.Common.Settings;
using ASC.Web.Core;

namespace ASC.ActiveDirectory.Base.Settings
{
    [Serializable]
    [DataContract]
    public class LdapSettings : BaseSettings<LdapSettings>, ICloneable
    {
        public override Guid ID
        {
            get { return new Guid("{197149b3-fbc9-44c2-b42a-232f7e729c16}"); }
        }

        public LdapSettings()
        {
            LdapMapping = new Dictionary<MappingFields, string>();
            AccessRights = new Dictionary<AccessRight, string>();
        }

        public enum MappingFields
        {
            FirstNameAttribute,
            SecondNameAttribute,
            BirthDayAttribute,
            GenderAttribute,
            MobilePhoneAttribute,
            MailAttribute,
            TitleAttribute,
            LocationAttribute,
            AvatarAttribute,

            AdditionalPhone,
            AdditionalMobilePhone,
            AdditionalMail,
            Skype
        }

        public enum AccessRight
        {
            FullAccess,
            Documents,
            Projects,
            CRM,
            Community,
            People,
            Mail
        }

        public static readonly Dictionary<AccessRight, Guid> AccessRightsGuids = new Dictionary<AccessRight, Guid>()
        {
            { AccessRight.FullAccess, Guid.Empty },
            { AccessRight.Documents, WebItemManager.DocumentsProductID },
            { AccessRight.Projects, WebItemManager.ProjectsProductID },
            { AccessRight.CRM, WebItemManager.CRMProductID },
            { AccessRight.Community, WebItemManager.CommunityProductID },
            { AccessRight.People, WebItemManager.PeopleProductID },
            { AccessRight.Mail, WebItemManager.MailProductID }
        };

        public override ISettings GetDefault()
        {
            var isMono = WorkContext.IsMono;

            var settings = new LdapSettings
            {
                Server = "",
                UserDN = "",
                PortNumber = LdapConstants.STANDART_LDAP_PORT,
                UserFilter = string.Format("({0}=*)",
                    isMono
                        ? LdapConstants.RfcLDAPAttributes.UID
                        : LdapConstants.ADSchemaAttributes.USER_PRINCIPAL_NAME),
                LoginAttribute = isMono
                    ? LdapConstants.RfcLDAPAttributes.UID
                    : LdapConstants.ADSchemaAttributes.ACCOUNT_NAME,
                FirstNameAttribute = LdapConstants.ADSchemaAttributes.FIRST_NAME,
                SecondNameAttribute = LdapConstants.ADSchemaAttributes.SURNAME,
                MailAttribute = LdapConstants.ADSchemaAttributes.MAIL,
                TitleAttribute = LdapConstants.ADSchemaAttributes.TITLE,
                MobilePhoneAttribute = LdapConstants.ADSchemaAttributes.MOBILE,
                LocationAttribute = LdapConstants.ADSchemaAttributes.STREET,
                GroupDN = "",
                GroupFilter = string.Format("({0}={1})", LdapConstants.ADSchemaAttributes.OBJECT_CLASS,
                    isMono
                        ? LdapConstants.ObjectClassKnowedValues.POSIX_GROUP
                        : LdapConstants.ObjectClassKnowedValues.GROUP),
                UserAttribute =
                    isMono
                        ? LdapConstants.RfcLDAPAttributes.UID
                        : LdapConstants.ADSchemaAttributes.DISTINGUISHED_NAME,
                GroupAttribute = isMono ? LdapConstants.RfcLDAPAttributes.MEMBER_UID : LdapConstants.ADSchemaAttributes.MEMBER,
                GroupNameAttribute = LdapConstants.ADSchemaAttributes.COMMON_NAME,
                Authentication = true,
                AcceptCertificate = false,
                AcceptCertificateHash = null,
                StartTls = false,
                Ssl = false,
                SendWelcomeEmail = false
            };

            return settings;
        }

        public static List<MappingFields> GetImportedFields { get { return Load().LdapMapping.Keys.ToList(); } }

        public override bool Equals(object obj)
        {
            var settings = obj as LdapSettings;

            return settings != null
                   && EnableLdapAuthentication == settings.EnableLdapAuthentication
                   && StartTls == settings.StartTls
                   && Ssl == settings.Ssl
                   && SendWelcomeEmail == settings.SendWelcomeEmail
                   && (string.IsNullOrEmpty(Server)
                       && string.IsNullOrEmpty(settings.Server)
                       || Server == settings.Server)
                   && (string.IsNullOrEmpty(UserDN)
                       && string.IsNullOrEmpty(settings.UserDN)
                       || UserDN == settings.UserDN)
                   && PortNumber == settings.PortNumber
                   && UserFilter == settings.UserFilter
                   && LoginAttribute == settings.LoginAttribute
                   && LdapMapping.Count == settings.LdapMapping.Count
                   && LdapMapping.All(pair => settings.LdapMapping.ContainsKey(pair.Key)
                       && pair.Value == settings.LdapMapping[pair.Key])
                   && AccessRights.Count == settings.AccessRights.Count
                   && AccessRights.All(pair => settings.AccessRights.ContainsKey(pair.Key)
                       && pair.Value == settings.AccessRights[pair.Key])
                   && GroupMembership == settings.GroupMembership
                   && (string.IsNullOrEmpty(GroupDN)
                       && string.IsNullOrEmpty(settings.GroupDN)
                       || GroupDN == settings.GroupDN)
                   && GroupFilter == settings.GroupFilter
                   && UserAttribute == settings.UserAttribute
                   && GroupAttribute == settings.GroupAttribute
                   && (string.IsNullOrEmpty(Login)
                       && string.IsNullOrEmpty(settings.Login)
                       || Login == settings.Login)
                   && Authentication == settings.Authentication;
        }

        public override int GetHashCode()
        {
            var hash = 3;
            hash = (hash * 2) + EnableLdapAuthentication.GetHashCode();
            hash = (hash * 2) + StartTls.GetHashCode();
            hash = (hash * 2) + Ssl.GetHashCode();
            hash = (hash * 2) + SendWelcomeEmail.GetHashCode();
            hash = (hash * 2) + Server.GetHashCode();
            hash = (hash * 2) + UserDN.GetHashCode();
            hash = (hash * 2) + PortNumber.GetHashCode();
            hash = (hash * 2) + UserFilter.GetHashCode();
            hash = (hash * 2) + LoginAttribute.GetHashCode();
            hash = (hash * 2) + GroupMembership.GetHashCode();
            hash = (hash * 2) + GroupDN.GetHashCode();
            hash = (hash * 2) + GroupNameAttribute.GetHashCode();
            hash = (hash * 2) + GroupFilter.GetHashCode();
            hash = (hash * 2) + UserAttribute.GetHashCode();
            hash = (hash * 2) + GroupAttribute.GetHashCode();
            hash = (hash * 2) + Authentication.GetHashCode();
            hash = (hash * 2) + Login.GetHashCode();

            foreach (var pair in LdapMapping)
                hash = (hash * 2) + pair.Value.GetHashCode();

            foreach (var pair in AccessRights)
                hash = (hash * 2) + pair.Value.GetHashCode();

            return hash;
        }

        public object Clone()
        {
            return MemberwiseClone();
        }

        [DataMember]
        public bool EnableLdapAuthentication { get; set; }

        [DataMember]
        public bool StartTls { get; set; }

        [DataMember]
        public bool Ssl { get; set; }

        [DataMember]
        public bool SendWelcomeEmail { get; set; }

        [DataMember]
        public string Server { get; set; }

        [DataMember]
        // ReSharper disable once InconsistentNaming
        public string UserDN { get; set; }

        [DataMember]
        public int PortNumber { get; set; }

        [DataMember]
        public string UserFilter { get; set; }

        [DataMember]
        public string LoginAttribute { get; set; }

        [DataMember]
        public Dictionary<MappingFields, string> LdapMapping { get; set; }

        //ToDo: use SId instead of group name
        [DataMember]
        public Dictionary<AccessRight, string> AccessRights { get; set; }

        [DataMember]
        public string FirstNameAttribute
        {
            get
            {
                return GetOldSetting(MappingFields.FirstNameAttribute);
            }

            set
            {
                SetOldSetting(MappingFields.FirstNameAttribute, value);
            }
        }

        [DataMember]
        public string SecondNameAttribute
        {
            get
            {
                return GetOldSetting(MappingFields.SecondNameAttribute);
            }

            set
            {
                SetOldSetting(MappingFields.SecondNameAttribute, value);
            }
        }

        [DataMember]
        public string MailAttribute
        {
            get
            {
                return GetOldSetting(MappingFields.MailAttribute);
            }

            set
            {
                SetOldSetting(MappingFields.MailAttribute, value);
            }
        }

        [DataMember]
        public string TitleAttribute
        {
            get
            {
                return GetOldSetting(MappingFields.TitleAttribute);
            }

            set
            {
                SetOldSetting(MappingFields.TitleAttribute, value);
            }
        }

        [DataMember]
        public string MobilePhoneAttribute
        {
            get
            {
                return GetOldSetting(MappingFields.MobilePhoneAttribute);
            }

            set
            {
                SetOldSetting(MappingFields.MobilePhoneAttribute, value);
            }
        }

        [DataMember]
        public string LocationAttribute
        {
            get
            {
                return GetOldSetting(MappingFields.LocationAttribute);
            }

            set
            {
                SetOldSetting(MappingFields.LocationAttribute, value);
            }
        }

        [DataMember]
        public bool GroupMembership { get; set; }

        [DataMember]
        // ReSharper disable once InconsistentNaming
        public string GroupDN { get; set; }

        [DataMember]
        public string GroupNameAttribute { get; set; }

        [DataMember]
        public string GroupFilter { get; set; }

        [DataMember]
        public string UserAttribute { get; set; }

        [DataMember]
        public string GroupAttribute { get; set; }

        [DataMember]
        public bool Authentication { get; set; }

        [DataMember]
        public string Login { get; set; }

        [DataMember]
        public string Password { get; set; }

        [DataMember]
        public byte[] PasswordBytes { get; set; }

        [DataMember]
        public bool IsDefault { get; set; }

        [DataMember]
        public bool AcceptCertificate { get; set; }

        [DataMember]
        public string AcceptCertificateHash { get; set; }

        private string GetOldSetting(MappingFields field)
        {
            if (LdapMapping == null)
                LdapMapping = new Dictionary<MappingFields, string>();

            if (LdapMapping.ContainsKey(field))
                return LdapMapping[field];
            else
                return "";
        }
        private void SetOldSetting(MappingFields field, string value)
        {
            if (LdapMapping == null)
                LdapMapping = new Dictionary<MappingFields, string>();

            if (string.IsNullOrEmpty(value))
            {
                if (LdapMapping.ContainsKey(field))
                {
                    LdapMapping.Remove(field);
                }
                return;
            }

            if (LdapMapping.ContainsKey(field))
            {
                LdapMapping[field] = value;
            }
            else
            {
                LdapMapping.Add(field, value);
            }
        }
    }

    [Serializable]
    [DataContract]
    public class LdapCronSettings : BaseSettings<LdapCronSettings>
    {
        public override Guid ID
        {
            get { return new Guid("{58C42C54-56CD-4BEF-A3ED-C60ACCF6E975}"); }
        }

        public override ISettings GetDefault()
        {
            return new LdapCronSettings()
            {
                Cron = null
            };
        }

        [DataMember]
        public string Cron { get; set; }
    }

    [Serializable]
    [DataContract]
    public class LdapCurrentAcccessSettings : BaseSettings<LdapCurrentAcccessSettings>
    {
        public override Guid ID
        {
            get { return new Guid("{134B5EAA-F612-4834-AEAB-34C90515EA4E}"); }
        }

        public override ISettings GetDefault()
        {
            return new LdapCurrentAcccessSettings() { CurrentAccessRights = null };
        }

        public LdapCurrentAcccessSettings()
        {
            CurrentAccessRights = new Dictionary<LdapSettings.AccessRight, List<string>>();
        }

        [DataMember]
        public Dictionary<LdapSettings.AccessRight, List<string>> CurrentAccessRights { get; set; }
    }

    [Serializable]
    [DataContract]
    public class LdapCurrentUserPhotos : BaseSettings<LdapCurrentUserPhotos>
    {
        public override Guid ID
        {
            get { return new Guid("{50AE3C2B-0783-480F-AF30-679D0F0A2D3E}"); }
        }

        public override ISettings GetDefault()
        {
            return new LdapCurrentUserPhotos() { CurrentPhotos = null };
        }

        public LdapCurrentUserPhotos()
        {
            CurrentPhotos = new Dictionary<Guid, string>();
        }

        [DataMember]
        public Dictionary<Guid, string> CurrentPhotos { get; set; }
    }

    [Serializable]
    [DataContract]
    public class LdapCurrentDomain : BaseSettings<LdapCurrentDomain>
    {
        public override Guid ID
        {
            get { return new Guid("{75A5F745-F697-4418-B38D-0FE0D277E258}"); }
        }

        public override ISettings GetDefault()
        {
            return new LdapCurrentDomain() { CurrentDomain = null };
        }

        [DataMember]
        public string CurrentDomain { get; set; }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/PromoCode/PromoCode.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Web.Studio.PublicResources;


namespace ASC.Web.Studio.UserControls.Management
{
    [AjaxNamespace("PromoCodeController")]
    public partial class PromoCode : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/PromoCode/PromoCode.ascx"; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            AjaxPro.Utility.RegisterTypeForAjax(GetType());
            Page.RegisterBodyScripts("~/UserControls/Management/PromoCode/promocode.js");
        }

        [AjaxMethod]
        public object ActivateKey(string promocode)
        {
            if (!string.IsNullOrEmpty(promocode))
            {
                try
                {
                    CoreContext.PaymentManager.ActivateKey(promocode);
                    return new { Status = 1, Message = Resource.SuccessfullySaveSettingsMessage };
                }
                catch (Exception err)
                {
                    LogManager.GetLogger("ASC.Web.FirstTime").Error(err);
                }
            }
            return new { Status = 0, Message = Resource.EmailAndPasswordIncorrectPromocode };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Users/TipsSettings/js/tipssettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.TipsSettings = new function() {
    var $ = jq;
    
    var $tipsSettingsBox = $('#tips-settings-box');

    var $toggleTipsSettingsContentBtn = $tipsSettingsBox.find('.toggle-button');
    var $tipsSettingsContent = $tipsSettingsBox.find('.tabs-content');
    var $updateTipsSettingsBtn = $tipsSettingsBox.find('.on_off_button');

    function init() {
        bindEvents();
    }
    
    function bindEvents() {
        $toggleTipsSettingsContentBtn.on('click', toogleTipsSettingsContent);
        $updateTipsSettingsBtn.on('click', updateTipsSettings);
    }

    function toogleTipsSettingsContent() {
        if ($tipsSettingsContent.is(':visible')) {
            $toggleTipsSettingsContentBtn.text($toggleTipsSettingsContentBtn.attr('data-showtext'));
            $tipsSettingsContent.hide();
        } else {
            $toggleTipsSettingsContentBtn.text($toggleTipsSettingsContentBtn.attr('data-hidetext'));
            $tipsSettingsContent.show();
        }
    }

    function updateTipsSettings() {
        var show = $updateTipsSettingsBtn.is('.off');
        Teamlab.updateTipsSettings({ show: show }, {
            success: function() {
                $updateTipsSettingsBtn.removeClass('on off').addClass(show ? 'on' : 'off');
                if (show && window.sessionStorage) {
                    window.sessionStorage.removeItem("tipsWasClosed");
                }
            },
            error: function() {
                toastr.error(ASC.Resources.Master.ResourceJS.CommonJSErrorMsg);
            }
        });
    }

    return {
        init: init
    };
};

jq(function() {
    window.TipsSettings.init();
});

<|start_filename|>module/ASC.Mail/ASC.Mail/Extensions/ServerDomainDnsExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Common.Utils;
using ASC.Mail.Core;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;

namespace ASC.Mail.Extensions
{
    public static class ServerDomainDnsExtensions
    {
        public static bool CheckDnsStatus(this ServerDomainDnsData dnsData, string domain)
        {
            if (string.IsNullOrEmpty(domain))
                return false;

            var dnsLookup = new DnsLookup();

            var mxVerified = dnsLookup.IsDomainMxRecordExists(domain, dnsData.MxRecord.Host);

            dnsData.MxRecord.IsVerified = mxVerified;

            var spfVerified = dnsLookup.IsDomainTxtRecordExists(domain, dnsData.SpfRecord.Value);

            dnsData.SpfRecord.IsVerified = spfVerified;

            var dkimVerified = dnsLookup.IsDomainDkimRecordExists(domain, dnsData.DkimRecord.Selector,
                dnsData.DkimRecord.PublicKey);

            dnsData.DkimRecord.IsVerified = dkimVerified;

            return mxVerified && spfVerified && dkimVerified;
        }

        public static bool UpdateMx(this ServerDns dns, string domain)
        {
            var utcNow = DateTime.UtcNow;
            var hasChanges = false;

            var dnsLookup = new DnsLookup();

            if (dns.MxDateChecked.HasValue && dns.MxDateChecked.Value.AddSeconds(dns.MxTtl) >= utcNow)
                return hasChanges;

            var mxRecord =
                dnsLookup
                    .GetDomainMxRecords(domain)
                    .FirstOrDefault(mx => mx.ExchangeDomainName.ToString().TrimEnd('.').Equals(dns.Mx));

            dns.MxVerified = mxRecord != null;
            dns.MxTtl = mxRecord != null ? mxRecord.TimeToLive : Defines.ServerDnsDefaultTtl;
            dns.MxDateChecked = utcNow;

            hasChanges = true;

            return hasChanges;
        }

        public static bool UpdateSpf(this ServerDns dns, string domain)
        {
            var utcNow = DateTime.UtcNow;

            var dnsLookup = new DnsLookup();

            if (dns.SpfDateChecked.HasValue && dns.SpfDateChecked.Value.AddSeconds(dns.SpfTtl) >= utcNow)
                return false;

            var txtRecords = dnsLookup
                .GetDomainTxtRecords(domain);

            var spfRecord = txtRecords.FirstOrDefault(
                txt => txt.TextData.Trim('\"')
                    .Equals(dns.Spf, StringComparison.InvariantCultureIgnoreCase));

            dns.SpfVerified = spfRecord != null;
            dns.SpfTtl = spfRecord != null ? spfRecord.TimeToLive : Defines.ServerDnsDefaultTtl;
            dns.SpfDateChecked = utcNow;

            return true;
        }

        public static bool UpdateDkim(this ServerDns dns, string domain)
        {
            var utcNow = DateTime.UtcNow;

            var dnsLookup = new DnsLookup();

            if (dns.DkimDateChecked.HasValue && dns.DkimDateChecked.Value.AddSeconds(dns.DkimTtl) >= utcNow)
                return false;

            var dkimRecordName = string.Format("{0}._domainkey.{1}", dns.DkimSelector, domain);

            var dkimRecord = dnsLookup
                .GetDomainTxtRecords(dkimRecordName).FirstOrDefault(
                    txt => txt.TextData.Trim('\"')
                        .Equals(dns.DkimPublicKey, StringComparison.InvariantCultureIgnoreCase));

            dns.DkimVerified = dkimRecord != null;
            dns.DkimTtl = dkimRecord != null ? dkimRecord.TimeToLive : Defines.ServerDnsDefaultTtl;
            dns.DkimDateChecked = utcNow;

            return true;
        }

        public static bool UpdateRecords(this ServerDns dns, string domain, bool force = false)
        {
            if (string.IsNullOrEmpty(domain) || dns == null)
                return false;

            var utcNow = DateTime.UtcNow;

            var hasChanges = false;

            if (force)
            {
                if (dns.UpdateMx(domain))
                {
                    hasChanges = true;
                }

                if (dns.UpdateSpf(domain))
                {
                    hasChanges = true;
                }

                if (dns.UpdateDkim(domain))
                {
                    hasChanges = true;
                }
            }
            else
            {
                if (dns.MxDateChecked.HasValue && dns.MxDateChecked.Value.AddSeconds(dns.MxTtl) >= utcNow &&
                    dns.SpfDateChecked.HasValue && dns.SpfDateChecked.Value.AddSeconds(dns.SpfTtl) >= utcNow &&
                    dns.DkimDateChecked.HasValue && dns.DkimDateChecked.Value.AddSeconds(dns.DkimTtl) >= utcNow)
                    return hasChanges;

                var engineFactory = new EngineFactory(dns.Tenant, dns.User);
                engineFactory.OperationEngine.CheckDomainDns(domain, dns);
            }

            return hasChanges;
        }
    }
}


<|start_filename|>common/ASC.Common/Data/StreamExtension.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;

public static class StreamExtension
{
    private const int BufferSize = 2048; //NOTE: set to 2048 to fit in minimum tcp window

    public static void StreamCopyTo(this Stream srcStream, Stream dstStream, int length)
    {
        if (srcStream == null) throw new ArgumentNullException("srcStream");
        if (dstStream == null) throw new ArgumentNullException("dstStream");

        var buffer = new byte[BufferSize];
        int totalRead = 0;
        int readed;
        while ((readed = srcStream.Read(buffer, 0, length - totalRead > BufferSize ? BufferSize : length - totalRead)) > 0 && totalRead < length)
        {
            dstStream.Write(buffer, 0, readed);
            totalRead += readed;
        }
    }
}


<|start_filename|>module/ASC.AuditTrail/Mappers/SettingsActionMapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.MessagingSystem;

namespace ASC.AuditTrail.Mappers
{
    internal class SettingsActionsMapper
    {
        public static Dictionary<MessageAction, MessageMaps> GetMaps()
        {
            return new Dictionary<MessageAction, MessageMaps>
                {
                    {
                        MessageAction.LanguageSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "LanguageSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.TimeZoneSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TimeZoneSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.DnsSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "DnsSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.TrustedMailDomainSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TrustedMailDomainSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.PasswordStrengthSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PasswordStrengthSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.TwoFactorAuthenticationSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TwoFactorAuthenticationSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.TwoFactorAuthenticationDisabled, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TwoFactorAuthenticationSettingsDisabled",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                                        {
                        MessageAction.TwoFactorAuthenticationEnabledBySms, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TwoFactorAuthenticationSettingsEnabledBySms",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                                        {
                        MessageAction.TwoFactorAuthenticationEnabledByTfaApp, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TwoFactorAuthenticationSettingsEnabledByTfaApp",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.AdministratorMessageSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "AdministratorMessageSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.DefaultStartPageSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "DefaultStartPageSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "GeneralModule"
                            }
                    },
                    {
                        MessageAction.ProductsListUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ProductsListUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.OwnerUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "OwnerChanged",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.AdministratorAdded, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "AdministratorAdded",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.UsersOpenedProductAccess, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "ProductAccessOpenedForUsers",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.GroupsOpenedProductAccess, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "ProductAccessOpenedForGroups",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.ProductAccessOpened, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "ProductAccessOpened",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.ProductAccessRestricted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "ProductAccessRestricted",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.ProductAddedAdministrator, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ProductAddedAdministrator",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.ProductDeletedAdministrator, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ProductDeletedAdministrator",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.AdministratorDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "AdministratorDeleted",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.AdministratorOpenedFullAccess, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "AdministratorOpenedFullAccess",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.GreetingSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "GreetingSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.TeamTemplateChanged, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TeamTemplateChanged",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.ColorThemeChanged, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ColorThemeChanged",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.OwnerSentPortalDeactivationInstructions, new MessageMaps
                            {
                                ActionTypeTextResourceName = "SendActionType",
                                ActionTextResourceName = "OwnerSentPortalDeactivationInstructions",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.OwnerSentPortalDeleteInstructions, new MessageMaps
                            {
                                ActionTypeTextResourceName = "SendActionType",
                                ActionTextResourceName = "OwnerSentPortalDeleteInstructions",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.LoginHistoryReportDownloaded, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DownloadActionType",
                                ActionTextResourceName = "LoginHistoryReportDownloaded",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.AuditTrailReportDownloaded, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DownloadActionType",
                                ActionTextResourceName = "AuditTrailReportDownloaded",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.PortalDeactivated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PortalDeactivated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.PortalDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "PortalDeleted",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.OwnerSentChangeOwnerInstructions, new MessageMaps
                            {
                                ActionTypeTextResourceName = "SendActionType",
                                ActionTextResourceName = "OwnerSentChangeOwnerInstructions",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.SSOEnabled, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "SSOEnabled",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.SSODisabled, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "SSODisabled",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.PortalAccessSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PortalAccessSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.DocumentServiceLocationSetting, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "DocumentServiceLocationSetting",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.AuthorizationKeysSetting, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "AuthorizationKeysSetting",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.FullTextSearchSetting, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "FullTextSearchSetting",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.StartTransferSetting, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "StartTransferSetting",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.StartBackupSetting, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "StartBackupSetting",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.LicenseKeyUploaded, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "LicenseKeyUploaded",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.StartStorageEncryption, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "StartStorageEncryption",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.StartStorageDecryption, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "StartStorageDecryption",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.CookieSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CookieSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.MailServiceSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "MailServiceSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.CustomNavigationSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "CustomNavigationSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.AuditSettingsUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "AuditSettingsUpdated",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.PrivacyRoomEnable, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PrivacyRoomEnable",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    },
                    {
                        MessageAction.PrivacyRoomDisable, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "PrivacyRoomDisable",
                                ProductResourceName = "SettingsProduct",
                                ModuleResourceName = "ProductsModule"
                            }
                    }
                };
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Iterators/MailboxIterator.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Logging;
using ASC.Mail.Core;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Core.Engine;
using ASC.Mail.Data.Contracts;

namespace ASC.Mail.Iterators
{
    /// <summary>
    /// The 'ConcreteIterator' class
    /// </summary>
    public class MailboxIterator : IMailboxIterator
    {
        private int Tenant { get; set; }
        private string UserId { get; set; }
        public bool? IsRemoved { get; private set; }
        public ILog Log { get; set; }

        public int MinMailboxId { get; private set; }
        public int MaxMailboxId { get; private set; }

        private MailboxEngine MailboxEngine { get; set; }

        // Constructor
        public MailboxIterator(int tenant = -1, string userId = null, bool? isRemoved = false, ILog log = null)
        {
            if (!string.IsNullOrEmpty(userId) && tenant < 0)
                throw new ArgumentException("Tenant must be initialized if user not empty");

            var engine = new EngineFactory(tenant, userId, log);

            MailboxEngine = engine.MailboxEngine;

            Tenant = tenant;
            UserId = userId;
            IsRemoved = isRemoved;

            Log = log ?? new NullLog();

            var result = MailboxEngine.GetRangeMailboxes(GetMailboxExp(Tenant, UserId, IsRemoved));

            if (result == null)
                return;

            MinMailboxId = result.Item1;
            MaxMailboxId = result.Item2;

            Current = null;
        }

        // Gets first item
        public MailBoxData First()
        {
            if (MinMailboxId == 0 && MinMailboxId == MaxMailboxId)
            {
                return null;
            }

            var exp = GetMailboxExp(MinMailboxId, Tenant, UserId, IsRemoved);
            var mailbox = MailboxEngine.GetMailboxData(exp);

            Current = mailbox == null && MinMailboxId < MaxMailboxId
                ? GetNextMailbox(MinMailboxId)
                : mailbox;

            return Current;
        }

        // Gets next item
        public MailBoxData Next()
        {
            if (IsDone)
                return null;

            Current = GetNextMailbox(Current.MailBoxId);

            return Current;
        }

        // Gets current iterator item
        public MailBoxData Current { get; private set; }

        // Gets whether iteration is complete
        public bool IsDone
        {
            get
            {
                return MinMailboxId == 0
                       || MinMailboxId > MaxMailboxId
                       || Current == null;
            }
        }

        private MailBoxData GetNextMailbox(int id)
        {
            do
            {
                if (id < MinMailboxId || id >= MaxMailboxId)
                    return null;

                MailBoxData mailbox;

                var exp = GetNextMailboxExp(id, Tenant, UserId, IsRemoved);

                int failedId;

                if (!MailboxEngine.TryGetNextMailboxData(exp, out mailbox, out failedId))
                {
                    if (failedId > 0)
                    {
                        id = failedId;

                        Log.ErrorFormat("MailboxEngine.GetNextMailboxData(Mailbox id = {0}) failed. Skip it.", id);

                        id++;
                    }
                    else
                    {
                        Log.ErrorFormat("MailboxEngine.GetNextMailboxData(Mailbox id = {0}) failed. End seek next.", id);
                        return null;
                    }
                }
                else
                {
                    return mailbox;
                }

            } while (id <= MaxMailboxId);

            return null;
        }

        private static IMailboxExp GetMailboxExp(int tenant = -1, string user = null, bool? isRemoved = false)
        {
            IMailboxExp mailboxExp;

            if (!string.IsNullOrEmpty(user) && tenant > -1)
            {
                mailboxExp = new UserMailboxExp(tenant, user, isRemoved);
            }
            else if (tenant > -1)
            {
                mailboxExp = new TenantMailboxExp(tenant, isRemoved);
            }
            else if (!string.IsNullOrEmpty(user))
            {
                throw new ArgumentException("Tenant must be initialized if user not empty");
            }
            else
            {
                mailboxExp = new SimpleMailboxExp(isRemoved);
            }

            return mailboxExp;
        }

        private static IMailboxExp GetMailboxExp(int id, int tenant, string user = null, bool? isRemoved = false)
        {
            IMailboxExp mailboxExp;

            if (!string.IsNullOrEmpty(user) && tenant > -1)
            {
                mailboxExp = new СoncreteUserMailboxExp(id, tenant, user, isRemoved);
            }
            else if (tenant > -1)
            {
                mailboxExp = new ConcreteTenantMailboxExp(id, tenant, isRemoved);
            }
            else if (!string.IsNullOrEmpty(user))
            {
                throw new ArgumentException("Tenant must be initialized if user not empty");
            }
            else
            {
                mailboxExp = new ConcreteSimpleMailboxExp(id, isRemoved);
            }

            return mailboxExp;
        }

        private static IMailboxExp GetNextMailboxExp(int id, int tenant, string user = null, bool? isRemoved = false)
        {
            IMailboxExp mailboxExp;

            if (!string.IsNullOrEmpty(user) && tenant > -1)
            {
                mailboxExp = new СoncreteUserNextMailboxExp(id, tenant, user, isRemoved);
            }
            else if (tenant > -1)
            {
                mailboxExp = new ConcreteTenantNextMailboxExp(id, tenant, isRemoved);
            }
            else if (!string.IsNullOrEmpty(user))
            {
                throw new ArgumentException("Tenant must be initialized if user not empty");
            }
            else
            {
                mailboxExp = new ConcreteSimpleNextMailboxExp(id, isRemoved);
            }

            return mailboxExp;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/InviteLink/InviteLink.ascx.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;


namespace ASC.Web.Studio.UserControls.Common.InviteLink
{
    public partial class InviteLink : System.Web.UI.UserControl
    {
        protected string LinkText;
        protected bool EnableAddUsers;
        protected bool EnableAddVisitors;

        public static string Location
        {
            get { return "~/UserControls/Common/InviteLink/InviteLink.ascx"; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            LinkText = CustomNamingPeople.Substitute<Resource>("InviteUsersToPortalLink").HtmlEncode();
            if (CoreContext.Configuration.Personal)
            {
                EnableAddUsers = true;
                EnableAddVisitors = true;
            }
            else
            {
                EnableAddUsers = TenantStatisticsProvider.GetUsersCount() < TenantExtra.GetTenantQuota().ActiveUsers;
                EnableAddVisitors = CoreContext.Configuration.Standalone || TenantStatisticsProvider.GetVisitorsCount() < TenantExtra.GetTenantQuota().ActiveUsers * Constants.CoefficientOfVisitors;
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/Responders/DirectResponder.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Api.Interfaces;
using ASC.Api.Interfaces.ResponseTypes;

namespace ASC.Api.Impl.Responders
{
    public class DirectResponder : IApiResponder
    {
        #region IApiResponder Members

        public string Name
        {
            get { return "direct"; }
        }

        public IEnumerable<string> GetSupportedExtensions()
        {
            return new string[0];
        }

        public bool CanSerializeType(Type type)
        {
            return false;
        }


        public bool CanRespondTo(IApiStandartResponce responce, HttpContextBase context)
        {
            return responce.Response is IApiDirectResponce;
        }

        public void RespondTo(IApiStandartResponce responce, HttpContextBase context)
        {
            ((IApiDirectResponce)responce.Response).WriteResponce(context.Response);
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Data.Backup/Storage/LocalBackupStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;

namespace ASC.Data.Backup.Storage
{
    internal class LocalBackupStorage : IBackupStorage
    {
        public string Upload(string storageBasePath, string localPath, Guid userId)
        {
            if (!Directory.Exists(storageBasePath))
            {
                throw new FileNotFoundException("Directory not found.");
            }
            var storagePath = Path.Combine(storageBasePath, Path.GetFileName(localPath));
            if (localPath != storagePath)
            {
                File.Copy(localPath, storagePath, true);
            }
            return storagePath;
        }

        public void Download(string storagePath, string targetLocalPath)
        {
            File.Copy(storagePath, targetLocalPath, true);
        }

        public void Delete(string storagePath)
        {
            File.Delete(storagePath);
        }

        public bool IsExists(string storagePath)
        {
            return File.Exists(storagePath);
        }

        public string GetPublicLink(string storagePath)
        {
            return string.Empty;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/PublicResources/ResourceJS.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Studio.PublicResources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class ResourceJS {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal ResourceJS() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Studio.PublicResources.ResourceJS", typeof(ResourceJS).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Validation code field cannot be empty.
        /// </summary>
        public static string ActivateMobilePhoneEmptyCode {
            get {
                return ResourceManager.GetString("ActivateMobilePhoneEmptyCode", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter mobile phone number.
        /// </summary>
        public static string ActivateMobilePhoneEmptyPhoneNumber {
            get {
                return ResourceManager.GetString("ActivateMobilePhoneEmptyPhoneNumber", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Validation code field cannot be empty.
        /// </summary>
        public static string ActivateTfaAppEmptyCode {
            get {
                return ResourceManager.GetString("ActivateTfaAppEmptyCode", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add.
        /// </summary>
        public static string AddButton {
            get {
                return ResourceManager.GetString("AddButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add filter.
        /// </summary>
        public static string AddFilter {
            get {
                return ResourceManager.GetString("AddFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Use the {0}?{1} and {0}*{1} symbols to perform a single/multiple-character search. For example, to search for all the words beginning with {0}O{1}, use the  {0}O*{1} query. To search for the exact phrase use the quotation marks.{2}Learn more...{3}.
        /// </summary>
        public static string AdvansedFilterInfoText {
            get {
                return ResourceManager.GetString("AdvansedFilterInfoText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ascending/descending.
        /// </summary>
        public static string AscOrDesc {
            get {
                return ResourceManager.GetString("AscOrDesc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The backup copy has been successfully created..
        /// </summary>
        public static string BackupMakeCopySuccess {
            get {
                return ResourceManager.GetString("BackupMakeCopySuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Busy.
        /// </summary>
        public static string BusyStatus {
            get {
                return ResourceManager.GetString("BusyStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Successful purchase of number.
        /// </summary>
        public static string BuyNumberSuccessMsg {
            get {
                return ResourceManager.GetString("BuyNumberSuccessMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incoming call.
        /// </summary>
        public static string CallIncoming {
            get {
                return ResourceManager.GetString("CallIncoming", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Missed call.
        /// </summary>
        public static string CallMissed {
            get {
                return ResourceManager.GetString("CallMissed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cancel.
        /// </summary>
        public static string CancelButton {
            get {
                return ResourceManager.GetString("CancelButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cannot generate certificate.
        /// </summary>
        public static string CannotGenerateCertificate {
            get {
                return ResourceManager.GetString("CannotGenerateCertificate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Changes are applied.
        /// </summary>
        public static string ChangesApplied {
            get {
                return ResourceManager.GetString("ChangesApplied", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Changes are successfully applied..
        /// </summary>
        public static string ChangesSuccessfullyAppliedMsg {
            get {
                return ResourceManager.GetString("ChangesSuccessfullyAppliedMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close.
        /// </summary>
        public static string CloseButton {
            get {
                return ResourceManager.GetString("CloseButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to An error has been encountered. Please contact your administrator..
        /// </summary>
        public static string CommonJSErrorMsg {
            get {
                return ResourceManager.GetString("CommonJSErrorMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Complete.
        /// </summary>
        public static string Complete {
            get {
                return ResourceManager.GetString("Complete", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to continue?.
        /// </summary>
        public static string ConfirmMessage {
            get {
                return ResourceManager.GetString("ConfirmMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new contact.
        /// </summary>
        public static string ContactSelectorAddText {
            get {
                return ResourceManager.GetString("ContactSelectorAddText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No contacts in this list.
        /// </summary>
        public static string ContactSelectorEmptyList {
            get {
                return ResourceManager.GetString("ContactSelectorEmptyList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the company title.
        /// </summary>
        public static string ContactSelectorEmptyNameError {
            get {
                return ResourceManager.GetString("ContactSelectorEmptyNameError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no contacts.
        /// </summary>
        public static string ContactSelectorNoItems {
            get {
                return ResourceManager.GetString("ContactSelectorNoItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such contact.
        /// </summary>
        public static string ContactSelectorNoResult {
            get {
                return ResourceManager.GetString("ContactSelectorNoResult", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There is no such company.
        /// </summary>
        public static string ContactSelectorNotFoundError {
            get {
                return ResourceManager.GetString("ContactSelectorNotFoundError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Continue.
        /// </summary>
        public static string ContinueButton {
            get {
                return ResourceManager.GetString("ContinueButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create.
        /// </summary>
        public static string CreateButton {
            get {
                return ResourceManager.GetString("CreateButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Error while generating report.
        /// </summary>
        public static string CreateReportError {
            get {
                return ResourceManager.GetString("CreateReportError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to april.
        /// </summary>
        public static string CronApril {
            get {
                return ResourceManager.GetString("CronApril", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to august.
        /// </summary>
        public static string CronAugust {
            get {
                return ResourceManager.GetString("CronAugust", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to december.
        /// </summary>
        public static string CronDecember {
            get {
                return ResourceManager.GetString("CronDecember", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every.
        /// </summary>
        public static string CronEmpty {
            get {
                return ResourceManager.GetString("CronEmpty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every day of the month.
        /// </summary>
        public static string CronEmptyDayOfMonth {
            get {
                return ResourceManager.GetString("CronEmptyDayOfMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every day of the week.
        /// </summary>
        public static string CronEmptyDayOfWeek {
            get {
                return ResourceManager.GetString("CronEmptyDayOfWeek", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every.
        /// </summary>
        public static string CronEmptyMinutes {
            get {
                return ResourceManager.GetString("CronEmptyMinutes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every month.
        /// </summary>
        public static string CronEmptyMonth {
            get {
                return ResourceManager.GetString("CronEmptyMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every hour.
        /// </summary>
        public static string CronEmptyTimeHours {
            get {
                return ResourceManager.GetString("CronEmptyTimeHours", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every minute.
        /// </summary>
        public static string CronEmptyTimeMinutes {
            get {
                return ResourceManager.GetString("CronEmptyTimeMinutes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The tag %s is not supported !.
        /// </summary>
        public static string CronError1 {
            get {
                return ResourceManager.GetString("CronError1", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bad number of elements.
        /// </summary>
        public static string CronError2 {
            get {
                return ResourceManager.GetString("CronError2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The jqueryelement should be set into jqCron settings.
        /// </summary>
        public static string CronError3 {
            get {
                return ResourceManager.GetString("CronError3", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unrecognized expression.
        /// </summary>
        public static string CronError4 {
            get {
                return ResourceManager.GetString("CronError4", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to february.
        /// </summary>
        public static string CronFebruary {
            get {
                return ResourceManager.GetString("CronFebruary", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to first.
        /// </summary>
        public static string CronFirst {
            get {
                return ResourceManager.GetString("CronFirst", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to friday.
        /// </summary>
        public static string CronFriday {
            get {
                return ResourceManager.GetString("CronFriday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to january.
        /// </summary>
        public static string CronJanuary {
            get {
                return ResourceManager.GetString("CronJanuary", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to july.
        /// </summary>
        public static string CronJuly {
            get {
                return ResourceManager.GetString("CronJuly", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to june.
        /// </summary>
        public static string CronJune {
            get {
                return ResourceManager.GetString("CronJune", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to last.
        /// </summary>
        public static string CronLast {
            get {
                return ResourceManager.GetString("CronLast", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to march.
        /// </summary>
        public static string CronMarch {
            get {
                return ResourceManager.GetString("CronMarch", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to may.
        /// </summary>
        public static string CronMay {
            get {
                return ResourceManager.GetString("CronMay", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to monday.
        /// </summary>
        public static string CronMonday {
            get {
                return ResourceManager.GetString("CronMonday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to day.
        /// </summary>
        public static string CronNameDay {
            get {
                return ResourceManager.GetString("CronNameDay", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to hour.
        /// </summary>
        public static string CronNameHour {
            get {
                return ResourceManager.GetString("CronNameHour", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to minute.
        /// </summary>
        public static string CronNameMinute {
            get {
                return ResourceManager.GetString("CronNameMinute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to month.
        /// </summary>
        public static string CronNameMonth {
            get {
                return ResourceManager.GetString("CronNameMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to week.
        /// </summary>
        public static string CronNameWeek {
            get {
                return ResourceManager.GetString("CronNameWeek", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to year.
        /// </summary>
        public static string CronNameYear {
            get {
                return ResourceManager.GetString("CronNameYear", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to november.
        /// </summary>
        public static string CronNovember {
            get {
                return ResourceManager.GetString("CronNovember", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to october.
        /// </summary>
        public static string CronOctober {
            get {
                return ResourceManager.GetString("CronOctober", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to saturday.
        /// </summary>
        public static string CronSaturday {
            get {
                return ResourceManager.GetString("CronSaturday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to september.
        /// </summary>
        public static string CronSeptember {
            get {
                return ResourceManager.GetString("CronSeptember", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to sunday.
        /// </summary>
        public static string CronSunday {
            get {
                return ResourceManager.GetString("CronSunday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to on &lt;b /&gt;.
        /// </summary>
        public static string CronTextDom {
            get {
                return ResourceManager.GetString("CronTextDom", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to on &lt;b /&gt;.
        /// </summary>
        public static string CronTextDow {
            get {
                return ResourceManager.GetString("CronTextDow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to at &lt;b /&gt; minute(s) past the hour UTC.
        /// </summary>
        public static string CronTextMins {
            get {
                return ResourceManager.GetString("CronTextMins", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to of &lt;b /&gt;.
        /// </summary>
        public static string CronTextMonth {
            get {
                return ResourceManager.GetString("CronTextMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Every &lt;b /&gt;.
        /// </summary>
        public static string CronTextPeriod {
            get {
                return ResourceManager.GetString("CronTextPeriod", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to at &lt;b /&gt;:&lt;b /&gt; UTC.
        /// </summary>
        public static string CronTextTime {
            get {
                return ResourceManager.GetString("CronTextTime", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to thursday.
        /// </summary>
        public static string CronThursday {
            get {
                return ResourceManager.GetString("CronThursday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to tuesday.
        /// </summary>
        public static string CronTuesday {
            get {
                return ResourceManager.GetString("CronTuesday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to wednesday.
        /// </summary>
        public static string CronWednesday {
            get {
                return ResourceManager.GetString("CronWednesday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string EditButton {
            get {
                return ResourceManager.GetString("EditButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comment cannot be empty.
        /// </summary>
        public static string EmptyCommentErrorMessage {
            get {
                return ResourceManager.GetString("EmptyCommentErrorMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select an area for avatar.
        /// </summary>
        public static string EmptySelectedArea {
            get {
                return ResourceManager.GetString("EmptySelectedArea", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Error.
        /// </summary>
        public static string Error {
            get {
                return ResourceManager.GetString("Error", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the email.
        /// </summary>
        public static string ErrorEmptyEmail {
            get {
                return ResourceManager.GetString("ErrorEmptyEmail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please fill in this field.
        /// </summary>
        public static string ErrorEmptyField {
            get {
                return ResourceManager.GetString("ErrorEmptyField", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the group title.
        /// </summary>
        public static string ErrorEmptyGroupTitle {
            get {
                return ResourceManager.GetString("ErrorEmptyGroupTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the first name.
        /// </summary>
        public static string ErrorEmptyUserFirstName {
            get {
                return ResourceManager.GetString("ErrorEmptyUserFirstName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the last name.
        /// </summary>
        public static string ErrorEmptyUserLastName {
            get {
                return ResourceManager.GetString("ErrorEmptyUserLastName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There is no such group.
        /// </summary>
        public static string ErrorGroupNotExist {
            get {
                return ResourceManager.GetString("ErrorGroupNotExist", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There is not such person.
        /// </summary>
        public static string ErrorHeadNotExist {
            get {
                return ResourceManager.GetString("ErrorHeadNotExist", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invalid first name.
        /// </summary>
        public static string ErrorInvalidUserFirstName {
            get {
                return ResourceManager.GetString("ErrorInvalidUserFirstName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invalid last name.
        /// </summary>
        public static string ErrorInvalidUserLastName {
            get {
                return ResourceManager.GetString("ErrorInvalidUserLastName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 64 chars maximum.
        /// </summary>
        public static string ErrorMesLongField64 {
            get {
                return ResourceManager.GetString("ErrorMesLongField64", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Registration date must be later than birth date.
        /// </summary>
        public static string ErrorMessage_InvalidDate {
            get {
                return ResourceManager.GetString("ErrorMessage_InvalidDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cannot add the same account and contact twice..
        /// </summary>
        public static string ErrorMessageContactsDuplicated {
            get {
                return ResourceManager.GetString("ErrorMessageContactsDuplicated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can only enter up to 64 characters for this field..
        /// </summary>
        public static string ErrorMessageLongField64 {
            get {
                return ResourceManager.GetString("ErrorMessageLongField64", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect email.
        /// </summary>
        public static string ErrorNotCorrectEmail {
            get {
                return ResourceManager.GetString("ErrorNotCorrectEmail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Portal name is already taken.
        /// </summary>
        public static string ErrorPortalNameExist {
            get {
                return ResourceManager.GetString("ErrorPortalNameExist", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not allowed characters in portal name.
        /// </summary>
        public static string ErrorPortalNameIncorrect {
            get {
                return ResourceManager.GetString("ErrorPortalNameIncorrect", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Portal name is too short.
        /// </summary>
        public static string ErrorPortalNameTooShort {
            get {
                return ResourceManager.GetString("ErrorPortalNameTooShort", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Portal name has not been changed.
        /// </summary>
        public static string ErrorPortalNameWasNotChanged {
            get {
                return ResourceManager.GetString("ErrorPortalNameWasNotChanged", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The users have been successfully added..
        /// </summary>
        public static string FinishImportUserTitle {
            get {
                return ResourceManager.GetString("FinishImportUserTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to First Name.
        /// </summary>
        public static string FirstName {
            get {
                return ResourceManager.GetString("FirstName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Group {0} was created successfully..
        /// </summary>
        public static string GroupSelectorAddSuccess {
            get {
                return ResourceManager.GetString("GroupSelectorAddSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new group.
        /// </summary>
        public static string GroupSelectorAddText {
            get {
                return ResourceManager.GetString("GroupSelectorAddText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No groups in this list.
        /// </summary>
        public static string GroupSelectorEmptyList {
            get {
                return ResourceManager.GetString("GroupSelectorEmptyList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such group.
        /// </summary>
        public static string GroupSelectorNoResults {
            get {
                return ResourceManager.GetString("GroupSelectorNoResults", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Hide.
        /// </summary>
        public static string HideLink {
            get {
                return ResourceManager.GetString("HideLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to of.
        /// </summary>
        public static string ImportOf {
            get {
                return ResourceManager.GetString("ImportOf", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect IP address format.
        /// </summary>
        public static string IncorrectIPAddressFormatError {
            get {
                return ResourceManager.GetString("IncorrectIPAddressFormatError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect metadata file type. An .xml file is required..
        /// </summary>
        public static string IncorrectMetadataFileType {
            get {
                return ResourceManager.GetString("IncorrectMetadataFileType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invalid certificate.
        /// </summary>
        public static string InvalidCertificate {
            get {
                return ResourceManager.GetString("InvalidCertificate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invalid metadata xml file.
        /// </summary>
        public static string InvalidMetadataXmlFile {
            get {
                return ResourceManager.GetString("InvalidMetadataXmlFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invite.
        /// </summary>
        public static string InviteButton {
            get {
                return ResourceManager.GetString("InviteButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Settings have been successfully updated.
        /// </summary>
        public static string IPRestrictionsSettingsSuccessfullyUpdated {
            get {
                return ResourceManager.GetString("IPRestrictionsSettingsSuccessfullyUpdated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Last Name.
        /// </summary>
        public static string LastName {
            get {
                return ResourceManager.GetString("LastName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to LDAP Attribute Name.
        /// </summary>
        public static string LdapAttributeOrigin {
            get {
                return ResourceManager.GetString("LdapAttributeOrigin", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to LDAP Group Name Attribute.
        /// </summary>
        public static string LdapSecurityPlaceholder {
            get {
                return ResourceManager.GetString("LdapSecurityPlaceholder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Certificate name does not match hostname.
        /// </summary>
        public static string LdapSettingsCertCnNoMatch {
            get {
                return ResourceManager.GetString("LdapSettingsCertCnNoMatch", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Certificate expired.
        /// </summary>
        public static string LdapSettingsCertExpired {
            get {
                return ResourceManager.GetString("LdapSettingsCertExpired", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No certificate  issuer chain was provided.
        /// </summary>
        public static string LdapSettingsCertIssuerChaining {
            get {
                return ResourceManager.GetString("LdapSettingsCertIssuerChaining", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Malformed certificate.
        /// </summary>
        public static string LdapSettingsCertMalformed {
            get {
                return ResourceManager.GetString("LdapSettingsCertMalformed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unrecognized Error.
        /// </summary>
        public static string LdapSettingsCertUnrecognizedError {
            get {
                return ResourceManager.GetString("LdapSettingsCertUnrecognizedError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Certificate Authority who issued the certificate is not trusted.
        /// </summary>
        public static string LdapSettingsCertUntrustedCa {
            get {
                return ResourceManager.GetString("LdapSettingsCertUntrustedCa", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Root Certificate Authority who issued the certificate is not trusted.
        /// </summary>
        public static string LdapSettingsCertUntrustedRoot {
            get {
                return ResourceManager.GetString("LdapSettingsCertUntrustedRoot", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Empty field.
        /// </summary>
        public static string LdapSettingsEmptyField {
            get {
                return ResourceManager.GetString("LdapSettingsEmptyField", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect port number.
        /// </summary>
        public static string LdapSettingsIncorrectPortNumber {
            get {
                return ResourceManager.GetString("LdapSettingsIncorrectPortNumber", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saving has been successfully completed.
        /// </summary>
        public static string LdapSettingsSuccess {
            get {
                return ResourceManager.GetString("LdapSettingsSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You need to read and agree with the License Agreement.
        /// </summary>
        public static string LicenseAgreementsError {
            get {
                return ResourceManager.GetString("LicenseAgreementsError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to License is not correct.
        /// </summary>
        public static string LicenseKeyError {
            get {
                return ResourceManager.GetString("LicenseKeyError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Link has been copied to the clipboard.
        /// </summary>
        public static string LinkCopySuccess {
            get {
                return ResourceManager.GetString("LinkCopySuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please wait....
        /// </summary>
        public static string LoadingDescription {
            get {
                return ResourceManager.GetString("LoadingDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Loading, please wait..
        /// </summary>
        public static string LoadingPleaseWait {
            get {
                return ResourceManager.GetString("LoadingPleaseWait", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Loading....
        /// </summary>
        public static string LoadingProcessing {
            get {
                return ResourceManager.GetString("LoadingProcessing", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to all day.
        /// </summary>
        public static string MailIcsCalendarAllDayEventLabel {
            get {
                return ResourceManager.GetString("MailIcsCalendarAllDayEventLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Event has been canceled..
        /// </summary>
        public static string MailIcsCancelDescription {
            get {
                return ResourceManager.GetString("MailIcsCancelDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Canceled: {0}.
        /// </summary>
        public static string MailIcsCancelSubject {
            get {
                return ResourceManager.GetString("MailIcsCancelSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Event has been finished..
        /// </summary>
        public static string MailIcsFinishDescription {
            get {
                return ResourceManager.GetString("MailIcsFinishDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} tentatively accepted the invitation to.
        /// </summary>
        public static string MailIcsReplyMaybeDescription {
            get {
                return ResourceManager.GetString("MailIcsReplyMaybeDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} declined the invitation to.
        /// </summary>
        public static string MailIcsReplyNoDescription {
            get {
                return ResourceManager.GetString("MailIcsReplyNoDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reply: {0}.
        /// </summary>
        public static string MailIcsReplySubject {
            get {
                return ResourceManager.GetString("MailIcsReplySubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} accepted the invitation to.
        /// </summary>
        public static string MailIcsReplyYesDescription {
            get {
                return ResourceManager.GetString("MailIcsReplyYesDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} invites you to.
        /// </summary>
        public static string MailIcsRequestDescription {
            get {
                return ResourceManager.GetString("MailIcsRequestDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invitation: {0}.
        /// </summary>
        public static string MailIcsRequestSubject {
            get {
                return ResourceManager.GetString("MailIcsRequestSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to and.
        /// </summary>
        public static string MailIcsRRuleAndLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleAndLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to approximate.
        /// </summary>
        public static string MailIcsRRuleApproximateLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleApproximateLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to at.
        /// </summary>
        public static string MailIcsRRuleAtLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleAtLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to day.
        /// </summary>
        public static string MailIcsRRuleDayLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleDayLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to days.
        /// </summary>
        public static string MailIcsRRuleDaysLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleDaysLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to every.
        /// </summary>
        public static string MailIcsRRuleEveryLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleEveryLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to for.
        /// </summary>
        public static string MailIcsRRuleForLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleForLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to hour.
        /// </summary>
        public static string MailIcsRRuleHourLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleHourLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to hours.
        /// </summary>
        public static string MailIcsRRuleHoursLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleHoursLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to in.
        /// </summary>
        public static string MailIcsRRuleInLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleInLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to last.
        /// </summary>
        public static string MailIcsRRuleLastLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleLastLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to month.
        /// </summary>
        public static string MailIcsRRuleMonthLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleMonthLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to months.
        /// </summary>
        public static string MailIcsRRuleMonthsLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleMonthsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to nd.
        /// </summary>
        public static string MailIcsRRuleNdLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleNdLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to on.
        /// </summary>
        public static string MailIcsRRuleOnLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleOnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to on the.
        /// </summary>
        public static string MailIcsRRuleOnTheLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleOnTheLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to or.
        /// </summary>
        public static string MailIcsRRuleOrLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleOrLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to unknown format.
        /// </summary>
        public static string MailIcsRRuleParseErrorLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleParseErrorLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to rd.
        /// </summary>
        public static string MailIcsRRuleRdLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleRdLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to st.
        /// </summary>
        public static string MailIcsRRuleStLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleStLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to the.
        /// </summary>
        public static string MailIcsRRuleTheLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleTheLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to th.
        /// </summary>
        public static string MailIcsRRuleThLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleThLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to time.
        /// </summary>
        public static string MailIcsRRuleTimeLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleTimeLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to times.
        /// </summary>
        public static string MailIcsRRuleTimesLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleTimesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to until.
        /// </summary>
        public static string MailIcsRRuleUntilLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleUntilLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to weekday.
        /// </summary>
        public static string MailIcsRRuleWeekdayLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleWeekdayLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to weekdays.
        /// </summary>
        public static string MailIcsRRuleWeekdaysLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleWeekdaysLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to week.
        /// </summary>
        public static string MailIcsRRuleWeekLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleWeekLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to weeks.
        /// </summary>
        public static string MailIcsRRuleWeeksLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleWeeksLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to year.
        /// </summary>
        public static string MailIcsRRuleYearLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleYearLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to years.
        /// </summary>
        public static string MailIcsRRuleYearsLabel {
            get {
                return ResourceManager.GetString("MailIcsRRuleYearsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Event has been changed..
        /// </summary>
        public static string MailIcsUpdateDescription {
            get {
                return ResourceManager.GetString("MailIcsUpdateDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Update: {0}.
        /// </summary>
        public static string MailIcsUpdateSubject {
            get {
                return ResourceManager.GetString("MailIcsUpdateSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You tentatively accepted the invitation to.
        /// </summary>
        public static string MailIcsYouReplyMaybeDescription {
            get {
                return ResourceManager.GetString("MailIcsYouReplyMaybeDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You declined the invitation to.
        /// </summary>
        public static string MailIcsYouReplyNoDescription {
            get {
                return ResourceManager.GetString("MailIcsYouReplyNoDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You accepted the invitation to.
        /// </summary>
        public static string MailIcsYouReplyYesDescription {
            get {
                return ResourceManager.GetString("MailIcsYouReplyYesDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You sent the invitation to.
        /// </summary>
        public static string MailIcsYouSentRequestDescription {
            get {
                return ResourceManager.GetString("MailIcsYouSentRequestDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to no subject.
        /// </summary>
        public static string MailNoSubject {
            get {
                return ResourceManager.GetString("MailNoSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to A problem has occurred while trying to send this message..
        /// </summary>
        public static string MailSendMessageError {
            get {
                return ResourceManager.GetString("MailSendMessageError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Event cancellation notification has been sent to attendees..
        /// </summary>
        public static string MailSentIcalCancelText {
            get {
                return ResourceManager.GetString("MailSentIcalCancelText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your request has been sent to attendees..
        /// </summary>
        public static string MailSentIcalRequestText {
            get {
                return ResourceManager.GetString("MailSentIcalRequestText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your response has been sent to the organizer..
        /// </summary>
        public static string MailSentIcalResponseText {
            get {
                return ResourceManager.GetString("MailSentIcalResponseText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message has been sent..
        /// </summary>
        public static string MailSentMessageText {
            get {
                return ResourceManager.GetString("MailSentMessageText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Additional Mail.
        /// </summary>
        public static string MappingAdditionalMail {
            get {
                return ResourceManager.GetString("MappingAdditionalMail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Additional Mobile Phone.
        /// </summary>
        public static string MappingAdditionalMobilePhone {
            get {
                return ResourceManager.GetString("MappingAdditionalMobilePhone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Additional Phone.
        /// </summary>
        public static string MappingAdditionalPhone {
            get {
                return ResourceManager.GetString("MappingAdditionalPhone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Profile Photo.
        /// </summary>
        public static string MappingAvatarAttribute {
            get {
                return ResourceManager.GetString("MappingAvatarAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Date of Birth.
        /// </summary>
        public static string MappingBirthDayAttribute {
            get {
                return ResourceManager.GetString("MappingBirthDayAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to First Name.
        /// </summary>
        public static string MappingFirstNameAttribute {
            get {
                return ResourceManager.GetString("MappingFirstNameAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sex.
        /// </summary>
        public static string MappingGenderAttribute {
            get {
                return ResourceManager.GetString("MappingGenderAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Location.
        /// </summary>
        public static string MappingLocationAttribute {
            get {
                return ResourceManager.GetString("MappingLocationAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail.
        /// </summary>
        public static string MappingMailAttribute {
            get {
                return ResourceManager.GetString("MappingMailAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Primary Mobile Phone.
        /// </summary>
        public static string MappingMobilePhoneAttribute {
            get {
                return ResourceManager.GetString("MappingMobilePhoneAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Second Name.
        /// </summary>
        public static string MappingSecondNameAttribute {
            get {
                return ResourceManager.GetString("MappingSecondNameAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Skype.
        /// </summary>
        public static string MappingSkype {
            get {
                return ResourceManager.GetString("MappingSkype", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string MappingTitleAttribute {
            get {
                return ResourceManager.GetString("MappingTitleAttribute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Me.
        /// </summary>
        public static string MeLabel {
            get {
                return ResourceManager.GetString("MeLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Metadata file not transferred.
        /// </summary>
        public static string MetadataFileNotTransferred {
            get {
                return ResourceManager.GetString("MetadataFileNotTransferred", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No milestone in this project.
        /// </summary>
        public static string MilestoneSelectorNoItems {
            get {
                return ResourceManager.GetString("MilestoneSelectorNoItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such milestone.
        /// </summary>
        public static string MilestoneSelectorNoResult {
            get {
                return ResourceManager.GetString("MilestoneSelectorNoResult", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Never Show.
        /// </summary>
        public static string NeverShow {
            get {
                return ResourceManager.GetString("NeverShow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have not added any templates.
        /// </summary>
        public static string NotAddedAnyTemplates {
            get {
                return ResourceManager.GetString("NotAddedAnyTemplates", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Offline.
        /// </summary>
        public static string OfflineStatus {
            get {
                return ResourceManager.GetString("OfflineStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Online.
        /// </summary>
        public static string OnlineStatus {
            get {
                return ResourceManager.GetString("OnlineStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string Open {
            get {
                return ResourceManager.GetString("Open", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open Talk.
        /// </summary>
        public static string OpenTalk {
            get {
                return ResourceManager.GetString("OpenTalk", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Error while performing operation.
        /// </summary>
        public static string OperationFailedError {
            get {
                return ResourceManager.GetString("OperationFailedError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Error while executing the operation..
        /// </summary>
        public static string OperationFailedMsg {
            get {
                return ResourceManager.GetString("OperationFailedMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Operation has been successfully completed..
        /// </summary>
        public static string OperationSuccededMsg {
            get {
                return ResourceManager.GetString("OperationSuccededMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}You are about to rename your portal.{1}{0}Are you sure you want to continue?{1}.
        /// </summary>
        public static string PortalRenameConfirmationPopup {
            get {
                return ResourceManager.GetString("PortalRenameConfirmationPopup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Portal renaming confirmation.
        /// </summary>
        public static string PortalRenameConfirmationTitle {
            get {
                return ResourceManager.GetString("PortalRenameConfirmationTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new project.
        /// </summary>
        public static string ProjectSelectorAddText {
            get {
                return ResourceManager.GetString("ProjectSelectorAddText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No projects in this list.
        /// </summary>
        public static string ProjectSelectorEmptyList {
            get {
                return ResourceManager.GetString("ProjectSelectorEmptyList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each project must have a manager.
        /// </summary>
        public static string ProjectSelectorEmptyManagerError {
            get {
                return ResourceManager.GetString("ProjectSelectorEmptyManagerError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each project must have a title.
        /// </summary>
        public static string ProjectSelectorEmptyTitleError {
            get {
                return ResourceManager.GetString("ProjectSelectorEmptyTitleError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No projects in this group.
        /// </summary>
        public static string ProjectSelectorNoItems {
            get {
                return ResourceManager.GetString("ProjectSelectorNoItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such project.
        /// </summary>
        public static string ProjectSelectorNoResult {
            get {
                return ResourceManager.GetString("ProjectSelectorNoResult", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such person.
        /// </summary>
        public static string ProjectSelectorNotPersonError {
            get {
                return ResourceManager.GetString("ProjectSelectorNotPersonError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Path.
        /// </summary>
        public static string RestoreConsumerPath {
            get {
                return ResourceManager.GetString("RestoreConsumerPath", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Payment accepted! Your plan will be updated in a few minutes.
        /// </summary>
        public static string SaasTariffPaymentAccepted {
            get {
                return ResourceManager.GetString("SaasTariffPaymentAccepted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Same restrictions.
        /// </summary>
        public static string SameIPRestrictionError {
            get {
                return ResourceManager.GetString("SameIPRestrictionError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The settings are successfully saved.
        /// </summary>
        public static string SavedTitle {
            get {
                return ResourceManager.GetString("SavedTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community.
        /// </summary>
        public static string SecurityMappingCommunity {
            get {
                return ResourceManager.GetString("SecurityMappingCommunity", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to CRM.
        /// </summary>
        public static string SecurityMappingCrm {
            get {
                return ResourceManager.GetString("SecurityMappingCrm", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Documents.
        /// </summary>
        public static string SecurityMappingDocuments {
            get {
                return ResourceManager.GetString("SecurityMappingDocuments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Full Access.
        /// </summary>
        public static string SecurityMappingFullAccess {
            get {
                return ResourceManager.GetString("SecurityMappingFullAccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail.
        /// </summary>
        public static string SecurityMappingMail {
            get {
                return ResourceManager.GetString("SecurityMappingMail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to People.
        /// </summary>
        public static string SecurityMappingPeople {
            get {
                return ResourceManager.GetString("SecurityMappingPeople", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects.
        /// </summary>
        public static string SecurityMappingProjects {
            get {
                return ResourceManager.GetString("SecurityMappingProjects", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select file.
        /// </summary>
        public static string SelectFile {
            get {
                return ResourceManager.GetString("SelectFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select folder.
        /// </summary>
        public static string SelectFolder {
            get {
                return ResourceManager.GetString("SelectFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Company.
        /// </summary>
        public static string SelectorCompany {
            get {
                return ResourceManager.GetString("SelectorCompany", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Company name.
        /// </summary>
        public static string SelectorCompanyName {
            get {
                return ResourceManager.GetString("SelectorCompanyName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Contact type.
        /// </summary>
        public static string SelectorContactType {
            get {
                return ResourceManager.GetString("SelectorContactType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Email.
        /// </summary>
        public static string SelectorEmail {
            get {
                return ResourceManager.GetString("SelectorEmail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to First Name.
        /// </summary>
        public static string SelectorFirstName {
            get {
                return ResourceManager.GetString("SelectorFirstName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Group.
        /// </summary>
        public static string SelectorGroup {
            get {
                return ResourceManager.GetString("SelectorGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Head.
        /// </summary>
        public static string SelectorHead {
            get {
                return ResourceManager.GetString("SelectorHead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Last Name.
        /// </summary>
        public static string SelectorLastName {
            get {
                return ResourceManager.GetString("SelectorLastName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Manager.
        /// </summary>
        public static string SelectorManager {
            get {
                return ResourceManager.GetString("SelectorManager", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Person.
        /// </summary>
        public static string SelectorPerson {
            get {
                return ResourceManager.GetString("SelectorPerson", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to selected.
        /// </summary>
        public static string SelectorSelectedItems {
            get {
                return ResourceManager.GetString("SelectorSelectedItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string SelectorTitle {
            get {
                return ResourceManager.GetString("SelectorTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Type.
        /// </summary>
        public static string SelectorType {
            get {
                return ResourceManager.GetString("SelectorType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to User.
        /// </summary>
        public static string SelectorUser {
            get {
                return ResourceManager.GetString("SelectorUser", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Guest.
        /// </summary>
        public static string SelectorVisitor {
            get {
                return ResourceManager.GetString("SelectorVisitor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your request is successfully submitted. Our manager will contact you in the nearest time..
        /// </summary>
        public static string SendTariffRequest1 {
            get {
                return ResourceManager.GetString("SendTariffRequest1", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to I created my own web-office. Join me here: {0} #ONLYOFFICE #WebOffice.
        /// </summary>
        public static string ShareInviteLinkDscr {
            get {
                return ResourceManager.GetString("ShareInviteLinkDscr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show.
        /// </summary>
        public static string ShowLink {
            get {
                return ResourceManager.GetString("ShowLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show Next.
        /// </summary>
        public static string ShowNext {
            get {
                return ResourceManager.GetString("ShowNext", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Certificate with same action type already exist.
        /// </summary>
        public static string SsoCertificateActionTypeError {
            get {
                return ResourceManager.GetString("SsoCertificateActionTypeError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Multiple Idp verification certificates are not supported. Please leave only Primary certificate..
        /// </summary>
        public static string SsoCertificateMultipleVerificationError {
            get {
                return ResourceManager.GetString("SsoCertificateMultipleVerificationError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Hide advanced settings.
        /// </summary>
        public static string SsoHideAdvancedSettings {
            get {
                return ResourceManager.GetString("SsoHideAdvancedSettings", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect metadata file type. An .xml file is required..
        /// </summary>
        public static string SsoMetadataFileTypeError {
            get {
                return ResourceManager.GetString("SsoMetadataFileTypeError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saving has been successfully completed.
        /// </summary>
        public static string SsoSettingsSuccess {
            get {
                return ResourceManager.GetString("SsoSettingsSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show advanced settings.
        /// </summary>
        public static string SsoShowAdvancedSettings {
            get {
                return ResourceManager.GetString("SsoShowAdvancedSettings", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Start filter.
        /// </summary>
        public static string StartFilter {
            get {
                return ResourceManager.GetString("StartFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connect.
        /// </summary>
        public static string StorageButtonEnable {
            get {
                return ResourceManager.GetString("StorageButtonEnable", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reset to Default.
        /// </summary>
        public static string StorageButtonResetToDefault {
            get {
                return ResourceManager.GetString("StorageButtonResetToDefault", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to CDN settings.
        /// </summary>
        public static string StorageCdnTitle {
            get {
                return ResourceManager.GetString("StorageCdnTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Storage settings.
        /// </summary>
        public static string StorageStorageTitle {
            get {
                return ResourceManager.GetString("StorageStorageTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} user(s) were successfully added to the portal.
        /// </summary>
        public static string SuccessfullyImportCountUsers {
            get {
                return ResourceManager.GetString("SuccessfullyImportCountUsers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Settings have been successfully updated.
        /// </summary>
        public static string SuccessfullySaveSettingsMessage {
            get {
                return ResourceManager.GetString("SuccessfullySaveSettingsMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Template not found.
        /// </summary>
        public static string TemplateNotFound {
            get {
                return ResourceManager.GetString("TemplateNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subscribe to Tips&amp;Tricks.
        /// </summary>
        public static string TipsAndTricksSubscribeBtn {
            get {
                return ResourceManager.GetString("TipsAndTricksSubscribeBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unsubscribe from Tips&amp;Tricks.
        /// </summary>
        public static string TipsAndTricksUnsubscribeBtn {
            get {
                return ResourceManager.GetString("TipsAndTricksUnsubscribeBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are about to unsubscribe from all notifications of the &quot;{0}&quot; module. Are you sure you want to continue?.
        /// </summary>
        public static string UnsubscribeProductMessage {
            get {
                return ResourceManager.GetString("UnsubscribeProductMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Empty file.
        /// </summary>
        public static string UploadVoipRingtoneEmptyFileErrorMsg {
            get {
                return ResourceManager.GetString("UploadVoipRingtoneEmptyFileErrorMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Error while uploading file.
        /// </summary>
        public static string UploadVoipRingtoneFileErrorMsg {
            get {
                return ResourceManager.GetString("UploadVoipRingtoneFileErrorMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Supported file format: mp3.
        /// </summary>
        public static string UploadVoipRingtoneFileFormatErrorMsg {
            get {
                return ResourceManager.GetString("UploadVoipRingtoneFileFormatErrorMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to File size cannot exceed 5MB .
        /// </summary>
        public static string UploadVoipRingtoneFileSizeErrorMsg {
            get {
                return ResourceManager.GetString("UploadVoipRingtoneFileSizeErrorMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to pending.
        /// </summary>
        public static string UserPending {
            get {
                return ResourceManager.GetString("UserPending", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The profile for {0} was created successfully.
        /// </summary>
        public static string UserSelectorAddSuccess {
            get {
                return ResourceManager.GetString("UserSelectorAddSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new profile.
        /// </summary>
        public static string UserSelectorAddText {
            get {
                return ResourceManager.GetString("UserSelectorAddText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No users in this list.
        /// </summary>
        public static string UserSelectorEmptyList {
            get {
                return ResourceManager.GetString("UserSelectorEmptyList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Exceeds the number of maximum active users.
        /// </summary>
        public static string UserSelectorErrorLimitUsers {
            get {
                return ResourceManager.GetString("UserSelectorErrorLimitUsers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No groups have been created at the portal so far. Go to the People module to group users..
        /// </summary>
        public static string UserSelectorNoGroups {
            get {
                return ResourceManager.GetString("UserSelectorNoGroups", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No users in this group.
        /// </summary>
        public static string UserSelectorNoItems {
            get {
                return ResourceManager.GetString("UserSelectorNoItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such user.
        /// </summary>
        public static string UserSelectorNoResults {
            get {
                return ResourceManager.GetString("UserSelectorNoResults", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you leave now all the entered or unsaved data will be lost..
        /// </summary>
        public static string WarningMessageBeforeUnload {
            get {
                return ResourceManager.GetString("WarningMessageBeforeUnload", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}This means that you can: {1}view portal content open for all portal users,{2}leave comments,{3}attach and download files.{4}.
        /// </summary>
        public static string WelcomeCollaboratorCan {
            get {
                return ResourceManager.GetString("WelcomeCollaboratorCan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to In case you need some additional rights please contact your portal administrator..
        /// </summary>
        public static string WelcomeCollaboratorOtherActions {
            get {
                return ResourceManager.GetString("WelcomeCollaboratorOtherActions", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Welcome to ONLYOFFICE.
        /// </summary>
        public static string WelcomeCollaboratorPopupHeader {
            get {
                return ResourceManager.GetString("WelcomeCollaboratorPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The portal administrator invited you as guest user to the portal..
        /// </summary>
        public static string WelcomeCollaboratorRole {
            get {
                return ResourceManager.GetString("WelcomeCollaboratorRole", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Start work.
        /// </summary>
        public static string WelcomeCollaboratorStartWork {
            get {
                return ResourceManager.GetString("WelcomeCollaboratorStartWork", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Welcome to ONLYOFFICE!.
        /// </summary>
        public static string WelcomeToTeamlab {
            get {
                return ResourceManager.GetString("WelcomeToTeamlab", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You haven&apos;t set up any password. You will be able to do it later using the &apos;Forgot your password?&apos; link at the portal login page. Are you sure you want to continue?.
        /// </summary>
        public static string WizardCancelConfirmMessage {
            get {
                return ResourceManager.GetString("WizardCancelConfirmMessage", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Core/Shared/NotFoundUser.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Core.Users;

namespace ASC.Forum
{
    public class NotFoundUser
    {
        public static UserInfo GetUser(Guid userGuid)
        {
            UserInfo ui = new UserInfo();
            ui.FirstName = "User";
            ui.LastName = "Lost";

            return ui;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/calendar/UserControls/popup/css/popup.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.asc-popup {
	position: absolute;
	border: 1px solid #d3d3d3;
	margin: 12px 0 0 0;
	padding: .2em .2em 0;
	background-color: #fff;
}

.asc-popup .arrow {
	position: absolute;
	background-image: url(../img/popup-arrow-big.png);
	background-position: 0px 0px;
	width: 20px;
	height: 11px;
	left: 5px;
	top: -10px;
}

.asc-ui-blocker {
	position: fixed;
	left: 0;
	top: 0;
	right: 0;
	bottom: 0;
	/*background-color: rgba(0, 0, 0, 0.2);*/
	background-color: transparent;
}



.asc-popupmenu {
	position: absolute;
	border: 1px solid #d1d1d1;
	padding: 4px;
	background-color: #fff;
	z-index: 1998;
	 box-shadow:0 2px 4px rgba(0, 0, 0, 0.3);
     -moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
     -webkit-box-shadow:0 2px 4px rgba(0, 0, 0, 0.3);
     border-radius: 4px;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
	
}

.asc-popupmenu .arrow {
	position: absolute;
	background-image: url(../img/popup-arrow.png);
	background-position: 0px 0px;
	width: 8px;
	height: 5px;
	left: 5px;
	top: -4px;
}

.asc-popupmenu .divider {
	border-bottom: 1px solid #d3d3d3;
	margin-bottom: .4em;
}

.asc-popupmenu .item {
	cursor: pointer;
	padding: 0 12px;
    line-height: 24px;
    margin-bottom: 1px;
}
.asc-popupmenu .item.dropdown-item-seporator {
    width: auto;
}

.asc-popupmenu .item:hover {
	background-color: #e9e9e9;
    border-radius: 2px;
    -moz-border-radius: 2px;
    -webkit-border-radius: 2px;
}

.asc-colorpicker {
	position: absolute;
	border: 1px solid #d3d3d3;
	margin: 6px 0 0 0;
	padding: .4em .4em;
	background-color: #fff;
	z-index: 2000;
}

.asc-colorpicker .arrow {
	position: absolute;
	background-image: url(../img/popup-arrow.png);
	background-position: 0px 0px;
	width: 8px;
	height: 5px;
	left: 5px;
	top: -4px;
}

.asc-colorpicker td {
	max-width: 17px;
	height: 15px;
	padding: 3px 3px;
	border: 1px solid transparent;
}

.asc-colorpicker td.selected {
	background-color: #ccc;
	border: 1px solid #999
}

.asc-colorpicker td.highlighted {
	background-color: #f5f5f5;
	border: 1px solid #ccc;
}

.asc-colorpicker .icon {
	width: 15px;
	height: 15px;
	vertical-align: middle;
	cursor: pointer;
}

.asc-colorpicker .iwrapper {
	text-align: left;
	margin-top: .3em;
	padding-right: 4px;
}

.asc-colorpicker .iwrapper > input {
	width: 60px;
	margin: 0;
	padding: 1px;
	outline: none;
	border-collapse: collapse;
	border-style: solid;
	border-width: 1px;
	border-color: #c7c7c7;
}
.asc-colorpicker .iwrapper > input:focus {
	border-color: #3186af;
}


<|start_filename|>common/ASC.Data.Backup/Storage/IBackupStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Data.Backup.Storage
{
    internal interface IBackupStorage
    {
        string Upload(string storageBasePath, string localPath, Guid userId);

        void Download(string storagePath, string targetLocalPath);

        void Delete(string storagePath);

        bool IsExists(string storagePath);

        string GetPublicLink(string storagePath);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Test/ProjectsTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Web.Projects.Test
{
    using System;
    using System.Collections.Generic;

    using ASC.Core;

    using NUnit.Framework;

    [TestFixture]
    public class ProjectsTest : BaseTest
    {
        [Test]
        public void Project()
        {
            var newProject = GenerateProject(SecurityContext.CurrentAccount.ID);

            SaveOrUpdate(newProject);

            Assert.AreNotEqual(newProject.ID, 0);

            var result = Get(newProject);

            Assert.AreEqual(newProject.ID, result.ID);

            newProject.Title = "NewTitle";
            newProject.Private = true;

            SaveOrUpdate(newProject);

            var updatedProject = Get(newProject);

            Assert.AreEqual(updatedProject.Title, newProject.Title);
            Assert.AreEqual(updatedProject.Private, newProject.Private);

            var team = new List<Guid>(4)
            {
                Owner,
                Admin,
                UserInTeam,
                Guest
            };

            AddTeamToProject(newProject, team);

            var getTeam = GetTeam(newProject.ID);
            CollectionAssert.AreEquivalent(team, getTeam);

            Delete(newProject);
            var deletedProject = Get(newProject);

            Assert.IsNull(deletedProject);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/Core/Business/Subscriptions/BookmarkingSubscriptionManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Bookmarking.Common;
using ASC.Core;
using ASC.Notify.Recipients;
using ASC.Web.Community.Modules.Bookmarking.Core.Resources;
using ASC.Web.Core.Subscriptions;

namespace ASC.Bookmarking.Business.Subscriptions
{
    public class BookmarkingSubscriptionManager : ISubscriptionManager
    {

        public BookmarkingSubscriptionManager()
        {

        }

        #region ISubscriptionManager Members

        #region Subscription Objects
        private List<SubscriptionObject> GetNewBookmarkSubscriptionObjects(Guid productID, Guid moduleOrGroupID, Guid typeID)
        {
            return GetSubscriptionObjects(true, false);
        }

        private List<SubscriptionObject> GetNewCommentSubscriptionObjects(Guid productID, Guid moduleOrGroupID, Guid typeID)
        {
            return GetSubscriptionObjects(false, true);
        }

        private List<SubscriptionObject> GetSubscriptionObjects(bool includeBookmarks, bool includeComments)
        {
            List<SubscriptionObject> subscriptionObjects = new List<SubscriptionObject>();

            IList<string> list = new List<string>();

            var currentAccount = SecurityContext.CurrentAccount;

            if (includeBookmarks)
            {

                list = new List<string>(
                    SubscriptionProvider.GetSubscriptions(
                        BookmarkingBusinessConstants.NotifyActionNewBookmark,
                        new DirectRecipient(currentAccount.ID.ToString(), currentAccount.Name), false)
                        );
                if (list.Count > 0)
                {
                    foreach (string id in list)
                    {
                        if (!string.IsNullOrEmpty(id))
                        {
                            subscriptionObjects.Add(new SubscriptionObject()
                            {
                                ID = id,
                                Name = BookmarkingBusinessResources.SubscriptionTypeNewBookmark,
                                URL = string.Empty,
                                SubscriptionType = GetSubscriptionTypes()[0]
                            });
                        }
                    }
                }
            }

            if (includeComments)
            {

                list = new List<string>(
                    SubscriptionProvider.GetSubscriptions(
                        BookmarkingBusinessConstants.NotifyActionNewComment,
                        new DirectRecipient(currentAccount.ID.ToString(), currentAccount.Name), false)
                        );
                if (list.Count > 0)
                {
                    var service = BookmarkingService.GetCurrentInstanse();
                    foreach (string id in list)
                    {
                        if (!string.IsNullOrEmpty(id))
                        {
                            try
                            {
                                var bookmark = service.GetBookmarkByID(Int32.Parse(id));
                                subscriptionObjects.Add(new SubscriptionObject()
                                {
                                    ID = id,
                                    Name = bookmark.Name,
                                    URL = VirtualPathUtility.ToAbsolute("~/Products/Community/Modules/Bookmarking/BookmarkInfo.aspx") + "?Url=" + HttpUtility.UrlEncode(bookmark.URL),
                                    SubscriptionType = GetSubscriptionTypes()[1]
                                });
                            }
                            catch { }
                        }
                    }
                }
            }
            return subscriptionObjects;
        }



        public List<SubscriptionObject> GetSubscriptionObjects(Guid subItem)
        {
            return GetSubscriptionObjects(true, true);

        }
        #endregion

        #region Subscription Types
        public List<SubscriptionType> GetSubscriptionTypes()
        {
            var subscriptionTypes = new List<SubscriptionType>();
            subscriptionTypes.Add(new SubscriptionType()
            {
                ID = BookmarkingBusinessConstants.NotifyActionNewBookmarkID,
                NotifyAction = BookmarkingBusinessConstants.NotifyActionNewBookmark,
                Name = BookmarkingBusinessResources.SubscriptionTypeNewBookmark,
                GetSubscriptionObjects = GetNewBookmarkSubscriptionObjects,
                IsEmptySubscriptionType = IsEmptyNewBookmarkSubscriptionType,
                Single = true,
                CanSubscribe = true
            });

            subscriptionTypes.Add(new SubscriptionType()
            {
                ID = BookmarkingBusinessConstants.NotifyActionNewCommentID,
                NotifyAction = BookmarkingBusinessConstants.NotifyActionNewComment,
                Name = BookmarkingBusinessResources.SubscriptionTypeNewComments,
                GetSubscriptionObjects = GetNewCommentSubscriptionObjects,
                IsEmptySubscriptionType = IsEmptyNewCommentsSubscriptionType
            });

            return subscriptionTypes;
        }

        private bool IsEmptyNewBookmarkSubscriptionType(Guid productID, Guid moduleOrGroupID, Guid typeID)
        {
            var currentAccount = SecurityContext.CurrentAccount;
            var list = new List<string>(
                    SubscriptionProvider.GetSubscriptions(
                        BookmarkingBusinessConstants.NotifyActionNewBookmark,
                        new DirectRecipient(currentAccount.ID.ToString(), currentAccount.Name), false)
                        );
            return list.Count == 0;
        }

        private bool IsEmptyNewCommentsSubscriptionType(Guid productID, Guid moduleOrGroupID, Guid typeID)
        {
            var currentAccount = SecurityContext.CurrentAccount;
            var list = new List<string>(
                    SubscriptionProvider.GetSubscriptions(
                        BookmarkingBusinessConstants.NotifyActionNewComment,
                        new DirectRecipient(currentAccount.ID.ToString(), currentAccount.Name), false)
                        );
            return list.Count == 0;
        }
        #endregion

        public ASC.Notify.Model.ISubscriptionProvider SubscriptionProvider
        {
            get
            {
                return BookmarkingNotifySource.Instance.GetSubscriptionProvider();
            }
        }

        #endregion
    }
}


<|start_filename|>module/ASC.Files.Thirdparty/ProviderDao/ProviderTagDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Files.Core;

namespace ASC.Files.Thirdparty.ProviderDao
{
    internal class ProviderTagDao : ProviderDaoBase, ITagDao
    {
        public IEnumerable<Tag> GetTags(Guid subject, TagType tagType, IEnumerable<FileEntry> fileEntries)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetTags(subject, tagType, fileEntries);
            }
        }

        public IEnumerable<Tag> GetTags(TagType tagType, IEnumerable<FileEntry> fileEntries)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetTags(tagType, fileEntries);
            }
        }

        public IEnumerable<Tag> GetNewTags(Guid subject, Folder parentFolder, bool deepSearch)
        {
            return GetSelector(parentFolder.ID).GetTagDao(parentFolder.ID).GetNewTags(subject, parentFolder, deepSearch);
        }

        #region Only for Teamlab Documents

        public IEnumerable<Tag> GetNewTags(Guid subject, IEnumerable<FileEntry> fileEntries)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetNewTags(subject, fileEntries);
            }
        }

        public IEnumerable<Tag> GetNewTags(Guid subject, FileEntry fileEntry)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetNewTags(subject, fileEntry);
            }
        }

        public IEnumerable<Tag> GetTags(Guid owner, TagType tagType)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetTags(owner, tagType);
            }
        }

        public IEnumerable<Tag> GetTags(string name, TagType tagType)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetTags(name, tagType);
            }
        }

        public IEnumerable<Tag> GetTags(string[] names, TagType tagType)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetTags(names, tagType);
            }
        }


        public IEnumerable<Tag> SaveTags(IEnumerable<Tag> tag)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.SaveTags(tag);
            }
        }

        public IEnumerable<Tag> SaveTags(Tag tag)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.SaveTags(tag);
            }
        }

        public void UpdateNewTags(IEnumerable<Tag> tag)
        {
            using (var tagDao = TryGetTagDao())
            {
                tagDao.UpdateNewTags(tag);
            }
        }

        public void UpdateNewTags(Tag tag)
        {
            using (var tagDao = TryGetTagDao())
            {
                tagDao.UpdateNewTags(tag);
            }
        }

        public void RemoveTags(IEnumerable<Tag> tag)
        {
            using (var tagDao = TryGetTagDao())
            {
                tagDao.RemoveTags(tag);
            }
        }

        public void RemoveTags(Tag tag)
        {
            using (var tagDao = TryGetTagDao())
            {
                tagDao.RemoveTags(tag);
            }
        }

        public IEnumerable<Tag> GetTags(object entryID, FileEntryType entryType, TagType tagType)
        {
            using (var tagDao = TryGetTagDao())
            {
                return tagDao.GetTags(entryID, entryType, tagType);
            }
        }

        #endregion

        public void Dispose()
        {
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/Reassigns.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Core;
using ASC.Web.People.Resources;
using ASC.Web.Studio;
using ASC.Web.Studio.Utility;

namespace ASC.Web.People
{
    public partial class Reassigns : MainPage
    {
        protected UserInfo UserInfo { get; private set; }

        protected string PageTitle { get; private set; }

        protected string HelpLink { get; private set; }

        protected string ProfileLink { get; private set; }

        protected bool RemoveData { get; private set; }

        protected bool DeleteProfile { get; private set; }

        protected bool IsAdmin()
        {
            return WebItemSecurity.IsProductAdministrator(WebItemManager.PeopleProductID, SecurityContext.CurrentAccount.ID);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            var username = Request["user"];

            if (!IsAdmin() || string.IsNullOrEmpty(username))
            {
                Response.Redirect("~/Products/People/", true);
            }

            UserInfo = CoreContext.UserManager.GetUserByUserName(Request["user"]);

            if (UserInfo.Status != EmployeeStatus.Terminated)
            {
                Response.Redirect("~/Products/People/", true);
            }

            RemoveData = string.Equals(Request["remove"], bool.TrueString, StringComparison.InvariantCultureIgnoreCase);

            DeleteProfile = string.Equals(Request["delete"], bool.TrueString, StringComparison.InvariantCultureIgnoreCase);

            PageTitle = UserInfo.DisplayUserName(false) + " - " + (RemoveData ? PeopleResource.RemovingData : PeopleResource.ReassignmentData);

            Title = HeaderStringHelper.GetPageTitle(PageTitle);

            PageTitle = HttpUtility.HtmlEncode(PageTitle);

            HelpLink = CommonLinkUtility.GetHelpLink();

            ProfileLink = CommonLinkUtility.GetUserProfile(UserInfo.ID);

            Page.RegisterInlineScript(string.Format("ASC.People.Reassigns.init(\"{0}\", {1});", UserInfo.ID, RemoveData.ToString().ToLowerInvariant()));
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiHttpHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Net;
using System.Reflection;
using System.Security;
using System.Threading;
using System.Web;
using System.Web.Routing;

using ASC.Api.Exceptions;
using ASC.Api.Interfaces;

using Autofac;

namespace ASC.Api.Impl
{
    public class ApiHttpHandler : ApiHttpHandlerBase
    {
        #region IApiHttpHandler Members


        public ApiHttpHandler(RouteData routeData)
            : base(routeData)
        {

        }

        protected override void DoProcess(HttpContextBase context)
        {
            Log.DebugFormat("strating request. context: '{0}'", ApiContext);

            //Neeeded to rollback errors
            context.Response.Buffer = true;
            context.Response.BufferOutput = true;

            IApiEntryPoint instance = null;

            try
            {
                Log.Debug("method invoke");
                ApiResponce.Count = ApiContext.Count;
                ApiResponce.StartIndex = ApiContext.StartIndex;

                if (Method != null)
                {
                    if (!string.IsNullOrEmpty(Method.Name))
                    {
                        instance = Container.ResolveNamed<IApiEntryPoint>(Method.Name, new TypedParameter(typeof(ApiContext), ApiContext));
                    }
                    else
                    {
                        instance = Container.Resolve<IApiEntryPoint>();
                    }

                    var responce = ApiManager.InvokeMethod(Method, ApiContext, instance);
                    if (responce is Exception)
                    {
                        SetError(context, (Exception)responce, HttpStatusCode.InternalServerError);
                    }
                    else
                    {
                        // success
                        PostProcessResponse(context, responce);
                    }
                }
                else
                {
                    SetError(context, new MissingMethodException("Method not found"), HttpStatusCode.NotFound);
                }
            }
            catch (TargetInvocationException targetInvocationException)
            {
                if (targetInvocationException.InnerException is ItemNotFoundException)
                {
                    SetError(context, targetInvocationException.InnerException, HttpStatusCode.NotFound, "The record could not be found");
                }
                else if (targetInvocationException.InnerException is ArgumentException)
                {
                    SetError(context, targetInvocationException.InnerException, HttpStatusCode.BadRequest, "Invalid arguments");
                }
                else if (targetInvocationException.InnerException is SecurityException)
                {
                    SetError(context, targetInvocationException.InnerException, HttpStatusCode.Forbidden, "Access denied");
                }
                else if (targetInvocationException.InnerException is InvalidOperationException)
                {
                    SetError(context, targetInvocationException.InnerException, HttpStatusCode.Forbidden);
                }
                else
                {
                    SetError(context, targetInvocationException.InnerException, HttpStatusCode.InternalServerError);
                }
            }
            catch (ApiArgumentMismatchException e)
            {
                SetError(context, e, HttpStatusCode.BadRequest, "Invalid arguments");
            }
            catch (Exception e)
            {
                SetError(context, e, HttpStatusCode.InternalServerError);
            }

            Exception responseError;
            try
            {
                RespondTo(Method, context);
                return;
            }
            catch (ThreadAbortException e)
            {
                //Do nothing. someone killing response
                Log.Error("thread aborted. response not sent", e);
                return;
            }
            catch (HttpException exception)
            {
                responseError = exception;
                SetError(context, exception, (HttpStatusCode)exception.GetHttpCode());//Set the code of throwed exception
            }
            catch (Exception exception)
            {
                responseError = exception;
                SetError(context, exception, HttpStatusCode.InternalServerError);
            }
            Log.Error("error happened while sending response. can't be here", responseError);
            RespondTo(Method, context);//If we got there then something went wrong
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/HttpHandlers/HttpPollHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Web;

namespace ASC.Web.Talk.HttpHandlers
{
    public class HttpPollHandler : HttpTaskAsyncHandler
    {
        private static readonly Uri boshUri = new Uri(VirtualPathUtility.AppendTrailingSlash(ConfigurationManagerExtension.AppSettings["BoshPath"] ?? "http://localhost:5280/http-poll/"));

        private void CopyStream(Stream from, Stream to)
        {
            var buffer = new byte[1024];
            while (true)
            {
                var read = from.Read(buffer, 0, buffer.Length);
                if (read == 0) break;

                to.Write(buffer, 0, read);
            }
        }

        public override async System.Threading.Tasks.Task ProcessRequestAsync(HttpContext context)
        {
            var request = (HttpWebRequest)WebRequest.Create(boshUri);
            request.Method = context.Request.HttpMethod;

            request.UserAgent = context.Request.UserAgent;
            request.Accept = string.Join(",", context.Request.AcceptTypes);
            if (!string.IsNullOrEmpty(context.Request.Headers["Accept-Encoding"]))
            {
                request.Headers["Accept-Encoding"] = context.Request.Headers["Accept-Encoding"];
            }
            request.ContentType = context.Request.ContentType;
            request.ContentLength = context.Request.ContentLength;

            using (var stream = await request.GetRequestStreamAsync())
            using (var writer = new StreamWriter(stream))
            {
                CopyStream(context.Request.InputStream, stream);

                writer.Flush();
                writer.Dispose();
            }

            using (var response = await request.GetResponseAsync())
            {
                context.Response.ContentType = response.ContentType;

                // copy headers & body
                foreach (string h in response.Headers)
                {
                    context.Response.AppendHeader(h, response.Headers[h]);
                }

                using (var respStream = response.GetResponseStream())
                {
                    CopyStream(respStream, context.Response.OutputStream);
                }
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Wiki.Master.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using AjaxPro;

using ASC.Core;
using ASC.Notify.Recipients;
using ASC.Web.Community.Wiki.Common;
using ASC.Web.Studio.Core;

using WikiNotifySource = ASC.Web.UserControls.Wiki.WikiNotifySource;

namespace ASC.Web.Community.Wiki
{
    [Flags]
    public enum WikiNavigationActionVisible
    {
        None = 0x000,
        AddNewPage = 0x001,
        UploadFile = 0x002,
        EditThePage = 0x004,
        ShowVersions = 0x008,
        PrintPage = 0x010,
        DeleteThePage = 0x020,
        SubscriptionOnNewPage = 0x040,
        SubscriptionThePage = 0x080,
        SubscriptionOnCategory = 0x100,
        CreateThePage = 0x200
    }

    [AjaxNamespace("MainWikiAjaxMaster")]
    public partial class WikiMaster : System.Web.UI.MasterPage
    {
        public delegate string GetDelUniqIdHandle();

        public event GetDelUniqIdHandle GetDelUniqId;

        public delegate WikiNavigationActionVisible GetNavigateActionsVisibleHandle();

        private static IDirectRecipient IAmAsRecipient
        {
            get { return (IDirectRecipient)WikiNotifySource.Instance.GetRecipientsProvider().GetRecipient(SecurityContext.CurrentAccount.ID.ToString()); }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterStyle("~/Products/Community/Modules/Wiki/App_Themes/default/css/wikicss.css");
            Utility.RegisterTypeForAjax(GetType(), Page);
        }

        public void PrintInfoMessage(string info, InfoType infoType)
        {
            MainWikiContainer.Options.InfoMessageText = info;
            MainWikiContainer.Options.InfoType = infoType;
        }

        protected string MasterResolveUrlLC(string url)
        {
            return this.ResolveUrlLC(url);
        }

        public string GetDeleteUniqueId()
        {
            if (GetDelUniqId == null)
                return string.Empty;

            return GetDelUniqId();
        }

        public string CurrentPageCaption
        {
            get { return MainWikiContainer.CurrentPageCaption; }
            set { MainWikiContainer.CurrentPageCaption = value; }
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public bool SubscribeOnEditPage(bool isSubscribe, string pageName)
        {
            pageName = HttpUtility.HtmlDecode(pageName);
            var subscriptionProvider = WikiNotifySource.Instance.GetSubscriptionProvider();
            if (IAmAsRecipient == null)
            {
                return false;
            }
            if (!isSubscribe)
            {

                subscriptionProvider.Subscribe(
                    Constants.EditPage,
                    pageName,
                    IAmAsRecipient
                    );
                return true;
            }
            else
            {
                subscriptionProvider.UnSubscribe(
                    Constants.EditPage,
                    pageName,
                    IAmAsRecipient
                    );
                return false;
            }
        }

    }
}

<|start_filename|>module/ASC.Files.Thirdparty/GoogleDrive/GoogleDriveStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security;
using System.Text;
using System.Web;

using ASC.Common;
using ASC.FederatedLogin;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Core;

using Google;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Drive.v3;
using Google.Apis.Services;

using Newtonsoft.Json.Linq;

using DriveFile = Google.Apis.Drive.v3.Data.File;
using MimeMapping = ASC.Common.Web.MimeMapping;

namespace ASC.Files.Thirdparty.GoogleDrive
{
    internal class GoogleDriveStorage
    {
        private OAuth20Token _token;

        private string AccessToken
        {
            get
            {
                if (_token == null) throw new Exception("Cannot create GoogleDrive session with given token");
                if (_token.IsExpired) _token = OAuth20TokenHelper.RefreshToken<GoogleLoginProvider>(_token);
                return _token.AccessToken;
            }
        }

        private DriveService _driveService;

        public bool IsOpened { get; private set; }

        public const long MaxChunkedUploadFileSize = 2L * 1024L * 1024L * 1024L;

        public void Open(OAuth20Token token)
        {
            if (IsOpened)
                return;

            if (token == null) throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token");
            _token = token;

            var tokenResponse = new TokenResponse
            {
                AccessToken = _token.AccessToken,
                RefreshToken = _token.RefreshToken,
                IssuedUtc = _token.Timestamp,
                ExpiresInSeconds = _token.ExpiresIn,
                TokenType = "Bearer"
            };

            var apiCodeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
            {
                ClientSecrets = new ClientSecrets
                {
                    ClientId = _token.ClientID,
                    ClientSecret = _token.ClientSecret
                },
                Scopes = new[] { DriveService.Scope.Drive }
            });

            _driveService = new DriveService(new BaseClientService.Initializer
            {
                HttpClientInitializer = new UserCredential(apiCodeFlow, string.Empty, tokenResponse)
            });

            IsOpened = true;
        }

        public void Close()
        {
            _driveService.Dispose();

            IsOpened = false;
        }


        public string GetRootFolderId()
        {
            var rootFolder = _driveService.Files.Get("root").Execute();

            return rootFolder.Id;
        }

        public DriveFile GetEntry(string entryId)
        {
            try
            {
                var request = _driveService.Files.Get(entryId);

                request.Fields = GoogleLoginProvider.FilesFields;

                return request.Execute();
            }
            catch (GoogleApiException ex)
            {
                if (ex.HttpStatusCode == HttpStatusCode.NotFound)
                {
                    return null;
                }
                throw;
            }
        }

        public List<DriveFile> GetEntries(string folderId, bool? folders = null)
        {
            var request = _driveService.Files.List();

            var query = "'" + folderId + "' in parents and trashed=false";

            if (folders.HasValue)
            {
                query += " and mimeType " + (folders.Value ? "" : "!") + "= '" + GoogleLoginProvider.GoogleDriveMimeTypeFolder + "'";
            }

            request.Q = query;

            request.Fields = "nextPageToken, files(" + GoogleLoginProvider.FilesFields + ")";

            var files = new List<DriveFile>();
            do
            {
                try
                {
                    var fileList = request.Execute();

                    files.AddRange(fileList.Files);

                    request.PageToken = fileList.NextPageToken;
                }
                catch (Exception)
                {
                    request.PageToken = null;
                }
            } while (!String.IsNullOrEmpty(request.PageToken));

            return files;
        }

        public Stream DownloadStream(DriveFile file, int offset = 0)
        {
            if (file == null) throw new ArgumentNullException("file");

            var downloadArg = string.Format("{0}?alt=media", file.Id);

            var ext = MimeMapping.GetExtention(file.MimeType);
            if (GoogleLoginProvider.GoogleDriveExt.Contains(ext))
            {
                var internalExt = FileUtility.GetGoogleDownloadableExtension(ext);
                var requiredMimeType = MimeMapping.GetMimeMapping(internalExt);

                downloadArg = string.Format("{0}/export?mimeType={1}",
                                            file.Id,
                                            HttpUtility.UrlEncode(requiredMimeType));
            }

            var request = WebRequest.Create(GoogleLoginProvider.GoogleUrlFile + downloadArg);
            request.Method = "GET";
            request.Headers.Add("Authorization", "Bearer " + AccessToken);

            var response = (HttpWebResponse)request.GetResponse();

            if (offset == 0 && file.Size.HasValue && file.Size > 0)
            {
                return new ResponseStream(response.GetResponseStream(), file.Size.Value);
            }

            var tempBuffer = TempStream.Create();
            using (var str = response.GetResponseStream())
            {
                if (str != null)
                {
                    str.CopyTo(tempBuffer);
                    tempBuffer.Flush();
                    tempBuffer.Seek(offset, SeekOrigin.Begin);
                }
            }

            return tempBuffer;
        }

        public DriveFile InsertEntry(Stream fileStream, string title, string parentId, bool folder = false)
        {
            var mimeType = folder ? GoogleLoginProvider.GoogleDriveMimeTypeFolder : MimeMapping.GetMimeMapping(title);

            var body = FileConstructor(title, mimeType, parentId);

            if (folder)
            {
                var requestFolder = _driveService.Files.Create(body);
                requestFolder.Fields = GoogleLoginProvider.FilesFields;
                return requestFolder.Execute();
            }

            var request = _driveService.Files.Create(body, fileStream, mimeType);
            request.Fields = GoogleLoginProvider.FilesFields;

            var result = request.Upload();
            if (result.Exception != null)
            {
                if (request.ResponseBody == null) throw result.Exception;
                Global.Logger.Error("Error while trying to insert entity. GoogleDrive insert returned an error.", result.Exception);
            }
            return request.ResponseBody;
        }

        public void DeleteEntry(string entryId)
        {
            _driveService.Files.Delete(entryId).Execute();
        }

        public DriveFile InsertEntryIntoFolder(DriveFile entry, string folderId)
        {
            var request = _driveService.Files.Update(FileConstructor(), entry.Id);
            request.AddParents = folderId;
            request.Fields = GoogleLoginProvider.FilesFields;
            return request.Execute();
        }

        public DriveFile RemoveEntryFromFolder(DriveFile entry, string folderId)
        {
            var request = _driveService.Files.Update(FileConstructor(), entry.Id);
            request.RemoveParents = folderId;
            request.Fields = GoogleLoginProvider.FilesFields;
            return request.Execute();
        }

        public DriveFile CopyEntry(string toFolderId, string originEntryId)
        {
            var body = FileConstructor(folderId: toFolderId);
            try
            {
                var request = _driveService.Files.Copy(body, originEntryId);
                request.Fields = GoogleLoginProvider.FilesFields;
                return request.Execute();
            }
            catch (GoogleApiException ex)
            {
                if (ex.HttpStatusCode == HttpStatusCode.Forbidden)
                {
                    throw new SecurityException(ex.Error.Message);
                }
                throw;
            }
        }

        public DriveFile RenameEntry(string fileId, string newTitle)
        {
            var request = _driveService.Files.Update(FileConstructor(newTitle), fileId);
            request.Fields = GoogleLoginProvider.FilesFields;
            return request.Execute();
        }

        public DriveFile SaveStream(string fileId, Stream fileStream, string fileTitle)
        {
            var mimeType = MimeMapping.GetMimeMapping(fileTitle);
            var file = FileConstructor(fileTitle, mimeType);

            var request = _driveService.Files.Update(file, fileId, fileStream, mimeType);
            request.Fields = GoogleLoginProvider.FilesFields;
            var result = request.Upload();
            if (result.Exception != null)
            {
                if (request.ResponseBody == null) throw result.Exception;
                Global.Logger.Error("Error while trying to insert entity. GoogleDrive save returned an error.", result.Exception);
            }

            return request.ResponseBody;
        }

        public DriveFile FileConstructor(string title = null, string mimeType = null, string folderId = null)
        {
            var file = new DriveFile();

            if (!string.IsNullOrEmpty(title)) file.Name = title;
            if (!string.IsNullOrEmpty(mimeType)) file.MimeType = mimeType;
            if (!String.IsNullOrEmpty(folderId)) file.Parents = new List<string> { folderId };

            return file;
        }

        public ResumableUploadSession CreateResumableSession(DriveFile driveFile, long contentLength)
        {
            if (driveFile == null) throw new ArgumentNullException("driveFile");

            var fileId = string.Empty;
            var method = "POST";
            var body = string.Empty;
            var folderId = driveFile.Parents.FirstOrDefault();

            if (driveFile.Id != null)
            {
                fileId = "/" + driveFile.Id;
                method = "PATCH";
            }
            else
            {
                var titleData = !string.IsNullOrEmpty(driveFile.Name) ? string.Format("\"name\":\"{0}\"", driveFile.Name) : "";
                var parentData = !string.IsNullOrEmpty(folderId) ? string.Format(",\"parents\":[\"{0}\"]", folderId) : "";

                body = !string.IsNullOrEmpty(titleData + parentData) ? string.Format("{{{0}{1}}}", titleData, parentData) : "";
            }

            var request = WebRequest.Create(GoogleLoginProvider.GoogleUrlFileUpload + fileId + "?uploadType=resumable");
            request.Method = method;

            var bytes = Encoding.UTF8.GetBytes(body);
            request.ContentLength = bytes.Length;
            request.ContentType = "application/json; charset=UTF-8";
            request.Headers.Add("X-Upload-Content-Type", MimeMapping.GetMimeMapping(driveFile.Name));
            request.Headers.Add("X-Upload-Content-Length", contentLength.ToString(CultureInfo.InvariantCulture));
            request.Headers.Add("Authorization", "Bearer " + AccessToken);

            request.GetRequestStream().Write(bytes, 0, bytes.Length);

            var uploadSession = new ResumableUploadSession(driveFile.Id, folderId, contentLength);
            using (var response = request.GetResponse())
            {
                uploadSession.Location = response.Headers["Location"];
            }
            uploadSession.Status = ResumableUploadSessionStatus.Started;

            return uploadSession;
        }

        public void Transfer(ResumableUploadSession googleDriveSession, Stream stream, long chunkLength)
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            if (googleDriveSession.Status != ResumableUploadSessionStatus.Started)
                throw new InvalidOperationException("Can't upload chunk for given upload session.");

            var request = WebRequest.Create(googleDriveSession.Location);
            request.Method = "PUT";
            request.ContentLength = chunkLength;
            request.Headers.Add("Authorization", "Bearer " + AccessToken);
            request.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}",
                                                               googleDriveSession.BytesTransfered,
                                                               googleDriveSession.BytesTransfered + chunkLength - 1,
                                                               googleDriveSession.BytesToTransfer));

            using (var requestStream = request.GetRequestStream())
            {
                stream.CopyTo(requestStream);
            }

            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException exception)
            {
                if (exception.Status == WebExceptionStatus.ProtocolError || exception.Status == WebExceptionStatus.UnknownError) //Status is UnknownError (unix)
                {
                    if (exception.Response != null && exception.Response.Headers.AllKeys.Contains("Range"))
                    {
                        response = (HttpWebResponse)exception.Response;
                    }
                    else if (exception.Message.Equals("Invalid status code: 308", StringComparison.InvariantCulture)) //response is null (unix)
                    {
                        response = null;
                    }
                    else
                    {
                        throw;
                    }
                }
                else
                {
                    throw;
                }
            }

            if (response == null || response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.OK)
            {
                var uplSession = googleDriveSession;
                uplSession.BytesTransfered += chunkLength;

                if (response != null)
                {
                    var locationHeader = response.Headers["Location"];
                    if (!string.IsNullOrEmpty(locationHeader))
                    {
                        uplSession.Location = locationHeader;
                    }
                }
            }
            else
            {
                googleDriveSession.Status = ResumableUploadSessionStatus.Completed;

                using (var responseStream = response.GetResponseStream())
                {
                    if (responseStream == null) return;
                    string responseString;
                    using (var readStream = new StreamReader(responseStream))
                    {
                        responseString = readStream.ReadToEnd();
                    }
                    var responseJson = JObject.Parse(responseString);

                    googleDriveSession.FileId = responseJson.Value<string>("id");
                }
            }

            if (response != null)
            {
                response.Close();
            }
        }

        public long GetMaxUploadSize()
        {
            var request = _driveService.About.Get();
            request.Fields = "maxUploadSize";
            var about = request.Execute();

            return about.MaxUploadSize.HasValue ? about.MaxUploadSize.Value : MaxChunkedUploadFileSize;
        }
    }

    public enum ResumableUploadSessionStatus
    {
        None,
        Started,
        Completed,
        Aborted
    }

    [Serializable]
    internal class ResumableUploadSession
    {
        public long BytesToTransfer { get; set; }

        public long BytesTransfered { get; set; }

        public string FileId { get; set; }

        public string FolderId { get; set; }

        public ResumableUploadSessionStatus Status { get; set; }

        public string Location { get; set; }

        public ResumableUploadSession(string fileId, string folderId, long bytesToTransfer)
        {
            FileId = fileId;
            FolderId = folderId;
            BytesToTransfer = bytesToTransfer;
            Status = ResumableUploadSessionStatus.None;
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Specific/AuthorizationApi/AuthenticationEntryPoint.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.Security;
using System.Security.Authentication;
using System.Threading;
using System.Web;

using ASC.ActiveDirectory;
using ASC.ActiveDirectory.Base.Settings;
using ASC.ActiveDirectory.ComplexOperations;
using ASC.Api.Attributes;
using ASC.Api.Interfaces;
using ASC.Api.Utils;
using ASC.Common.Caching;
using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.FederatedLogin.LoginProviders;
using ASC.IPSecurity;
using ASC.MessagingSystem;
using ASC.Security.Cryptography;
using ASC.Web.Core.Sms;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Core.SMS;
using ASC.Web.Studio.Core.TFA;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Common;
using ASC.Web.Studio.Utility;

using Constants = ASC.Core.Configuration.Constants;
using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Specific.AuthorizationApi
{
    /// <summary>
    /// Authorization for api
    /// </summary>
    public class AuthenticationEntryPoint : IApiEntryPoint
    {
        private static readonly ICache Cache = AscCache.Memory;


        /// <summary>
        /// Entry point name
        /// </summary>
        public string Name
        {
            get { return "authentication"; }
        }

        private static HttpRequest Request
        {
            get { return HttpContext.Current.Request; }
        }

        /// <summary>
        /// Gets authentication token for use in api authorization
        /// </summary>
        /// <short>
        /// Get token
        /// </short>
        /// <param name="userName">user name or email</param>
        /// <param name="password">password</param>
        /// <param name="provider">social media provider type</param>
        /// <param name="accessToken">provider token</param>
        /// <returns>tokent to use in 'Authorization' header when calling API methods</returns>
        /// <exception cref="AuthenticationException">Thrown when not authenticated</exception>
        [Create(@"", false, false)] //NOTE: this method doesn't requires auth!!!  //NOTE: this method doesn't check payment!!!
        public AuthenticationTokenData AuthenticateMe(string userName, string password, string provider, string accessToken)
        {
            bool viaEmail;
            var user = GetUser(userName, password, provider, accessToken, out viaEmail);

            if (StudioSmsNotificationSettings.IsVisibleSettings && StudioSmsNotificationSettings.Enable)
            {
                if (string.IsNullOrEmpty(user.MobilePhone) || user.MobilePhoneActivationStatus == MobilePhoneActivationStatus.NotActivated)
                    return new AuthenticationTokenData
                    {
                        Sms = true
                    };

                SmsManager.PutAuthCode(user, false);

                return new AuthenticationTokenData
                {
                    Sms = true,
                    PhoneNoise = SmsSender.BuildPhoneNoise(user.MobilePhone),
                    Expires = new ApiDateTime(DateTime.UtcNow.Add(SmsKeyStorage.StoreInterval))
                };
            }

            if (TfaAppAuthSettings.IsVisibleSettings && TfaAppAuthSettings.Enable)
            {
                if (!TfaAppUserSettings.EnableForUser(user.ID))
                    return new AuthenticationTokenData
                    {
                        Tfa = true,
                        TfaKey = user.GenerateSetupCode().ManualEntryKey
                    };

                return new AuthenticationTokenData
                {
                    Tfa = true
                };
            }

            try
            {
                var token = SecurityContext.AuthenticateMe(user.ID);

                MessageService.Send(Request, viaEmail ? MessageAction.LoginSuccessViaApi : MessageAction.LoginSuccessViaApiSocialAccount);

                var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;
                var expires = TenantCookieSettings.GetExpiresTime(tenant);

                return new AuthenticationTokenData
                {
                    Token = token,
                    Expires = new ApiDateTime(expires)
                };
            }
            catch
            {
                MessageService.Send(Request, user.DisplayUserName(false), viaEmail ? MessageAction.LoginFailViaApi : MessageAction.LoginFailViaApiSocialAccount);
                throw new AuthenticationException("User authentication failed");
            }
            finally
            {
                SecurityContext.Logout();
            }
        }

        /// <summary>
        /// Set mobile phone for user
        /// </summary>
        /// <param name="userName">user name or email</param>
        /// <param name="password">password</param>
        /// <param name="provider">social media provider type</param>
        /// <param name="accessToken">provider token</param>
        /// <param name="mobilePhone">new mobile phone</param>
        /// <returns>mobile phone</returns>
        [Create(@"setphone", false, false)] //NOTE: this method doesn't requires auth!!!  //NOTE: this method doesn't check payment!!!
        public AuthenticationTokenData SaveMobilePhone(string userName, string password, string provider, string accessToken, string mobilePhone)
        {
            bool viaEmail;
            var user = GetUser(userName, password, provider, accessToken, out viaEmail);
            mobilePhone = SmsManager.SaveMobilePhone(user, mobilePhone);
            MessageService.Send(HttpContext.Current.Request, MessageAction.UserUpdatedMobileNumber, MessageTarget.Create(user.ID), user.DisplayUserName(false), mobilePhone);

            return new AuthenticationTokenData
            {
                Sms = true,
                PhoneNoise = SmsSender.BuildPhoneNoise(mobilePhone),
                Expires = new ApiDateTime(DateTime.UtcNow.Add(SmsKeyStorage.StoreInterval))
            };
        }

        /// <summary>
        /// Send sms code again
        /// </summary>
        /// <param name="userName">user name or email</param>
        /// <param name="password">password</param>
        /// <param name="provider">social media provider type</param>
        /// <param name="accessToken">provider token</param>
        /// <returns>mobile phone</returns>
        [Create(@"sendsms", false, false)] //NOTE: this method doesn't requires auth!!!  //NOTE: this method doesn't check payment!!!
        public AuthenticationTokenData SendSmsCode(string userName, string password, string provider, string accessToken)
        {
            bool viaEmail;
            var user = GetUser(userName, password, provider, accessToken, out viaEmail);
            SmsManager.PutAuthCode(user, true);

            return new AuthenticationTokenData
            {
                Sms = true,
                PhoneNoise = SmsSender.BuildPhoneNoise(user.MobilePhone),
                Expires = new ApiDateTime(DateTime.UtcNow.Add(SmsKeyStorage.StoreInterval))
            };
        }

        /// <summary>
        /// Gets two-factor authentication token for use in api authorization
        /// </summary>
        /// <short>
        /// Get token
        /// </short>
        /// <param name="userName">user name or email</param>
        /// <param name="password">password</param>
        /// <param name="provider">social media provider type</param>
        /// <param name="accessToken">provider token</param>
        /// <param name="code">two-factor authentication code</param>
        /// <returns>tokent to use in 'Authorization' header when calling API methods</returns>
        [Create(@"{code}", false, false)] //NOTE: this method doesn't requires auth!!!  //NOTE: this method doesn't check payment!!!
        public AuthenticationTokenData AuthenticateMe(string userName, string password, string provider, string accessToken, string code)
        {
            bool viaEmail;
            var user = GetUser(userName, password, provider, accessToken, out viaEmail);

            var sms = false;
            try
            {
                if (StudioSmsNotificationSettings.IsVisibleSettings && StudioSmsNotificationSettings.Enable)
                {
                    sms = true;
                    SmsManager.ValidateSmsCode(user, code);
                }
                else if (TfaAppAuthSettings.IsVisibleSettings && TfaAppAuthSettings.Enable)
                {
                    if (user.ValidateAuthCode(code))
                    {
                        MessageService.Send(HttpContext.Current.Request, MessageAction.UserConnectedTfaApp, MessageTarget.Create(user.ID));
                    }
                }
                else
                {
                    throw new SecurityException("Auth code is not available");
                }

                var token = SecurityContext.AuthenticateMe(user.ID);

                MessageService.Send(Request, sms ? MessageAction.LoginSuccessViaApiSms : MessageAction.LoginSuccessViaApiTfa);

                var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;
                var expires = TenantCookieSettings.GetExpiresTime(tenant);

                var result = new AuthenticationTokenData
                {
                    Token = <PASSWORD>,
                    Expires = new ApiDateTime(expires)
                };

                if (sms)
                {
                    result.Sms = true;
                    result.PhoneNoise = SmsSender.BuildPhoneNoise(user.MobilePhone);
                }
                else
                {
                    result.Tfa = true;
                }

                return result;
            }
            catch
            {
                MessageService.Send(Request, user.DisplayUserName(false), sms
                                                                              ? MessageAction.LoginFailViaApiSms
                                                                              : MessageAction.LoginFailViaApiTfa,
                                    MessageTarget.Create(user.ID));
                throw new AuthenticationException("User authentication failed");
            }
            finally
            {
                SecurityContext.Logout();
            }
        }

        /// <summary>
        /// Request of invitation by email on personal.onlyoffice.com
        /// </summary>
        /// <param name="email">Email address</param>
        /// <param name="lang">Culture</param>
        /// <param name="spam">User consent to subscribe to the ONLYOFFICE newsletter</param>
        /// <param name="recaptchaResponse">recaptcha token</param>
        /// <visible>false</visible>
        [Create(@"register", false)] //NOTE: this method doesn't requires auth!!!
        public string RegisterUserOnPersonal(string email, string lang, bool spam, string recaptchaResponse)
        {
            if (!CoreContext.Configuration.Personal) throw new MethodAccessException("Method is only available on personal.onlyoffice.com");

            try
            {
                if (CoreContext.Configuration.CustomMode) lang = "ru-RU";

                var cultureInfo = SetupInfo.GetPersonalCulture(lang).Value;

                if (cultureInfo != null)
                {
                    Thread.CurrentThread.CurrentUICulture = cultureInfo;
                }

                email.ThrowIfNull(new ArgumentException(Resource.ErrorEmailEmpty, "email"));

                if (!email.TestEmailRegex()) throw new ArgumentException(Resource.ErrorNotCorrectEmail, "email");

                if (!SetupInfo.IsSecretEmail(email)
                    && !string.IsNullOrEmpty(SetupInfo.RecaptchaPublicKey) && !string.IsNullOrEmpty(SetupInfo.RecaptchaPrivateKey))
                {
                    var ip = Request.Headers["X-Forwarded-For"] ?? Request.UserHostAddress;

                    if (String.IsNullOrEmpty(recaptchaResponse)
                        || !Authorize.ValidateRecaptcha(recaptchaResponse, ip))
                    {
                        throw new Authorize.RecaptchaException(Resource.RecaptchaInvalid);
                    }
                }

                var newUserInfo = CoreContext.UserManager.GetUserByEmail(email);

                if (CoreContext.UserManager.UserExists(newUserInfo.ID))
                {
                    if (!SetupInfo.IsSecretEmail(email) || SecurityContext.IsAuthenticated)
                    {
                        throw new Exception(CustomNamingPeople.Substitute<Resource>("ErrorEmailAlreadyExists"));
                    }

                    try
                    {
                        SecurityContext.AuthenticateMe(Constants.CoreSystem);
                        CoreContext.UserManager.DeleteUser(newUserInfo.ID);
                    }
                    finally
                    {
                        SecurityContext.Logout();
                    }
                }
                if (!spam)
                {
                    try
                    {
                        const string _databaseID = "com";
                        using (var db = DbManager.FromHttpContext(_databaseID))
                        {
                            db.ExecuteNonQuery(new SqlInsert("template_unsubscribe", false)
                                                   .InColumnValue("email", email.ToLowerInvariant())
                                                   .InColumnValue("reason", "personal")
                                );
                            LogManager.GetLogger("ASC.Web").Debug(String.Format("Write to template_unsubscribe {0}", email.ToLowerInvariant()));
                        }
                    }
                    catch (Exception ex)
                    {
                        LogManager.GetLogger("ASC.Web").Debug(String.Format("ERROR write to template_unsubscribe {0}, email:{1}", ex.Message, email.ToLowerInvariant()));
                    }
                }
                StudioNotifyService.Instance.SendInvitePersonal(email);
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
            return string.Empty;
        }

        /// <summary>
        /// Check userName and password
        /// </summary>
        /// <param name="userName">user name or email</param>
        /// <param name="password">password</param>
        /// <param name="key"></param>
        /// <exception cref="AuthenticationException">Thrown when not authenticated</exception>
        /// <visible>false</visible>
        [Create(@"login", false, false)] //NOTE: this method doesn't requires auth!!!  //NOTE: this method doesn't check payment!!!
        public bool AuthenticateMe(string userName, string password, string key)
        {
            var authInterval = TimeSpan.FromMinutes(5);
            var checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(userName + password + ConfirmType.Auth, key, authInterval);
            if (checkKeyResult != EmailValidationKeyProvider.ValidationResult.Ok) throw new SecurityException("Access Denied.");

            bool viaEmail;
            var user = GetUser(userName, password, null, null, out viaEmail);
            return user != null;
        }

        private static UserInfo GetUser(string userName, string password, string provider, string accessToken, out bool viaEmail)
        {
            viaEmail = true;
            var action = MessageAction.LoginFailViaApi;
            UserInfo user = null;
            try
            {
                if (string.IsNullOrEmpty(provider) || provider == "email")
                {
                    userName.ThrowIfNull(new ArgumentException(@"userName empty", "userName"));
                    password.ThrowIfNull(new ArgumentException(@"password empty", "password"));

                    int counter;
                    int.TryParse(Cache.Get<String>("loginsec/" + userName), out counter);
                    if (++counter > SetupInfo.LoginThreshold && !SetupInfo.IsSecretEmail(userName))
                    {
                        throw new Authorize.BruteForceCredentialException();
                    }
                    Cache.Insert("loginsec/" + userName, counter.ToString(CultureInfo.InvariantCulture), DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)));

                    if (EnableLdap)
                    {
                        var localization = new LdapLocalization(Resource.ResourceManager);
                        var ldapUserManager = new LdapUserManager(localization);

                        ldapUserManager.TryGetAndSyncLdapUserInfo(userName, password, out user);
                    }

                    if (user == null || !CoreContext.UserManager.UserExists(user.ID))
                    {
                        var passwordHash = PasswordHasher.GetClientPassword(password);
                        user = CoreContext.UserManager.GetUsersByPasswordHash(
                            CoreContext.TenantManager.GetCurrentTenant().TenantId,
                            userName,
                            passwordHash);
                    }

                    if (user == null || !CoreContext.UserManager.UserExists(user.ID))
                    {
                        throw new Exception("user not found");
                    }

                    Cache.Insert("loginsec/" + userName, (--counter).ToString(CultureInfo.InvariantCulture), DateTime.UtcNow.Add(TimeSpan.FromMinutes(1)));
                }
                else
                {
                    viaEmail = false;

                    action = MessageAction.LoginFailViaApiSocialAccount;
                    var thirdPartyProfile = ProviderManager.GetLoginProfile(provider, accessToken);
                    userName = thirdPartyProfile.EMail;

                    user = LoginWithThirdParty.GetUserByThirdParty(thirdPartyProfile);
                }
            }
            catch (Authorize.BruteForceCredentialException)
            {
                MessageService.Send(Request, !string.IsNullOrEmpty(userName) ? userName : AuditResource.EmailNotSpecified, MessageAction.LoginFailBruteForce);
                throw new AuthenticationException("Login Fail. Too many attempts");
            }
            catch
            {
                MessageService.Send(Request, !string.IsNullOrEmpty(userName) ? userName : AuditResource.EmailNotSpecified, action);
                throw new AuthenticationException("User authentication failed");
            }

            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            var settings = IPRestrictionsSettings.Load();
            if (settings.Enable && user.ID != tenant.OwnerId && !IPSecurity.IPSecurity.Verify(tenant))
            {
                throw new IPSecurityException();
            }

            return user;
        }

        protected static bool EnableLdap
        {
            get
            {
                if (!SetupInfo.IsVisibleSettings(ManagementType.LdapSettings.ToString()) ||
                    (CoreContext.Configuration.Standalone &&
                        !CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Ldap))
                {
                    return false;
                }

                var enabled = LdapSettings.Load().EnableLdapAuthentication;

                return enabled;
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/Serializers/SerializerContractResolver.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Utils;

using Newtonsoft.Json.Serialization;

namespace ASC.Api.Impl.Serializers
{
    internal class SerializerContractResolver : CamelCasePropertyNamesContractResolver
    {
        private readonly Type _responseType;
        private readonly HashSet<string> _filterToFields;

        public SerializerContractResolver(object response, ApiContext context)
        {
            if (response != null)
            {
                //Try resolve context
                try
                {
                    if (context != null && context.Fields != null && context.Fields.Any())
                    {
                        //Get type
                        _filterToFields = new HashSet<string>(context.Fields, new StringIgnoreCaseComparer());
                        _responseType = response.GetType();
                        if (Binder.IsCollection(_responseType))
                        {
                            //Get collection type
                            _responseType = Binder.GetCollectionType(_responseType);
                        }
                    }
                }
                catch
                {

                }
            }
        }

        private struct FieldsResolverKey : IEquatable<FieldsResolverKey>
        {
            private readonly Type _contractType;
            private readonly string _fields;

            public FieldsResolverKey(Type contractType, IEnumerable<string> fields)
            {
                _contractType = contractType;
                _fields = string.Join(",", fields.Select(x => x.Trim().ToLowerInvariant()).OrderBy(x => x).ToArray());
            }

            public override bool Equals(object obj)
            {
                return base.Equals(obj);
            }

            public bool Equals(FieldsResolverKey other)
            {
                return other._contractType == _contractType && Equals(other._fields, _fields);
            }

            public override int GetHashCode()
            {
                unchecked
                {
                    return ((_contractType != null ? _contractType.GetHashCode() : 0) * 397) ^ (_fields != null ? _fields.GetHashCode() : 0);
                }
            }

            public static bool operator ==(FieldsResolverKey left, FieldsResolverKey right)
            {
                return left.Equals(right);
            }

            public static bool operator !=(FieldsResolverKey left, FieldsResolverKey right)
            {
                return !left.Equals(right);
            }
        }

        private static readonly IDictionary<FieldsResolverKey, JsonContract> FieldsContractCache = new ConcurrentDictionary<FieldsResolverKey, JsonContract>();

        public override JsonContract ResolveContract(Type type)
        {
            if (IsSourceType(type) && _filterToFields != null && _filterToFields.Any())
            {
                var key = new FieldsResolverKey(type, _filterToFields);
                JsonContract contract;
                if (!FieldsContractCache.TryGetValue(key, out contract))
                {
                    //Do a new resolve
                    contract = CreateContract(type);
                    //Cache it
                    FieldsContractCache[key] = contract;
                }
                return contract;
            }
            return base.ResolveContract(type);
        }

        protected override JsonProperty CreateProperty(System.Reflection.MemberInfo member, Newtonsoft.Json.MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            if (_filterToFields != null && member.DeclaringType != null && IsSourceType(member.DeclaringType))
            {
                if (!_filterToFields.Contains(member.Name))
                    return null;
            }
            return property;
        }

        protected override IList<JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
        {
            var properties = base.CreateProperties(type, memberSerialization);
            if (_filterToFields != null && IsSourceType(type))
            {
                properties = properties.Where(x => _filterToFields.Contains(x.PropertyName)).ToList();
            }
            return properties;
        }

        protected override List<System.Reflection.MemberInfo> GetSerializableMembers(Type objectType)
        {
            var baseMembers = base.GetSerializableMembers(objectType);
            if (_filterToFields != null && IsSourceType(objectType))
            {
                //Filter!
                baseMembers = baseMembers.Where(x => _filterToFields.Contains(x.Name)).ToList();
            }
            return baseMembers;
        }

        private bool IsSourceType(Type type)
        {
            return _responseType != null && (type == _responseType || _responseType.IsAssignableFrom(type) || type.IsAssignableFrom(_responseType));
        }

    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Utils/FileShareLink.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Common.Utils;
using ASC.Files.Core;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Studio.Utility;

using File = ASC.Files.Core.File;
using FileShare = ASC.Files.Core.Security.FileShare;

namespace ASC.Web.Files.Utils
{
    public static class FileShareLink
    {
        public static string GetLink(File file, bool withHash = true)
        {
            var url = file.DownloadUrl;

            if (FileUtility.CanWebView(file.Title))
                url = FilesLinkUtility.GetFileWebPreviewUrl(file.Title, file.ID);

            if (withHash)
            {
                var linkParams = CreateKey(file.ID.ToString());
                url += "&" + FilesLinkUtility.DocShareKey + "=" + HttpUtility.UrlEncode(linkParams);
            }

            return CommonLinkUtility.GetFullAbsolutePath(url);
        }

        public static string CreateKey(string fileId)
        {
            return Signature.Create(fileId, Global.GetDocDbKey());
        }

        public static string Parse(string doc)
        {
            return Signature.Read<string>(doc ?? String.Empty, Global.GetDocDbKey());
        }

        public static bool Check(string doc, bool checkRead, IFileDao fileDao, out File file)
        {
            var fileShare = Check(doc, fileDao, out file);
            return (!checkRead
                    && (fileShare == FileShare.ReadWrite
                        || fileShare == FileShare.CustomFilter
                        || fileShare == FileShare.Review
                        || fileShare == FileShare.FillForms
                        || fileShare == FileShare.Comment))
                || (checkRead && fileShare != FileShare.Restrict);
        }

        public static FileShare Check(string doc, IFileDao fileDao, out File file)
        {
            file = null;
            if (string.IsNullOrEmpty(doc)) return FileShare.Restrict;
            var fileId = Parse(doc);
            file = fileDao.GetFile(fileId);
            if (file == null) return FileShare.Restrict;

            var filesSecurity = Global.GetFilesSecurity();
            if (filesSecurity.CanEdit(file, FileConstant.ShareLinkId)) return FileShare.ReadWrite;
            if (filesSecurity.CanCustomFilterEdit(file, FileConstant.ShareLinkId)) return FileShare.CustomFilter;
            if (filesSecurity.CanReview(file, FileConstant.ShareLinkId)) return FileShare.Review;
            if (filesSecurity.CanFillForms(file, FileConstant.ShareLinkId)) return FileShare.FillForms;
            if (filesSecurity.CanComment(file, FileConstant.ShareLinkId)) return FileShare.Comment;
            if (filesSecurity.CanRead(file, FileConstant.ShareLinkId)) return FileShare.Read;
            return FileShare.Restrict;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/Operations/Base/MailOperationType.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Core.Engine.Operations.Base
{
    public enum MailOperationType
    {
        RecalculateFolders = 1,
        RemoveMailbox,
        RemoveDomain,
        CheckDomainDns,
        RemoveUserFolder,
        ApplyFilter,
        ApplyAnyFilters,
        DownloadAllAttachments
    }

    public enum MailOperationDownloadAllAttachmentsProgress
    {
        Init = 1,
        GetAttachments = 5,
        Zipping = 10,
        ArchivePreparation = 85,
        CreateLink = 90,
        Finished = 100
    }

    public enum MailOperationRemoveMailboxProgress
    {
        Init = 1,
        RemoveFromDb = 20,
        FreeQuota = 40,
        RecalculateFolder = 50,
        ClearCache = 60,
        RemoveIndex = 70,
        Finished = 100
    }

    public enum MailOperationRecalculateMailboxProgress
    {
        Init = 1,
        CountUnreadMessages = 10,
        CountTotalMessages = 20,
        CountUreadConversation = 30,
        CountTotalConversation = 40,
        UpdateFoldersCounters = 50,
        CountUnreadUserFolderMessages = 60,
        CountTotalUserFolderMessages = 70,
        CountUreadUserFolderConversation = 80,
        CountTotalUserFolderConversation = 90,
        UpdateUserFoldersCounters = 95,
        Finished = 100
    }

    public enum MailOperationRemoveDomainProgress
    {
        Init = 1,
        RemoveFromDb = 20,
        FreeQuota = 40,
        RecalculateFolder = 60,
        ClearCache = 70,
        RemoveIndex = 80,
        Finished = 100
    }

    public enum MailOperationCheckDomainDnsProgress
    {
        Init = 1,
        CheckMx = 20,
        CheckSpf = 40,
        CheckDkim = 60,
        UpdateResults = 80,
        Finished = 100
    }

    public enum MailOperationRemoveUserFolderProgress
    {
        Init = 1,
        MoveMailsToTrash = 25,
        DeleteFolders = 50,
        Finished = 100
    }

    public enum MailOperationApplyFilterProgress
    {
        Init = 1,
        Filtering = 25,
        FilteringAndApplying = 40,
        Finished = 100
    }
}


<|start_filename|>web/core/ASC.Web.Core/WebZones/WebZoneAttribute.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Web.Core.WebZones
{
    [Flags]
    public enum WebZoneType
    {
        Nowhere = 1,
        StartProductList = 2,
        TopNavigationProductList = 4,
        CustomProductList = 8,

        All = Nowhere | StartProductList | TopNavigationProductList | CustomProductList
    }

    [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class WebZoneAttribute : Attribute
    {
        public WebZoneType Type { get; private set; }

        public WebZoneAttribute(WebZoneType type)
        {
            Type = type;
        }
    }

    public interface IRenderWebItem
    {
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Interfaces/ITagDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao.Interfaces
{
    public interface ITagDao
    {
        /// <summary>
        ///     Get tag by id.
        /// </summary>
        /// <param name="id">id</param>
        Tag GetTag(int id);

        /// <summary>
        ///     Get CRM tag by id.
        /// </summary>
        /// <param name="id">id</param>
        Tag GetCrmTag(int id);

        /// <summary>
        ///     Get tag by name.
        /// </summary>
        /// <param name="name">name</param>
        Tag GetTag(string name);

        /// <summary>
        ///     Get a list of tags
        /// </summary>
        List<Tag> GetTags();

        /// <summary>
        ///     Get a list of CRM tags
        /// </summary>
        List<Tag> GetCrmTags();

        /// <summary>
        ///     Get a list of CRM tags
        /// </summary>
        /// <param name="contactIds">id</param>
        List<Tag> GetCrmTags(List<int> contactIds);

        /// <summary>
        ///     Save or update tag
        /// </summary>
        /// <param name="tag"></param>
        int SaveTag(Tag tag);

        /// <summary>
        ///     Delete tag
        /// </summary>
        /// <param name="id">id</param>
        int DeleteTag(int id);

        /// <summary>
        ///     Delete tags
        /// </summary>
        /// <param name="tagIds">id</param>
        int DeleteTags(List<int> tagIds);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Entities/CurrencyInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Web.CRM.Resources;

namespace ASC.CRM.Core
{
    [DataContract]
    public class CurrencyInfo
    {
        private readonly String _resourceKey;

        [DataMember(Name = "title")]
        public String Title
        {
            get
            {

                if (String.IsNullOrEmpty(_resourceKey))
                    return String.Empty;

                return CRMCommonResource.ResourceManager.GetString(_resourceKey);

            }
        }

        [DataMember(Name = "symbol")]
        public string Symbol { get; set; }

        [DataMember(Name = "abbreviation")]
        public string Abbreviation { get; set; }

        [DataMember(Name = "cultureName")]
        public string CultureName { get; set; }

        [DataMember(Name = "isConvertable")]
        public bool IsConvertable { get; set; }

        [DataMember(Name = "isBasic")]
        public bool IsBasic { get; set; }


        public CurrencyInfo(string resourceKey, string abbreviation, string symbol, string cultureName, bool isConvertable, bool isBasic)
        {
            _resourceKey = resourceKey;
            Symbol = symbol;
            Abbreviation = abbreviation;
            CultureName = cultureName;
            IsConvertable = isConvertable;
            IsBasic = isBasic;
        }

        public override bool Equals(object obj)
        {
            var ci = obj as CurrencyInfo;
            return ci != null && string.Compare(Title, ci.Title, true) == 0;
        }

        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }

        public override string ToString()
        {
            return string.Concat(Abbreviation, "-", Title);
        }

    }
}

<|start_filename|>module/ASC.Feed/Feed.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ASC.Feed.Aggregator
{
    [DataContract]
    public class Feed
    {
        public Feed()
        {
        }

        public Feed(Guid author, DateTime date, bool variate = false)
        {
            AuthorId = author;
            ModifiedBy = author;

            CreatedDate = date;
            ModifiedDate = date;

            Action = FeedAction.Created;
            Variate = variate;
        }

        [DataMember]
        public string Item { get; set; }

        [DataMember]
        public string ItemId { get; set; }

        [DataMember]
        public string Id
        {
            get { return string.Format("{0}_{1}", Item, ItemId); }
        }

        [DataMember]
        public Guid AuthorId { get; private set; }

        [DataMember]
        public Guid ModifiedBy { get; set; }

        [DataMember]
        public DateTime CreatedDate { get; private set; }

        [DataMember]
        public DateTime ModifiedDate { get; set; }

        [DataMember]
        public string Product { get; set; }

        [DataMember]
        public string Module { get; set; }

        [DataMember]
        public string ExtraLocation { get; set; }

        [DataMember]
        public string ExtraLocationUrl { get; set; }

        [DataMember]
        public FeedAction Action { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string ItemUrl { get; set; }

        [DataMember]
        public string Description { get; set; }

        [DataMember]
        public string AdditionalInfo { get; set; }

        [DataMember]
        public string AdditionalInfo2 { get; set; }

        [DataMember]
        public string AdditionalInfo3 { get; set; }

        [DataMember]
        public string AdditionalInfo4 { get; set; }

        [DataMember]
        public bool HasPreview { get; set; }

        [DataMember]
        public bool CanComment { get; set; }

        [DataMember]
        public object Target { get; set; }

        [DataMember]
        public string CommentApiUrl { get; set; }

        [DataMember]
        public IEnumerable<FeedComment> Comments { get; set; }


        // это значит, что новость может обновляться (пр. добавление комментариев);
        // следовательно и права доступа могут устаревать
        public bool Variate { get; private set; }

        public string GroupId { get; set; }

        public string Keywords { get; set; }
    }
}

<|start_filename|>common/ASC.Core.Common/Tenants/Tenant.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;

namespace ASC.Core.Tenants
{
    [Serializable]
    public class Tenant
    {
        public const int DEFAULT_TENANT = -1;

        public static readonly string HostName = Dns.GetHostName().ToLowerInvariant();

        public Tenant()
        {
            TenantId = DEFAULT_TENANT;
            TimeZone = TimeZoneInfo.Utc;
            Language = CultureInfo.CurrentCulture.Name;
            TrustedDomains = new List<string>();
            TrustedDomainsType = TenantTrustedDomainsType.None;
            CreatedDateTime = DateTime.UtcNow;
            Status = TenantStatus.Active;
            StatusChangeDate = DateTime.UtcNow;
            VersionChanged = DateTime.UtcNow;
            Industry = TenantIndustry.Other;
        }

        public Tenant(string alias)
            : this()
        {
            TenantAlias = alias.ToLowerInvariant();
        }

        public Tenant(int id, string alias)
            : this(alias)
        {
            TenantId = id;
        }


        public int TenantId { get; internal set; }

        public string TenantAlias { get; set; }

        public string MappedDomain { get; set; }

        public int Version { get; set; }

        public DateTime VersionChanged { get; set; }

        public string TenantDomain { get { return GetTenantDomain(); } }

        public string HostedRegion { get; set; }

        public string Name { get; set; }

        public string Language { get; set; }

        public TimeZoneInfo TimeZone { get; set; }

        public List<string> TrustedDomains { get; private set; }

        public TenantTrustedDomainsType TrustedDomainsType { get; set; }

        public Guid OwnerId { get; set; }

        public DateTime CreatedDateTime { get; internal set; }

        public CultureInfo GetCulture() { return !string.IsNullOrEmpty(Language) ? CultureInfo.GetCultureInfo(Language) : CultureInfo.CurrentCulture; }

        public DateTime LastModified { get; set; }

        public TenantStatus Status { get; internal set; }

        public DateTime StatusChangeDate { get; internal set; }

        public string PartnerId { get; set; }

        public string AffiliateId { get; set; }

        public string Campaign { get; set; }

        public string PaymentId { get; set; }

        public TenantIndustry Industry { get; set; }

        public bool Spam { get; set; }

        public bool Calls { get; set; }

        public void SetStatus(TenantStatus status)
        {
            Status = status;
            StatusChangeDate = DateTime.UtcNow;
        }


        public override bool Equals(object obj)
        {
            var t = obj as Tenant;
            return t != null && t.TenantId == TenantId;
        }

        public override int GetHashCode()
        {
            return TenantId;
        }

        public override string ToString()
        {
            return TenantDomain ?? TenantAlias;
        }


        internal string GetTrustedDomains()
        {
            TrustedDomains.RemoveAll(d => string.IsNullOrEmpty(d));
            if (TrustedDomains.Count == 0) return null;
            return string.Join("|", TrustedDomains.ToArray());
        }

        internal void SetTrustedDomains(string trustedDomains)
        {
            if (string.IsNullOrEmpty(trustedDomains))
            {
                TrustedDomains.Clear();
            }
            else
            {
                TrustedDomains.AddRange(trustedDomains.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries));
            }
        }

        public String GetTenantDomain(bool allowMappedDomain = true)
        {
            var result = String.Empty;

            var baseHost = TenantUtil.GetBaseDomain(HostedRegion);

            if (string.IsNullOrEmpty(baseHost) && !string.IsNullOrEmpty(HostedRegion))
            {
                baseHost = HostedRegion;
            }

            if (baseHost == "localhost" || TenantAlias == "localhost")
            {
                //single tenant on local host
                TenantAlias = "localhost";
                result = HostName;
            }
            else
            {
                result = string.Format("{0}.{1}", TenantAlias, baseHost).TrimEnd('.').ToLowerInvariant();
            }
            if (!string.IsNullOrEmpty(MappedDomain) && allowMappedDomain)
            {
                if (MappedDomain.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase))
                {
                    MappedDomain = MappedDomain.Substring(7);
                }
                if (MappedDomain.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
                {
                    MappedDomain = MappedDomain.Substring(8);
                }
                result = MappedDomain.ToLowerInvariant();
            }

            return result;
        }
    }
}

<|start_filename|>module/ASC.Feed/Constants.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Feed
{
    public class Constants
    {
        public const string FeedDbId = "core";
        public const string ProjectsDbId = "projects";
        public const string FilesDbId = "files";
        public const string CommunityDbId = "community";
        public const string CrmDbId = "crm";

        #region Modules

        public static string BookmarksModule
        {
            get { return "bookmarks"; }
        }

        public static string BlogsModule
        {
            get { return "blogs"; }
        }

        public static string ForumsModule
        {
            get { return "forums"; }
        }

        public static string EventsModule
        {
            get { return "events"; }
        }

        public static string ProjectsModule
        {
            get { return "projects"; }
        }

        public static string MilestonesModule
        {
            get { return "milestones"; }
        }

        public static string DiscussionsModule
        {
            get { return "discussions"; }
        }

        public static string TasksModule
        {
            get { return "tasks"; }
        }

        public static string CommentsModule
        {
            get { return "comments"; }
        }

        public static string CrmTasksModule
        {
            get { return "crmTasks"; }
        }

        public static string ContactsModule
        {
            get { return "contacts"; }
        }

        public static string DealsModule
        {
            get { return "deals"; }
        }

        public static string CasesModule
        {
            get { return "cases"; }
        }

        public static string FilesModule
        {
            get { return "files"; }
        }

        public static string FoldersModule
        {
            get { return "folders"; }
        }

        #endregion
    }
}


<|start_filename|>module/ASC.AuditTrail/AuditEvent.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.MessagingSystem;

namespace ASC.AuditTrail
{
    public class AuditEvent : BaseEvent
    {
        public string Initiator { get; set; }

        [Event("ActionIdCol", 33)]
        public int Action { get; set; }

        [Event("ActionTypeCol", 30)]
        public string ActionTypeText { get; set; }

        [Event("ProductCol", 31)]
        public string Product { get; set; }

        [Event("ModuleCol", 32)]
        public string Module { get; set; }

        [Event("TargetIdCol", 34)]
        public MessageTarget Target { get; set; }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/Resources/BookmarkingUCResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Community.Modules.Bookmarking.UserControls.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class BookmarkingUCResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal BookmarkingUCResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Community.Modules.Bookmarking.UserControls.Resources.BookmarkingUCResourc" +
                            "e", typeof(BookmarkingUCResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new bookmark.
        /// </summary>
        public static string AddBookmarkLink {
            get {
                return ResourceManager.GetString("AddBookmarkLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add bookmark to favorites.
        /// </summary>
        public static string AddBookmarkToFavouriteLinkTitle {
            get {
                return ResourceManager.GetString("AddBookmarkToFavouriteLinkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add to Favorites.
        /// </summary>
        public static string AddToFavourite {
            get {
                return ResourceManager.GetString("AddToFavourite", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creating Bookmark....
        /// </summary>
        public static string BookmarkCreationIsInProgressLabel {
            get {
                return ResourceManager.GetString("BookmarkCreationIsInProgressLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Description.
        /// </summary>
        public static string BookmarkDescription {
            get {
                return ResourceManager.GetString("BookmarkDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bookmark detailed description.
        /// </summary>
        public static string BookmarkDetailsLinkTitle {
            get {
                return ResourceManager.GetString("BookmarkDetailsLinkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bookmarked by.
        /// </summary>
        public static string BookmarkedBy {
            get {
                return ResourceManager.GetString("BookmarkedBy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Search in bookmarks.
        /// </summary>
        public static string BookmarkingSearch {
            get {
                return ResourceManager.GetString("BookmarkingSearch", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Name.
        /// </summary>
        public static string BookmarkName {
            get {
                return ResourceManager.GetString("BookmarkName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Number of people who added this bookmark to favorites.
        /// </summary>
        public static string BookmarkRaitingLinkTitle {
            get {
                return ResourceManager.GetString("BookmarkRaitingLinkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Bookmarks.
        /// </summary>
        public static string BookmarksNavigationItem {
            get {
                return ResourceManager.GetString("BookmarksNavigationItem", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter the needed tags separating them with commas.
        /// </summary>
        public static string BookmarkTagDescription {
            get {
                return ResourceManager.GetString("BookmarkTagDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to URL.
        /// </summary>
        public static string BookmarkUrl {
            get {
                return ResourceManager.GetString("BookmarkUrl", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cancel.
        /// </summary>
        public static string Cancel {
            get {
                return ResourceManager.GetString("Cancel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Check URL.
        /// </summary>
        public static string CheckBookmarkUrlButton {
            get {
                return ResourceManager.GetString("CheckBookmarkUrlButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Checking URL....
        /// </summary>
        public static string CheckingUrlIsInProgressLabel {
            get {
                return ResourceManager.GetString("CheckingUrlIsInProgressLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comments.
        /// </summary>
        public static string Comments {
            get {
                return ResourceManager.GetString("Comments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comments.
        /// </summary>
        public static string CommentsGenitivePlural {
            get {
                return ResourceManager.GetString("CommentsGenitivePlural", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comments.
        /// </summary>
        public static string CommentsGenitiveSingular {
            get {
                return ResourceManager.GetString("CommentsGenitiveSingular", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to bookmark comments.
        /// </summary>
        public static string CommentsLinkTitle {
            get {
                return ResourceManager.GetString("CommentsLinkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comment.
        /// </summary>
        public static string CommentsNominative {
            get {
                return ResourceManager.GetString("CommentsNominative", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new bookmark.
        /// </summary>
        public static string CreateNewBookmarkLinkTitle {
            get {
                return ResourceManager.GetString("CreateNewBookmarkLinkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Details.
        /// </summary>
        public static string Details {
            get {
                return ResourceManager.GetString("Details", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit.
        /// </summary>
        public static string EditFavouriteBookmarkLink {
            get {
                return ResourceManager.GetString("EditFavouriteBookmarkLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit bookmark.
        /// </summary>
        public static string EditFavouriteBookmarkLinkTitle {
            get {
                return ResourceManager.GetString("EditFavouriteBookmarkLinkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit bookmark.
        /// </summary>
        public static string EditFavouriteBookmarkTitle {
            get {
                return ResourceManager.GetString("EditFavouriteBookmarkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The bookmark URL field cannot be empty.
        /// </summary>
        public static string EmptyBookmarkUrlErrorMessage {
            get {
                return ResourceManager.GetString("EmptyBookmarkUrlErrorMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No bookmarks have been added yet.
        /// </summary>
        public static string EmptyScreenCaption {
            get {
                return ResourceManager.GetString("EmptyScreenCaption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create the first bookmark.
        /// </summary>
        public static string EmptyScreenLink {
            get {
                return ResourceManager.GetString("EmptyScreenLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No bookmarks found.
        /// </summary>
        public static string EmptyScreenSearchCaption {
            get {
                return ResourceManager.GetString("EmptyScreenSearchCaption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create your bookmarks, store and share useful information with your colleagues directly on your portal saving links to web resources which allow you to easily get back to your favorite place..
        /// </summary>
        public static string EmptyScreenText {
            get {
                return ResourceManager.GetString("EmptyScreenText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to View bookmarks which store useful information directly on your portal. Saved links to web resources allow users to easily get back to their favorite places..
        /// </summary>
        public static string EmptyScreenTextVisitor {
            get {
                return ResourceManager.GetString("EmptyScreenTextVisitor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Favorites.
        /// </summary>
        public static string FavouritesNavigationItem {
            get {
                return ResourceManager.GetString("FavouritesNavigationItem", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Month.
        /// </summary>
        public static string MonthLabel {
            get {
                return ResourceManager.GetString("MonthLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Most Recent.
        /// </summary>
        public static string MostRecentLabel {
            get {
                return ResourceManager.GetString("MostRecentLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Most Popular.
        /// </summary>
        public static string PopularityLabel {
            get {
                return ResourceManager.GetString("PopularityLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Remove bookmark from favorites.
        /// </summary>
        public static string RemoveBookmarkFromFavouritesLinkTitle {
            get {
                return ResourceManager.GetString("RemoveBookmarkFromFavouritesLinkTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Remove.
        /// </summary>
        public static string RemoveButton {
            get {
                return ResourceManager.GetString("RemoveButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to remove the bookmark?.
        /// </summary>
        public static string RemoveConfirmMessage {
            get {
                return ResourceManager.GetString("RemoveConfirmMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to remove the {0} bookmark from favorites?.
        /// </summary>
        public static string RemoveFromFavouriteConfirmMessage {
            get {
                return ResourceManager.GetString("RemoveFromFavouriteConfirmMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Remove Bookmark.
        /// </summary>
        public static string RemoveFromFavouriteTitle {
            get {
                return ResourceManager.GetString("RemoveFromFavouriteTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Removing Bookmark....
        /// </summary>
        public static string RemovingBookmarkFromFavouriteIsInProgressLabel {
            get {
                return ResourceManager.GetString("RemovingBookmarkFromFavouriteIsInProgressLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string Save {
            get {
                return ResourceManager.GetString("Save", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show:.
        /// </summary>
        public static string ShowLabel {
            get {
                return ResourceManager.GetString("ShowLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show on page.
        /// </summary>
        public static string ShowOnPage {
            get {
                return ResourceManager.GetString("ShowOnPage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subscribe to comments.
        /// </summary>
        public static string SubscribeOnBookmarkComments {
            get {
                return ResourceManager.GetString("SubscribeOnBookmarkComments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tag.
        /// </summary>
        public static string TagBookmarks {
            get {
                return ResourceManager.GetString("TagBookmarks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tags.
        /// </summary>
        public static string Tags {
            get {
                return ResourceManager.GetString("Tags", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Top of the Day.
        /// </summary>
        public static string TopOfTheDayLabel {
            get {
                return ResourceManager.GetString("TopOfTheDayLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Total.
        /// </summary>
        public static string TotalPages {
            get {
                return ResourceManager.GetString("TotalPages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unsubscribe from comments.
        /// </summary>
        public static string UnSubscribeOnBookmarkComments {
            get {
                return ResourceManager.GetString("UnSubscribeOnBookmarkComments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Week.
        /// </summary>
        public static string WeekLabel {
            get {
                return ResourceManager.GetString("WeekLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Year.
        /// </summary>
        public static string YearLabel {
            get {
                return ResourceManager.GetString("YearLabel", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Core/Notify/StudioNotifySource.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Core.Notify;
using ASC.Notify.Model;
using ASC.Notify.Patterns;
using ASC.Notify.Recipients;

namespace ASC.Web.Studio.Core.Notify
{
    class StudioNotifySource : NotifySource
    {
        public StudioNotifySource()
            : base("asc.web.studio")
        {
        }


        protected override IActionProvider CreateActionProvider()
        {
            return new ConstActionProvider(
                    Actions.SelfProfileUpdated,
                    Actions.JoinUsers,
                    Actions.SendWhatsNew,
                    Actions.UserHasJoin,
                    Actions.BackupCreated,
                    Actions.RestoreStarted,
                    Actions.RestoreCompletedV115,
                    Actions.PortalDeactivate,
                    Actions.PortalDelete,
                    Actions.PortalDeleteSuccessV115,
                    Actions.DnsChange,
                    Actions.ConfirmOwnerChange,
                    Actions.EmailChangeV115,
                    Actions.PasswordChange,
                    Actions.ActivateEmail,
                    Actions.ProfileDelete,
                    Actions.ProfileHasDeletedItself,
                    Actions.ReassignsCompleted,
                    Actions.ReassignsFailed,
                    Actions.RemoveUserDataCompleted,
                    Actions.RemoveUserDataCompletedCustomMode,
                    Actions.RemoveUserDataFailed,
                    Actions.PhoneChange,
                    Actions.MigrationPortalStart,
                    Actions.MigrationPortalSuccessV115,
                    Actions.MigrationPortalError,
                    Actions.MigrationPortalServerFailure,

                    Actions.UserMessageToAdmin,

                    Actions.VoipWarning,
                    Actions.VoipBlocked,

                    Actions.SaasAdminActivationV115,
                    Actions.EnterpriseAdminActivationV10,
                    Actions.EnterpriseWhitelabelAdminActivationV10,
                    Actions.OpensourceAdminActivationV11,

                    Actions.SaasAdminWelcomeV115,
                    Actions.EnterpriseAdminWelcomeV10,
                    Actions.EnterpriseWhitelabelAdminWelcomeV10,
                    Actions.OpensourceAdminWelcomeV11,

                    Actions.SaasUserActivationV115,
                    Actions.EnterpriseUserActivationV10,
                    Actions.EnterpriseWhitelabelUserActivationV10,
                    Actions.OpensourceUserActivationV11,

                    Actions.SaasUserWelcomeV115,
                    Actions.EnterpriseUserWelcomeV10,
                    Actions.EnterpriseWhitelabelUserWelcomeV10,
                    Actions.EnterpriseWhitelabelUserWelcomeCustomMode,
                    Actions.OpensourceUserWelcomeV11,

                    Actions.SaasGuestActivationV115,
                    Actions.EnterpriseGuestActivationV10,
                    Actions.EnterpriseWhitelabelGuestActivationV10,
                    Actions.OpensourceGuestActivationV11,

                    Actions.SaasGuestWelcomeV115,
                    Actions.EnterpriseGuestWelcomeV10,
                    Actions.EnterpriseWhitelabelGuestWelcomeV10,
                    Actions.OpensourceGuestWelcomeV11,

                    Actions.EnterpriseAdminCustomizePortalV10,
                    Actions.EnterpriseWhitelabelAdminCustomizePortalV10,
                    Actions.EnterpriseAdminInviteTeammatesV10,
                    Actions.EnterpriseAdminWithoutActivityV10,
                    Actions.EnterpriseAdminUserDocsTipsV10,
                    Actions.EnterpriseAdminUserAppsTipsV10,

                    Actions.EnterpriseAdminTrialWarningBefore7V10,
                    Actions.EnterpriseAdminTrialWarningV10,

                    Actions.EnterpriseAdminPaymentWarningBefore7V10,
                    Actions.EnterpriseWhitelabelAdminPaymentWarningBefore7V10,
                    Actions.EnterpriseAdminPaymentWarningV10,
                    Actions.EnterpriseWhitelabelAdminPaymentWarningV10,

                    Actions.SaasAdminUserDocsTipsV115,
                    Actions.SaasAdminComfortTipsV115,
                    Actions.SaasAdminUserAppsTipsV115,

                    Actions.SaasAdminTrialWarningBefore5V115,
                    Actions.SaasAdminTrialWarningV115,
                    Actions.SaasAdminTrialWarningAfter1V115,
                    Actions.SaasAdminTrialWarningAfterHalfYearV115,

                    Actions.SaasAdminPaymentWarningEvery2MonthsV115,

                    Actions.SaasAdminModulesV115,

                    Actions.OpensourceAdminDocsTipsV11,
                    Actions.OpensourceUserDocsTipsV11,

                    Actions.PersonalActivate,
                    Actions.PersonalAfterRegistration1,
                    Actions.PersonalAfterRegistration7,
                    Actions.PersonalAfterRegistration14,
                    Actions.PersonalAfterRegistration21,
                    Actions.PersonalAfterRegistration28,
                    Actions.PersonalConfirmation,
                    Actions.PersonalPasswordChange,
                    Actions.PersonalEmailChangeV115,
                    Actions.PersonalProfileDelete,

                    Actions.MailboxCreated,
                    Actions.MailboxWithoutSettingsCreated,

                    Actions.MailboxCreated,
                    Actions.MailboxWithoutSettingsCreated,

                    Actions.PersonalCustomModeAfterRegistration1,
                    Actions.PersonalCustomModeAfterRegistration7,
                    Actions.PersonalCustomModeConfirmation,
                    Actions.PersonalCustomModePasswordChange,
                    Actions.PersonalCustomModeEmailChangeV115,
                    Actions.PersonalCustomModeProfileDelete,

                    Actions.SaasCustomModeRegData,

                    Actions.StorageEncryptionStart,
                    Actions.StorageEncryptionSuccess,
                    Actions.StorageEncryptionError,
                    Actions.StorageDecryptionStart,
                    Actions.StorageDecryptionSuccess,
                    Actions.StorageDecryptionError
                );
        }

        protected override IPatternProvider CreatePatternsProvider()
        {
            return new XmlPatternProvider2(WebPatternResource.webstudio_patterns);
        }

        protected override ISubscriptionProvider CreateSubscriptionProvider()
        {
            return new AdminNotifySubscriptionProvider(base.CreateSubscriptionProvider());
        }


        private class AdminNotifySubscriptionProvider : ISubscriptionProvider
        {
            private readonly ISubscriptionProvider provider;


            public AdminNotifySubscriptionProvider(ISubscriptionProvider provider)
            {
                this.provider = provider;
            }

            public object GetSubscriptionRecord(INotifyAction action, IRecipient recipient, string objectID)
            {
                return provider.GetSubscriptionRecord(GetAdminAction(action), recipient, objectID);
            }

            public string[] GetSubscriptions(INotifyAction action, IRecipient recipient, bool checkSubscription = true)
            {
                return provider.GetSubscriptions(GetAdminAction(action), recipient, checkSubscription);
            }

            public void Subscribe(INotifyAction action, string objectID, IRecipient recipient)
            {
                provider.Subscribe(GetAdminAction(action), objectID, recipient);
            }

            public void UnSubscribe(INotifyAction action, IRecipient recipient)
            {
                provider.UnSubscribe(GetAdminAction(action), recipient);
            }

            public void UnSubscribe(INotifyAction action)
            {
                provider.UnSubscribe(GetAdminAction(action));
            }

            public void UnSubscribe(INotifyAction action, string objectID)
            {
                provider.UnSubscribe(GetAdminAction(action), objectID);
            }

            public void UnSubscribe(INotifyAction action, string objectID, IRecipient recipient)
            {
                provider.UnSubscribe(GetAdminAction(action), objectID, recipient);
            }

            public void UpdateSubscriptionMethod(INotifyAction action, IRecipient recipient, params string[] senderNames)
            {
                provider.UpdateSubscriptionMethod(GetAdminAction(action), recipient, senderNames);
            }

            public IRecipient[] GetRecipients(INotifyAction action, string objectID)
            {
                return provider.GetRecipients(GetAdminAction(action), objectID);
            }

            public string[] GetSubscriptionMethod(INotifyAction action, IRecipient recipient)
            {
                return provider.GetSubscriptionMethod(GetAdminAction(action), recipient);
            }

            public bool IsUnsubscribe(IDirectRecipient recipient, INotifyAction action, string objectID)
            {
                return provider.IsUnsubscribe(recipient, action, objectID);
            }

            private INotifyAction GetAdminAction(INotifyAction action)
            {
                if (Actions.SelfProfileUpdated.ID == action.ID ||
                    Actions.UserHasJoin.ID == action.ID ||
                    Actions.UserMessageToAdmin.ID == action.ID ||
                    Actions.VoipWarning.ID == action.ID ||
                    Actions.VoipBlocked.ID == action.ID
                    )
                {
                    return Actions.AdminNotify;
                }
                else
                {
                    return action;
                }
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/News/Code/Feed.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Security;
using ASC.Common.Security.Authorizing;
using ASC.Core;
using ASC.Core.Tenants;

namespace ASC.Web.Community.News.Code
{
    [Serializable]
    public class Feed : ISecurityObject
    {
        public long Id { get; set; }

        public FeedType FeedType { get; set; }

        public string Caption { get; set; }

        public string Text { get; set; }

        public DateTime Date { get; set; }

        public string Creator { get; set; }

        public virtual bool Readed { get; internal set; }


        public Feed()
        {
            FeedType = FeedType.News;
            Creator = SecurityContext.CurrentAccount.ID.ToString();
            Date = TenantUtil.DateTimeNow();
            Readed = false;
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            var feed = obj as Feed;
            return feed != null && Id == feed.Id;
        }

        public override string ToString()
        {
            return Caption;
        }

        public Type ObjectType
        {
            get { return GetType(); }
        }

        public object SecurityId
        {
            get { return Id; }
        }

        public IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId,
                                                 SecurityCallContext callContext)
        {
            var roles = new List<IRole>();

            if (Equals(account.ID, new Guid(Creator)))
            {
                roles.Add(Constants.Owner);
            }

            return roles;
        }

        public ISecurityObjectId InheritFrom(ISecurityObjectId objectId)
        {
            throw new NotImplementedException();
        }

        public bool InheritSupported
        {
            get { return false; }
        }

        public bool ObjectRolesSupported
        {
            get { return true; }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/ServerDomainDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao
{
    public class ServerDomainDao : BaseDao, IServerDomainDao
    {
        protected static ITable table = new MailTableFactory().Create<ServerDomainTable>();

        public ServerDomainDao(IDbManager dbManager, int tenant)
            : base(table, dbManager, tenant)
        {
        }

        public int Save(ServerDomain domain)
        {
            var query = new SqlInsert(ServerDomainTable.TABLE_NAME)
                .InColumnValue(ServerDomainTable.Columns.Id, domain.Id)
                .InColumnValue(ServerDomainTable.Columns.DomainName, domain.Name)
                .InColumnValue(ServerDomainTable.Columns.Tenant, Tenant)
                .InColumnValue(ServerDomainTable.Columns.IsVerified, domain.IsVerified)
                .Identity(0, 0, true);

            if (domain.Id <= 0)
            {
                query.InColumnValue(ServerDomainTable.Columns.DateAdded, DateTime.UtcNow);
            }

            var id = Db.ExecuteScalar<int>(query);

            return id;
        }

        public int Delete(int id)
        {
            var query = new SqlDelete(ServerDomainTable.TABLE_NAME)
                .Where(ServerDomainTable.Columns.Tenant, Tenant)
                .Where(ServerDomainTable.Columns.Id, id);

            var result = Db.ExecuteNonQuery(query);

            query = new SqlDelete(ServerDnsTable.TABLE_NAME)
                .Where(ServerDnsTable.Columns.Tenant, Tenant)
                .Where(ServerDnsTable.Columns.DomainId, id);

            Db.ExecuteNonQuery(query);

            return result;
        }

        public List<ServerDomain> GetDomains()
        {
            var query = Query()
                .Where(Exp.In(ServerDomainTable.Columns.Tenant, new List<int> { Tenant, Defines.SHARED_TENANT_ID }));

            var list = Db.ExecuteList(query)
                .ConvertAll(ToServerDomain);

            return list;
        }

        public List<ServerDomain> GetAllDomains()
        {
            var query = Query();

            var list = Db.ExecuteList(query)
                .ConvertAll(ToServerDomain);

            return list;
        }

        public ServerDomain GetDomain(int id)
        {
            var query = Query()
                .Where(Exp.In(ServerDomainTable.Columns.Tenant, new List<int> { Tenant, Defines.SHARED_TENANT_ID }))
                .Where(ServerDomainTable.Columns.Id, id);

            var domain = Db.ExecuteList(query)
                .ConvertAll(ToServerDomain)
                .SingleOrDefault();

            return domain;
        }

        public bool IsDomainExists(string name)
        {
            var query = Query()
                .Where(ServerDomainTable.Columns.DomainName, name);

            var domain = Db.ExecuteList(query)
                .ConvertAll(ToServerDomain)
                .SingleOrDefault();

            return domain != null;
        }

        public int SetVerified(int id, bool isVerified)
        {
            var query = new SqlUpdate(ServerDomainTable.TABLE_NAME)
                .Set(ServerDomainTable.Columns.IsVerified, isVerified)
                .Set(ServerDomainTable.Columns.DateChecked, DateTime.UtcNow)
                .Where(ServerDomainTable.Columns.Id, id);

            return Db.ExecuteNonQuery(query);
        }

        protected ServerDomain ToServerDomain(object[] r)
        {
            var d = new ServerDomain
            {
                Id = Convert.ToInt32(r[0]),
                Tenant = Convert.ToInt32(r[1]),
                Name = Convert.ToString(r[2]),
                IsVerified = Convert.ToBoolean(r[3]),
                DateAdded = Convert.ToDateTime(r[4]),
                DateChecked = Convert.ToDateTime(r[5])
            };

            return d;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/AttachmentDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Expressions.Attachment;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class AttachmentDao : BaseDao, IAttachmentDao
    {
        protected static ITable table = new MailTableFactory().Create<AttachmentTable>();

        protected string CurrentUserId { get; private set; }

        public AttachmentDao(IDbManager dbManager, int tenant, string user = null)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public Attachment GetAttachment(IAttachmentExp exp)
        {
            var query = Query(AttachmentTable.TABLE_NAME)
                .InnerJoin(MailTable.TABLE_NAME.Alias(MailTable.TABLE_NAME),
                    Exp.EqColumns(MailTable.Columns.Id.Prefix(MailTable.TABLE_NAME),
                        AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME)))
                .Select(MailTable.Columns.Stream.Prefix(MailTable.TABLE_NAME),
                    MailTable.Columns.User.Prefix(MailTable.TABLE_NAME))
                .Where(exp.GetExpression());

            return Db.ExecuteList(query)
                .ConvertAll(ToAttachment)
                .FirstOrDefault();
        }

        public List<Attachment> GetAttachments(IAttachmentsExp exp)
        {
            var query = Query(AttachmentTable.TABLE_NAME)
                .InnerJoin(MailTable.TABLE_NAME.Alias(MailTable.TABLE_NAME),
                    Exp.EqColumns(MailTable.Columns.Id.Prefix(MailTable.TABLE_NAME),
                        AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME)))
                .Select(MailTable.Columns.Stream.Prefix(MailTable.TABLE_NAME),
                    MailTable.Columns.User.Prefix(MailTable.TABLE_NAME))
                .Where(exp.GetExpression());

            return Db.ExecuteList(query)
                .ConvertAll(ToAttachment);
        }

        public long GetAttachmentsSize(IAttachmentsExp exp)
        {
            var query = new SqlQuery(AttachmentTable.TABLE_NAME.Alias(AttachmentTable.TABLE_NAME))
                .InnerJoin(MailTable.TABLE_NAME.Alias(MailTable.TABLE_NAME),
                    Exp.EqColumns(MailTable.Columns.Id.Prefix(MailTable.TABLE_NAME),
                        AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME)))
                .SelectSum(AttachmentTable.Columns.Size.Prefix(AttachmentTable.TABLE_NAME))
                .Where(exp.GetExpression());

            var size = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToInt64(r[0]))
                .FirstOrDefault();

            return size;
        }

        public int GetAttachmentsMaxFileNumber(IAttachmentsExp exp)
        {
            var query = new SqlQuery(AttachmentTable.TABLE_NAME.Alias(AttachmentTable.TABLE_NAME))
                .InnerJoin(MailTable.TABLE_NAME.Alias(MailTable.TABLE_NAME),
                    Exp.EqColumns(MailTable.Columns.Id.Prefix(MailTable.TABLE_NAME),
                        AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME)))
                .SelectMax(AttachmentTable.Columns.FileNumber.Prefix(AttachmentTable.TABLE_NAME))
                .Where(exp.GetExpression());

            var max = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToInt32(r[0]))
                .SingleOrDefault();

            return max;
        }

        public int GetAttachmentsCount(IAttachmentsExp exp)
        {
            var query = new SqlQuery(AttachmentTable.TABLE_NAME.Alias(AttachmentTable.TABLE_NAME))
                .InnerJoin(MailTable.TABLE_NAME.Alias(MailTable.TABLE_NAME),
                    Exp.EqColumns(MailTable.Columns.Id.Prefix(MailTable.TABLE_NAME),
                        AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME)))
                .SelectCount(AttachmentTable.Columns.Id.Prefix(AttachmentTable.TABLE_NAME))
                .Where(exp.GetExpression());

            var count = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToInt32(r[0]))
                .SingleOrDefault();

            return count;
        }

        public bool SetAttachmnetsRemoved(IAttachmentsExp exp)
        {
            var query = new SqlUpdate(AttachmentTable.TABLE_NAME.Alias(AttachmentTable.TABLE_NAME))
                .InnerJoin(MailTable.TABLE_NAME.Alias(MailTable.TABLE_NAME),
                    Exp.EqColumns(MailTable.Columns.Id.Prefix(MailTable.TABLE_NAME),
                        AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME)))
                .Set(AttachmentTable.Columns.IsRemoved, true)
                .Where(exp.GetExpression());

            var result = Db.ExecuteNonQuery(query);

            return result > 0;
        }

        public int SaveAttachment(Attachment attachment)
        {
            var query = new SqlInsert(AttachmentTable.TABLE_NAME, true)
                .InColumnValue(AttachmentTable.Columns.Id, attachment.Id)
                .InColumnValue(AttachmentTable.Columns.MailId, attachment.MailId)
                .InColumnValue(AttachmentTable.Columns.Name, attachment.Name)
                .InColumnValue(AttachmentTable.Columns.StoredName, attachment.StoredName)
                .InColumnValue(AttachmentTable.Columns.Type, attachment.Type)
                .InColumnValue(AttachmentTable.Columns.Size, attachment.Size)
                .InColumnValue(AttachmentTable.Columns.FileNumber, attachment.FileNumber)
                .InColumnValue(AttachmentTable.Columns.IsRemoved, attachment.IsRemoved)
                .InColumnValue(AttachmentTable.Columns.ContentId, attachment.ContentId)
                .InColumnValue(AttachmentTable.Columns.Tenant, attachment.Tenant)
                .InColumnValue(AttachmentTable.Columns.MailboxId, attachment.MailboxId)
                .Identity(0, 0, true);

            var id = Db.ExecuteScalar<int>(query);

            return id;
        }

        protected Attachment ToAttachment(object[] r)
        {
            var a = new Attachment
            {
                Id = Convert.ToInt32(r[0]),
                MailId = Convert.ToInt32(r[1]),
                Name = Convert.ToString(r[2]),
                StoredName = Convert.ToString(r[3]),
                Type = Convert.ToString(r[4]),
                Size = Convert.ToInt32(r[5]),
                IsRemoved = Convert.ToBoolean(r[6]),
                FileNumber = Convert.ToInt32(r[7]),
                ContentId = Convert.ToString(r[8]),
                Tenant = Convert.ToInt32(r[9]),
                MailboxId = Convert.ToInt32(r[10]),
                Stream = Convert.ToString(r[11]),
                User = Convert.ToString(r[12])
            };

            return a;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/MailboxServerDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao
{
    public class MailboxServerDao : BaseDao, IMailboxServerDao
    {
        protected static ITable table = new MailTableFactory().Create<MailboxServerTable>();

        public MailboxServerDao(IDbManager dbManager)
            : base(table, dbManager, -1)
        {
        }

        public MailboxServer GetServer(int id)
        {
            var query = Query()
                .Where(MailboxServerTable.Columns.Id, id);

            return Db.ExecuteList(query)
                .ConvertAll(ToMailboxServer)
               .SingleOrDefault();
        }

        public List<MailboxServer> GetServers(int providerId, bool isUserData = false)
        {
            var query = Query()
                .Where(MailboxServerTable.Columns.ProviderId, providerId)
                .Where(MailboxServerTable.Columns.IsUserData, isUserData);

            return Db.ExecuteList(query)
                .ConvertAll(ToMailboxServer);
        }

        public int SaveServer(MailboxServer mailboxServer)
        {
            var query = new SqlInsert(MailboxServerTable.TABLE_NAME, true)
                .InColumnValue(MailboxServerTable.Columns.Id, mailboxServer.Id)
                .InColumnValue(MailboxServerTable.Columns.ProviderId, mailboxServer.ProviderId)
                .InColumnValue(MailboxServerTable.Columns.Type, mailboxServer.Type)
                .InColumnValue(MailboxServerTable.Columns.Hostname, mailboxServer.Hostname)
                .InColumnValue(MailboxServerTable.Columns.Port, mailboxServer.Port)
                .InColumnValue(MailboxServerTable.Columns.SocketType, mailboxServer.SocketType)
                .InColumnValue(MailboxServerTable.Columns.Username, mailboxServer.Username)
                .InColumnValue(MailboxServerTable.Columns.Authentication, mailboxServer.Authentication)
                .InColumnValue(MailboxServerTable.Columns.IsUserData, mailboxServer.IsUserData)
                .Identity(0, 0, true);

            var id = Db.ExecuteScalar<int>(query);

            return id;
        }

        public int DelteServer(int id)
        {
            var query = new SqlDelete(MailboxServerTable.TABLE_NAME)
                .Where(MailboxServerTable.Columns.Id, id);

            return Db.ExecuteNonQuery(query);
        }

        protected MailboxServer ToMailboxServer(object[] r)
        {
            var s = new MailboxServer
            {
                Id = Convert.ToInt32(r[0]),
                ProviderId = Convert.ToInt32(r[1]),
                Type = Convert.ToString(r[2]),
                Hostname = Convert.ToString(r[3]),
                Port = Convert.ToInt32(r[4]),
                SocketType = Convert.ToString(r[5]),
                Username = Convert.ToString(r[6]),
                Authentication = Convert.ToString(r[7]),
                IsUserData = Convert.ToBoolean(r[8])
            };

            return s;
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/Wrappers/SubtaskWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Api.Employee;
using ASC.Projects.Core.Domain;
using ASC.Specific;

namespace ASC.Api.Projects.Wrappers
{
    [DataContract(Name = "subtask", Namespace = "")]
    public class SubtaskWrapper : ObjectWrapperFullBase
    {
        [DataMember]
        public bool CanEdit { get; set; }

        [DataMember]
        public int TaskId { get; set; }

        private SubtaskWrapper()
        {
        }

        public SubtaskWrapper(ProjectApiBase projectApiBase, Subtask subtask, Task task)
        {
            Id = subtask.ID;
            Title = subtask.Title;
            Status = (int)subtask.Status;
            if (subtask.Responsible != Guid.Empty)
            {
                Responsible = projectApiBase.GetEmployeeWraper(subtask.Responsible);
            }
            Created = (ApiDateTime)subtask.CreateOn;
            CreatedBy = projectApiBase.GetEmployeeWraper(subtask.CreateBy);
            Updated = (ApiDateTime)subtask.LastModifiedOn;
            if (subtask.CreateBy != subtask.LastModifiedBy)
            {
                UpdatedBy = projectApiBase.GetEmployeeWraper(subtask.LastModifiedBy);
            }
            CanEdit = projectApiBase.ProjectSecurity.CanEdit(task, subtask);

            TaskId = task.ID;
        }


        public static SubtaskWrapper GetSample()
        {
            return new SubtaskWrapper
            {
                Id = 1233,
                Title = "Sample subtask",
                Description = "Sample description",
                Status = (int)TaskStatus.Open,
                Responsible = EmployeeWraper.GetSample(),
                Created = ApiDateTime.GetSample(),
                CreatedBy = EmployeeWraper.GetSample(),
                Updated = ApiDateTime.GetSample(),
                UpdatedBy = EmployeeWraper.GetSample(),
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/js/talk.messagesmanager.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC = window.ASC || {};

window.ASC.TMTalk = window.ASC.TMTalk || {};

window.ASC.TMTalk.messagesManager = (function () {
  var
    isInit = false,
    multicastDomain = null,
    multicastIsSupported = false,
    history = {},
    monthNames = [],
    dayNames = [],
    maxHistoryCount = 10,
    shortDateFormat = '',
    fullDateFormat = '',
    customEvents = {
      // load history by filter complete
      loadFilteredHistory : 'onloadfilteredhistory',
      // load history complete
      loadHistory : 'onloadhistory',
      // show history
      openHistory : 'onopenhistory',
      // hide history
      closeHistory : 'onclosehistory',
      // composing message
      composingMessageFromChat : 'oncomposingmessagefromchat',
      // pause message
      pausedMessageFromChat : 'onpausedmessagefromchat',
      // sent messsage to contact
      sentMessageToChat : 'onsentmessagetochat',
      // receiving message from contact
      recvMessageFromChat : 'onrecvmessagefromchar',
      // receiving message from contact
      recvOfflineMessagesFromChat : 'onrecvofflinemessagesfromchar',
      // sent message to conference
      sentMessageToConference : 'onsentmessagetoconference',
      // receiving message from conference
      recvMessageFromConference : 'onrecvmessagefromconference'
    },
    eventManager = new CustomEvent(customEvents);

    var leftPad = function (n) {
      n = '' + n;
      return n.length === 1 ? '0' + n : n;
    };

    var formatDate = function(d, fmt, monthnames,daynames) {
      var
        c = '',
        r = [],
        escape = false,
        hours = d.getHours(),
        isam = hours < 12,
        day = '';

      monthnames = monthnames || ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
      daynames   = daynames   || ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
        
      if (fmt.search(/%p|%P/) !== -1) {
        if (hours > 12) {
          hours = hours - 12;
        } else if (hours == 0) {
          hours = 12;
        }
      }
      if (window.moment) {
          day = window.moment(d).calendar(null, {
              lastWeek: 'dddd DD.MM.YYYY',
              sameElse: 'dddd DD.MM.YYYY'
          }).split(' ')[0];
      } else {
          day = daynames[d.getDay()]
      }
      for (var i = 0, n = fmt.length; i < n; ++i) {
        c = fmt.charAt(i);
        if (escape) {
          switch (c) {
            case 'h': c = '' + hours; break;
            case 'H': c = leftPad(hours); break;
            case 'M': c = leftPad(d.getMinutes()); break;
            case 'S': c = leftPad(d.getSeconds()); break;
            case 'd': c = '' + d.getDate(); break;
            case 'm': c = '' + (d.getMonth() + 1); break;
            case 'y': c = '' + d.getFullYear(); break;
            case 'b': c = '' + monthnames[d.getMonth()]; break;
            case 'p': c = (isam) ? ('' + 'am') : ('' + 'pm'); break;
            case 'P': c = (isam) ? ('' + 'AM') : ('' + 'PM'); break;
              case 'D': c = '' + day; break;
          }
          r.push(c);
          escape = false;
        } else {
          if (c == '%') {
            escape = true;
          } else {
            r.push(c);
          }
        }
      }
      return r.join('');
  };

  var stampFormatDate = function (date) {
    return '' + date.getFullYear() + leftPad((date.getMonth() + 1)) + leftPad(date.getDate()) + 'T' + leftPad(date.getHours()) + ':' + leftPad(date.getMinutes()) + ':' + leftPad(date.getSeconds());
  };

  var filteringMessages = function (messages, from, to) {
    var
      timemessage = new Date(0).getTime(),
      timefrom = from.getTime(),
      timeto = to.getTime(),
      messagesInd = 0,
      filteredmessages = [];
    messagesInd = messages.length;
    while (messagesInd--) {
      timemessage = messages[messagesInd].date.getTime();
      if (timemessage >= timefrom && timemessage <= timeto) {
        filteredmessages.unshift(messages[messagesInd]);
      }
    }
    return filteredmessages;
  };

  var init = function (shortdate, fulldate, monthnames, historycount, daynames) {
    if (isInit === true) {
      return undefined;
    }
    isInit = true;
      // TODO
    dayNames = daynames.split(',');
    monthNames = monthnames.split(',');
    shortDateFormat = shortdate;
    fullDateFormat = fulldate;

    if (isFinite(+historycount)) {
      maxHistoryCount = +historycount;
    }

    

    ASC.TMTalk.connectionManager.bind(ASC.TMTalk.connectionManager.events.retrievesFeatures, onRetrievesFeatures);
  };

  var onRetrievesFeatures = function (domain, features) {
    var featuresInd = features.length;
    while (featuresInd--) {
      switch (features[featuresInd].getAttribute('var')) {
        case Strophe.NS.ADDRESS :
          multicastIsSupported = true;
          multicastDomain = domain;
          break;
      }
    }
  };

  var bind = function (eventName, handler, params) {
    return eventManager.bind(eventName, handler, params);
  };

  var unbind = function (handlerId) {
    return eventManager.unbind(handlerId);
  };

  var getHistory = function (jid, historycount) {
    if (ASC.TMTalk.connectionManager.connected() === false) {
      eventManager.call(customEvents.loadHistory, window, [jid, history.hasOwnProperty(jid) ? history[jid].messages : [], 0]);
      return undefined;
    }
    if (history.hasOwnProperty(jid) && history[jid].loaded === true) {
      eventManager.call(customEvents.loadHistory, window, [jid, history[jid].messages, 0]);
      return undefined;
    }
    if (!history.hasOwnProperty(jid)) {
      history[jid] = {
        loaded    : false,
        messages  : [],
        archive   : null
      };
    }
    var messageslen = history[jid].messages.length;
    history[jid].messages = [];
    ASC.TMTalk.connectionManager.getMessagesByNumber(jid, (isFinite(+historycount) ? +historycount : maxHistoryCount) + messageslen);
  };

  var updateHistory = function (jid, startindex, count, text) {
     history[jid] = {
        loaded: false,
        messages: [],
        archive: null
     };
     ASC.TMTalk.connectionManager.getMessagesByRange(jid, startindex, count, text);
  };
  
  var updateOpenRoomsHistory = function () {
      var openedRooms = localStorageManager.getItem("openedRooms") != undefined ? localStorageManager.getItem("openedRooms") : {};
      for (var key in openedRooms) {
          ASC.TMTalk.messagesManager.updateHistory(key, 0, 20, '');
      }
  };
    
  var getHistoryByFilter = function (jid, from, to) {
    if (ASC.TMTalk.connectionManager.connected() === false) {
      eventManager.call(customEvents.loadFilteredHistory, window, [jid, history.hasOwnProperty(jid) ? filteringMessages(history[jid].archive.messages, from, to) : []]);
      return undefined;
    }
    if (history.hasOwnProperty(jid) && history[jid].archive !== null && from.getTime() >= history[jid].archive.from.getTime()) {
      eventManager.call(customEvents.loadFilteredHistory, window, [jid, filteringMessages(history[jid].archive.messages, from, to)]);
      return undefined;
    }
    if (!history.hasOwnProperty(jid)) {
      history[jid] = {
        loaded    : false,
        messages  : [],
        archive   : null
      };
    }
    if (history[jid].archive === null) {
      history[jid].archive = {from : new Date(), messages : []};
    }
    if (from.getTime() < history[jid].archive.from.getTime()) {
      history[jid].archive.messages = [];
      ASC.TMTalk.connectionManager.getMessagesByDate(jid, stampFormatDate(from), stampFormatDate(to));
    }
  };

  var loadHistory = function (iq, removeOld, searchText) {
    var
      child = null,
      isMe = false,
      childs = null,
      childsInd = 0,
      items = null,
      itemsInd = 0,
      body = '',
      date = null,
      from = '',
      type = '',
      sender = '',
      messages = [],
      jid = iq.getAttribute('from'),
      ownjid = ASC.TMTalk.connectionManager.getJid();

    if (!history.hasOwnProperty(jid)) {
      return undefined;
    }

    items = iq.getElementsByTagName('item');
    if (items.length === 0) {
      items = Strophe.getElementsByTagName(iq, 'item');
    }

    itemsInd = items.length;
    while (itemsInd--) {
      from = items[itemsInd].getAttribute('from');
      type = items[itemsInd].getAttribute('type');
      sender = type === 'groupchat' ? from.substring(from.indexOf('/') + 1, from.length) : from.substring(0, from.indexOf('/')).toLowerCase();
      sender = sender === '' ? from : sender;
      childs = items[itemsInd].childNodes;
      childsInd = childs.length;
      while (childsInd--) {
        child = childs[childsInd];
        if (child.nodeType == '1') {
          switch (child.tagName.toLowerCase()) {
            case 'body' :
              body = ASC.TMTalk.dom.getContent(child);
              break;
            case 'x' :
              if (child.getAttribute('xmlns') == Strophe.NS.TIMESTAMP) {
                date = child.getAttribute('stamp').split('T');
                date[1] = date[1].split(':');
                date = new Date(Date.UTC(+date[0].substr(0, 4), +date[0].substr(4, 2) - 1, +date[0].substr(6, 2), +date[1][0], +date[1][1], +date[1][2]));
                //date.setMinutes(date.getMinutes() - new Date().getTimezoneOffset());
                date = date instanceof Date ? date : new Date();
              }
              break;
          }
        }
      }
      date = date === null ? new Date() : date;
      isMe = type === 'groupchat' ? ASC.TMTalk.mucManager.isMe(from) : ownjid === sender;
      messages.unshift({
        jid         : jid,
        date        : date,
        displayDate : getDisplayDate(date),
        displayName : ASC.TMTalk.contactsManager.getContactName(sender),
        body        : body,
        isOwn       : isMe
      });
    }

    if (jid) {
      var newmessages = history[jid].messages.length;
      history[jid].loaded = true;
      history[jid].messages = messages;
        eventManager.call(customEvents.loadHistory, window, [jid, history[jid].messages, newmessages, removeOld, searchText]);
    }
  };

  var loadHistoryByFilter = function (iq, dateFrom, dateTo) {
    if (typeof dateFrom !== 'string' || typeof dateTo !== 'string') {
      return undefined;
    }

    dateFrom = dateFrom.split('T');
    dateFrom[1] = dateFrom[1].split(':');
    dateFrom = new Date(Date.UTC(+dateFrom[0].substr(0, 4), +dateFrom[0].substr(4, 2) - 1, +dateFrom[0].substr(6, 2), +dateFrom[1][0], +dateFrom[1][1], +dateFrom[1][2]));
    dateFrom = dateFrom instanceof Date ? dateFrom : null;

    dateFrom.setTime(dateFrom.getTime() + dateFrom.getTimezoneOffset() * 60000);

    dateTo = dateTo.split('T');
    dateTo[1] = dateTo[1].split(':');
    dateTo = new Date(Date.UTC(+dateTo[0].substr(0, 4), +dateTo[0].substr(4, 2) - 1, +dateTo[0].substr(6, 2), +dateTo[1][0], +dateTo[1][1], +dateTo[1][2]));
    dateTo = dateTo instanceof Date ? dateTo : null;

    dateTo.setTime(dateTo.getTime() + dateTo.getTimezoneOffset() * 60000);

    if (dateFrom === null || dateTo === null) {
      return undefined;
    }

    var
      child = null,
      childs = null,
      childsInd = 0,
      items = null,
      itemsInd = 0,
      body = '',
      date = null,
      from = '',
      sender = '',
      messages = [],
      jid = iq.getAttribute('from'),
      ownjid = ASC.TMTalk.connectionManager.getJid();

    if (!history.hasOwnProperty(jid)) {
      return undefined;
    }

    items = iq.getElementsByTagName('item');
    if (items.length === 0) {
      items = Strophe.getElementsByTagName(iq, 'item');
    }

    itemsInd = items.length;
    while (itemsInd--) {
      from = items[itemsInd].getAttribute('from');
      sender = from.substring(0, from.indexOf('/')).toLowerCase();
      sender = sender === '' ? from : sender;
      childs = items[itemsInd].childNodes;
      childsInd = childs.length;
      while (childsInd--) {
        child = childs[childsInd];
        if (child.nodeType == '1') {
          switch (child.tagName.toLowerCase()) {
            case 'body' :
              body = ASC.TMTalk.dom.getContent(child);
              break;
            case 'x' :
              if (child.getAttribute('xmlns') == Strophe.NS.TIMESTAMP) {
                date = child.getAttribute('stamp').split('T');
                date[1] = date[1].split(':');
                date = new Date(Date.UTC(+date[0].substr(0, 4), +date[0].substr(4, 2) - 1, +date[0].substr(6, 2), +date[1][0], +date[1][1], +date[1][2]));
                //date.setMinutes(date.getMinutes() - new Date().getTimezoneOffset());
                date = date instanceof Date ? date : new Date();
              }
              break;
          }
        }
      }
      date = date === null ? new Date() : date;
      messages.unshift({
        jid         : jid,
        date        : date,
        displayDate : getDisplayDate(date),
        displayName : ASC.TMTalk.contactsManager.getContactName(sender),
        body        : body,
        isOwn       : ownjid === sender
      });
    }
    history[jid].archive.from = dateFrom;
    history[jid].archive.messages = messages;
    eventManager.call(customEvents.loadFilteredHistory, window, [jid, filteringMessages(history[jid].archive.messages, dateFrom, dateTo)]);
  };

  var openHistory = function (jid) {
    eventManager.call(customEvents.openHistory, window, [jid]);
  };
  var clearCurrentHistory = function (jid) {
      if (history[jid]) {
         delete history[jid]; 
      }
  };
  var closeHistory = function (jid) {
    eventManager.call(customEvents.closeHistory, window, [jid]);
  };

  var composingMessageFromChat = function (message) {
    var
      from = message.getAttribute('from'),
      jid = from.substring(0, from.indexOf('/')).toLowerCase();

    eventManager.call(customEvents.composingMessageFromChat, window, [jid === '' ? from : jid]);
  };

  var pausedMessageFromChat = function (message) {
    var
      from = message.getAttribute('from'),
      jid = from.substring(0, from.indexOf('/')).toLowerCase();

    eventManager.call(customEvents.pausedMessageFromChat, window, [jid === '' ? from : jid]);
  };

  var sendMessageToChat = function (jid, body, unsend) {
    if (ASC.TMTalk.connectionManager.connected() === false) {
      return undefined;
    }
    var date = new Date();
    if (jid && typeof body === 'string' && body.length > 0) {
      if (unsend !== true) {
        ASC.TMTalk.connectionManager.sendMessage(jid, body, 'chat');
      }
      var message = {
        jid         : jid,
        date        : date,
        displayDate : getDisplayDate(date),
        displayName : ASC.TMTalk.contactsManager.getContactName(),
        body        : body,
        isOwn       : true
      };
      if (!history.hasOwnProperty(jid)) {
        history[jid] = {
          loaded    : false,
          messages  : [],
          archive   : null
        };
      }
      history[jid].messages.push(message);
      if (history[jid].archive !== null) {
        history[jid].archive.messages.push(message);
      }
      eventManager.call(customEvents.sentMessageToChat, window, [jid, message.displayName, message.displayDate, date, body]);
    }
  };

  var recvMulticastMessage = function (message) {
    var
      nodes = null,
      date = new Date(),
      body = '',
      from = message.getAttribute('from'),
      jid = from.substring(0, from.indexOf('/')).toLowerCase();

    jid = jid === '' ? from : jid;
    nodes = message.getElementsByTagName('body');
    if (nodes.length === 0) {
      nodes = Strophe.getElementsByTagName(message, 'body');
    }
    if (nodes.length > 0) {
      body = ASC.TMTalk.dom.getContent(nodes[0]);
    }

    if (jid && body.length > 0) {
      var message = {
        jid         : jid,
        date        : date,
        displayDate : getDisplayDate(date),
        displayName : ASC.TMTalk.contactsManager.getContactName(jid),
        body        : body,
        isOwn       : false
      };
      if (!history.hasOwnProperty(jid)) {
        history[jid] = {
          loaded    : false,
          messages  : [],
          archive   : null
        };
      }
      history[jid].messages.push(message);
      if (history[jid].archive !== null) {
        history[jid].archive.messages.push(message);
      }

      eventManager.call(customEvents.recvMessageFromChat, window, [jid, message.displayName, message.displayDate, date, body]);
    }
  };

  var recvOfflineMessagesFromChat = function (messages) {
      
    var
      date = null,
      nodes = null,
      body = '',
      from = '',
      jid = '',
      message = null,
      offlinemessages = {};

    for (var i = 0, n = messages.length; i < n; i++) {
      message = messages[i];

      body = '';
      date = new Date();
      from = message.getAttribute('from');
      jid = from.substring(0, from.indexOf('/')).toLowerCase();
      jid = jid === '' ? from : jid;

      nodes = message.getElementsByTagName('body');
      if (nodes.length === 0) {
        nodes = Strophe.getElementsByTagName(message, 'body');
      }
      if (nodes.length > 0) {
        body = ASC.TMTalk.dom.getContent(nodes[0]);
      }

      nodes = message.getElementsByTagName('delay');
      if (nodes.length === 0) {
        nodes = Strophe.getElementsByTagName(message, 'delay');
      }
      if (nodes.length > 0) {
        date = nodes[0].getAttribute('stamp');
        if (date) {
          date = date.split('T');
          date[1] = date[1].split(':');
          date = new Date(Date.UTC(+date[0].substr(0, 4), +date[0].substr(4, 2) - 1, +date[0].substr(6, 2), +date[1][0], +date[1][1], +date[1][2]));
          //date.setMinutes(date.getMinutes() - new Date().getTimezoneOffset());
          date = date instanceof Date ? date : new Date();
        }
      }

      if (jid && body.length > 0) {
        var msg = {
          jid         : jid,
          date        : date,
          displayDate : getDisplayDate(date),
          displayName : ASC.TMTalk.contactsManager.getContactName(jid),
          body        : body,
          isOwn       : false
        };
        if (!offlinemessages.hasOwnProperty(jid)) {
          offlinemessages[jid] = [];
        }
        offlinemessages[jid].push(msg);
        if (!history.hasOwnProperty(jid)) {
          history[jid] = {
            loaded    : false,
            messages  : [],
            archive   : null
          };
        }
        history[jid].messages.push(msg);
        if (history[jid].archive !== null) {
          history[jid].archive.messages.push(msg);
        }
      }
    }
    for (jid in offlinemessages) {
      if (offlinemessages.hasOwnProperty(jid)) {
        eventManager.call(customEvents.recvOfflineMessagesFromChat, window, [jid, offlinemessages[jid]]);
      }
    }
    //for (i = 0, n = offlinemessages.length; i < n; i++) {
    //  message = offlinemessages[i];
    //  eventManager.call(customEvents.pausedMessageFromChat, window, [message.jid]);
    //  eventManager.call(customEvents.recvOfflineMessageFromChat, window, [message.jid, message.displayName, message.displayDate, message.date, message.body, true]);
    //}
  };

  var recvMessageFromChat = function (message, offlineStorage) {
    var
      nodes = null,
      date = new Date(),
      body = '',
      from = message.getAttribute('from'),
      jid = from.substring(0, from.indexOf('/')).toLowerCase();

    jid = jid === '' ? from : jid;
    nodes = message.getElementsByTagName('body');
    if (nodes.length === 0) {
      nodes = Strophe.getElementsByTagName(message, 'body');
    }
    if (nodes.length > 0) {
      body = ASC.TMTalk.dom.getContent(nodes[0]);
    }

    nodes = message.getElementsByTagName('delay');
    if (nodes.length === 0) {
      nodes = Strophe.getElementsByTagName(message, 'delay');
    }
    if (nodes.length > 0) {
      date = nodes[0].getAttribute('stamp');
      if (date) {
        date = date.split('T');
        date[1] = date[1].split(':');
        date = new Date(Date.UTC(+date[0].substr(0, 4), +date[0].substr(4, 2) - 1, +date[0].substr(6, 2), +date[1][0], +date[1][1], +date[1][2]));
        //date.setMinutes(date.getMinutes() - new Date().getTimezoneOffset());
        date = date instanceof Date ? date : new Date();
      }
    }

    if (jid && body.length > 0) {
      var msg = {
        jid         : jid,
        date        : date,
        displayDate : getDisplayDate(date),
        displayName : ASC.TMTalk.contactsManager.getContactName(jid),
        body        : body,
        isOwn       : false
      };
      if (!history.hasOwnProperty(jid)) {
        history[jid] = {
          loaded    : false,
          messages  : [],
          archive   : null
        };
      }
      history[jid].messages.push(msg);
      if (history[jid].archive !== null) {
        history[jid].archive.messages.push(msg);
      }

      eventManager.call(customEvents.pausedMessageFromChat, window, [jid]);
      eventManager.call(customEvents.recvMessageFromChat, window, [jid, msg.displayName, msg.displayDate, date, body, offlineStorage === true]);
    }
  };

  var sendMessageToConference = function (jid, message) {
    if (ASC.TMTalk.connectionManager.connected() === false) {
      return undefined;
    }
    if (jid && typeof message === 'string' && message.length > 0) {
      ASC.TMTalk.connectionManager.sendMessage(jid, message, 'groupchat');
    }
  };

  var recvMessageFromConference = function (message) {
    var
      nodes = null,
      nodesInd = 0,
      child = null,
      childs = null,
      childsInd = 0,
      timestamp = null,
      from = message.getAttribute('from'),
      name = '',
      roomjid = from.substring(0, from.indexOf('/')).toLowerCase(),
      date = null,
      body = '';

    childs = message.childNodes;
    childsInd = childs.length;
    while (childsInd--) {
      child = childs[childsInd];
      if (child.nodeType == '1') {
        switch (child.tagName.toLowerCase()) {
          case 'body' :
            body = ASC.TMTalk.dom.getContent(child);
            break;
          case 'x' :
            if (child.getAttribute('xmlns') == Strophe.NS.TIMESTAMP) {
              date = child.getAttribute('stamp').split('T');
              date[1] = date[1].split(':');
              date = new Date(Date.UTC(+date[0].substr(0, 4), +date[0].substr(4, 2) - 1, +date[0].substr(6, 2), +date[1][0], +date[1][1], +date[1][2]));
              //date.setMinutes(date.getMinutes() - new Date().getTimezoneOffset());
              date = date instanceof Date ? date : new Date();
            }
            break;
        }
      }
    }

    name = ASC.TMTalk.mucManager.getContactName(from);
    if (name === from) {
      name = from.substring(from.indexOf('/') + 1);
    }

    if (name && roomjid && date && body.length > 0) {
      eventManager.call(customEvents.recvMessageFromConference, window, [roomjid, name, getDisplayDate(date), date, body, ASC.TMTalk.mucManager.isMe(from)]);
    }
  };

  var sendMultiuserMessage = function (jids, body) {
    if (ASC.TMTalk.connectionManager.connected() === false) {
      return undefined;
    }
    if (typeof body === 'string' && body.length > 0) {
      if (multicastIsSupported === true && multicastDomain !== null) {
        ASC.TMTalk.connectionManager.sendMulticastMessage(multicastDomain, jids, body);

        var jidsInd = jids.length;
        while (jidsInd--) {
          sendMessageToChat(jids[jidsInd], body, true);
        }
      } else {
        var jidsInd = jids.length;
        while (jidsInd--) {
          sendMessageToChat(jids[jidsInd], body);
        }
      }
    }
  };
  var getDisplayDate = function (date) {
     // var displaydate = formatDate(date, date.getTime() < new Date().getTime() ? fullDateFormat : shortDateFormat, monthNames);
      var displaydate = formatDate(date, '%D %d.%m.%y %H:%M', monthNames, dayNames);
      return displaydate !== '' ? displaydate : date.toLocaleTimeString();
  };

  var historyLoaded = function (jid) {
    return history.hasOwnProperty(jid) && history[jid].loaded;
  };

  return {
    init  : init,

    bind    : bind,
    unbind  : unbind,

    events  : customEvents,

    formatDate  : formatDate,

    composingMessageFromChat  : composingMessageFromChat,
    pausedMessageFromChat     : pausedMessageFromChat,

    sendMultiuserMessage        : sendMultiuserMessage,
    sendMessageToChat           : sendMessageToChat,
    sendMessageToConference     : sendMessageToConference,
    recvMessageFromChat         : recvMessageFromChat,
    recvMulticastMessage        : recvMulticastMessage,
    recvMessageFromConference   : recvMessageFromConference,
    recvOfflineMessagesFromChat : recvOfflineMessagesFromChat,

    updateHistory       : updateHistory,
    updateOpenRoomsHistory: updateOpenRoomsHistory,
    getHistory          : getHistory,
    getHistoryByFilter  : getHistoryByFilter,
    loadHistory         : loadHistory,
    loadHistoryByFilter : loadHistoryByFilter,
    openHistory         : openHistory,
    closeHistory        : closeHistory,
    historyLoaded       : historyLoaded,
    clearCurrentHistory : clearCurrentHistory,

    getDisplayDate  : getDisplayDate
  };
})();


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/UserFolderXMailDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao
{
    public class UserFolderXMailDao : BaseDao, IUserFolderXMailDao
    {
        protected static ITable table = new MailTableFactory().Create<UserFoldertXMailTable>();

        protected string CurrentUserId { get; private set; }

        public UserFolderXMailDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public UserFolderXMail Get(int mailId)
        {
            var query = Query()
                .Where(UserFoldertXMailTable.Columns.Tenant, Tenant)
                .Where(UserFoldertXMailTable.Columns.User, CurrentUserId)
                .Where(UserFoldertXMailTable.Columns.MailId, mailId);

            var result = Db.ExecuteList(query)
                .ConvertAll(ToUserFolderXMail)
                .SingleOrDefault();

            return result;
        }

        public List<UserFolderXMail> GetList(uint? folderId = null, List<int> mailIds = null)
        {
            var query = Query()
                .Where(UserFoldertXMailTable.Columns.Tenant, Tenant)
                .Where(UserFoldertXMailTable.Columns.User, CurrentUserId);

            if (folderId.HasValue)
            {
                query.Where(UserFoldertXMailTable.Columns.FolderId, folderId.Value);
            }

            if (mailIds != null && mailIds.Any())
            {
                query.Where(Exp.In(UserFoldertXMailTable.Columns.MailId, mailIds));
            }

            var list = Db.ExecuteList(query)
                .ConvertAll(ToUserFolderXMail);

            return list;
        }

        public List<int> GetMailIds(uint folderId)
        {
            var query = new SqlQuery(UserFoldertXMailTable.TABLE_NAME)
                .Select(UserFoldertXMailTable.Columns.MailId)
                .Where(UserFoldertXMailTable.Columns.Tenant, Tenant)
                .Where(UserFoldertXMailTable.Columns.User, CurrentUserId)
                .Where(UserFoldertXMailTable.Columns.FolderId, folderId);

            var list = Db.ExecuteList(query)
                .ConvertAll(r => Convert.ToInt32(r[0]));

            return list;
        }

        private delegate SqlInsert CreateInsertDelegate();

        public void SetMessagesFolder(IEnumerable<int> messageIds, uint folderId)
        {
            var idMessages = messageIds as IList<int> ?? messageIds.ToList();
            if (!idMessages.Any())
                return;

            CreateInsertDelegate createInsertQuery = ()
                => new SqlInsert(UserFoldertXMailTable.TABLE_NAME)
                    .IgnoreExists(true)
                    .InColumns(UserFoldertXMailTable.Columns.Tenant,
                        UserFoldertXMailTable.Columns.User,
                        UserFoldertXMailTable.Columns.MailId,
                        UserFoldertXMailTable.Columns.FolderId);

            var insertQuery = createInsertQuery();

            int i, messagessLen;
            for (i = 0, messagessLen = idMessages.Count; i < messagessLen; i++)
            {
                var messageId = idMessages[i];

                insertQuery
                    .Values(Tenant, CurrentUserId, messageId, folderId);

                if ((i % 100 != 0 || i == 0) && i + 1 != messagessLen)
                    continue;

                Db.ExecuteNonQuery(insertQuery);

                insertQuery = createInsertQuery();
            }
        }

        public int Save(UserFolderXMail item)
        {
            var query = new SqlInsert(UserFoldertXMailTable.TABLE_NAME, true)
                .InColumnValue(UserFoldertXMailTable.Columns.Tenant, item.Tenant)
                .InColumnValue(UserFoldertXMailTable.Columns.User, item.User)
                .InColumnValue(UserFoldertXMailTable.Columns.MailId, item.MailId)
                .InColumnValue(UserFoldertXMailTable.Columns.FolderId, item.FolderId);

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        public int Remove(int? mailId = null, uint? folderId = null)
        {
            var query = new SqlDelete(UserFoldertXMailTable.TABLE_NAME)
                .Where(UserFoldertXMailTable.Columns.Tenant, Tenant)
                .Where(UserFoldertXMailTable.Columns.User, CurrentUserId);

            if (mailId.HasValue)
            {
                query.Where(UserFoldertXMailTable.Columns.MailId, mailId.Value);
            }

            if (folderId.HasValue)
            {
                query.Where(UserFoldertXMailTable.Columns.FolderId, folderId.Value);
            }

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        public int Remove(List<int> mailIds)
        {
            var query = new SqlDelete(UserFoldertXMailTable.TABLE_NAME)
                .Where(UserFoldertXMailTable.Columns.Tenant, Tenant)
                .Where(UserFoldertXMailTable.Columns.User, CurrentUserId)
                .Where(Exp.In(UserFoldertXMailTable.Columns.MailId, mailIds));

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        private static readonly string QueryDeleteFormat =
                string.Format(
                    "delete t from {0} t inner join {1} m " +
                    "on t.{2} = m.{3} and t.{4} = m.{5} and t.{6} = m.{7} " +
                    "where m.{8} = @mailbox_id and m.{5} = @tenant and m.{7} = @user",
                    UserFoldertXMailTable.TABLE_NAME, MailTable.TABLE_NAME,
                    UserFoldertXMailTable.Columns.MailId, MailTable.Columns.Id,
                    UserFoldertXMailTable.Columns.Tenant, MailTable.Columns.Tenant,
                    UserFoldertXMailTable.Columns.User, MailTable.Columns.User,
                    MailTable.Columns.MailboxId);

        public int RemoveByMailbox(int mailboxId)
        {
            return Db.ExecuteNonQuery(QueryDeleteFormat, new { mailbox_id = mailboxId, tenant = Tenant, user = CurrentUserId });
        }

        protected UserFolderXMail ToUserFolderXMail(object[] r)
        {
            var folderXMail = new UserFolderXMail
            {
                Tenant = Convert.ToInt32(r[0]),
                User = Convert.ToString(r[1]),
                MailId = Convert.ToInt32(r[2]),
                FolderId = Convert.ToUInt32(r[3]),
                TimeModified = Convert.ToDateTime(r[4])
            };

            return folderXMail;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/js/filechoice.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC.Files.FileChoice = (function () {
    var isInit = false;

    var init = function (folderId, onlyFolder, thirdParty, fromEditor, originForPost) {
        if (fromEditor) {
            thirdParty = undefined;
        }
        if (isInit === false) {
            isInit = true;

            if (typeof thirdParty == "string") {
                if (thirdParty == "") {
                    thirdParty = undefined;
                } else {
                    thirdParty = (thirdParty == "true");
                }
            }

            jq("#fileSelectorTree").css("visibility", "visible");

            var callback = function () {
                ASC.Files.FileSelector.openDialog(folderId, onlyFolder, thirdParty);
                if (onlyFolder) {
                    ASC.Files.FileChoice.eventAfter();
                }
            };

            if (thirdParty) {
                jq("#fileSelectorTree>ul>li:not(.third-party-entry)").toggle(false);
                ASC.Files.FileSelector.createThirdPartyTree(callback);
            }

            if (onlyFolder) {
                jq("body").addClass("only-folder");

                ASC.Files.FileSelector.onSubmit = function (selectedFolderId) {
                    var folderTitle = ASC.Files.FileSelector.fileSelectorTree.getFolderTitle(selectedFolderId);

                    var path = ASC.Files.FileSelector.fileSelectorTree.getPath(selectedFolderId);
                    var pathId = jq(path).map(function (i, fId) {
                        return ASC.Files.FileSelector.fileSelectorTree.getFolderTitle(fId);
                    });

                    pathId.push(folderTitle);
                    var pathTitle = pathId.toArray().join(' > ');

                    var message = JSON.stringify({
                        folderId: selectedFolderId,
                        pathTitle: pathTitle,
                    });

                    window.parent.postMessage(message, originForPost);
                };
            } else {
                ASC.Files.Folders.eventAfter = function () {
                    ASC.Files.FileChoice.eventAfter();
                };

                ASC.Files.FileSelector.onSubmit = function (files) {

                    if (!fromEditor) {
                        if (jq(".file-selector-files").hasClass("file-selector-single")) {
                            var file = files[0];
                            var message = JSON.stringify({
                                fileId: file.id,
                                fileTitle: file.title,
                            });
                        } else {
                            message = JSON.stringify({
                                files: files,
                                folderShareable: ASC.Files.Folders.currentFolder.shareable
                            });
                        }

                        window.parent.postMessage(message, originForPost);
                    } else {
                        file = files[0];

                        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.GetPresignedUri, function (jsonData, params, errorMessage) {
                            if (typeof errorMessage != "undefined") {
                                toastr.error(errorMessage);
                                return;
                            }
                            var data = {
                                file: jsonData,
                                Referer: "onlyoffice"
                            };

                            message = JSON.stringify(data);

                            window.parent.postMessage(message, originForPost);
                        });

                        ASC.Files.ServiceManager.getPresignedUri(ASC.Files.ServiceManager.events.GetPresignedUri, {fileId: file.id});
                    }
                };
            }

            ASC.Files.FileSelector.onCancel = function () {
                var data = {
                    file: null,
                    Referer: "onlyoffice"
                };
                var message = JSON.stringify(data);
                window.parent.postMessage(message, originForPost);
            };

            if (!thirdParty) {
                callback();
            }
        }
    };

    var eventAfter = function () {
    };

    return {
        init: init,
        eventAfter:eventAfter
    };
})();

//(function ($) {
//    $(function () {
//        ASC.Files.FileChoice.init();
//    });
//})(jQuery);

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/ExceptionEventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class provides data for error events and methods.
    /// </summary>
    public class ExceptionEventArgs : EventArgs
    {
        #region Members

        private readonly Exception m_pException;

        #endregion

        #region Properties

        /// <summary>
        /// Gets exception.
        /// </summary>
        public Exception Exception
        {
            get { return m_pException; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="exception">Exception.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>exception</b> is null reference value.</exception>
        public ExceptionEventArgs(Exception exception)
        {
            if (exception == null)
            {
                throw new ArgumentNullException("exception");
            }

            m_pException = exception;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/js/common.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/*******************************************************************************
JQuery Extension
*******************************************************************************/

jq.browser.safari = (jq.browser.safari && !/chrome/.test(navigator.userAgent.toLowerCase())) == !0;

/*******************************************************************************
*******************************************************************************/

if (typeof ASC === "undefined") {
    ASC = {};
}
if (typeof ASC.CRM === "undefined") {
    ASC.CRM = (function() { return {} })();
}

jQuery.extend({

    forceNumber: function (settings) {
        var options = jQuery.extend({
            parent: "body",
            input: "",
            integerOnly: true,
            positiveOnly: true,
            onPasteCallback: null,
            separator: '.',
            lengthAfterSeparator: null
        }, settings);

        if (options.input == "") return;

        options.regex = new RegExp(['^', options.positiveOnly ? '' : '-?', '\\d*$'].join(''));
        if (options.integerOnly === false) {
            if (options.lengthAfterSeparator != null) {
                options.regex = new RegExp(['^', options.positiveOnly ? '' : '-?', '\\d*(', options.separator, '\\d{1,', options.lengthAfterSeparator, '})?$'].join(''));
            } else {
                options.regex = new RegExp(['^', options.positiveOnly ? '' : '-?', '\\d*(', options.separator, '\\d*)?$'].join(''));
            }
        }

        jq(options.parent).on("keypress", options.input, function (event) {
            var obj = this,
                key = event.which,
                caret = obj.selectionStart,
                val = jq(obj).val();

            // Backspace, Tab, Del ...
            if (key == 8 || key == 9 || key == 0) return;

            if (event.hasOwnProperty("ctrlKey") && event.ctrlKey === true && (key === 99 || key === 97)) {//ctrl + c and ctrl + a
                return;
            }

            if (event.hasOwnProperty("ctrlKey") && event.ctrlKey === true && key === 118) {//ctrl + v
                return onPaste(obj, options);
            } else {
                key = String.fromCharCode(key);

                var isSign = key == "-",
                    isNumber = /\d/.test(key),
                    hasSign = val.indexOf("-") != -1,
                    isSeparator = (key == options.separator && val.length),
                    hasSeparator = val.indexOf(options.separator) != -1; 


                if (options.integerOnly) {
                    if (options.positiveOnly) {
                        if (isNumber) return;
                    } else {
                        if (isNumber || isSign && !hasSign && caret == 0) return;
                    }
                } else {

                    var decimalPartLength = 0,
                        decimalPartLengthCorrect = true;
                    if (options.lengthAfterSeparator != null && isFinite(options.lengthAfterSeparator)) {
                        if (isSeparator) {
                            decimalPartLength = val.length - caret;
                        }
                        if ((isNumber || !options.positiveOnly && isSign) && hasSeparator) {
                            decimalPartLength = val.length - val.indexOf(options.separator) - 1 + (caret > val.indexOf(options.separator) ? 1 : 0);
                        }
                        decimalPartLengthCorrect = decimalPartLength <= options.lengthAfterSeparator;
                    }

                    if (options.positiveOnly) {
                        if ((isNumber || isSeparator && !hasSeparator) && decimalPartLengthCorrect) return;
                    } else {
                        if ((isNumber || (isSeparator && !hasSeparator) || (isSign && !hasSign && caret == 0)) && decimalPartLengthCorrect) return;
                    }
                }

                event.returnValue = false;
                if (event.preventDefault) event.preventDefault();
            }
        });

        jq(options.parent).on("paste", options.input, function (event) {
            onPaste(this, options);
        });

        function onPaste(obj, opts) {
            var oldValue = obj.value,
                $obj = jq(obj);

            setTimeout(
                function () {
                    var text = $obj.val();
                    if (!opts.regex.test(text)) {
                        $obj.val(oldValue);
                        return;
                    }

                    if (typeof (opts.onPasteCallback) === "function") opts.onPasteCallback();
                }, 0);

            return true;
        };
    },

    /**
    * Returns get parameters.
    *
    * If the desired param does not exist, null will be returned
    *
    * @example value = $.getURLParam("paramName");
    */
    getURLParam: function(strParamName) {
        strParamName = strParamName.toLowerCase();

        var strReturn = "",
            strHref = window.location.href.toLowerCase(),
            bFound = false,

            cmpstring = strParamName + "=",
            cmplen = cmpstring.length;

        if (strHref.indexOf("?") > -1) {
            var strQueryString = strHref.substr(strHref.indexOf("?") + 1),
                aQueryString = strQueryString.split("&");
            for (var iParam = 0; iParam < aQueryString.length; iParam++) {
                if (aQueryString[iParam].substr(0, cmplen) == cmpstring) {
                    var aParam = aQueryString[iParam].split("=");
                    strReturn = aParam[1];
                    bFound = true;
                    break;
                }

            }
        }
        if (bFound == false) { return null; }

        if (strReturn.indexOf("#") > -1) {
            return strReturn.split("#")[0];
        }
        return strReturn;
    }
}
);

jQuery.extend(StudioManager, {
    GetCRMImage: function (imageName) {
        return ASC.CRM.Data.ImageWebPath + "/" + imageName;
    }
});

jq.fn.datepickerWithButton = function(options) {
    return this.datepicker(jQuery.extend({
        showOn: "both",
        buttonText: "",
        buttonImageOnly: false
    }, options));
}

/*******************************************************************************
*******************************************************************************/

ASC.CRM.Common = (function() {
    return {

        tooltip: function (target_items, name, alwaysLeft) {
            var cornerHTML = "",
                tooltip = null,
                my_tooltip = null,
                left = 0,
                top = 0,
                addLeft = 0;

            var hideDescrPanel = function (tooltipItem) {
                setTimeout(function () {
                    if (!tooltipItem.data("overTaskDescrPanel")) {
                        tooltipItem.hide();
                    }
                }, 150);
            };


            jq(target_items).each(function () {
                var id = jq.trim(jq(this).attr('id')).split('_')[1],
                    title = jq.trim(jq(this).attr('title')),
                    params = ASC.CRM.Common.getTooltipParams(jq(this)),
                    my_tooltip = null;
                if (title == "" && params == "") {
                    return;
                }
                if (jq("#" + name + id).length > 0) {
                    jq("#" + name + id).remove();
                }

                jq("body").append(["<div class='studio-action-panel tooltip' id='",
                                        name, id, "'>",
                                        jq.htmlEncodeLight(title).replace(/&#10;/g, "<br/>").replace(/  /g, " &nbsp;"),
                                        params,
                                        "</div>"].join(''));

                my_tooltip = jq("#" + name + id);

                jq(this).removeAttr("title")
                    .unbind("mouseenter").mouseenter(function () {
                        var $obj = jq(this),
                            top = $obj.offset().top + $obj.height() + 5,
                            left = $obj.offset().left + 5;

                        jq(my_tooltip).data("overTaskDescrPanel", true);
                        jq(my_tooltip).css("top", top);

                        if (typeof (alwaysLeft) != "undefined" && alwaysLeft === true) {
                            var right = jq(window).width() - left - 35;
                            jq(my_tooltip).css("right", right);

                        } else {
                            jq(my_tooltip).css("left", left);
                        }
                        jq("div[id^='" + name + "']:not(div[id='" + name + id + "'])").hide();
                        my_tooltip.fadeIn(300);
                    })
                    .unbind("mouseleave").mouseleave(function () {
                        jq(my_tooltip).data("overTaskDescrPanel", false);
                        hideDescrPanel(my_tooltip);
                    });

                jq(my_tooltip)
                    .mouseenter(function () {
                        jq(my_tooltip).data("overTaskDescrPanel", true);
                    })
                    .mouseleave(function () {
                        jq(my_tooltip).data("overTaskDescrPanel", false);
                        hideDescrPanel(my_tooltip);
                    });

                jq(document).on("keypress", function (evt) {
                    if (!(evt.hasOwnProperty("ctrlKey") && evt.ctrlKey === true && (evt.which === 99 || evt.which === 97))) {//ctrl + c and ctrl + a
                        jq(my_tooltip).data("overTaskDescrPanel", false);
                        hideDescrPanel(my_tooltip);
                    }
                });
            });
        },

        getTooltipParams: function (obj) {
            var $o = jq(obj),
                label = jq.trim($o.attr("ttl_label")),
                value = jq.trim($o.attr("ttl_value")),
                dscr_label = jq.trim($o.attr("dscr_label")),
                dscr_value = jq.trim($o.attr("dscr_value")),
                resp_label = jq.trim($o.attr("resp_label")),
                resp_value = jq.trim($o.attr("resp_value"));

            $o.removeAttr("ttl_label");
            $o.removeAttr("ttl_value");
            $o.removeAttr("dscr_label");
            $o.removeAttr("dscr_value");
            $o.removeAttr("resp_label");
            $o.removeAttr("resp_value");

            if ((label == "" || value == "") &&
                (dscr_label == "" || dscr_value == "") &&
                (resp_label == "" || resp_value == "")) {
                return "";
            }
            var res = ["<table class='tooltipTable' cellspacing='0' cellpadding='0'>",
                        "<colgroup>",
                            "<col style='width: 1%;' />",
                            "<col style='width: 15px;' />",
                            "<col />",
                        "</colgroup>",
                       "<tbody>",
            ].join('');


            if (label != "" && value != "") {
                res += ["<tr><td><div class='param'>",
                        jq.htmlEncodeLight(label).replace(/&#10;/g, "<br/>").replace(/  /g, " &nbsp;"),
                        ":</div></td>",
                        "<td></td>",
                        "<td><div class='value'>",
                        jq.htmlEncodeLight(value).replace(/&#10;/g, "<br/>").replace(/  /g, " &nbsp;"),
                        "</div></td></tr>"].join('');
            }

            if (dscr_label != "" && dscr_value != "") {
                res += ["<tr><td><div class='param'>",
                        jq.htmlEncodeLight(dscr_label).replace(/&#10;/g, "<br/>").replace(/  /g, " &nbsp;"),
                        ":</div></td>",
                        "<td></td>",
                        "<td><div class='value'>",
                        jq.htmlEncodeLight(dscr_value).replace(/&#10;/g, "<br/>").replace(/  /g, " &nbsp;"),
                        "</div></td></tr>"].join('');
            }

            if (resp_label != "" && resp_value != "") {
                res += ["<tr><td><div class='param'>",
                        jq.htmlEncodeLight(resp_label).replace(/&#10;/g, "<br/>").replace(/  /g, " &nbsp;"),
                        ":</div></td>",
                        "<td></td>",
                        "<td><div class='value'>",
                        jq.htmlEncodeLight(resp_value).replace(/&#10;/g, "<br/>").replace(/  /g, " &nbsp;"),
                        "</div></td></tr>"].join('');
            }

            res += "</tbody></table>";
            return res;
        },

        registerChangeHoverStateByParent: function (elemSelector, hoverParentSelector) {
            var hasParent = true;
            if (typeof (hoverParentSelector) == "undefined" || hoverParentSelector == null || hoverParentSelector == "") {
                hasParent = false;
                hoverParentSelector = elemSelector;
            }

            jq(document).on("mouseover", hoverParentSelector, function () {
                var $elt = {};
                if (hasParent) {
                    $elt = jq(this).find(elemSelector);
                } else {
                    $elt = jq(this);
                }
                if ($elt.length == 0) return;
                $elt.addClass("hover");
            });

            jq(document).on("mouseout", hoverParentSelector, function () {
                var $elt;
                if (hasParent) {
                    $elt = jq(this).find(elemSelector);
                } else {
                    $elt = jq(this);
                }
                if ($elt.length == 0) return;
                $elt.removeClass("hover");
            });
        },

        RegisterContactInfoCard: function () {
            if (jq("#contactInfoCardResources").length == 0) {
                jq.tmpl("contactInfoCardResourcesTmpl", null).appendTo("body");
            }

            var CRMContactInfoCard = new PopupBox('popup_ContactInfoCard', 320, 140, 'tintLight', 'popupbox-border', '',
            {
                apiMethodName: "Teamlab.getCrmContact",
                tmplName: "contactInfoCardTmpl",
                customFactory: ASC.CRM.Common.contactItemFactory
            });

            jq(window).on("registerContactInfoCard", function (event, newElem) {
                var id = newElem.attr('id');
                if (id != null && id != '') {
                    CRMContactInfoCard.RegistryElement(id, newElem.attr('data-id'));
                }
            });

            jq(".crm-companyInfoCardLink, .crm-peopleInfoCardLink").each(function (index) {
                jq(window).trigger("registerContactInfoCard", [jq(this)]);
            });
        },

        contactItemFactory: function (contact, params) {
            contact.showCompanyLink = (typeof (params) != "undefined" && params != null && params.hasOwnProperty("showCompanyLink") && params.showCompanyLink);
            contact.showUnlinkBtn = (typeof (params) != "undefined" && params != null && params.hasOwnProperty("showUnlinkBtn") && params.showUnlinkBtn);
            contact.showActionMenu = (typeof (params) != "undefined" && params != null && params.hasOwnProperty("showActionMenu") && params.showActionMenu);

            var basePathForLink = StudioManager.getLocationPathToModule("CRM") + "Default.aspx?id=";

            contact.contactLink = basePathForLink + contact.id;
            if (contact.showCompanyLink && typeof (contact.company) && contact.company != null) {
                contact.company.contactLink = basePathForLink + contact.company.id;
            }

            contact.primaryAddress = null;
            contact.primaryEmail = null;
            if (typeof (contact.addresses) != "undefined" && contact.addresses.length != 0) {
                for (var addr in contact.addresses) {
                    if (contact.addresses.hasOwnProperty(addr)) {
                        var addressObj = contact.addresses[addr];
                        if (addressObj.isPrimary) {
                            var query = ASC.CRM.Common.getAddressQueryForMap(addressObj);
                            contact.primaryAddress = {
                                Data: ASC.CRM.Common.getAddressTextForDisplay(addressObj),
                                Href: "http://maps.google.com/maps?q=" + query,
                                categoryName: addressObj.categoryName
                            };
                            break;
                        }
                    }
                }
            }

            if (typeof (contact.commonData) != "undefined" && contact.commonData.length != 0) {
                for (var item in contact.commonData) {
                    if (contact.commonData.hasOwnProperty(item)) {
                        var itemObj = contact.commonData[item];
                        if (itemObj.infoType == 1 && itemObj.isPrimary) {//Primary Email
                            contact.primaryEmail = itemObj;
                            break;
                        }
                    }
                }
            }
        },

        getAddressTextForDisplay: function (addressObj) {
            if (typeof (addressObj) != "object") return "";

            var items = [],
                subitems = [];

            if (addressObj.street)
                items.push(jq.htmlEncodeLight(addressObj.street));

            if (addressObj.city)
                subitems.push(addressObj.city);

            if (addressObj.state)
                subitems.push(addressObj.state);

            if (addressObj.zip)
                subitems.push(addressObj.zip);

            if (subitems.length)
                items.push(jq.htmlEncodeLight(subitems.join(", ")));

            if (addressObj.country)
                items.push(jq.htmlEncodeLight(addressObj.country));

            return items.join(",<br/>");
        },

        getAddressQueryForMap: function (addressObj) {
            if (typeof (addressObj) != "object") return "";

            var items = [];

            if (addressObj.street)
                items.push(addressObj.street);

            if (addressObj.city)
                items.push(addressObj.city);

            if (addressObj.state)
                items.push(addressObj.state);

            if (addressObj.zip)
                items.push(addressObj.zip);

            if (addressObj.country)
                items.push(addressObj.country);

            return jq.trim(items.join(", ")).replace(/</ig, '&lt;').replace(/>/ig, '&gt;').replace(/\n/ig, ' ');
        },


        isHiddenForScroll: function (el) {
            var pos = el.position(),
                scrTop = jq(window).scrollTop(),
                scrLeft = jq(window).scrollLeft();
            if (pos.top > scrTop && pos.left > scrLeft &&
                pos.top + el.height() < scrTop + jq(window).height() &&
                    pos.left + el.width() < scrLeft + jq(window).width()) {
                return false;
            }
            return true;
        },

        renderCustomFields: function (customFieldList, custom_field_id_prefix, customFieldTmplID, customFieldTmplAppendToObjSelector) {
            var tmpSelectFields = [],
                field = {};
            for (var i = 0, n = customFieldList.length; i < n; i++) {
                field = customFieldList[i];

                if (jQuery.trim(field.mask) == "") {
                    continue;
                }

                field.mask = jq.evalJSON(field.mask);
                if (customFieldList[i].fieldType == 2) {
                    tmpSelectFields.push(customFieldList[i]);
                }
            }
            jq.tmpl(customFieldTmplID, customFieldList).appendTo(customFieldTmplAppendToObjSelector);

            for (var k = 0, len = tmpSelectFields.length; k < len; k++) {
                jq('#' + custom_field_id_prefix + tmpSelectFields[k].id).val(tmpSelectFields[k].value);
            }
        },

        sortCustomFieldList: function (customFieldList) {
            var sortedList = [],
                subList = {
                    label: "",
                    labelid: 0,
                    list: []
                };

            for (var i = 0, n = customFieldList.length; i < n; i++) {
                var field = customFieldList[i];
                if (jQuery.trim(field.mask) != "") {
                    field.mask = jq.evalJSON(field.mask);
                }
                if (field.fieldType == 4 || i == n - 1) {
                    if (field.fieldType != 4) {
                        subList.list.push(field);
                    }

                    sortedList.push(subList);

                    if (field.fieldType == 4) {
                        subList = {
                            label: field.label,
                            labelid: field.id,
                            list: []
                        };
                    }
                } else {
                    subList.list.push(field);
                }
            }

            for (var i = 0, n = sortedList.length; i < n; i++) {
                if (sortedList[i].list.length == 0) {
                    sortedList.splice(i, 1);
                    i--;
                    n--;
                }
            }
            return sortedList;
        },

        initTextEditCalendars: function () {
            var $calendars = jq("input.textEditCalendar"),
                $c = null,
                value = "";
            for (var i = 0, n = $calendars.length; i < n; i++) {
                $c = jq($calendars[i]);
                value = jq.trim($c.val());
                $c.mask(ASC.Resources.Master.DatePatternJQ);

                if (value == "") {
                    $c.val("");
                }
                $c.datepickerWithButton();
            }
        },

        changeCountInTab: function (actionOrCount, tabAnchorName) {
            var contactTab;

            if (typeof (tabAnchorName) != "undefined" && tabAnchorName != "") {
                if (jq("li.viewSwitcherTab_" + tabAnchorName).length == 0) {
                    return false;
                }
                contactTab = jq("li.viewSwitcherTab_" + tabAnchorName);
            } else {
                if (jq("li[id$=_ViewSwitcherTab].viewSwitcherTabSelected").length == 0) {
                    return false;
                }
                contactTab = jq("li[id$=_ViewSwitcherTab].viewSwitcherTabSelected")[0];
            }

            var contactTabTextArray = jq(contactTab).text().split(" ");

            if (typeof (actionOrCount) == "string") {
                if (actionOrCount == "add") {
                    if (contactTabTextArray.length > 1) {
                        var newValue = parseInt(contactTabTextArray[contactTabTextArray.length - 1].replace("(", "").replace(")", "")) + 1;
                        contactTabTextArray[contactTabTextArray.length - 1] = jq.format("({0})", newValue);
                        jq(contactTab).text(contactTabTextArray.join(" "));
                    } else {
                        jq(contactTab).text(jq.format("{0} (1)", contactTabTextArray[0]));
                    }
                } else if (actionOrCount == "delete") {
                    var newValue = parseInt(contactTabTextArray[contactTabTextArray.length - 1].replace("(", "").replace(")", "")) - 1;
                    if (newValue > 0) {
                        contactTabTextArray[contactTabTextArray.length - 1] = jq.format("({0})", newValue);
                        jq(contactTab).text(contactTabTextArray.join(" "));
                    } else {
                        jq(contactTab).text(contactTabTextArray[0]);
                    }
                }
            } else if (typeof (actionOrCount) == "number") {
                var count = parseInt(actionOrCount);
                if (count > 0) {
                    jq(contactTab).text(jq.format("{0} ({1})", contactTabTextArray[0], count));
                } else {
                    jq(contactTab).text(contactTabTextArray[0]);
                }
            }
        },

        getHexRGBColor: function (color) {
            color = color.replace(/\s/g, "");
            var aRGB = color.match(/^rgb\((\d{1,3}[%]?),(\d{1,3}[%]?),(\d{1,3}[%]?)\)$/i);

            if (aRGB) {
                color = '#';
                for (var i = 1; i <= 3; i++) {
                    color += Math.round((aRGB[i][aRGB[i].length - 1] == "%" ? 2.55 : 1) * parseInt(aRGB[i])).toString(16).replace(/^(.)$/, '0$1');
                }
            } else {
                color = color.replace(/^#?([\da-f])([\da-f])([\da-f])$/i, '$1$1$2$2$3$3');
            }

            return color;
        },

        animateElement: function (options) {
            if (typeof (options) != "object") {
                return;
            }
            var element = options.element;

            if (ASC.CRM.Common.isHiddenForScroll(element)) {
                jq.scrollTo(element);
                if (typeof (options.whenScrollFunc) === "function") {
                    options.whenScrollFunc();
                }
            }

            if (typeof (options.afterScrollFunc) === "function") {
                options.afterScrollFunc();
            }

            element.css({ "background-color": "#ffffcc" });
            element.animate({ backgroundColor: '#ffffff' }, 2000, function () {
                element.css({ "background-color": "" });
            });
        },

        removeExportButtons: function () {
            if (jq("#exportListToCSV").length == 1) {
                jq("#exportListToCSV").parent().remove();
            }
        },

        hideExportButtons: function () {
            if (jq("#exportListToCSV").length == 1) {
                jq("#exportListToCSV").parent().addClass("display-none");
            }
            if (!jq("#otherActions li:not(.display-none)").length) {
                jq("#menuOtherActionsButton").hide();
            }
        },

        showExportButtons: function () {
            if (jq("#exportListToCSV").length == 1) {
                jq("#exportListToCSV").parent().removeClass("display-none");
            }
            if (!!jq("#otherActions li:not(.display-none)").length) {
                jq("#menuOtherActionsButton").show();
            }
        },

        exportCurrentListToCsv : function() {
            jq("#otherActions").hide();
            ASC.CRM.PartialExport.startExport();
        },

        getMailModuleBasePath: function () {
            var products = "products",
                mass = location.href.toLowerCase().split(products);
            return mass[0] + "addons/mail/";
        },

        isArray: function (o) {
            return o ? o.constructor.toString().indexOf("Array") != -1 : false;
        },

        getAccessListHtml: function (userGuids) {
            if (typeof (userGuids) == "undefined" || userGuids.length == 0) { return ""; }
            var html = "";
            for (var i = 0, n = userGuids.length; i < n; i++) {
                var usr = window.UserManager.getUser(userGuids[i]);
                html += [
                    i == 0 ? "" : ",<span class='splitter'></span>",
                    usr != null ? usr.displayName : ASC.CRM.Data.ProfileRemoved
                ].join('');
            }
            return html;
        },

        convertText: function (str, toText) {
            str = typeof str === 'string' ? str : '';
            if (!str) {
                return '';
            }

            if (toText === true) {
                var
                    symbols = [
                    ['&lt;', '<'],
                    ['&gt;', '>'],
                    ['&and;', '\\^'],
                    ['&sim;', '~'],
                    ['&amp;', '&']
                    ];

                var symInd = symbols.length;
                while (symInd--) {
                    str = str.replace(new RegExp(symbols[symInd][1], 'g'), symbols[symInd][0]);
                }
                return str;
            }

            var o = document.createElement('textarea');
            o.innerHTML = str;
            return o.value;
        },

        loadContactFoto: function (curImgObj, newImgObj, handlerSrc, withAnimation) {
            if (handlerSrc.indexOf("filehandler.ashx") != -1) {
                jq.ajax({
                    type: "GET",
                    url: handlerSrc,
                    success: function (response) {
                        try {
                            if (curImgObj.attr("src").indexOf(response) === -1) {
                                newImgObj.one("load", function () {
                                    if (typeof (withAnimation) != "undefined" && withAnimation === true) {
                                        var left = (newImgObj.parent().width() - newImgObj.width()) / 2,
                                            top = (newImgObj.parent().height() - newImgObj.height()) / 2;
                                        newImgObj
                                            .css("left", left)
                                            .css("top", top);

                                        curImgObj.fadeOut(500);
                                        newImgObj.fadeIn(500);
                                    } else {
                                        curImgObj.hide();
                                        newImgObj.show();
                                    }
                                });
                                newImgObj.attr("src", [response, "?", new Date().getTime()].join(''));
                            }
                        }
                        catch (e) { }
                    }
                });
            } else {
                newImgObj.attr("src", handlerSrc);
                curImgObj.hide();
                newImgObj.show();
            }
        },

        getPagingParamsFromCookie : function (cookieKey) {
            var cookie = jq.cookies.get(cookieKey);
            if (cookie != null) {
                if (cookie.hasOwnProperty("page") && cookie.hasOwnProperty("countOnPage")) {
                    return {
                        countOnPage : cookie.countOnPage,
                        page : cookie.page
                    };
                }
            }
            return null;
        },

        arrayUnique : function(array) {
            var a = array.concat();
            for (var i  = 0; i < a.length; ++i) {
                for (var j = i + 1; j < a.length; ++j) {
                    if (a[i] === a[j])
                        a.splice(j--, 1);
                }
            }
            return a;
        },

        numberFormat: function (number, _cfg) {
            var _cfg_default = {
                before: '',
                after: '',
                decimals: 2,
                dec_point: '.',
                thousands_sep: ','
            };

            function thousands_sep(num, sep) {
                if (num.length <= 3) { return num; }
                var _count = num.length,
                    num_parser = '',
                    count_digits = 0;
                for (var _p = (_count - 1) ; _p >= 0; _p--) {
                    var num_digit = num.substr(_p, 1);
                    if (count_digits % 3 == 0 && count_digits != 0 && !isNaN(parseFloat(num_digit))) num_parser = sep + num_parser;
                    num_parser = num_digit + num_parser;
                    count_digits++;
                }
                return num_parser;
            }

            if (typeof number !== 'number') {
                number = parseFloat(number);
                if (isNaN(number)) return false;
            }

            if (_cfg && typeof _cfg === 'object') {
                _cfg = jq.extend(_cfg_default, _cfg);
            } else {
                _cfg = _cfg_default;
            }
            number = number.toFixed(_cfg.decimals);
            if (number.indexOf('.') != -1) {
                var number_arr = number.split('.'),
                    number = thousands_sep(number_arr[0], _cfg.thousands_sep) + _cfg.dec_point + number_arr[1];
            } else {
                var number = thousands_sep(number, _cfg.thousands_sep);
            }
            return [_cfg.before, number, _cfg.after].join('');
        },

        historyEventMsgObjFactory : function(eventItem) {
            var content = jq.parseJSON(eventItem.content);
            eventItem.content = content.subject != null && content.subject != "" ? content.subject : ASC.CRM.Resources.CRMJSResource.NoSubject;
            eventItem.message = {
                id : eventItem.id,
                subject : eventItem.content,
                is_sended : content.is_sended,
                important: content.important,
                from : content.from,
                to : content.to,
                cc : content.cc,
                bcc: content.bcc,
                message_url: content.message_url
            };
            if (content.hasOwnProperty("date_created")) {
                try {
                    eventItem.message.date_created = Teamlab.getDisplayDatetime(Teamlab.serializeDate(content.date_created));
                } catch(e) {
                    eventItem.message.date_created = content.date_created;
                }
            } else {
                eventItem.message.date_created = eventItem.displayCrtdate
            }
            if (content.cc != "" || content.bcc != "") {
                var cc_text = content.cc != "" ? content.cc : "";
                cc_text += content.bcc != "" ?
                    ((cc_text != "" ? ", " : "") + content.bcc) :
                    "";
                eventItem.message.cc_text = cc_text;
            }

            var basePathMail = ASC.CRM.Common.getMailModuleBasePath();
            eventItem.message.fromHref = [
                                            basePathMail,
                                            "#composeto/email=",
                                            eventItem.message.from
            ].join('');

            eventItem.message.toHref = [
                                            basePathMail,
                                            "#composeto/email=",
                                            eventItem.message.to
            ].join('');
        },

        setDocumentTitle : function (module) {
            document.title = jq.format("{0} - {1}", module, ASC.CRM.Resources.CRMCommonResource.ProductName);
        },

        bindOnbeforeUnloadEvent: function () {
            if (window.onbeforeunload == null) {
                window.onbeforeunload = function (e) {
                    return ASC.Resources.Master.ResourceJS.WarningMessageBeforeUnload;
                };
            }
        },
        unbindOnbeforeUnloadEvent: function () {
            window.onbeforeunload = null;
        },

        getRelativeItemsLinkString: function (count, typeUrl, view) {
            var relativeItemsString = "",
                oneElement = "",
                manyElements = "",
                noElements = "";

            if (typeUrl == null) { typeUrl = ""; }
            if (view == null) { view = ""; }

            switch (jq.trim(typeUrl)) {
                case "deal_milestone":
                    oneElement = ASC.CRM.Resources.CRMJSResource.OneDeal;
                    manyElements = ASC.CRM.Resources.CRMJSResource.ManyDeals;
                    noElements = ASC.CRM.Resources.CRMJSResource.NoDeals;
                    break;
                case "contact_stage":
                case "contact_type":
                    oneElement = ASC.CRM.Resources.CRMJSResource.OneContact;
                    manyElements = ASC.CRM.Resources.CRMJSResource.ManyContacts;
                    noElements = ASC.CRM.Resources.CRMJSResource.NoContacts;
                    break;
                case "task_category":
                    oneElement = ASC.CRM.Resources.CRMJSResource.OneTask;
                    manyElements = ASC.CRM.Resources.CRMJSResource.ManyTasks;
                    noElements = ASC.CRM.Resources.CRMJSResource.NoTasks;
                    break;
                case "history_category":
                    oneElement = ASC.CRM.Resources.CRMJSResource.OneEvent;
                    manyElements = ASC.CRM.Resources.CRMJSResource.ManyEvents;
                    noElements = ASC.CRM.Resources.CRMJSResource.NoEvents;
                    break;
                case "custom_field":
                case "tag":
                    switch (jq.trim(view)) {
                        case "opportunity":
                            oneElement = ASC.CRM.Resources.CRMJSResource.OneDeal;
                            manyElements = ASC.CRM.Resources.CRMJSResource.ManyDeals;
                            noElements = ASC.CRM.Resources.CRMJSResource.NoDeals;
                            break;
                        case "case":
                            oneElement = ASC.CRM.Resources.CRMJSResource.OneCase;
                            manyElements = ASC.CRM.Resources.CRMJSResource.ManyCases;
                            noElements = ASC.CRM.Resources.CRMJSResource.NoCases;
                            break;

                        case "company":
                            oneElement = ASC.CRM.Resources.CRMJSResource.OneCompany;
                            manyElements = ASC.CRM.Resources.CRMJSResource.ManyCompanies;
                            noElements = ASC.CRM.Resources.CRMJSResource.NoCompanies;
                            break;
                        case "people":
                        case "person":
                            oneElement = ASC.CRM.Resources.CRMJSResource.OnePerson;
                            manyElements = ASC.CRM.Resources.CRMJSResource.ManyPersons;
                            noElements = ASC.CRM.Resources.CRMJSResource.NoPersons;
                            break;

                        default:
                            oneElement = ASC.CRM.Resources.CRMJSResource.OneContact;
                            manyElements = ASC.CRM.Resources.CRMJSResource.ManyContacts;
                            noElements = ASC.CRM.Resources.CRMJSResource.NoContacts;
                            break;
                    }
            }

            if (count == 0) {
                return noElements;
            }
            if (count == 1) {
                relativeItemsString = "1 " + oneElement;
            } else {
                relativeItemsString = count + " " + manyElements;
            }
            return relativeItemsString;
        },

        createInvoiceMail: function (invoice, newTab) {

            Teamlab.getCrmContactInfo({}, invoice.contact.id, {
                success: function (params, info) {
                    var email = "";

                    for (var i = 0, n = info.length; i < n; i++) {
                        if (info[i].infoType == 1) {
                            email = info[i].data;
                            if (info[i].isPrimary) {
                                break;
                            }
                        }
                    }

                    invoice.contact.email = email;

                    var message = new ASC.Mail.Message();
                    message.to = [invoice.contact.email || ""];
                    message.subject = '';
                    message.body = invoice.description.replace(/\r\n|\n|\r/g, '<br>');
                    message.AddDocumentsForSave([invoice.fileId]);

                    ASC.Mail.Utility
                        .SaveMessageInDrafts(message)
                        .done(function (params, data) {
                            LoadingBanner.hideLoading();
                            if (newTab && newTab.location) {
                                newTab.location.href = data.messageUrl;
                            } else {
                                window.location.href = data.messageUrl;
                            }
                        })
                        .fail(function (params, error) {
                            console.log(params, error);
                            if (error === "No accounts.") {
                                if (newTab) {
                                    newTab.close();
                                }
                                if (jq("#noMailAccountsError").length == 0) {
                                    jq.tmpl("template-blockUIPanel", {
                                        id: "noMailAccountsError",
                                        headerTest: ASC.CRM.Resources.CRMCommonResource.Alert,
                                        questionText: "",
                                        innerHtmlText: ['<div>', ASC.CRM.Resources.CRMCommonResource.NoMailAccountsAvailableError, '</div>'].join(''),
                                        CancelBtn: ASC.CRM.Resources.CRMCommonResource.Close,
                                        OKBtn: ASC.CRM.Resources.CRMCommonResource.AddMailAccount,
                                        OKBtnClass: "OKAddMailAccount"
                                    }).appendTo(".mainContainerClass .containerBodyBlock");

                                    jq("#noMailAccountsError").on("click", ".OKAddMailAccount", function () {
                                        window.open(ASC.CRM.Common.getMailModuleBasePath(), "_blank");
                                        jq.unblockUI();
                                    });
                                }

                                PopupKeyUpActionProvider.EnableEsc = false;
                                StudioBlockUIManager.blockUI("#noMailAccountsError", 500);
                            }

                            LoadingBanner.hideLoading();
                        });
                },
                error: function (params, error) {
                    console.log(error);
                }
            });
        },

        setPostionPageLoader: function () {
            jq(".mainPageContent").children(".loader-page").css({
                top: jq(window).height() / 2 + "px"
            });
        }
    }
})();

ASC.CRM.PrivatePanel = (function() {
    return {
        changeIsPrivateCheckBox: function () {
            if (jq("#isPrivate").is(":checked")) {
                jq("#privateSettingsBlock").show();
            } else {
                jq("#privateSettingsBlock").hide();
            }
        },
        init: function (showNotifyPanel, notifyLabel, usersWhoHasAccess, userIDs, disabledUserIDs) {
            ASC.CRM.UserSelectorListView.Init(
                    "",
                    "UserSelectorListView",
                    showNotifyPanel,
                    notifyLabel,
                    usersWhoHasAccess,
                    userIDs,
                    disabledUserIDs,
                    "#privateSettingsBlock",
                    true);
            if (jq("#privateSettingsBlock").is(":visible")) {
                jq("#isPrivate").prop("checked", true);
            } else {
                jq("#isPrivate").prop("checked", false);
            }
        }
    };
})();


ASC.CRM.HistoryView = (function () {
    var historyCKEditor = null;
    var busy = false;

    function onGetException(params, errors) {
        console.log('common.js ', errors);
        LoadingBanner.hideLoading();
    };

    var _changeItem = function(item) {
        jq("#itemID").val(item.id);
    };

    var _renderContent = function() {
        if (ASC.CRM.HistoryView.isFirstTime == true) {
            ASC.CRM.HistoryView.isFirstTime = false;
            return;
        }
        LoadingBanner.displayLoading();
        ASC.CRM.HistoryView.ShowMore = true;
        _getEvents(0);
    };

    var _addRecordsToContent = function() {
        if (!ASC.CRM.HistoryView.ShowMore) { return false; }

        jq("#showMoreEventsButtons .crm-showMoreLink").hide();
        jq("#showMoreEventsButtons .loading-link").show();

        _getEvents(jq("#eventsTable tr").length);
    };

    var _getEvents = function(startIndex) {
        var filterSettings = {};
        filterSettings = ASC.CRM.HistoryView.getFilterSettings();

        filterSettings.entityid = ASC.CRM.HistoryView.ContactID != 0 ? ASC.CRM.HistoryView.ContactID : ASC.CRM.HistoryView.EntityID;
        filterSettings.entitytype = ASC.CRM.ListTaskView.EntityType;
        filterSettings.Count = ASC.CRM.HistoryView.CountOfRows;

        filterSettings.startIndex = startIndex;

        Teamlab.getCrmHistoryEvents({ startIndex: startIndex || 0 }, { filter: filterSettings, success: ASC.CRM.HistoryView.CallbackMethods.get_events_by_filter });
    };

    var _readDataEvent = function () {
        var content = jq("#historyBlock textarea").val();
        if (ASC.CRM.HistoryView.historyCKEditor) {
            content = ASC.CRM.HistoryView.historyCKEditor.getData();
        }
        var _contactID, _entityType, _entityID,
            dataEvent = {
                content: jq.trim(content),
                categoryId: eventCategorySelector.CategoryID
            };
        if (ASC.CRM.HistoryView.ContactID != 0) {
            dataEvent.contactID = ASC.CRM.HistoryView.ContactID;
            if (jq("#itemID").val() != "" && parseInt(jq("#itemID").val()) > 0 && jq("#typeID").val() != "") {
                dataEvent.entityId = jq("#itemID").val();
                dataEvent.entityType = jq("#typeID").val();
            }
        } else {
            if (jq("#contactID").val() != 0) dataEvent.contactID = jq("#contactID").val();
            dataEvent.entityId = ASC.CRM.HistoryView.EntityID;
            dataEvent.entityType = ASC.CRM.HistoryView.EntityType;
        }

        if (jq.trim(jq("#historyBlock .textEditCalendar").val()) != "") {
            dataEvent.created = jq("#historyBlock .textEditCalendar").datepicker('getDate');
            var now = new Date();
            dataEvent.created.setHours(now.getHours(), now.getMinutes(), now.getSeconds());

        } else {
            dataEvent.created = new Date();
            jq("#historyBlock .textEditCalendar").datepicker('setDate', dataEvent.created);
        }

        if (window.SelectedUsers_HistoryUserSelector.IDs.length != 0) {
            dataEvent.notifyUserList = window.SelectedUsers_HistoryUserSelector.IDs;
        }
        return dataEvent;
    };

    var _fillEventToEntityItems = function() {
        var entityTypeOpportunity = 1,
            entityTypeCase = 7,
            dealsFilters = {
                contactID: ASC.CRM.HistoryView.ContactID,
                contactAlsoIsParticipant: true
            },
            casesFilters = {
                contactID: ASC.CRM.HistoryView.ContactID
            };

        Teamlab.joint()
            .getCrmOpportunities({}, { filter: dealsFilters })
            .getCrmCases({}, { filter: casesFilters })
            .start({}, {
                success: function(params, opportunities, cases) {
                    jq("#eventLinkToPanel").replaceWith(jq.tmpl("eventLinkToPanelTmpl",
                    {
                        contactID: ASC.CRM.HistoryView.ContactID,
                        entityTypeOpportunity: entityTypeOpportunity,
                        entityTypeCase: entityTypeCase,
                        deals: opportunities,
                        cases: cases
                    }));

                    jq("#typeSwitcherSelect")
                     .val(-2)
                     .change(function (evt) {
                         switch (this.value) {
                             case "-2":
                                 ASC.CRM.HistoryView.changeType(-2, '');
                                 break;
                             case "-1":
                                 jq(this).val(-2).change();
                                 break;
                             default:
                                 for (var i = 0, n = ASC.CRM.Data.historyEntityTypes.length; i < n; i++) {
                                     if (this.value == ASC.CRM.Data.historyEntityTypes[i].value) {
                                         ASC.CRM.HistoryView.changeType(ASC.CRM.Data.historyEntityTypes[i].value, ASC.CRM.Data.historyEntityTypes[i].apiname);
                                         break;
                                     }
                                 }
                                 break;
                         }
                     })
                     .tlCombobox();

                    jq("#dealsSwitcherSelect")
                        .show()
                        .val(-2)
                        .change(function (evt) {
                            _changeItem({ id: this.value });
                        })
                        .tlCombobox().tlCombobox("hide");

                    jq("#casesSwitcherSelect")
                        .show()
                        .val(-2)
                        .change(function (evt) {
                            _changeItem({ id: this.value });
                        })
                        .tlCombobox().tlCombobox("hide");

                    if (!(params[0].__count > 0)) {
                        jq("#typeSwitcherSelect>option[value='" + entityTypeOpportunity + "']:not(.hidden)").addClass("hidden");
                        jq("#typeSwitcherSelect").tlCombobox();
                    }

                    if (!(params[1].__count > 0)) {
                        jq("#typeSwitcherSelect>option[value='" + entityTypeCase + "']:not(.hidden)").addClass("hidden");
                        jq("#typeSwitcherSelect").tlCombobox();
                    }

                    if (params[0].__count > 0 || params[1].__count > 0) {
                        jq("#eventLinkToPanel").removeClass("empty-select");
                    } else {
                        jq("#eventLinkToPanel").addClass("empty-select");
                    }
                }
            });
    };

    var _fillEventToEntityContacts = function () {
        Teamlab.getCrmEntityMembers({
            showCompanyLink: true,
            showUnlinkBtn: false,
            showActionMenu: true
        },
        ASC.CRM.HistoryView.EntityType,
        ASC.CRM.HistoryView.EntityID,
        {
            success: function (params, contacts) {
                jq("#eventLinkToPanel").replaceWith(jq.tmpl("eventLinkToPanelTmpl",
                {
                    contactID: 0,
                    contacts: contacts
                }));

                jq("#typeSwitcherSelect")
                     .val(-2)
                     .change(function (evt) {
                         switch (this.value) {
                             case "-2":
                                 ASC.CRM.HistoryView.changeType(-2, '');
                                 break;
                             case "-1":
                                 jq(this).val(-2).change();
                                 break;
                             default:
                                 for (var i = 0, n = ASC.CRM.Data.historyEntityTypes.length; i < n; i++) {
                                     if (this.value == ASC.CRM.Data.historyEntityTypes[i].value) {
                                         ASC.CRM.HistoryView.changeType(ASC.CRM.Data.historyEntityTypes[i].value, ASC.CRM.Data.historyEntityTypes[i].apiname);
                                         break;
                                     }
                                 }
                                 break;
                         }
                     })
                     .tlCombobox();

                jq("#contactSwitcherSelect")
                       .val(-2)
                       .change(function (evt) {
                           switch (this.value) {
                               case "-2":
                                   ASC.CRM.HistoryView.changeContact(-1);
                                   break;
                               case "-1":
                                   ASC.CRM.HistoryView.changeContact(-1);
                                   jq(this).val(-2).change();
                                   break;
                               default:
                                   ASC.CRM.HistoryView.changeContact(this.value);
                                   break;
                           }
                       })
                       .tlCombobox();

                        if (params.__count > 0) {
                            jq("#eventLinkToPanel").removeClass("empty-select");
                        } else {
                            jq("#eventLinkToPanel").addClass("empty-select");
                        }
            }
        });
    };

    var _initEmptyScreen = function(){
        jq.tmpl("template-emptyScreen",
            { ID: "emptyContentForEventsFilter",
                ImgSrc: ASC.CRM.Data.EmptyScrImgs["empty_screen_filter"],
                Header: ASC.CRM.Resources.CRMCommonResource.EmptyHistoryHeader,
                Describe: ASC.CRM.Resources.CRMCommonResource.EmptyHistoryDescription,
                ButtonHTML: ["<a class='clearFilterButton link dotline' href='javascript:void(0);' ",
                        "onclick='ASC.CRM.HistoryView.advansedFilter.advansedFilter(null);'>",
                        ASC.CRM.Resources.CRMCommonResource.ClearFilter,
                        "</a>"
                ].join(''),
                CssClass: "display-none"
            }).insertAfter("#eventsList");
    };

    var _initFileUploader = function() {
        ASC.CRM.FileUploader.OnBeginCallback_function = function () {
            busy = true;
            LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.AddThisNoteProggress;
            LoadingBanner.showLoaderBtn("#historyBlock");
            jq("#historyBlock textarea, #historyBlock input, #historyBlock select").attr("disabled", true);
            jq(".attachLink").addClass("disabledLink");
        };

        ASC.CRM.FileUploader.OnAllUploadCompleteCallback_function = function() {
            var data = _readDataEvent();
            data.fileId = ASC.CRM.FileUploader.fileIDs;

            Teamlab.addCrmHistoryEvent({}, data,
                {
                    success: ASC.CRM.HistoryView.CallbackMethods.add_event,
                    after: function (params) {
                        busy = false;
                        LoadingBanner.hideLoaderBtn("#historyBlock");
                        jq("#historyBlock .middle-button-container a.button.blue.middle").addClass("disable");                        
                        jq("#historyBlock textarea, #historyBlock input, #historyBlock select").attr("disabled", false);
                        jq(".attachLink").removeClass("disabledLink");
                    }
                });
        };

        ASC.CRM.FileUploader.activateUploader();
        ASC.CRM.FileUploader.fileIDs.clear();

        //Teamlab.bind(Teamlab.events.getException, onGetException);
    };

    var _initEventCategorySelector = function () {
        var helpInfoText = ASC.CRM.Data.IsCRMAdmin ? jq.format(ASC.CRM.Resources.CRMCommonResource.HistoryCategoriesHelpInfo,
            "<a class='linkAction' href='Settings.aspx?type=history_category' target='blank'>",
            "</a>") : "",
            selectedCategory = {};

        if (ASC.CRM.Data.eventsCategories.length > 0) {
            selectedCategory = ASC.CRM.Data.eventsCategories[0];
        } else {
            selectedCategory = { id: 0, title: "", imgSrc: "" };
        }

        window.eventCategorySelector = new ASC.CRM.CategorySelector("eventCategorySelector", selectedCategory);
        eventCategorySelector.renderControl(ASC.CRM.Data.eventsCategories, selectedCategory, "#categorySelectorContainer", 160, helpInfoText);
    };

    var _getHistoryEventByID = function (id) {
        for (var i = 0, n = ASC.CRM.HistoryView.EventsList.length; i < n; i++) {
            if (ASC.CRM.HistoryView.EventsList[i].id == id) {
                return ASC.CRM.HistoryView.EventsList[i];
            }
        }
        return null;
    };

    var _deleteHistoryEventByID = function (id) {
        for (var i = 0, n = ASC.CRM.HistoryView.EventsList.length; i < n; i++) {
            if (ASC.CRM.HistoryView.EventsList[i].id == id) {
                ASC.CRM.HistoryView.EventsList.splice(i, 1);
                return;
            }
        }
    };

    var _initFilter = function () {
        if (!jq("#eventsAdvansedFilter").advansedFilter) return;

        var tmpDate = new Date(),
            today = new Date(tmpDate.getFullYear(), tmpDate.getMonth(), tmpDate.getDate(), 0, 0, 0, 0),
            yesterday = new Date(new Date(today).setDate(tmpDate.getDate() - 1)),

            todayString = Teamlab.serializeTimestamp(today),
            yesterdayString = Teamlab.serializeTimestamp(yesterday);

        ASC.CRM.HistoryView.advansedFilter = jq("#eventsAdvansedFilter")
                .advansedFilter({
                    anykey: false,
                    hintDefaultDisable: false,
                    maxfilters: -1,
                    maxlength: "100",
                    store: false,
                    filters: [
                                {
                                    type: "flag",
                                    id: "my",
                                    apiparamname: "createBy",
                                    title: ASC.CRM.Resources.CRMCommonResource.MyEventsFilter,
                                    group: ASC.CRM.Resources.CRMCommonResource.FilterByResponsible,
                                    groupby: "responsible",
                                    defaultparams: { value: Teamlab.profile.id }
                                },
                                {
                                    type: "person",
                                    id: "responsibleID",
                                    apiparamname: "createBy",
                                    title: ASC.CRM.Resources.CRMCommonResource.CustomResponsibleFilter,
                                    group: ASC.CRM.Resources.CRMCommonResource.FilterByResponsible,
                                    groupby: "responsible",
                                    filtertitle: ASC.CRM.Resources.CRMCommonResource.FilterByResponsible
                                },
                                {
                                    type: "combobox",
                                    id: "today",
                                    apiparamname: jq.toJSON(["fromDate", "toDate"]),
                                    title: ASC.CRM.Resources.CRMCommonResource.Today,
                                    filtertitle: ASC.CRM.Resources.CRMCommonResource.Date,
                                    group: ASC.CRM.Resources.CRMCommonResource.Date,
                                    groupby: "date",
                                    options:
                                            [
                                            { value: jq.toJSON([todayString, todayString]), classname: '', title: ASC.CRM.Resources.CRMCommonResource.Today, def: true },
                                            { value: jq.toJSON([yesterdayString, yesterdayString]), classname: '', title: ASC.CRM.Resources.CRMCommonResource.Yesterday }
                                            ]
                                },
                                {
                                    type: "combobox",
                                    id: "yesterday",
                                    apiparamname: jq.toJSON(["fromDate", "toDate"]),
                                    title: ASC.CRM.Resources.CRMCommonResource.Yesterday,
                                    filtertitle: ASC.CRM.Resources.CRMCommonResource.Date,
                                    group: ASC.CRM.Resources.CRMCommonResource.Date,
                                    groupby: "date",
                                    options:
                                            [
                                            { value: jq.toJSON([todayString, todayString]), classname: '', title: ASC.CRM.Resources.CRMCommonResource.Today },
                                            { value: jq.toJSON([yesterdayString, yesterdayString]), classname: '', title: ASC.CRM.Resources.CRMCommonResource.Yesterday, def: true }
                                            ]
                                },
                                {
                                    type: "daterange",
                                    id: "fromToDate",
                                    title: ASC.CRM.Resources.CRMCommonResource.CustomDateFilter,
                                    group: ASC.CRM.Resources.CRMCommonResource.Date,
                                    groupby: "date",
                                    filtertitle: ASC.CRM.Resources.CRMCommonResource.Date
                                },
                                {
                                    type: "combobox",
                                    id: "categoryID",
                                    apiparamname: "categoryID",
                                    title: ASC.CRM.Resources.CRMCommonResource.ByCategory,
                                    group: ASC.CRM.Resources.CRMCommonResource.Other,
                                    options: jq.merge(jq.merge([], ASC.CRM.Data.eventsCategories), ASC.CRM.Data.systemCategories),
                                    defaulttitle: ASC.CRM.Resources.CRMCommonResource.Choose,
                                    defaultvalue: "0"
                                }
                    ],
                    sorters: [
                                { id: "created", title: ASC.CRM.Resources.CRMCommonResource.Date, dsc: true, def: true },
                                { id: "createby", title: ASC.CRM.Resources.CRMCommonResource.Author, dsc: false, def: false },
                                { id: "content", title: ASC.CRM.Resources.CRMCommonResource.Content, dsc: false, def: false },
                                { id: "category", title: ASC.CRM.Resources.CRMCommonResource.Category, dsc: false, def: false }
                    ]
                })
                .bind("setfilter", ASC.CRM.HistoryView.setFilter)
                .bind("resetfilter", ASC.CRM.HistoryView.resetFilter);
    };

    var _initUserSelectorForNotify = function () {

        if (typeof (window.UserList_HistoryUserSelector) != "undefined" && window.UserList_HistoryUserSelector != null) {
            var adminsGuids = [];
            for (var i = 0, n = ASC.CRM.Data.crmAdminList.length; i < n; i++) {
                adminsGuids.push(ASC.CRM.Data.crmAdminList[i].id);
            }
            window.UserList_HistoryUserSelector = ASC.CRM.Common.arrayUnique(window.UserList_HistoryUserSelector.concat(adminsGuids));
            for (var i = 0, n = window.UserList_HistoryUserSelector.length; i < n; i++) {
                if (window.UserList_HistoryUserSelector[i] === Teamlab.profile.id) {
                    window.UserList_HistoryUserSelector.splice(i, 1);
                    break;
                }
            }
        } else {
            window.UserList_HistoryUserSelector = null;
        }

        ASC.CRM.UserSelectorListView.Init("_HistoryUserSelector",
                                          "HistoryUserSelector",
                                          false,
                                          "",
                                          [],
                                          window.UserList_HistoryUserSelector,
                                          new Array(Teamlab.profile.id),
                                          "#historyViewUserSelector",
                                          false);

        jq("#selectedUsers_HistoryUserSelector").appendTo("#selectedUsers_HistoryUserSelector_Container");

        if (window.UserList_HistoryUserSelector != null && window.UserList_HistoryUserSelector.length == 0) {
            jq(".historyViewUserSelectorCont").hide();
        }

    };

    return {
        historyCKEditor: historyCKEditor,
        CallbackMethods: {
            get_events_by_filter: function(params, events) {
                if (typeof (params.__nextIndex) == "undefined") {
                    ASC.CRM.HistoryView.ShowMore = false;
                }
                if (params.startIndex === 0) {
                    ASC.CRM.HistoryView.EventsList = [];
                }

                for (var i = 0, n = events.length; i < n; i++) {
                    ASC.CRM.HistoryView.eventItemFactory(events[i]);
                    ASC.CRM.HistoryView.EventsList.push(events[i]);
                }

                if (params.startIndex === 0) {
                    jq("#eventsTable tbody tr").remove();

                    if (events.length == 0) {
                        if (typeof (ASC.CRM.HistoryView.advansedFilter) == "undefined"
                            || ASC.CRM.HistoryView.advansedFilter.advansedFilter().length == 1) {
                            jq("#eventsList").hide();
                            jq("#eventsFilterContainer").hide();
                            jq("#emptyContentForEventsFilter:not(.display-none)").addClass("display-none");
                            ASC.CRM.HistoryView.ShowMore = false;
                            LoadingBanner.hideLoading();
                            return false;
                        } else {
                            jq("#eventsList").hide();
                            jq("#eventsFilterContainer").show();
                            jq("#emptyContentForEventsFilter.display-none").removeClass("display-none");
                            LoadingBanner.hideLoading();
                            return false;
                        }
                    }

                    jq.tmpl("historyRowTmpl", events).appendTo("#eventsTable tbody");

                    jq("#emptyContentForEventsFilter:not(.display-none)").addClass("display-none");
                    jq("#eventsFilterContainer").show();
                    jq("#eventsList").show();
                    ASC.CRM.HistoryView.resizeFilter();

                    LoadingBanner.hideLoading();
                } else {
                    if (events.length == 0 && jq("#eventsTable tbody tr").length == 0) {
                        jq("#eventsList").hide();
                        jq("#eventsFilterContainer").show();
                        jq("#emptyContentForEventsFilter.display-none)").removeClass("display-none");
                        LoadingBanner.hideLoading();
                        return false;
                    }
                    jq.tmpl("historyRowTmpl", events).appendTo("#eventsTable tbody");
                }
                for (var i = 0, n = events.length; i < n; i++) {
                    if (events[i].files != null) {
                        jq.dropdownToggle({
                            dropdownID: "eventAttach_" + events[i].id,
                            switcherSelector: "#eventAttachSwither_" + events[i].id,
                            addTop: 5,
                            rightPos: true
                        });
                    }
                }

                jq("#showMoreEventsButtons .loading-link").hide();
                if (ASC.CRM.HistoryView.ShowMore) {
                    jq("#showMoreEventsButtons .crm-showMoreLink").show();
                } else {
                    jq("#showMoreEventsButtons .crm-showMoreLink").hide();
                }
            },

            add_event: function(params, event) {
                ASC.CRM.HistoryView.eventItemFactory(event);

                if (ASC.CRM.HistoryView.historyCKEditor) {
                    ASC.CRM.HistoryView.historyCKEditor.setData("");
                    ASC.CRM.HistoryView.historyCKEditor.focus();
                } else {
                    jq("#historyBlock textarea").val("");
                    jq("#historyBlock textarea").focus();
                }

                jq("#contactSwitcherSelect").val(-2).change();
                jq("#typeSwitcherSelect").val(-2).change();
                ASC.CRM.HistoryView.changeType(-1, '');
                ASC.CRM.HistoryView.changeContact(-1);

                jq("#usrSrListViewAdvUsrSrContainer_HistoryUserSelector .addUserLink").useradvancedSelector("undisable", window.SelectedUsers_HistoryUserSelector.IDs);
                window.SelectedUsers_HistoryUserSelector.IDs.clear();
                window.SelectedUsers_HistoryUserSelector.Names.clear();
                jq("#selectedUsers_HistoryUserSelector div").remove();

                if (!params.fromAttachmentsControl) {
                    ASC.CRM.FileUploader.reinit();
                    ASC.CRM.HistoryView.showAttachmentPanel(false);
                }

                if (jq("#eventsTable tbody tr").length == 0) {
                    jq("#emptyContentForEventsFilter:not(.display-none)").addClass("display-none");
                    jq("#eventsFilterContainer").show();
                    jq("#eventsList").show();
                    ASC.CRM.HistoryView.resizeFilter();
                }
                jq.tmpl("historyRowTmpl", event).prependTo("#eventsTable tbody");

                if (event.files != null)
                    jq.dropdownToggle({
                        dropdownID: "eventAttach_" + event.id,
                        switcherSelector: "#eventAttachSwither_" + event.id,
                        addTop: 5,
                        rightPos: true
                    });

                ASC.CRM.HistoryView.EventsList.unshift(event);
                if (event.files != null) {
                    if (typeof (window.Attachments) != "undefined") {
                        window.Attachments.appendFilesToLayout(event.files);
                    }
                }
            },

            delete_event: function(params, event) {
                jq("#eventAttach_" + event.id).find("[id^=fileContent_]").each(function() {
                    var fileID = jq(this).attr("id").split("_")[1];
                    if (typeof (window.Attachments) != "undefined") {
                        window.Attachments.deleteFileFromLayout(fileID);
                    }
                });
                _deleteHistoryEventByID(event.id);

                jq("#event_" + event.id).animate({ opacity: "hide" }, 500);
                setTimeout(function() {
                    jq("#event_" + event.id).remove();
                    if (jq("#eventsTable tr").length == 0) {
                        if (typeof (ASC.CRM.HistoryView.advansedFilter) != "undefined"
                            && ASC.CRM.HistoryView.advansedFilter.advansedFilter().length == 1) {
                            jq("#eventsFilterContainer").hide();
                            jq("#eventsList").hide();
                        } else {
                            _renderContent();
                        }
                    }
                }, 500);
            },

            delete_file_from_event: function(params, file) {
                if (typeof (window.Attachments) != "undefined") {
                    window.Attachments.deleteFileFromLayout(file.id);
                }
                ASC.CRM.HistoryView.deleteFileFromEventLayout(file.id, params.messageID);
            }
        },


        init: function(contactID, entityType, entityID) {
            ASC.CRM.HistoryView.ContactID = contactID;
            ASC.CRM.HistoryView.EntityID = entityID;
            ASC.CRM.HistoryView.EntityType = entityType;

            ASC.CRM.HistoryView.CountOfRows = ASC.CRM.Data.DefaultEntryCountOnPage;

            ASC.CRM.HistoryView.EventsList = [];
            ASC.CRM.HistoryView.ShowMore = true;
            ASC.CRM.HistoryView.isFilterVisible = false;
            ASC.CRM.HistoryView.isTabActive = false;
            ASC.CRM.HistoryView.isFirstTime = true;

            //init emptyScreen for filter
            _initEmptyScreen();

            _initUserSelectorForNotify();

            jq("#showMoreEventsButtons .crm-showMoreLink").bind("click", function() {
                _addRecordsToContent();
            });

            jq("#DepsAndUsersContainer").css("z-index", 999);

            jq("#historyBlock input.textEditCalendar").mask(ASC.Resources.Master.DatePatternJQ);
            jq("#historyBlock input.textEditCalendar").datepickerWithButton().datepicker('setDate', window.historyView_dateTimeNowShortDateString);

            jq("#historyBlock table #selectedUsers").remove();

            _initFileUploader();

            _initEventCategorySelector();

            setInterval(function() {
                if (jq("#historyBlock").is(":visible")) {
                    ASC.CRM.HistoryView.activate();
                }
            }, 100);

            setInterval(function () {
                var $button = jq("#historyBlock .middle-button-container a.button.blue.middle");
                var $input = jq("#historyBlock input.textEditCalendar");
                var $message = jq("#historyBlock .lond-data-text");
                var isValid = true;
                var text = jq.trim(ASC.CRM.HistoryView.historyCKEditor ? ASC.CRM.HistoryView.historyCKEditor.getData() : jq("#historyCKEditor").val());

                if (!text.length) {
                    $message.text("").addClass("display-none");
                    isValid = false;
                } else if (text.length > ASC.CRM.Data.MaxHistoryEventCharacters) {
                    $message
                        .text(ASC.CRM.Resources.CRMCommonResource.HistoryLongDataMsg.format(text.length - ASC.CRM.Data.MaxHistoryEventCharacters))
                        .removeClass("display-none");
                    isValid = false;
                } else {
                    $message.text("").addClass("display-none");
                }

                if (jq.isDateFormat($input.val().trim())) {
                    $input.css("borderColor", "");
                } else {
                    $input.css("borderColor", "#CC0000");
                    isValid = false;
                }

                if (isValid) {
                    $button.removeClass("disable");
                } else {
                    $button.addClass("disable");
                }

            }, 500);

            _initFilter();
        },

        bindCKEditorEvents: function () {
            if (ASC.CRM.HistoryView.historyCKEditor) {
                CKEDITOR.instances['historyCKEditor'].on('focus', function (event) {
                    jq("#historyCKEditor").trigger('click');
                    jq(".hasDatepicker").datepicker("hide");
                });
            }
        },

        setFilter: function(evt, $container, filter, params, selectedfilters) { _renderContent(); },
        resetFilter: function(evt, $container, filter, selectedfilters) { _renderContent(); },

        activate: function () {
            if (ASC.CRM.HistoryView.isTabActive == false) {
                ASC.CRM.HistoryView.isTabActive = true;

                ASC.CRM.HistoryView.refreshToEntitySelectors();
                _renderContent();
            }
        },

        refreshToEntitySelectors: function () {
            LoadingBanner.displayLoading();
            if (ASC.CRM.HistoryView.ContactID > 0) {
                _fillEventToEntityItems();
            } else {
                _fillEventToEntityContacts();
            }
        },

        resizeFilter: function () {
            if (typeof(ASC.CRM.HistoryView.advansedFilter) !== "undefined") {
                var visible = jq("#eventsFilterContainer").is(":hidden") == false;
                if (ASC.CRM.HistoryView.isFilterVisible == false && visible) {
                    ASC.CRM.HistoryView.isFilterVisible = true;
                    if (ASC.CRM.HistoryView.advansedFilter) {
                        jq("#eventsAdvansedFilter").advansedFilter("resize");
                    }
                }
            }
        },

        getFilterSettings: function() {
            var settings = {};

            if (ASC.CRM.HistoryView.advansedFilter.advansedFilter == null) return settings;

            var param = ASC.CRM.HistoryView.advansedFilter.advansedFilter();

            jq(param).each(function(i, item) {
                switch (item.id) {
                    case "sorter":
                        settings.sortBy = item.params.id;
                        settings.sortOrder = item.params.dsc == true ? 'descending' : 'ascending';
                        break;
                    case "text":
                        settings.filterValue = item.params.value;
                        break;
                    case "fromToDate":
                        settings.fromDate = new Date(item.params.from);
                        settings.toDate = new Date(item.params.to);
                        break;
                    default:
                        if (item.hasOwnProperty("apiparamname") && item.params.hasOwnProperty("value") && item.params.value != null) {
                            try {
                                var apiparamnames = jq.parseJSON(item.apiparamname),
                                    apiparamvalues = jq.parseJSON(item.params.value);
                                if (apiparamnames.length != apiparamvalues.length) {
                                    settings[item.apiparamname] = item.params.value;
                                }
                                for (var i = 0, len = apiparamnames.length; i < len; i++) {
                                    if (jq.trim(apiparamvalues[i]).length != 0) {
                                        settings[apiparamnames[i]] = apiparamvalues[i];
                                    }
                                }
                            } catch (err) {
                                settings[item.apiparamname] = item.params.value;
                            }
                        }
                        break;
                }
            });
            return settings;
        },

        eventItemFactory: function(eventItem) {
            if (eventItem.entity != null) {
                switch (eventItem.entity.entityType) {
                    case "opportunity":
                        eventItem.entityURL = "Deals.aspx?id=" + eventItem.entity.entityId;
                        eventItem.entityType = ASC.CRM.Resources.CRMJSResource.Deal;
                        break;
                    case "case":
                        eventItem.entityURL = "Cases.aspx?id=" + eventItem.entity.entityId;
                        eventItem.entityType = ASC.CRM.Resources.CRMJSResource.Case;
                        break;
                    default:
                        eventItem.entityURL = "";
                        eventItem.entityType = "";
                        break;
                }
            }

            eventItem.category.cssClass = eventItem.category.imagePath.split('/')[eventItem.category.imagePath.split('/').length - 1].split('.')[0];
            if (eventItem.category.cssClass == "32-attach") {
                eventItem.category.cssClass = "event_category_attach_file";
            }

            if (eventItem.category.id == -3) {// System event category for mails
                try {
                    ASC.CRM.Common.historyEventMsgObjFactory(eventItem);

                    eventItem.createdDate = eventItem.message.date_created;
                    eventItem.createdBy.displayName = eventItem.message.from;

                    eventItem.category.cssClass = eventItem.message.is_sended ? "event_category_system_email_out" : "event_category_system_email_in";
                }
                catch (e) {}
            }
        },

        deleteFile: function(fileID, messageID) {
            Teamlab.removeCrmFile({ messageID: messageID }, fileID, {
                success: ASC.CRM.HistoryView.CallbackMethods.delete_file_from_event
            });
        },

        deleteFileFromEventLayout: function(fileID, messageID) {
            jq("#fileContent_" + fileID).remove();
            if (jq("#eventAttach_" + messageID + ">ul.dropdown-content>li").length == 0) {
                jq(jq("#eventAttach_" + messageID).parent()).html("");
            }
        },

        showAttachmentPanel: function(showPanel) {
            if (showPanel) {
                if (jq("#attachShowButton").hasClass('disabledLink')) {
                    return false;
                }
                jq('#attachOptions').show();
                jq("#attachShowButton").hide();
                jq("#attachHideButton").show();
            } else {
                if (jq("#attachHideButton").hasClass('disabledLink')) {
                    return false;
                }
                jq('#attachOptions').hide();
                jq("#attachHideButton").hide();
                jq("#attachShowButton").show();
            }
        },

        addEvent: function(btnObj) {
            if (busy || jq(btnObj).hasClass("disable")) return;

            var text = jq("#historyBlock textarea").val();
            if (ASC.CRM.HistoryView.historyCKEditor) {
                text = ASC.CRM.HistoryView.historyCKEditor.getData();
            }

            text = jq.trim(text);

            if (!text.length || text.length > ASC.CRM.Data.MaxHistoryEventCharacters) return;

            if (ASC.CRM.FileUploader.getUploadFileCount() > 0) {
                ASC.CRM.FileUploader.start();
            } else {
                var data = _readDataEvent();
                Teamlab.addCrmHistoryEvent({}, data,
                {
                    success: ASC.CRM.HistoryView.CallbackMethods.add_event,
                    before: function(params) {
                        busy = true;
                        LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.AddThisNoteProggress;
                        LoadingBanner.showLoaderBtn("#historyBlock");
                        jq("#historyBlock textarea, #historyBlock input, #historyBlock select").attr("disabled", true);
                    },
                    after: function (params) {
                        busy = false;
                        LoadingBanner.hideLoaderBtn("#historyBlock");
                        jq("#historyBlock .middle-button-container a.button.blue.middle").addClass("disable");
                        jq("#historyBlock textarea, #historyBlock input, #historyBlock select").attr("disabled", false);
                    }
                });
            }
        },


        deleteEvent: function(id) {
            Teamlab.removeCrmHistoryEvent({}, id,
                {
                    success: ASC.CRM.HistoryView.CallbackMethods.delete_event,
                    before: function(params) { jq("#eventTrashImg_" + id).hide(); jq("#eventLoaderImg_" + id).show(); },
                    after: function (params) { jq("#eventLoaderImg_" + id).hide(); jq("#eventTrashImg_" + id).show(); }
                });
        },


        changeType: function(type, stringType) {
            jq("#typeID").val(stringType);
            jq("#itemID").val(-1);

            switch (type) {
                case 1: //opportunity
                    jq("#casesSwitcherSelect").tlcombobox('hide');
                    jq("#casesSwitcherSelect").val(-2).change();
                    jq("#dealsSwitcherSelect").tlcombobox('show');
                    jq("#typeSwitcherSelect>option[value='-1'].hidden").removeClass("hidden");
                    jq("#typeSwitcherSelect").tlCombobox();
                    break;
                case 7: //cases
                    jq("#dealsSwitcherSelect").tlcombobox('hide');
                    jq("#dealsSwitcherSelect").val(-2).change();
                    jq("#casesSwitcherSelect").tlcombobox('show');
                    jq("#typeSwitcherSelect>option[value='-1'].hidden").removeClass("hidden");
                    jq("#typeSwitcherSelect").tlCombobox();
                    break;
                default:
                    jq("#dealsSwitcherSelect").tlcombobox('hide');
                    jq("#casesSwitcherSelect").tlcombobox('hide');
                    jq("#dealsSwitcherSelect").val(-2).change();
                    jq("#casesSwitcherSelect").val(-2).change();
                    jq("#typeSwitcherSelect>option[value='-1']:not(.hidden)").addClass("hidden");
                    jq("#typeSwitcherSelect").tlCombobox();
                    break;
            }
        },

        changeContact: function(contactID) {
            jq("#contactID").val(contactID);

            if (contactID > 0) {
                jq("#contactSwitcherSelect>option[value='-1'].hidden").removeClass("hidden");
                jq("#contactSwitcherSelect").tlCombobox();
            } else {
                jq("#contactSwitcherSelect>option[value='-1']:not(.hidden)").addClass("hidden");
                jq("#contactSwitcherSelect").tlCombobox();
            }
        },

        appendOption: function (type, option) {
            if (type != "contact" && type != "case" && type != "opportunity") return;

            var entityTypeOpportunity = 1,
                $select = jq('#contactSwitcherSelect');
            if (type == "case") {
                $select = jq('#casesSwitcherSelect');
            } else if (type == "opportunity") {
                $select = jq('#dealsSwitcherSelect');

                var $hiddenOptDeal = jq("#typeSwitcherSelect>option[value='" + entityTypeOpportunity + "'].hidden");
                if ($hiddenOptDeal.length == 1) {
                    $hiddenOptDeal.removeClass("hidden");
                    jq("#typeSwitcherSelect").tlCombobox();
                }
            }

            var $tlcombobox = $select.parents('span.tl-combobox:first');
            $tlcombobox = $tlcombobox.length > 0 ? $tlcombobox : $select;
            $tlcombobox.parent().removeClass('empty-select');
            jq(document.createElement('option')).attr('value', option.value).text(option.title).appendTo($select);
            $select.tlCombobox();
            return $select;
        },

        removeOption: function (type, value) {
            if (type != "contact" && type != "case" && type != "opportunity") return;

            var $select = jq('#contactSwitcherSelect');
            if (type == "case") {
                $select = jq('#casesSwitcherSelect');
            } else if (type == "opportunity") {
                $select = jq('#dealsSwitcherSelect');
            }

            $select.find('option[value="' + value + '"]').remove();
            $select.tlCombobox();
            var 
                value = -1,
                $options = $select.find('option'),
                optionsInd = $options.length;
            while (optionsInd--) {
                value = jq($options[optionsInd]).attr('value');
                value = isFinite(+value) ? +value : -1;
                if (value > 0) {
                    break;
                }
            }
            if (optionsInd === -1) {
                var $tlcombobox = $select.parents('span.tl-combobox:first');
                $tlcombobox = $tlcombobox.length > 0 ? $tlcombobox : $select;
                $tlcombobox.parent().addClass('empty-select');
            }
            return $select;
        }
    };
})();


ASC.CRM.HistoryMailView = (function () {

    var createBodyIFrame = function (message) {
        var $frame = jq('<iframe id="message_body_frame_' + message.id +
        '" scrolling="auto" frameborder="0" width="100%" style="height:100%;">An iframe capable browser is required to view this web site.</iframe>');

        $frame.bind('load', function () {
            $frame.unbind('load');
            var $body = jq(this).contents().find('body');

            $body.css('cssText', 'height: 0;');
            message.html_body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">' + message.html_body;
            $body.html(message.html_body);
            $body.find("a").attr('target', '_blank');

            var $blockquote = jq($body.find('div.gmail_quote:first')[0] || $body.find('blockquote:first')[0]);

            if ($blockquote) {
                $blockquote.wrap('<div class="tmmail_quote"/>');

                var $wrap_block_quote = $body.find('div.tmmail_quote:first');

                if ($wrap_block_quote) {
                    $wrap_block_quote.before(
                        '<style>' +
                            '#controll-blockquote {width: 12px; display: inline-block; background-color: #F2F2F2; border: 1px solid #D7D8DC; cursor: pointer; padding: 0 5px; margin: 10px 0;}' +
                            '#controll-blockquote:hover {background-color: #D7D8DC; border: 1px solid #666;}' +
                            '#controll-blockquote div {margin-top: -8px; font-weight: bold; color: #D7D8DC; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none;}' +
                            '#controll-blockquote:hover div {color: #666;}' +
                            '</style>' +
                            '<div id="controll-blockquote"><div>...</div></div>');

                    $wrap_block_quote.hide();

                    var $btn_blockquote = $body.find('#controll-blockquote');
                    if ($btn_blockquote) {
                        $btn_blockquote.click(function () {
                            $wrap_block_quote.toggle();
                            var iframe = jq('#message_body_frame_' + message.id);
                            iframe.attr('scrolling', 'no');
                            setTimeout(function () {
                                iframe.attr('scrolling', 'auto');
                                _updateIframeSize(message.id, true);
                            }, 1);
                        });
                    }
                }
            }

            var index = $body.find("img").length;
            if (index > 0) {
                var timerId = setTimeout(function () {
                    _updateIframeSize(message.id);
                }, 50);

                $body.find('img').each(function () {
                    jq(this).bind("load", function () {
                        if (--index == 0) {
                            clearTimeout(timerId);
                            _updateIframeSize(message.id, true);
                        }
                    });
                });
            } else {
                _updateIframeSize(message.id, true);
            }
        });

        return $frame;
    };

    var _getTextNodeParams = function (textNode) {
        var param = null;
        if (document.createRange) {
            var range = document.createRange();
            range.selectNodeContents(textNode);
            if (range.getBoundingClientRect) {
                var rect = range.getBoundingClientRect();
                if (rect) {
                    param = rect;
                }
            }
        }
        return param;
    };

    var _updateIframeSize = function (id, finish) {
        var node_type = {
            element: 1,
            text: 3
        };

        /** IMPORTANT: All framed documents *must* have a DOCTYPE applied **/
        var iframe = jq('#message_body_frame_' + id),
            body = iframe.contents().find('body');

        //body.css('cssText', 'height: auto; max-width: ' + iframe.width() + 'px !important;');
        body.css('cssText', 'height: 0; max-width: ' + iframe.width() + 'px !important;');
        var contents = body.contents(),
            new_height = 0,
            text_node_param;

        if (window.ActiveXObject || window.sidebar) { // IE, Firefox
            for (var i = 0, n = contents.length; i < n; i++) {
                var offset = 0,
                    item = contents[i];

                if (item.nodeType == node_type.element) {
                    offset = jq(item).offset().top + Math.max(item.scrollHeight, item.clientHeight, jq(item).outerHeight(true));
                } else if (item.nodeType == node_type.text) {
                    text_node_param = _getTextNodeParams(item);
                    offset = text_node_param == null ? 0 : text_node_param.bottom + 1;
                }

                if (new_height < offset) new_height = offset;
            }
            new_height += body.offset().top;
        } else {
            new_height = iframe.contents().outerHeight(true);
            if (true == finish) new_height += body.offset().top;
        }

        // for scroll. It's height about 17px
        if (true == finish) {
            new_height += 20;
        }


        iframe.css('height', new_height + 'px');
    };


    var _displayIFrameMsgEvent = function (event) {
        jq("#mailHistoryEventContainer .messageHeader").html(jq.tmpl("historyMailTemplate", event.message));
        var bodyIFrameObj = createBodyIFrame(event.message);

        jq("#mailHistoryEventContainer .messageContent").html('').append(bodyIFrameObj);
    };

    return {
        init: function (event) {
            if (event == "" || event == null) return;
            try {
                event = jq.parseJSON(jq.base64.decode(event));
                ASC.CRM.Common.historyEventMsgObjFactory(event);
            } catch (e) {
                console.log(e);
                return;
            }

            try {
                if (event.message.hasOwnProperty("html_body")) {
                    _displayIFrameMsgEvent(event)
                } else {
                    jq.ajax({
                        type: "GET",
                        url: event.message.message_url,
                        success: function (response) {
                            try {
                                event.message.html_body = response;
                                _displayIFrameMsgEvent(event);
                            }
                            catch (e) { }
                        }
                    });
                }
            } catch (e) { }
        }
    };
})();

ASC.CRM.ContactSelector = new function() {
    var _hideAllAutocompleteBlocks = function() {
        jq("body>ul.ui-autocomplete").hide();
    };

    var _getSourceAutocompleteCallback = function(advancedInput, objName, obj, contacts) {
        var result = [];// contacts = null;
        if (contacts != null && contacts.length != 0) {
            for (var i = 0, n = contacts.length; i < n; i++) {
                if (jq.inArray(contacts[i].id, obj.SelectedContacts) === -1
                    && (typeof (obj.ExcludedArrayIDs) == "undefined" || jq.inArray(contacts[i].id, obj.ExcludedArrayIDs) === -1)) {
                    result.push(contacts[i]);
                }
            }
        }
        if (result == [] || result == null || result == 0) {
            var $trObj = jq(advancedInput).children('tbody').children('tr'),
                width = $trObj.width() - ($trObj.children('td').length - 3) * 18 - 2;
            jq("#noMatches_" + objName).css("width", width + "px");
            jq("#noMatches_" + objName).show();
        }
        return result;
    };

    var _initAutocomplete = function($input, advancedInput, objName, obj) {
        if ($input.length == 0) return;
        $input.autocomplete({
            //appendTo: "#selector_" + obj.ObjName,
            minLength: 0,
            delay: 300,
            focus: function (event, ui) {
                event.preventDefault ? event.preventDefault() : (event.returnValue = false);

                var autocomplete = jq(this).data("ui-autocomplete"),
                    menu = autocomplete.menu,

                    scroll = menu.element.scrollTop(),
                    offset = menu.active.offset().top - menu.element.offset().top,
                    elementHeight = menu.element.height();
                if (offset < 0) {
                    menu.element.scrollTop(scroll + offset);
                } else if (offset + menu.active.height() > elementHeight) {
                    menu.element.scrollTop(scroll + offset - elementHeight + menu.active.height());
                }
            },
            select: function (event, ui) {
                if (typeof (obj.SelectItemEvent) == "undefined") {
                    obj.setContact(this, ui.item.id, ui.item.displayName, ui.item.smallFotoUrl);
                    obj.showInfoContent(this);
                    return false;
                } else {
                    obj.SelectItemEvent(ui.item, { input: this, newContact: false });
                    jq(this).val("");
                    return false;
                }
            },
            selectFirst: false,
            search: function (event, ui) {
                if (jq(advancedInput).is(":visible")) {
                    return true;
                } else {
                    return false;
                }
            },
            source: function(request, response) {
                if (obj.IsInPopup) {
                    var ul = this.menu.element,
                        popupParent = jq(advancedInput).parents(".blockUI.blockPage:first");
                    if (popupParent.length != 0) {
                        if (popupParent.css("position") == "fixed") {
                            ul.css("position", "fixed");
                            jq("#noMatches_" + objName).css("position", "fixed");
                        } else {
                            ul.css("position", "absolute");
                            jq("#noMatches_" + objName).css("position", "absolute");
                        }
                    }
                }

                var term = request.term;

                if (term in obj.Cache) {
                    var contacts = obj.Cache[term];
                    response(_getSourceAutocompleteCallback(advancedInput, objName, obj, contacts));
                    return;
                } else {
                    for (var cacheterm in obj.Cache) {
                        if (obj.Cache[cacheterm].length == 0 && term.indexOf(cacheterm) == 0) {
                            var contacts = [];
                            response(_getSourceAutocompleteCallback(advancedInput, objName, obj, contacts));
                            return;
                        }
                    }
                }

                var data = { prefix: term, searchType: obj.SelectorType, entityType: obj.EntityType, entityID: obj.EntityID };

                Teamlab.getCrmContactsByPrefix({},
                {
                    filter: data,
                    success: function(par, contacts) {
                        jq("#loaderImg_" + objName).hide();
                        jq("#searchImg_" + objName).show();

                        obj.Cache[term] = contacts;
                        response(_getSourceAutocompleteCallback(advancedInput, objName, obj, contacts));
                    },
                    before: function(par) {
                        jq("#searchImg_" + objName).hide();
                        jq("#loaderImg_" + objName).show();
                    }
                });
            }
        });

        $input.data("ui-autocomplete")._renderMenu = function (ul, items) {
            var s = this;
            jq.each(items, function (jq, items) {
                s._renderItemData(ul, items);
            });

            if (obj.IsInPopup && jq.browser.mobile && ul.parents(".blockUI.blockPage:first").length == 0) {
                var popupParent = jq(advancedInput).parents(".blockUI.blockPage:first");
                if (popupParent.length != 0) {
                    ul.appendTo(popupParent.children());
                }
            }
        };

        $input.data("ui-autocomplete")._renderItem = function(ul, item) {
            jq("#noMatches_" + objName).hide();
            if (jq.inArray(item.id, obj.SelectedContacts) != -1) return;
            if (typeof (obj.ExcludedArrayIDs) != "undefined") {
                if (jq.inArray(item.id, obj.ExcludedArrayIDs) != -1) return;
            }
            var parent = item.company != null
                ? jq.format("<br/><span class='text-medium-describe'>{0}: {1}</span>", ASC.CRM.Resources.CRMJSResource.Company, item.company.displayName)
                : "";

            return jq("<li></li>").data("item.autocomplete", item)
                        .append(jq("<a href='javascript:void(0)'></a>").html(jq.htmlEncodeLight(item.displayName) + parent))
                        .appendTo(ul);
        };

        $input.data("ui-autocomplete")._resizeMenu = function() {
            var ul = this.menu.element,
                $trObj = jq(advancedInput).children("tbody").children("tr"),
                inputWidth = $trObj.width() - ($trObj.children("td").length - 3) * 18;
            ul.outerWidth(Math.max(inputWidth, this.element.outerWidth()));
        };

        $input.data("ui-autocomplete")._suggest = function(a) {
            var b = this.menu.element.empty().zIndex(this.element.zIndex() + 1);
            this._renderMenu(b, a);
            //this.menu.deactivate();
            this.menu.refresh();
            b.show();
            this._resizeMenu();
            b.position(jq.extend({ of: jq(this.element).parents("table:first") }, this.options.position));
        };
    };


    var _initClickEventHandler = function(input, objName) {
        var $noMatchesList = jq("div[id^='noMatches_" + objName + "']"),
            $noMatches = {};

        jq(input).bind("click", function (e) {
            $noMatchesList.hide();
            jq(this).autocomplete("search", jq.trim(jq(input).val()));
        });

        jq(document).click(function (event) {
            for (var i = 0, n = $noMatchesList.length; i < n; i++) {
                $noMatches = jq($noMatchesList[i]);

                if ($noMatches.is(":visible")) {
                    var $targetElement = jq((event.target) ? event.target : event.srcElement);
                    if (!$targetElement.parents().addBack().is("#" + $noMatches.attr("id").replace("noMatches_", "contactTitle_") + ", " + "#" + $noMatches.attr("id"))) {
                        $noMatches.hide();
                    }
                }
            }
        });
    };

    var _initKeyUpEventHandler = function(input) {
        jq(input).bind("keyup", function(e) {
            if (jq.trim(jq(this).val()) == "") {
                jq(this).parents("table:first").find("label.crossButton").hide();
            } else {
                jq(this).parents("table:first").find("label.crossButton").show();
            }
        });

    };


    this.ContactSelector = function(objName, params) {
        if (typeof (params) != "object") return;
        if (typeof (window[objName]) != "undefined") return window[objName];

        this.ObjName = objName;
        //default params
        this.SelectorType = -1; //Any
        this.ShowOnlySelectorContent = false;
        this.SelectedContacts = [];
        this.ExcludedArrayIDs = [];
        this.EntityType = -1; //Any
        this.EntityID = 0;
        this.DescriptionText = "";
        this.DeleteContactText = "";
        this.AddContactText = "";

        this.CrossButtonEventClick;
        this.SelectItemEvent;

        this.IsInPopup = false;
        this.AcceptNewContactShowOnly = false;

        this.ShowChangeButton = true;
        this.ShowAddButton = true;
        this.ShowDeleteButton = true;
        this.ShowContactImg = true;
        this.ShowNewCompanyContent = true;
        this.ShowNewContactContent = true;
        this.HTMLParent = "";

        var CurrentItem = this;
        //end default params


        if (params.hasOwnProperty("SelectorType")) {
            this.SelectorType = params.SelectorType;
        }
        if (params.hasOwnProperty("EntityType")) {
            this.EntityType = params.EntityType;
        }
        this.EntityID = params.EntityID || 0;

        if (params.hasOwnProperty("ShowOnlySelectorContent")) {
            this.ShowOnlySelectorContent = params.ShowOnlySelectorContent;
        }
        this.DescriptionText = params.DescriptionText || "";
        this.DeleteContactText = params.DeleteContactText || "";
        this.AddContactText = params.AddContactText || "";

        if (params.hasOwnProperty("IsInPopup")) {
            this.IsInPopup = params.IsInPopup;
        }
        if (params.hasOwnProperty("AcceptNewContactShowOnly")) {
            this.AcceptNewContactShowOnly = params.AcceptNewContactShowOnly;
        }

        if (params.hasOwnProperty("ShowChangeButton")) {
            this.ShowChangeButton = params.ShowChangeButton;
        }
        if (params.hasOwnProperty("ShowAddButton")) {
            this.ShowAddButton = params.ShowAddButton;
        }
        if (params.hasOwnProperty("ShowDeleteButton")) {
            this.ShowDeleteButton = params.ShowDeleteButton;
        }
        if (params.hasOwnProperty("ShowContactImg")) {
            this.ShowContactImg = params.ShowContactImg;
        }
        if (params.hasOwnProperty("ShowNewCompanyContent")) {
            this.ShowNewCompanyContent = params.ShowNewCompanyContent;
        }
        if (params.hasOwnProperty("ShowNewContactContent")) {
            this.ShowNewContactContent = params.ShowNewContactContent;
        }

        if (params.hasOwnProperty("presetSelectedContactsJson") && params.presetSelectedContactsJson != '') {
            if (typeof (params.presetSelectedContactsJson) == "object") {
                this.presetSelectedContacts = params.presetSelectedContactsJson;
            } else {
                this.presetSelectedContacts = jq.parseJSON(params.presetSelectedContactsJson);
            }
            if (this.presetSelectedContacts != null) {
                for (var i = 0, n = this.presetSelectedContacts.length; i < n; i++) {
                    this.SelectedContacts.push(this.presetSelectedContacts[i].id);
                }
            }
        }

        this.ExcludedArrayIDs = params.ExcludedArrayIDs || [];
        this.HTMLParent = params.HTMLParent || "";

        this.drawContactSelector = function() {
            if (CurrentItem.HTMLParent != "" && jq(CurrentItem.HTMLParent).length == 1 && jq("#selector_" + CurrentItem.ObjName).length == 0) {
                jq.tmpl("contactSelectorContainerTmpl", CurrentItem).appendTo(CurrentItem.HTMLParent);
            }

            CurrentItem.Cache = {};

            if (CurrentItem.SelectedContacts.length > 0 && CurrentItem.ShowOnlySelectorContent === false) {
                if (CurrentItem.presetSelectedContacts != null) {
                    for (var i = 0, n = CurrentItem.presetSelectedContacts.length; i < n; i++) {
                        CurrentItem.AddNewSelectorWithSelectedContact(CurrentItem.presetSelectedContacts[i]);
                    }
                }
            } else {
                CurrentItem.AddNewSelectorWithSelectedContact(null);
            }

            delete CurrentItem.presetSelectedContacts;
            var $selectorRows = jq("#selector_" + objName).children("div:first").children("div.contactSelector-item");
            jq($selectorRows[$selectorRows.length - 1]).addClass("withPlus");
        };

        this.changeContact = function (objID) {
            var id = parseInt(jq("#contactID_" + objID).val()),
                index = jq.inArray(id, CurrentItem.SelectedContacts);
            if (index != -1) {
                CurrentItem.SelectedContacts.splice(index, 1);
            }

            jq(window).trigger("editContactInSelector", [jq("#item_" + objID), this.ObjName]);
            //CurrentItem.setContact(jq("#contactTitle_" + objID), 0, "", "");
            jq("#contactID_" + objID).val(0);
            CurrentItem.showSelectorContent(jq("#contactTitle_" + objID));
        };

        this.deleteContact = function(objID) {
            var id = parseInt(jq("#contactID_" + objID).val()),
                index = jq.inArray(id, CurrentItem.SelectedContacts);
            if (index != -1) {
                CurrentItem.SelectedContacts.splice(index, 1);
            }

            jq(window).trigger("deleteContactFromSelector", [jq("#item_" + objID), this.ObjName]);

            jq("#item_" + objID).remove();
            var $selectorRows = jq("#selector_" + CurrentItem.ObjName).children("div:first").children("div.contactSelector-item");
            $selectorRows.filter(".withPlus").removeClass("withPlus");
            jq($selectorRows[$selectorRows.length - 1]).addClass("withPlus");
        };


        this.clearSelector = function () {
            CurrentItem.SelectedContacts = [];

            var $selectorRows = jq("#selector_" + CurrentItem.ObjName).children("div:first").children("div.contactSelector-item");
            if ($selectorRows.length > 1) {
                if (CurrentItem.ShowAddButton === true) {
                    jq($selectorRows[0]).addClass("withPlus");
                }
                $selectorRows.filter(":not(:first)").remove();
            }
        };


        this.crossButtonEventClick = function (objID) {
            jq("#selectorContent_" + objID).children(".contactSelector-inputContainer").find(".crossButton").hide();

            if (typeof (CurrentItem.CrossButtonEventClick) == "undefined") {
                var id = parseInt(jq("#contactID_" + objID).val()),
                    index = jq.inArray(id, CurrentItem.SelectedContacts);
                if (index != -1) {
                    CurrentItem.SelectedContacts.splice(index, 1);
                }
                jq("#contactTitle_" + objID).val("").blur();
                jq("#contactID_" + objID).val(0);
                jq("#noMatches_" + objID).hide();
            } else {
                CurrentItem.CrossButtonEventClick();
            }
        };

        this.setContact = function (obj, id, title, img) {
            if (jq(obj).length == 0) return;
            var objID = jq(obj).attr('id').replace("contactTitle_", ""),
                $avatarImg = jq("#infoContent_" + objID).find('img:first');

            jq(obj).val(title);

            if (img != "" && $avatarImg.length == 1) {
                if (img.indexOf("filehandler.ashx") != -1) {
                    jq.ajax({
                        type: "GET",
                        url: img,
                        success: function (response) {
                            try {
                                $avatarImg.attr("src", response);
                            }
                            catch (e) { }
                        }
                    });
                } else {
                    $avatarImg.attr("src", img);
                }
            }

            jq("#infoContent_" + objID).find('b:first').html(jq.htmlEncodeLight(title));
            jq("#contactID_" + objID).val(id);
            if (jq.inArray(id, CurrentItem.SelectedContacts) == -1 && id != 0) {
                CurrentItem.SelectedContacts.push(id);
            }
            jq(obj).val("");
            jq(window).trigger("setContactInSelector", [id, this.ObjName]);
        };

        this.showInfoContent = function (obj) {
            var objID = jq(obj).attr('id').replace("contactTitle_", "");
            jq('#selectorContent_' + objID).hide();
            jq("#newContactContent_" + objID).hide();
            jq('#infoContent_' + objID).show();
        };

        this.showSelectorContent = function (obj) {
            var objID = jq(obj).attr('id').replace("contactTitle_", "");

            if (jq.trim(jq(obj).val()) == "") {
                jq(obj).parents("table:first").find("label.crossButton").hide();
            } else {
                jq(obj).parents("table:first").find("label.crossButton").show();
            }

            jq('#infoContent_' + objID).hide();
            jq("#newContactContent_" + objID).hide();
            jq('#selectorContent_' + objID).show();
            jq(window).trigger("afterResetSelectedContact", [jq("#item_" + objID), this.ObjName]);
        };

        this.AddNewSelector = function(addSelectorLink) {
            if (addSelectorLink.hasClass("disabledLink")) return;
            addSelectorLink.addClass("disabledLink");
            CurrentItem.AddNewSelectorWithSelectedContact(null);
            addSelectorLink.removeClass("disabledLink");
        };

        this.AddNewSelectorWithSelectedContact = function(contact) {
            var index = 0,
                lastSelector = jq("#selector_" + CurrentItem.ObjName + " input[id^=contactTitle_]:last");
            if (jq(lastSelector).length > 0) {
                index = parseInt(jq(lastSelector).attr("id").replace("contactTitle_" + CurrentItem.ObjName + "_", "")) + 1;
            }

            var $newSelectorObj = jq.tmpl("contactSelectorRowTmpl",
                {
                    ObjID: CurrentItem.ObjName + "_" + index,
                    ObjName: CurrentItem.ObjName,
                    ShowOnlySelectorContent: CurrentItem.ShowOnlySelectorContent,
                    ShowNewCompanyContent: CurrentItem.ShowNewCompanyContent,
                    ShowNewContactContent: CurrentItem.ShowNewContactContent,
                    ShowContactImg: CurrentItem.ShowContactImg,
                    ShowDeleteButton: CurrentItem.ShowDeleteButton,
                    ShowAddButton: CurrentItem.ShowAddButton,
                    ShowChangeButton: CurrentItem.ShowChangeButton,

                    DeleteContactText: CurrentItem.DeleteContactText,
                    AddButtonText: CurrentItem.AddContactText,
                    WatermarkText: CurrentItem.DescriptionText,
                    selectedContact: contact
                });

            jq("#selector_" + CurrentItem.ObjName + " div:first").append($newSelectorObj);

            var $selectorRows = jq("#selector_" + CurrentItem.ObjName).children("div:first").children("div.contactSelector-item");

            $selectorRows.filter(".withPlus").removeClass("withPlus");
            jq($selectorRows[$selectorRows.length - 1]).addClass("withPlus");

            var $input = jq("#contactTitle_" + CurrentItem.ObjName + "_" + index);
            _initAutocomplete($input, jq($input).parents("table:first"), CurrentItem.ObjName + '_' + index, CurrentItem);
            _initClickEventHandler($input, CurrentItem.ObjName);
            _initKeyUpEventHandler($input);

            if (contact != null) {
                if (contact.smallFotoUrl.indexOf("filehandler.ashx") != -1) {
                    jq.ajax({
                        type: "GET",
                        url: contact.smallFotoUrl,
                        success: function (response) {
                            try {
                                jq("#infoContent_" + CurrentItem.ObjName + "_" + index).find("img:first").attr("src", response);
                            }
                            catch (e) { }
                        }
                    });
                }
            }
        };


        this.quickSearch = function (objID) {
            _hideAllAutocompleteBlocks();
            var $input = jq("#contactTitle_" + objID);
            $input.autocomplete("search", jq.trim($input.val()));
        };

        this.showNewCompany = function(objID) {
            var $selectorObj = this;
            jq("#newContactContent_" + objID + " input").val("");
            jq("#hiddenIsCompany_" + objID).val("true");
            jq("#noMatches_" + objID).hide();
            jq("#infoContent_" + objID).hide();
            jq("#selectorContent_" + objID).hide();
            jq("#newContactImg_" + objID).hide();
            jq("#newContactFirstName_" + objID).hide();
            jq("#newContactLastName_" + objID).hide();
            jq("#newContactContent_" + objID).show();
            jq("#newCompanyImg_" + objID).show();

            jq("#newCompanyTitle_" + objID).unbind("keyup").bind("keyup", function (e) {
                var code;
                if (e.keyCode) {
                    code = e.keyCode;
                } else if (e.which) {
                    code = e.which;
                }
                if (code == 13) {//Enter
                    $selectorObj.acceptNewContact(objID);
                }
                if (code == 27) {//ESC
                    $selectorObj.rejectNewContact(objID);
                }
            });

            var $input = jq("#contactTitle_" + objID);
            jq("#newCompanyTitle_" + objID).val($input.val()).show().focus();
        };

        this.showNewContact = function(objID) {
            var $selectorObj = this;
            jq("#newContactContent_" + objID + " input").val("");
            jq("#hiddenIsCompany_" + objID).val("false");
            jq("#noMatches_" + objID).hide();
            jq("#infoContent_" + objID).hide();
            jq("#selectorContent_" + objID).hide();
            jq("#newCompanyImg_" + objID).hide();
            jq("#newCompanyTitle_" + objID).hide();
            jq("#newContactContent_" + objID).show();
            jq("#newContactImg_" + objID).show();

            jq("#newContactFirstName_" + objID + ", #newContactLastName_" + objID).unbind("keyup").bind("keyup", function (e) {
                var code;
                if (e.keyCode) {
                    code = e.keyCode;
                } else if (e.which) {
                    code = e.which;
                }
                if (code == 13) {//Enter
                    $selectorObj.acceptNewContact(objID);
                }
                if (code == 27) {//ESC
                    $selectorObj.rejectNewContact(objID);
                }
            });

            var $input = jq("#contactTitle_" + objID);
            jq("#newContactLastName_" + objID).show();
            jq("#newContactFirstName_" + objID).val($input.val()).show().focus();
        };

        this.acceptNewContact = function(objID) {
            var data = {},
                isCompany = jq("#hiddenIsCompany_" + objID).val() == "true",

                $newCompanyTitleInput = jq("#newCompanyTitle_" + objID),
                $newContactFirstNameInput = jq("#newContactFirstName_" + objID),
                $newContactLastName = jq("#newContactLastName_" + objID),

                compName = $newCompanyTitleInput.length == 1 ? jq.trim($newCompanyTitleInput.val()) : "",
                firstName = $newContactFirstNameInput.length == 1 ? jq.trim($newContactFirstNameInput.val()) : "",
                lastName = $newContactLastName.length == 1 ? jq.trim($newContactLastName.val()) : "",

                obj = this,
                $input = jq("#contactTitle_" + objID);

            if (isCompany) {
                data.companyName = compName;
            } else {
                data.firstName = firstName;
                data.lastName = lastName;
            }
            data.managerList = new Array(Teamlab.profile.id);
            data.shareType = 0;

            var isValid = true;

            if (isCompany && compName == "") {
                jq("#newCompanyTitle_" + objID).addClass("requiredInputError");
                isValid = false;
            } else {
                jq("#newCompanyTitle_" + objID).removeClass("requiredInputError");
            }

            if (!isCompany && firstName == "") {
                jq("#newContactFirstName_" + objID).addClass("requiredInputError");
                isValid = false;
            } else {
                jq("#newContactFirstName_" + objID).removeClass("requiredInputError");
            }

            if (!isValid)
                return false;

            if (obj.AcceptNewContactShowOnly) {
                var imgSrc = isCompany ? jq("#newCompanyImg_" + objID).attr("src") : jq("#newContactImg_" + objID).attr('src'),
                    displayName = [data.firstName, ' ', data.lastName].join(''),
                    contactId = 0;

                if (typeof (obj.SelectItemEvent) == "undefined") {
                    jq("#infoContent_" + objID).show();
                    jq("#selectorContent_" + objID).hide();
                    obj.setContact($input, contactId, displayName, imgSrc);
                    obj.showInfoContent($input);
                    jq("#infoContent_" + objID + " img:first").attr("src", imgSrc);

                } else {
                    var contactInfo = { id: contactId, displayName: displayName, smallFotoUrl: imgSrc };
                    obj.showSelectorContent($input);
                    $input.val("");
                    obj.SelectItemEvent(contactInfo, { input: $input, newContact: true, data: data });
                }


            } else {
                Teamlab.addCrmContact({}, isCompany, data,
                {
                    before: function () {
                        jq("#newContactContent_" + objID).hide();
                    },
                    success: function (par, contact) {
                        if (typeof (obj.SelectItemEvent) == "undefined") {
                            jq("#infoContent_" + objID).show();
                            jq("#selectorContent_" + objID).hide();
                            obj.setContact($input, contact.id, contact.displayName, contact.smallFotoUrl);
                            obj.showInfoContent($input);

                            var imgSrc = isCompany ? jq("#newCompanyImg_" + objID).attr("src") : jq("#newContactImg_" + objID).attr('src');
                            jq("#infoContent_" + objID + " img:first").attr("src", imgSrc);

                        } else {
                            var contactInfo = { id: contact.id, displayName: contact.displayName, smallFotoUrl: contact.smallFotoUrl };
                            $input.val("");
                            obj.showSelectorContent($input);
                            obj.SelectItemEvent(contactInfo, { input: $input, newContact: true });
                        }
                    }
                });
            }
        };

        this.rejectNewContact = function(objID) {
            jq("#infoContent_" + objID).hide();
            jq("#selectorContent_" + objID).show();
            jq("#newContactContent_" + objID).hide();
            jq("#noMatches_" + objID).show();
            jq("#newContactContent_" + objID + " input").removeClass("requiredInputError");
        };

        jq(document).ready(function () {
            CurrentItem.drawContactSelector();
            jq(window).trigger("contactSelectorIsReady", [objName]);
        });
    };
};

ASC.CRM.UpdateCRMCaldavCalendar = function (task, action, oldResponsibleId) {
    var postData = {
        calendarId: "crm_calendar",
        uid: "crm_" + task.type + "_" + task.id,
        responsibles: [task.responsible.id]
    };

    var url = ASC.Resources.Master.ApiPath + "calendar/caldavevent.json";
    switch (action) {
        case 0: //new
        case 1: //update
            postData.alert = task.alertValue || 0;
            jq.ajax({
                type: 'put',
                url: url,
                data: postData,
                complete: function (d) {

                }
            });
            if (task.responsible.id !== oldResponsibleId && oldResponsibleId !== undefined) {
                jq.ajax({
                    type: 'delete',
                    url: url,
                    data: {
                        calendarId: "crm_calendar",
                        uid: "crm_" + task.type + "_" + task.id,
                        responsibles: [oldResponsibleId]
                    },
                    complete: function (d) {}
                });
            }
            break;
        case 2:
            jq.ajax({
                type: 'delete',
                url: url,
                data: postData,
                complete: function (d) {}
            });
            break;
    }
};

ASC.CRM.CategorySelector = function (objName, currentCategory) {
    this.ObjName = objName;
    this.Me = function() { return jq("#" + this.ObjName); };
    this.CategoryTitle = currentCategory.title;
    this.CategoryID = currentCategory.id;

    if (jq.browser.mobile === false) {
        jq.dropdownToggle({
            dropdownID: this.ObjName + "_categoriesContainer",
            switcherSelector: ["#", this.ObjName, "_selectorContainer"].join(""),
            simpleToggle: true
        });
        ASC.CRM.Common.registerChangeHoverStateByParent("label.event_category", ["#", this.ObjName, "_categoriesContainer .categorySelector-category"].join(""));
    }

    this.changeContact = function(obj) {
        if (!jq.browser.mobile) {
            var id = parseInt(jq(obj).attr("id").split("_")[2]),
                title = jq("div", jq(obj)).text();
            this.setContact(id, title);
            this.hideSelectorContent();
        } else {
            var id = parseInt(jq(obj).val());
            var title = jq(obj).text();
            this.setContact(id, title);
        }
    };

    this.setContact = function(id, title) {
        this.CategoryID = id;
        this.CategoryTitle = title;

        if (!jq.browser.mobile) {
            jq('input[id=' + this.ObjName + '_categoryID]', this.Me()).val(id);
            jq('input[id=' + this.ObjName + '_categoryTitle]', this.Me()).val(title);
        } else {
            jq("option[id=" + this.ObjName + "_category_" + id + "]", this.Me()).attr("selected", true);
        }
    };

    this.hideSelectorContent = function() {
        jq('div[id=' + this.ObjName + '_categoriesContainer]', this.Me()).hide();
    };

    this.showSelectorContent = function() {
        jq('div[id=' + this.ObjName + '_categoriesContainer]', this.Me()).toggle();
    };

    this.getRowByContactID = function(id) {
        if (id > 0) {
            return jq.browser.mobile === true ?
                    jq("option[id=" + this.ObjName + "_category_" + id + "]", this.Me()) :
                    jq("div[id=" + this.ObjName + "_category_" + id + "]", this.Me());
        } else {
            return jq.browser.mobile === true ?
                    jq("option[id^=" + this.ObjName + "_category_]:first", this.Me()) :
                    jq("div[id^=" + this.ObjName + "_category_]:first", this.Me());
        }
    };

    this.renderControl = function(categories, selectedCategory, htmlParentSelector, maxWidth, helpInfoText) {
        if (typeof maxWidth == "undefined" || maxWidth == 0) {
            maxWidth = 230;
        }
        if (typeof helpInfoText != "undefined" && helpInfoText != "") {
            maxWidth -= 20;
        }
        jq.tmpl("categorySelectorTemplate",
            {
                jsObjName: this.ObjName,
                helpInfoText: helpInfoText,
                maxWidth: maxWidth,
                categories: categories,
                selectedCategory : selectedCategory
            }).appendTo(htmlParentSelector);
    };
};

ASC.CRM.TagView = (function() {

    var _addTagToCurrentEntity = function (params, text) {
        Teamlab.addCrmTag(params, ASC.CRM.TagView.EntityType, ASC.CRM.TagView.EntityID, text,
                {
                    success: ASC.CRM.TagView.callback_add_tag,
                    before: function () {
                        jq("#tagContainer .adding_tag_loading").show();
                        jq("#addTagDialog").hide();
                    },
                    after: function () {
                        jq("#tagContainer .adding_tag_loading").hide();
                    }
                });
    };

    var _addTag = function(params, text) {
        if (text != null && text != "") {
            if (ASC.CRM.TagView.EntityID != 0 && !ASC.CRM.TagView.OnlyInterface) {
                _addTagToCurrentEntity(params, text);
            } else if (!params.hasOwnProperty("element") && !ASC.CRM.TagView.OnlyInterface) {
                Teamlab.addCrmEntityTag(params, ASC.CRM.TagView.EntityType, text,
                    {
                        success: ASC.CRM.TagView.callback_add_tag,
                        before: function () {
                            jq("#tagContainer .adding_tag_loading").show();
                            jq("#addTagDialog").hide();
                        },
                        after: function () {
                            jq("#tagContainer .adding_tag_loading").hide();
                        }
                    });
            } else {
                ASC.CRM.TagView.callback_add_tag(params, Teamlab.create('crm-tag', null, text));
                jq("#addTagDialog").hide();
            }
        }
    };

    var _deleteTag = function ($element) {
        var text = jQuery.base64.decode($element.children(".tag_title:first").attr("data-value"));

        if (ASC.CRM.TagView.EntityID != 0 && !ASC.CRM.TagView.OnlyInterface) {
            Teamlab.removeCrmTag({ element: $element }, ASC.CRM.TagView.EntityType, ASC.CRM.TagView.EntityID, text,
                {
                    success: ASC.CRM.TagView.callback_delete_tag
                });
        } else {
            ASC.CRM.TagView.callback_delete_tag({ element: $element }, Teamlab.create('crm-tag', null, text));
        }
    };

    return {
        init: function(entityType, onlyInterface, params) {
            ASC.CRM.TagView.EntityType = entityType;
            ASC.CRM.TagView.OnlyInterface = onlyInterface;

            if (typeof (params) != "undefined" && params.hasOwnProperty("addTag") && typeof (params.addTag) === "function") {
                ASC.CRM.TagView.addTagExtension = params.addTag;
            }
            if (typeof (params) != "undefined" && params.hasOwnProperty("deleteTag") && typeof (params.deleteTag) === "function") {
                ASC.CRM.TagView.deleteTag = params.deleteTag;
            }

            var URLParamID = jq.getURLParam("id");
            if (isNaN(URLParamID)) {
                return;
            }

            ASC.CRM.TagView.EntityID = URLParamID * 1;

            if (jq("#addTagDialog a.dropdown-item").length == 0) {
                jq("#addTagDialog .h_line").hide();
            }

            jq.dropdownToggle({
                dropdownID: "addTagDialog",
                switcherSelector: "#addNewTag",
                addTop: 1,
                addLeft: 0,
                simpleToggle: (typeof (params) != "undefined" && params.hasOwnProperty("simpleToggle")) ? params.simpleToggle : true
            });

            jq("#addThisTag").click(function() {
                ASC.CRM.TagView.addTagExtension({}, jq.trim(jq("#addTagDialog input:first").val()));
            });

            jq("#addTagDialog input").focus().unbind("keyup").keyup(function(e) {
                var code;
                if (!e) {
                    e = event;
                }
                if (e.keyCode) {
                    code = e.keyCode;
                } else if (e.which) {
                    code = e.which;
                }

                if (code == 13) {
                    var text = jq.trim(jq("#addTagDialog input:first").val());
                    if (text == "") {
                        return;
                    }
                    ASC.CRM.TagView.addTagExtension({}, text);
                }
            });

            if (jq.browser.mobile === true) {
                jq("#tagContainer").on("click", ".tag_item", function() {
                    jq(this).addClass("tag_hover");
                });
            }
        },

        deleteTag: function ($element) {
            _deleteTag($element);
        },

        addTagExtension: function (params, text) {
            _addTag(params, text);
        },

        addExistingTag: function(element) {
            var tagTitle = jQuery.base64.decode(jq(element).attr("data-value"));

            ASC.CRM.TagView.addTagExtension({ element: element }, tagTitle);
        },

        callback_add_tag : function(params, tag) {
            jq.tmpl("taqTmpl", { "tagLabel": tag }).appendTo("#tagContainer>div:first");
            jq("#addTagDialog input:first").val("");
            if (params.hasOwnProperty("element")) {
                jq(params.element).remove();
                if (jq("#addTagDialog a.dropdown-item").length == 0) {
                    jq("#addTagDialog .h_line").hide();
                }
            }
            jq(window).trigger("addTagComplete", tag);
        },

        callback_delete_tag: function(params, tag) {
            params.element.remove();
            jq("#addTagDialog .h_line").show();
            jq.tmpl("tagInAllTagsTmpl", { "tagLabel": tag }).appendTo("#addTagDialog ul.dropdown-content");
            jq(window).trigger("deleteTagComplete", tag);
        },

        prepareTagDataForSubmitForm: function($input) {
            var tagData = {};
            tagData.tagListInfo = [];
            jq("#tagContainer .tag_item .tag_title").each(function() {
                var tagValue = jq.trim(jq(this).text());
                if (tagValue) {
                    tagData.tagListInfo.push(tagValue);
                }
            });
            if (tagData.tagListInfo.length > 0) {
                $input.val(jq.toJSON(tagData));
            } else {
                $input.val();
            }
        }
    };
})();



ASC.CRM.ImportFromCSVView = (function() {

    var initOtherActionMenu = function() {
        ASC.CRM.Common.removeExportButtons();
        jq("#menuCreateNewTask").bind("click", function() { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    };

    return {
        init: function(intEntityType, entityType) {
            jq("#delimiterCharacterSelect,#encodingSelect, #quoteCharacterSelect").tlcombobox({ align: "left" });
            initOtherActionMenu();

            if (intEntityType != 3) {//not tasks
                jq.tmpl("tagViewTmpl",
                       {
                           tags: [],
                           availableTags: ASC.CRM.Data.tagList,
                           containerClass: "initial"
                       })
                       .appendTo("#importFromCSVTags");
                ASC.CRM.TagView.init(entityType, true, { simpleToggle: false });
            }

            if (intEntityType == 0) {//contact

                ASC.CRM.UserSelectorListView.Init(
                   "_ImportContactsManager",
                   "UserSelectorListView_ImportContactsManager",
                   false,
                   ASC.CRM.Resources.CRMContactResource.NotifyContactManager,
                   new Array(ASC.CRM.Resources.CurrentUser),
                   null,
                   new Array(Teamlab.profile.id),
                   "#importContactsManager",
                   false);

                var $html = jq.tmpl("makePublicPanelTemplate",
                    {
                        Title: ASC.CRM.Resources.CRMContactResource.MakePublicPanelTitleForImportContacts,
                        Description: ASC.CRM.Resources.CRMContactResource.MakePublicPanelDescrForContact,
                        IsPublicItem: false,
                        CheckBoxLabel: ASC.CRM.Resources.CRMContactResource.MakePublicPanelCheckBoxLabelForImportContacts

                    });

                $html.find(".makePublicPanelSelector")
                    .append(jq("<option value='2'></option>").text(ASC.CRM.Resources.CRMCommonResource.AccessRightsForReading))
                    .append(jq("<option value='1'></option>").text(ASC.CRM.Resources.CRMCommonResource.AccessRightsForReadWriting))
                    .val("2")
                    .tlCombobox({ align: "left" });

                $html.appendTo("#makePublicPanel");
            }

            Teamlab.getStatusCrmImportFromCSV({},
                { entityType: entityType },
                {
                    max_request_attempts: 1,
                    success: function (params, response) {
                        if (response == null || jQuery.isEmptyObject(response) || response.isCompleted) {
                            ASC.CRM.ImportEntities.init(intEntityType, entityType);
                        } else {
                            jq("#importFromCSVSteps").hide();
                            jq("#importStartedFinalMessage").show();
                            ASC.CRM.ImportEntities.checkImportStatus(true, entityType);
                        }
                    },
                    error: function (params, errors) {
                        var err = errors[0];
                        if (err != null) {
                            toastr.error(err);
                        }
                    }
                });
        }
    };
})();

ASC.CRM.ImportEntities = (function ($) {
    var _CSVFileURI = "",
        _curIndexSampleRow = 0,
        _ajaxUploader,
        _entityType,
        _entityTypeName,
        _sampleRowCache = new Object(),
        _settingsBase = new Object();

    var _refreshSampleRowItems = function(data) {
        var resultData = jq.parseJSON(data),
            sampleRow = resultData.data,
            sampleRowColumnIndex = 0;

        jq("#columnMapping tbody tr td").each(
                function(index) {
                    if ((index + 1) % 3 == 0)
                        jq(this).text(sampleRow[sampleRowColumnIndex++]);
                });

        if (resultData.isMaxIndex) {
            jq("#nextSample").hide().prev().hide();
        }
    };

    var _getSampleRow = function() {
        var sampleRowCacheKey = _CSVFileURI + '' + _curIndexSampleRow;

        if (_sampleRowCache[sampleRowCacheKey]) {
            _refreshSampleRowItems(_sampleRowCache[sampleRowCacheKey]);
            return;
        }

        Teamlab.getCrmImportFromCSVSampleRow({},
            { csvFileURI:_CSVFileURI, indexRow : _curIndexSampleRow, jsonSettings: jq.toJSON(_settingsBase) },
            {
                before: function (params) {
                    jq("#columnMapping thead tr td:last span:last").block();
                },
                after: function (params) {
                    jq("#columnMapping thead tr td:last span:last").unblock();
                },
                success: function (params, response) {
                    _sampleRowCache[sampleRowCacheKey] = response;
                    _refreshSampleRowItems(response);
                },
                error: function (params, errors) {
                    var err = errors[0];
                    if (err != null) {
                        _showErrorPanel(err);
                    }
                }
            });
    };

    var _nextStep = function(step) {
        jq(jq.format("#importFromCSVSteps dd:eq({0})", step - 1)).hide();
        jq(jq.format("#importFromCSVSteps dt:eq({0})", step - 1)).hide();
        jq(jq.format("#importFromCSVSteps dd:eq({0})", step)).show();
        jq(jq.format("#importFromCSVSteps dt:eq({0})", step)).show();
    };

    var _getSettingsBase = function () {
        return {
            has_header: jq("#ignoreFirstRow").is(":checked"),
            delimiter_character: jq("#delimiterCharacterSelect option:selected").val(),
            encoding: jq("#encodingSelect option:selected").val(),
            quote_character: jq("#quoteCharacterSelect option:selected").val()
        };
    };

    var _ajaxUploaderOnSubmitCallback = function(file, extension) {
        _settingsBase = _getSettingsBase();

        this._settings.data["importSettings"] = jq.toJSON(_settingsBase);
        LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.ImportFromCSVStepOneProgressLable
        LoadingBanner.showLoaderBtn("#importFromCSVSteps");
    };

    var _ajaxUploaderonCompleteCallback = function(file, response) {
        var responseObj = jq.parseJSON(response);
        if (!responseObj.Success) {
            _showErrorPanel(responseObj.Error || responseObj.Message);
            jq("#uploadCSVFile").removeClass("edit_button").addClass("import_button");
            jq("#uploadCSVFile").text(ASC.CRM.Resources.CRMJSResource.SelectCSVFileButton);
            jq("#uploadCSVFile").prev().hide();
            LoadingBanner.hideLoaderBtn("#importFromCSVSteps");
            //ASC.CRM.ImportEntities.prevStep(0);
            return false;
        }

        var responseData = jq.parseJSON(jQuery.base64.decode(responseObj.Data));
        _CSVFileURI = responseData.assignedPath;

        if (responseData.isMaxIndex) {
            jq("#prevSample").parent().hide();
        } else {
            jq("#prevSample").parent().show();
        }

        var stepTwoContent = jq("#columnMapping tbody");

        stepTwoContent.html("");
        jq.tmpl("columnMappingTemplate", responseData, {
            renderSelector: function(rowIndex) {
                var columnSelector = jq("#columnSelectorBase").clone();
                columnSelector.attr("id", jq.format("columnSelector_{0}", rowIndex));
                columnSelector.show();
                return jq("<div>").append(columnSelector).html();
            }
        }).appendTo(stepTwoContent);

        var selectItems = jq("#columnMapping select");

        selectItems.each(function() {
            try {
                var curSelect = jq(this),
                    columnHeader = jq.trim(curSelect.parent().prev().text());
                if (jq.browser.msie) {
                    var leftBracketColumnCount = jq(columnHeader.match(/\(/g)).length,
                        rightBracketColumnCount = jq(columnHeader.match(/\)/g)).length;

                    if (leftBracketColumnCount != rightBracketColumnCount) return;
                }
                var findedItem = curSelect.find("option")
                                .filter(function(){
                                    return jq.trim(jq(this).text()).toLowerCase() == columnHeader.toLowerCase();
                                })
                                .first();
                findedItem.attr("selected", true);
            }
            catch (e) {
            }
        });

        selectItems.on("change", function() {
            var curSelector = jq(this);
            if (curSelector.find("option:first").is(":selected")) {
                curSelector.parents("td").addClass("missing");
            } else {
                curSelector.parents("td").removeClass("missing");
            }
        });

        selectItems.change();

        _nextStep(1);
        LoadingBanner.hideLoaderBtn("#importFromCSVSteps");
    };

    var _initErrorPanel = function () {
        jq.tmpl("template-blockUIPanel", {
            id: "importErrorPanel",
            headerTest: ASC.CRM.Resources.CRMCommonResource.Error,
            questionText: "",
            innerHtmlText: "<div class=\"errorNote\"></div>",
            OKBtn: ASC.CRM.Resources.CRMCommonResource.OK
        }).insertAfter("#columnMapping");

        jq("#importErrorPanel .button.blue").on("click", function () { jq.unblockUI(); });
    };

    var _showErrorPanel = function (msg) {
        LoadingBanner.hideLoaderBtn("#importFromCSVSteps");
        jq("#importErrorPanel .errorNote").text(msg);
        //PopupKeyUpActionProvider.EnableEsc = false;
        StudioBlockUIManager.blockUI("#importErrorPanel", 500);
    };

    var _resetUploader = function () {
        jq("#importFromCSVSteps dd:first .middle-button-container a.button.blue.middle:first").addClass("disable");
        jq("#uploadCSVFile")
            .removeClass("edit_button")
            .addClass("import_button")
            .text(ASC.CRM.Resources.CRMJSResource.SelectCSVFileButton)
            .prev().hide();
        ASC.CRM.ImportEntities.prevStep(0);
    };

    return {
        init: function (entityType, entityTypeName) {

            _entityType = entityType;
            _entityTypeName = entityTypeName;

            if (_entityType == 0 || entityType == "0") {
                jq("#removingDuplicatesBehaviorPanel").show();
            } else {
                jq("#removingDuplicatesBehaviorPanel").hide();
            }

            jq.tmpl("columnSelectorTemplate", ASC.CRM.Data.columnSelectorData).appendTo("#columnSelectorBase");
            jq("#columnSelectorBase").find("option[name=is_header]").each(function() {
                var curItem = jq(this);
                curItem.nextUntil('option[name=is_header]').wrapAll(jq("<optgroup>").attr("label", curItem.val()));
                curItem.remove();
            });

            _ajaxUploader = new AjaxUpload('uploadCSVFile', {
                action: 'ajaxupload.ashx?type=ASC.Web.CRM.Classes.ImportFileHandler,ASC.Web.CRM',
                autoSubmit: false,
                onChange: function (file, extension) {
                    _CSVFileURI = "";

                    if (!file) {
                        _resetUploader();
                        return false;
                    }

                    if (!extension || extension[0].toLowerCase() != "csv") {
                        _showErrorPanel(ASC.CRM.Resources.CRMJSResource.ErrorMessage_NotSupportedFileFormat);
                        _resetUploader();
                        return false;
                    }

                    var messageContainer = jq("#uploadCSVFile").prev();
                    messageContainer.show();
                    messageContainer.text(jq.format(ASC.CRM.Resources.CRMJSResource.SelectedCSVFileLabel, file));
                    jq("#uploadCSVFile").removeClass("import_button").addClass("edit_button").text(ASC.CRM.Resources.CRMJSResource.Change);
                    jq("#importFromCSVSteps dd:first .middle-button-container a.button.blue.middle:first").removeClass("disable");
                    return true;
                },
                onSubmit: _ajaxUploaderOnSubmitCallback,
                onComplete: _ajaxUploaderonCompleteCallback
            });

            _initErrorPanel();
        },
        prevStep: function(step) {
            jq(jq.format("#importFromCSVSteps dd:eq({0})", step + 1)).hide();
            jq(jq.format("#importFromCSVSteps dt:eq({0})", step + 1)).hide();

            jq(jq.format("#importFromCSVSteps dd:eq({0})", step)).show();
            jq(jq.format("#importFromCSVSteps dt:eq({0})", step)).show();

            if (step != 0) return;

            //jq("#importFromCSVSteps dd:first .middle-button-container a.button.blue.middle:first").addClass("disable");
        },

        getColumnMapping: function() {
            var result = {};
            jq("#columnMapping select").each(function() {
                var name = jq.trim(jq(this).find("option:selected").attr("name"));
                if (name == "" || name == -1) { return true; }
                if (typeof result[name] == "undefined") {
                    result[name] = new Array();
                }

                var idParts = this.id.split("_");
                if (idParts.length < 2) { return true; }

                result[name].push(idParts[1]);
            });
            return result;
        },

        startImport: function() {
            jq("select[id^=columnSelector].requiredInputError").removeClass("requiredInputError");
            var columnMapping = ASC.CRM.ImportEntities.getColumnMapping(),
                columnMappingSelector = jq("#columnMapping select"),
                isValid = true;

            for (var p in columnMapping) {
                if (columnMapping[p].length > 1 && p != "tag") {
                    for (var i = 0, n = columnMapping[p].length; i < n; i++) {
                        jq("#columnSelector_" + columnMapping[p][i]).addClass("requiredInputError");
                    }
                    isValid = false;
                }
            }
            if (!isValid) {
                _showErrorPanel(ASC.CRM.Resources.CRMJSResource.ErrorMappingMoreBasicColumn);
                return;
            }

            switch (_entityType) {
                case "0":
                case 0:  //  Contact
                    {
                        var firstNameOptions = columnMappingSelector.find("option[name=firstName]:selected"),
                            companyNameOptions = columnMappingSelector.find("option[name=companyName]:selected");

                        if (firstNameOptions.length == 0 && companyNameOptions.length == 0) {
                            _showErrorPanel(ASC.CRM.Resources.CRMJSResource.ErrorContactNotMappingBasicColumn);
                            return;
                        }
                    }
                    break;
                case "1":
                case 1:  //  Opportunity
                    {
                        var titleOptions = columnMappingSelector.find("option[name=title]:selected"),
                            responsibleOptions = columnMappingSelector.find("option[name=responsible]:selected");

                        if (titleOptions.length == 0 || responsibleOptions.length == 0) {
                            _showErrorPanel(ASC.CRM.Resources.CRMJSResource.ErrorOpportunityNotMappingBasicColumn);
                            return;
                        }
                    }
                    break;
                case "3":
                case 3:  //  Task
                    {
                        var titleOptions = columnMappingSelector.find("option[name=title]:selected"),
                            dueDateOptions = columnMappingSelector.find("option[name=due_date]:selected"),
                            responsibleOptions = columnMappingSelector.find("option[name=responsible]:selected");

                        if (titleOptions.length == 0 ||
                            dueDateOptions.length == 0 ||
                            responsibleOptions.length == 0) {
                            _showErrorPanel(ASC.CRM.Resources.CRMJSResource.ErrorTaskNotMappingBasicColumn);
                            return;
                        }
                    }
                    break;
                case "7":
                case 7:  //  Case
                    var titleOptions = columnMappingSelector.find("option[name=title]:selected");
                    if (titleOptions.length == 0) {
                        _showErrorPanel(ASC.CRM.Resources.CRMJSResource.ErrorCasesNotMappingBasicColumn);
                        return;
                    }
                    break;
                default:
                    break;
            }

            var importSetting = _settingsBase;

            importSetting["column_mapping"] = columnMapping;

            if (_entityType != 3 && _entityType != "3") { //not task
                importSetting["tags"] = jq.map(jq("#tagContainer .tag_title"),
                       function (item) {
                           return jq(item).text().trim();
                       });
            }

            if (_entityType == 0 || _entityType == "0") {//contact
                var contactManagers = new Array(Teamlab.profile.id);

                for (var i = 0, n = window.SelectedUsers_ImportContactsManager.IDs.length; i < n; i++) {
                    contactManagers.push(window.SelectedUsers_ImportContactsManager.IDs[i]);
                }
                importSetting["contact_managers"] = contactManagers;
                importSetting["share_type"] = jq("#isPublic").is(":checked") ? jq(".makePublicPanel select.makePublicPanelSelector").val() : 0;
            } else if (_entityType != 3 && _entityType != "3") {
                var privateUsers = new Array(SelectedUsers.CurrentUserID);

                for (var i = 0, n = SelectedUsers.IDs.length; i < n; i++) {
                    privateUsers.push(SelectedUsers.IDs[i]);
                }
                importSetting["access_list"] = privateUsers;
                importSetting["is_private"] = jq("#isPrivate").is(":checked");
            }

            if (_entityType == 0 || _entityType == "0") {
                importSetting.removing_duplicates_behavior = jq("input[name='removingDuplicatesBehavior']:checked").val();
            }

            Teamlab.startCrmImportFromCSV({},
                { entityType: _entityTypeName, csvFileURI: _CSVFileURI, jsonSettings: jq.toJSON(importSetting) },
                {
                    before: function(params) {
                        LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.ImportFromCSVStepTwoProgressLable;
                        LoadingBanner.showLoaderBtn("#importFromCSVSteps");
                    },
                    after: function (params) {
                        LoadingBanner.hideLoaderBtn("#importFromCSVSteps");
                    },
                    success: function (params, response) {
                        jq("#importFromCSVSteps").hide();
                        jq("#importStartedFinalMessage").show();
                        ASC.CRM.ImportEntities.checkImportStatus(true, _entityTypeName);
                    },
                    error: function (params, errors) {
                        var err = errors[0];
                        if (err != null) {
                            _showErrorPanel(err);
                        }
                    }

                });
        },

        startUploadCSVFile: function (obj) {
            if (jq(obj).hasClass("disable"))
                return;

            if (_CSVFileURI == "") {
                _ajaxUploader.submit();
            } else {

                _settingsBase = _getSettingsBase();
                _ajaxUploader._settings.data["importSettings"] = jq.toJSON(_settingsBase);

                LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.ImportFromCSVStepOneProgressLable
                LoadingBanner.showLoaderBtn("#importFromCSVSteps");

                Teamlab.uploadFakeCrmImportFromCSV({},
                    { csvFileURI: _CSVFileURI, jsonSettings: jq.toJSON(_settingsBase) },
                    {
                        success: function (params, response) {
                            var result = {
                                Success: response.success,
                                Data: response.data,
                                Message: response.message,
                            };

                            _ajaxUploaderonCompleteCallback(null, jq.toJSON(result));
                        },
                        error: function (params, errors) {
                            var err = errors[0];
                            if (err != null) {
                                toastr.error(err);
                            }
                        }

                    });
            }
        },
        getPrevSampleRow: function() {
            _curIndexSampleRow--;
            jq("#nextSample").show().prev().show();

            if (_curIndexSampleRow == 0) {
                jq("#prevSample").hide().next().hide();
            }
            _getSampleRow();
        },
        getNextSampleRow: function() {
            _curIndexSampleRow++;

            jq("#prevSample").show().next().show();
            _getSampleRow();
        },

        checkImportStatus: function (isFirstVisit, entityType) {
            if (isFirstVisit) {
                jq("#importStartedFinalMessage div.progress").css("width", "0%");
                jq("#importStartedFinalMessage div.percent").text("0%");
                jq("#importErrorBox").hide();
                jq("#importStartedFinalMessage div.progressErrorBox").html("");
            }

            Teamlab.getStatusCrmImportFromCSV({},
               { entityType: entityType },
               {
                   max_request_attempts: 1,
                   success: function (params, response) {
                       if (response == null || jQuery.isEmptyObject(response)) {
                           jq("#importStartedFinalMessage div.progress").css("width", "100%");
                           jq("#importStartedFinalMessage div.percent").text("100%");
                           jq("#importErrorBox").hide();
                           jq("#importStartedFinalMessage div.progressErrorBox").html("");
                           return false;
                       }

                       jq("#importStartedFinalMessage div.progress").css("width", parseInt(response.percentage) + "%");
                       jq("#importStartedFinalMessage div.percent").text(parseInt(response.percentage) + "%");

                       if (response.error != null && response.error != "") {
                           ASC.CRM.ImportEntities.buildErrorList(response);
                       } else {
                           if (!response.isCompleted) {
                               setTimeout("ASC.CRM.ImportEntities.checkImportStatus(false, '" + entityType + "')", 3000);
                           }
                       }
                   },
                   error: function (params, errors) {
                       var err = errors[0];
                       if (err != null) {
                           _showErrorPanel(err);
                       }
                   }
               });
        },

        buildErrorList: function(res) {
            var mess = "error";
            switch (typeof res.error) {
                case "object":
                    mess = res.error.Message + "<br/>";
                    break;
                case "string":
                    mess = res.error;
                    break;
            }
            var link = jq("#importStartedFinalMessage #importLinkBox a").clone().removeClass("button.blue");
            jq("#importStartedFinalMessage div.progressErrorBox")
                .html(jq("<div></div>").addClass("red-text").html(mess))
                .append(link);
            jq("#importStartedFinalMessage #importErrorBox").show();
            jq("#importStartedFinalMessage #importLinkBox").hide();
        }

    };
})(jQuery);


ASC.CRM.UserSelectorListView = new function() {
    this.Init = function (objId, objName, showNotifyPanel, notifyLabel, usersWhoHasAccess, userIDs, disabledUserIDs, parentHtmlSelector, inPopup) {
        window[objName] = new ASC.CRM.UserSelectorListView.InitNewUserSelectorListView(
                                                                    objId,
                                                                    objName,
                                                                    usersWhoHasAccess,
                                                                    showNotifyPanel,
                                                                    notifyLabel,
                                                                    parentHtmlSelector);

        //ASC.Resources.Master.EmployeeAllDepartments,
        var $addUsrLink = jq("#usrSrListViewAdvUsrSrContainer" + objId + " .addUserLink");
        $addUsrLink.useradvancedSelector(
                {
                    showme: false,
                    inPopup: inPopup,
                    onechosen: false,
                    showGroups: true,
                    withGuests: false
                });

        var users = [],
            items = $addUsrLink.data("items");
        if (ASC.CRM.Data.isCrmAvailableForAllUsers == true) {
            users = jq.merge([], items);
        } else {
            for (var i = 0, n = ASC.CRM.Data.crmAvailableWithAdminList.length; i < n; i++){
                for (var j = 0, m = items.length; j < m; j++){
                    if (ASC.CRM.Data.crmAvailableWithAdminList[i].id == items[j].id) {
                        users.push(items[j]);
                        continue;
                    }
                }
            }
        }

        var disabledUserIDs = disabledUserIDs != null && disabledUserIDs != "" && disabledUserIDs.length != 0 ? disabledUserIDs : [],
            newUsrList = [];

        if (userIDs != null || disabledUserIDs.length != 0) {
            if (userIDs != null) {
                for (var i = 0, n = users.length; i < n; i++) {
                    if (userIDs.indexOf(users[i].id) != -1 && disabledUserIDs.indexOf(users[i].id) == -1) {
                        newUsrList.push(users[i]);
                    }
                }
            } else {
                for (var i = 0, n = users.length; i < n; i++) {
                    if (disabledUserIDs.indexOf(users[i].id) == -1) {
                        newUsrList.push(users[i]);
                    }
                }
            }
        } else {
            newUsrList = users;
        }

        $addUsrLink.useradvancedSelector("rewriteItemList", newUsrList, []);

        $addUsrLink.on("showList", function (event, items) {
            for (var i = 0, n = items.length; i < n; i++) {
                window[objName].PushUserIntoList(objId, objName, items[i].id, items[i].title);
            }
        });

        if (window["SelectedUsers" + objId].IDs.length == 0) {
            jq("#cbxNotify" + objId).removeAttr("checked");
            jq("#notifyPanel" + objId).hide();
        }

        if (window["SelectedUsers" + objId].IDs.length != 0) {
            $addUsrLink.useradvancedSelector("disable", window["SelectedUsers" + objId].IDs);
        }
    };

    this.InitNewUserSelectorListView = function (objId, objName, usersWhoHasAccess, showNotifyPanel, notifyLabel, parentHtmlSelector) {
        if (typeof (window[objName]) != "undefined") return window[objName];

        this.ObjId = objId;
        this.ObjName = objName;
        this.ShowNotifyPanel = showNotifyPanel;

        this.NotifyLabel = notifyLabel;
        this.DeleteImgSrc = window["SelectedUsers" + objId].DeleteImgSrc;

        this.PushUserIntoList = function (objId, objName, uID, uName) {
            var alreadyExist = false,
                windowSelectedUsersObj = window["SelectedUsers" + objId];

            for (var i = 0, n = windowSelectedUsersObj.IDs.length; i < n; i++)
                if (windowSelectedUsersObj.IDs[i] == uID) {
                    alreadyExist = true;
                    break;
                }

            if (alreadyExist) return false;

            windowSelectedUsersObj.IDs.push(uID);
            windowSelectedUsersObj.Names.push(uName);

            var item = jq("<div></div>")
                    .attr("id", "selectedUser_" + uID + objId)
                    .addClass("selectedUser"),

                deleteImg = jq("<img>")
                    .attr("src", windowSelectedUsersObj.DeleteImgSrc)
                    .css("margin", "0px 4px -2px 0px")
                    .css("display", "none")
                    .css("width", "12px")
                    .css("height", "12px")
                    .css("cursor", "pointer")
                    .attr("id", "deleteSelectedUserImg_" + uID + objId)
                    .attr("title", windowSelectedUsersObj.DeleteImgTitle);

            item.append(jq.htmlEncodeLight(uName)).append(deleteImg);

            jq("#selectedUsers" + objId).append(item);

            jq("#selectedUser_" + uID + objId).unbind("mouseover").bind("mouseover", function () {
                window[objName].SelectedItem_mouseOver(jq(this));
            });

            jq("#selectedUser_" + uID + objId).unbind("mouseout").bind("mouseout", function () {
                window[objName].SelectedItem_mouseOut(jq(this));
            });

            jq("#deleteSelectedUserImg_" + uID + objId).unbind("click").bind("click", function () {
                window[objName].SelectedUser_deleteItem(jq(this));
            });

            jq("#cbxNotify" + objId).prop("checked", true);
            jq("#notifyPanel" + objId).show();

            jq("#usrSrListViewAdvUsrSrContainer" + objId + " .addUserLink").useradvancedSelector("reset", true);
            jq("#usrSrListViewAdvUsrSrContainer" + objId + " .addUserLink").useradvancedSelector("disable", [uID])

            jq("#selectedUsers" + objId).parent().find("div[id=DepsAndUsersContainer]").hide();
            jq(window).trigger("advUserSelectorPushUserComplete", [objId, uID]);
        };

        this.SelectedItem_mouseOver = function (obj) {
            var iID = jq(obj).attr("id").split("_")[1];
            if (jq(obj).hasClass("selectedUser")) {
                jq("#selectedUser_" + iID + this.ObjId + " img:first").hide();
                jq("#selectedUser_" + iID + this.ObjId + " img:last").show();
            }
        };

        this.SelectedItem_mouseOut = function (obj) {
            var iID = jq(obj).attr("id").split("_")[1];
            if (jq(obj).hasClass("selectedUser")) {
                jq("#selectedUser_" + iID + this.ObjId + " img:first").show();
                jq("#selectedUser_" + iID + this.ObjId + " img:last").hide();
            }
        };

        this.SelectedUser_deleteItem = function (obj) {
            var uID = jq(obj).attr("id").split("_")[1];
            jq("#selectedUser_" + uID + this.ObjId).remove();

            var windowSelectedUsersObj = window["SelectedUsers" + this.ObjId];

            for (var i = 0; i < windowSelectedUsersObj.IDs.length; i++) {
                if (windowSelectedUsersObj.IDs[i] == uID) {
                    windowSelectedUsersObj.IDs.splice(i, 1);
                    windowSelectedUsersObj.Names.splice(i, 1);
                    break;
                }
            }

            if (windowSelectedUsersObj.IDs.length == 0) {
                jq("#cbxNotify" + this.ObjId).removeAttr("checked");
                jq("#notifyPanel" + this.ObjId).hide();
            }

            jq("#usrSrListViewAdvUsrSrContainer" + objId + " .addUserLink").useradvancedSelector("undisable", [uID])
            jq(window).trigger("advUserSelectorDeleteComplete", [this.ObjId, uID]);
        };

        var selectedUsers = [];

        for (var i = 0, n = window["SelectedUsers" + objId].IDs.length; i < n; i++) {
            selectedUsers.push({
                id: window["SelectedUsers" + objId].IDs[i],
                displayName: window["SelectedUsers" + objId].Names[i]
            });
        }

        jq.tmpl("userSelectorListViewTemplate", {
            objId : objId,
            objName: objName,
            usersWhoHasAccess: usersWhoHasAccess,
            deleteImgSrc: this.DeleteImgSrc,
            selectedUsers: selectedUsers,
            showNotifyPanel: showNotifyPanel,
            notifyLabel: notifyLabel,
            addEmployeeLabel: ASC.CRM.Resources.AddUser
        }).appendTo(parentHtmlSelector);

        return this;
    };
};


ASC.CRM.PartialExport = (function () {

    var initialized = false,
        filterObj = null,
        entityType = null;

    function startExport(data) {

        ProgressDialog.generate(data ||
        {
            entityType: entityType,
            base64FilterString: jq(filterObj).advansedFilter("hash")
        });
    }

    function init(filter, type) {
        filterObj = filter;
        entityType = type;

        ProgressDialog.init(
            {
                header: ASC.CRM.Resources.CRMCommonResource.ExportData,
                footer: ASC.CRM.Resources.CRMCommonResource.ExportDataInfo.format("<a class='link underline' href='/Products/Files/'>", "</a>"),
                progress: ASC.CRM.Resources.CRMCommonResource.ExportDataProgress
            },
            jq("#studioPageContent .mainPageContent .containerBodyBlock:first"),
            {
                terminate: Teamlab.cancelCrmCancelPartialExport,
                status: Teamlab.getCrmPartialExportStatus,
                generate: Teamlab.startCrmPartialExport
            });
        
        if (initialized) return;
        
        initialized = true;
    };

    return {
        init: init,
        startExport: startExport
    };
})();

<|start_filename|>common/ASC.Core.Common/Core/IUserService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Core.Users;

namespace ASC.Core
{
    public interface IUserService
    {
        IDictionary<Guid, UserInfo> GetUsers(int tenant, DateTime from);

        UserInfo GetUser(int tenant, Guid id);

        UserInfo GetUser(int tenant, string email);

        UserInfo GetUserByPasswordHash(int tenant, string login, string passwordHash);

        UserInfo SaveUser(int tenant, UserInfo user);

        void RemoveUser(int tenant, Guid id);

        byte[] GetUserPhoto(int tenant, Guid id);

        void SetUserPhoto(int tenant, Guid id, byte[] photo);

        DateTime GetUserPasswordStamp(int tenant, Guid id);

        void SetUserPasswordHash(int tenant, Guid id, string passwordHash);


        IDictionary<Guid, Group> GetGroups(int tenant, DateTime from);

        Group GetGroup(int tenant, Guid id);

        Group SaveGroup(int tenant, Group group);

        void RemoveGroup(int tenant, Guid id);


        IDictionary<string, UserGroupRef> GetUserGroupRefs(int tenant, DateTime from);

        UserGroupRef SaveUserGroupRef(int tenant, UserGroupRef r);

        void RemoveUserGroupRef(int tenant, Guid userId, Guid groupId, UserGroupRefType refType);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/mail.accountsmodal.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.accountsModal = (function($) {
    var isInit = false,
        accountEmail = '',
        wndQuestion = undefined,
        onSuccessOperationCallback,
        progressBarIntervalId = null,
        GET_STATUS_TIMEOUT = 1000,
        oauthMailboxId = -1,
        redTextColor = '#B40404',
        greenTextColor = '#44BB00',
        maxPwdLen = 30;

    var ids = {
        'email': 'email',
        'password': 'password',
        'server_type': 'server-type',
        'server': 'server',
        'smtp_server': 'smtp_server',
        'port': 'port',
        'name': 'name',
        'smtp_port': 'smtp_port',
        'account': 'account',
        'smtp_account': 'smtp_account',
        'smtp_password': '<PASSWORD>',
        'outcoming_encryption_type': 'outcoming_encryption_type',
        'incoming_encryption_type': 'incoming_encryption_type',
        'auth_type_in_sel': 'auth_type_in_sel',
        'auth_type_smtp_sel': 'auth_type_smtp_sel',
        'mail_limit': 'mail-limit'
    };

    var defaultPorts = {
        smtp: 25,
        smtp_ssl: 465,
        imap: 143,
        imap_ssl: 993,
        pop: 110,
        pop_ssl: 995
    };

    var encriptionTypes = {
        plain: 0,
        ssl: 1,
        starttls: 2
    };

    var authTypes = {
        none: 0,
        simple: 1,
        encrypted: 4
    };

    var init = function() {
        if (isInit === false) {
            isInit = true;

            window.Teamlab.bind(window.Teamlab.events.createMailMailboxSimple, onCreateAccount);
            window.Teamlab.bind(window.Teamlab.events.createMailMailboxOAuth, onCreateAccount);
            window.Teamlab.bind(window.Teamlab.events.createMailMailbox, onCreateAccount);

            wndQuestion = $('#questionWnd');
            wndQuestion.find('.buttons .cancel').bind('click', function() {
                hide();
                return false;
            });

            wndQuestion.find('.buttons .remove').bind('click', function () {
                hide();

                if (!accountEmail)
                    return false;

                var account = accountsManager.getAccountByAddress(accountEmail);

                if ($('.needReassign').prop('checked')) {
                    var reassignEmail = $('#reassignMessagesSelector').attr('mailbox_email');

                    Teamlab.reassignMailMessages({}, 3, reassignEmail, function (params, data) {
                        window.toastr.success(window.MailScriptResource.MailDraftsReassigned);
                    });

                    Teamlab.reassignMailMessages({}, 7, reassignEmail, function (params, data) {
                        window.toastr.success(window.MailScriptResource.MailTemplatesReassigned);
                    });
                }

                if (account.is_teamlab && (account.is_shared_domain || Teamlab.profile.isAdmin || ASC.Resources.Master.IsProductAdmin)) {
                    serviceManager.removeMailbox(account.mailbox_id, { account: account }, {
                        success: function (params, data) {
                            window.LoadingBanner.displayMailLoading();

                            ProgressDialog.init({
                                header: ASC.Resources.Master.ResourceJS.LoadingDescription,
                                percentage: 0
                            }, jq("#bottomLoaderPanel"), null, 1);

                            ProgressDialog.show();

                            progressBarIntervalId = setInterval(function () {
                                return checkRemoveMailboxStatus(data, params.account);
                            },
                            GET_STATUS_TIMEOUT);
                        },
                        error: function (params, error) {
                            administrationError.showErrorToastr("getCommonMailDomain", error);
                        }
                    }, ASC.Resources.Master.ResourceJS.LoadingProcessing);

                } else {
                    serviceManager.removeBox(account.email, { account: account }, {
                        success: function (params, data) {
                            window.LoadingBanner.displayMailLoading();

                            ProgressDialog.init({
                                header: ASC.Resources.Master.ResourceJS.LoadingDescription,
                                percentage: 0
                            }, jq("#bottomLoaderPanel"), null, 1);

                            ProgressDialog.show();

                            progressBarIntervalId = setInterval(function () {
                                return checkRemoveMailboxStatus(data, params.account)
                            },
                            GET_STATUS_TIMEOUT);
                        },
                        error: function (params, error) {
                            administrationError.showErrorToastr("getCommonMailDomain", error);
                        }
                    }, ASC.Resources.Master.ResourceJS.LoadingProcessing);
                }

                return false;
            });

            wndQuestion.find('.buttons .activate').bind('click', function() {
                hide();

                if (!accountEmail)
                    return false;

                activateAccountWithoutQuestion(accountEmail);

                return false;
            });

            wndQuestion.find('.buttons .deactivate').bind('click', function() {
                hide();

                if (!accountEmail)
                    return false;

                serviceManager.setMailboxState(accountEmail, false, { email: accountEmail, enabled: false }, {
                    error: function (e, error) {
                        administrationError.showErrorToastr("setMailboxState", error);
                    }
                }, ASC.Resources.Master.ResourceJS.LoadingProcessing);
                return false;
            });

            $('#manageWindow .cancelButton').css('cursor', 'pointer');
            $('#manageWindow .cancelButton').removeAttr('onclick');
            $('#manageWindow .cancelButton').click(function() {
                hide(true);
            });
        }
    };

    function checkRemoveMailboxStatus(operation, account) {
        serviceManager.getMailOperationStatus(operation.id,
        null,
        {
            success: function (params, data) {
                var status = translateOperationStatus(data.percents);

                if (data.completed) {
                    clearInterval(progressBarIntervalId);
                    progressBarIntervalId = null;
                    accountsManager.removeAccount(account.email);
                    serviceManager.updateFolders();
                    serviceManager.getTags();
                    serviceManager.getAccounts();
                    window.LoadingBanner.hideLoading();
                    ProgressDialog.setProgress(data.percents, status);

                    setTimeout(function () {
                        ProgressDialog.close();
                        ProgressDialog.setProgress(0, ASC.Resources.Master.ResourceJS.LoadingDescription);
                    }, 1000);
                } else {
                    ProgressDialog.setProgress(data.percents, status);
                }
            },
            error: function (e, error) {
                console.error("checkRemoveMailboxStatus", e, error);
                clearInterval(progressBarIntervalId);
                progressBarIntervalId = null;
                window.LoadingBanner.hideLoading();
            }
        });
    }

    function translateOperationStatus(percent) {
        var resource = ASC.Mail.Resources.MailApiResource;

        if (percent === 1) return resource.SetupTenantAndUserHeader;
        if (percent === 20) return resource.RemoveMailboxFromDbHeader;
        if (percent === 40) return resource.DecreaseQuotaSpaceHeader;
        if (percent === 50) return resource.RecalculateFoldersCountersHeader;
        if (percent === 60) return resource.ClearAccountsCacheHeader;
        if (percent === 70) return resource.RemoveElasticSearchIndexMessagesHeader;
        if (percent === 100) return resource.FinishedHeader;
    }

    function activateAccountWithoutQuestion(email) {
        var account = accountsManager.getAccountByAddress(email);

        if (!account)
            return false;

        var mailboxEmail = account.is_alias ? accountsManager.getAccountById(account.mailbox_id).email : accountEmail;

        serviceManager.setMailboxState(mailboxEmail, true, { email: accountEmail, enabled: true, onSuccessOperationCallback: onSuccessOperationCallback }, {
            error: function (e, errors) {
                console.error("activateAccountWithoutQuestion", errors);

                mailAlerts.showAlert({
                    type: ASC.Mail.Constants.Alerts.AuthConnectFailure,
                    id_mailbox: account.mailbox_id,
                    data: null,
                    redirectToAccounts: false,
                    activateOnSuccess: true
                });
            }
        }, ASC.Resources.Master.ResourceJS.LoadingProcessing);

        return true;
    }

    function addBox() {
        showWizard();
    }

    function addMailbox() {
        var $rootEl;
        var currentDomain;

        if (window.MailCommonDomain) {
            showMy(window.MailCommonDomain);
        } else {
            serviceManager.getCommonMailDomain({}, {
                success: function (e, domain) {
                    window.MailCommonDomain = domain;
                    showMy(domain);
                },
                error: function (e, error) {
                    administrationError.showErrorToastr("getCommonMailDomain", error);
                }
            }, ASC.Resources.Master.ResourceJS.LoadingProcessing);
        }

        function showMy(domain) {

            currentDomain = domain;

            var html = $.tmpl('createMyMailboxPopupTmpl', { domain: domain });

            $(html).find('.save').unbind('click').bind('click', addMyMailbox);

            $(html).find('.cancel').unbind('click').bind('click', function () {
                if ($(this).hasClass('disable')) {
                    return false;
                }
                popup.hide();
                return false;
            });

            popup.hide();
            
            popup.addPopup(window.MailScriptResource.CreateMyMailboxPopupHeader, html, 450);

            $rootEl = $('#mail_server_create_my_mailbox_popup');

            $rootEl.find('#mail_server_add_my_mailbox .mailbox_name').unbind('textchange').bind('textchange', function () {
                turnOffAllRequiredError();
            });

            PopupKeyUpActionProvider.EnterAction = "jq('#mail_server_create_my_mailbox_popup:visible .save').trigger('click');";

            setFocusToInput();
        }
        
        function addMyMailbox() {
            if ($(this).hasClass('disable')) {
                return false;
            }

            window.LoadingBanner.hideLoading();

            var isValid = true;

            var mailboxName = $rootEl.find('#mail_server_add_my_mailbox .mailbox_name').val();
            if (mailboxName.length === 0) {
                TMMail.setRequiredHint('mail_server_add_my_mailbox', window.MailScriptResource.ErrorEmptyField);
                TMMail.setRequiredError('mail_server_add_my_mailbox', true);
                isValid = false;
            } else if (!ASC.Mail.Utility.IsValidEmail(mailboxName + '@' + currentDomain.name)) {
                TMMail.setRequiredHint('mail_server_add_my_mailbox', window.MailScriptResource.ErrorIncorrectEmail);
                TMMail.setRequiredError('mail_server_add_my_mailbox', true);
                isValid = false;
            }

            if (!isValid) {
                setFocusToInput();
                return false;
            }

            turnOffAllRequiredError();
            displayLoading($rootEl, true);
            disablePopupControls($rootEl, true);

            showLoader(window.MailScriptResource.MailboxCreation);
            
            serviceManager.addMyMailbox(mailboxName,
                { email: mailboxName + "@" + currentDomain.name, name: Teamlab.profile.displayName, enabled: true, restrict: false, oauth: false },
                {
                    success: function (params, mailbox) {
                        displayLoading($rootEl, false);
                        disablePopupControls($rootEl, false);

                        if (TMMail.pageIs('sysfolders') && accountsManager.getAccountList().length == 0) {
                            blankPages.showEmptyFolder();
                        }
                        var autoreply = {
                            turnOn: false,
                            turnOnToDate: false,
                            fromDate: "0001-01-01T00:00:00",
                            html: "",
                            mailboxId: mailbox.id,
                            onlyContacts: false,
                            subject: "",
                            toDate: "0001-01-01T00:00:00"
                        };
                        accountsPage.addAccount(mailbox.address.email, autoreply, params.enabled, params.oauth, true);

                        var account = {
                            name: TMMail.ltgt(params.name),
                            email: TMMail.ltgt(mailbox.address.email),
                            enabled: params.enabled,
                            signature: {
                                html: "",
                                isActive: false,
                                mailboxId: mailbox.id,
                                tenant: 0
                            },
                            autoreply: autoreply,
                            is_alias: false,
                            is_group: false,
                            oauth: params.oauth,
                            emailInFolder: null,
                            is_teamlab: true,
                            mailbox_id: mailbox.id,
                            is_default: false,
                            is_shared_domain: true,
                            authError: false,
                            quotaError: false
                        };

                        accountsManager.addAccount(account);

                        accountsPanel.update();

                        hide();
                        window.toastr.success(window.MailActionCompleteResource.AddMailboxSuccess.format(mailbox.address.email));
                    },
                    error: function (ev, error) {
                        popup.error(administrationError.getErrorText("addMailbox", error));
                        displayLoading($rootEl, false);
                        disablePopupControls($rootEl, false);
                    }
                });

            return false;
        }

        function turnOffAllRequiredError() {
            TMMail.setRequiredError('mail_server_add_mailbox', false);
            TMMail.setRequiredError('mail_server_add_mailbox', false);
        }

        function setFocusToInput() {
            $rootEl.find('.mailbox_name').focus();
    }
    }

    function displayLoading(rootEl, isVisible) {
        var loader = rootEl.find('.progressContainer .loader');
        var toastr = rootEl.find('.progressContainer .toast-popup-container');
        if (loader) {
            if (isVisible) {
                toastr.remove();
                loader.show();
            } else {
                loader.hide();
            }
        }
    }

    function disablePopupControls(rootEl, disable) {
        TMMail.disableButton(rootEl.find('.cancel'), disable);
        TMMail.disableButton(rootEl.find('.save'), disable);
        TMMail.disableButton($('#commonPopup .cancelButton'), disable);
        popup.disableCancel(disable);
        TMMail.disableInput(rootEl.find('input'), disable);
    }

    function removeBox(account) {
        if (!account)
            return;

        accountEmail = account;
        questionBox('remove');
    }

    function editBox(account, activateOnSuccess) {
        serviceManager.getBox(account, { action: 'edit', activateOnSuccess: activateOnSuccess },
        {
            success: onGetBox
        }, ASC.Resources.Master.ResourceJS.LoadingProcessing);
    }

    function setDefaultAccount(account, setDefault) {
        serviceManager.setDefaultAccount(account, setDefault, ASC.Resources.Master.ResourceJS.LoadingProcessing);
    }

    function checkPassword() {
        var cnt = $("#mail_server_change_mailbox_password_popup:visible");

        if (!cnt || !cnt.length) return;

        var $password = cnt.find("#passValue");

        if (!$password || !$password.length) return;

        var inputValues = $password.val(),
            inputLength = inputValues.length,
            progress = jq('.validationProgress'),
            progressStep = ($password.width() + 41) / ASC.Mail.Constants.PASSWORD_SETTINGS.MinLength;

        progress.width(inputLength * progressStep);

        (passwordValidation(inputValues))
               ? (progress.css('background', greenTextColor), TMMail.setRequiredError('mailboxPwd', false))
               : progress.css('background', redTextColor);
    };

    function showOrHidePassword() {
        var cnt = $("#mail_server_change_mailbox_password_popup:visible");

        if (!cnt || !cnt.length) return;

        var $passwordShow = cnt.find("#passwordShow"),
            $password = cnt.find("#passValue"),
            $passwordShowLabel = cnt.find("#passwordShowLabel");

        ($passwordShow.prop('checked'))
            ? ($password.prop('type', 'text'),
                $passwordShowLabel.removeClass('hidePwd').addClass('showPwd'))
            : ($password.prop('type', 'password'),
                $passwordShowLabel.removeClass('showPwd').addClass('hidePwd'));
    };

    function copyToClipboard() {
        var cnt = $("#mail_server_change_mailbox_password_popup:visible");

        if (!cnt || !cnt.length) return;

        var email = cnt.attr("data_id"),
            password = cnt.find("#passValue").val(),
            clip = jq('#clip').val('email: ' + email + '\npassword: ' + password);
        clip.select();
        document.execCommand('copy');
        window.toastr.success(ASC.Mail.Resources.EmailAndPasswordCopiedToClipboard);
    };

    function passwordValidation(inputValues) {
        var upper,
            digits,
            special;

        (ASC.Mail.Constants.PASSWORD_SETTINGS.UpperCase)
            ? upper = /[A-Z]/.test(inputValues)
            : upper = true;

        (ASC.Mail.Constants.PASSWORD_SETTINGS.Digits)
            ? digits = /\d/.test(inputValues)
            : digits = true;

        (ASC.Mail.Constants.PASSWORD_SETTINGS.SpecSymbols)
            ? special = /[!@#$%^&*]/.test(inputValues)
            : special = true;

        var onlyLatinLetters = !(/[^\x00-\x7F]+/.test(inputValues));
        var noSpaces = !(/\s+/.test(inputValues));

        checkPasswordInfoColor(inputValues, upper, digits, special, onlyLatinLetters, noSpaces);

        return digits && upper && special && inputValues.length >= ASC.Mail.Constants.PASSWORD_SETTINGS.MinLength && onlyLatinLetters && noSpaces;
    };

    function checkPasswordInfoColor(inputValues, upper, digits, special, onlyLatinLetters, noSpaces) {
        var cnt = $("#mail_server_change_mailbox_password_popup:visible");

        if (!cnt || !cnt.length) return;

        var $passUpper = cnt.find("#passUpper"),
            $passDigits = cnt.find("#passDigits"),
            $passSpecial = cnt.find("#passSpecial"),
            $passMinLength = cnt.find("#passMinLength"),
            $passLatinLetters = cnt.find("#passLatinLetters"),
            $passNoSpaces = cnt.find("#passNoSpaces");

        (upper)
            ? greenText($passUpper)
            : redText($passUpper);

        (digits)
            ? greenText($passDigits)
            : redText($passDigits);

        (special)
            ? greenText($passSpecial)
            : redText($passSpecial);

        (inputValues.length >= ASC.Mail.Constants.PASSWORD_SETTINGS.MinLength)
            ? greenText($passMinLength)
            : redText($passMinLength);

        (onlyLatinLetters)
            ? greenText($passLatinLetters)
            : redText($passLatinLetters);

        (noSpaces)
            ? greenText($passNoSpaces)
            : redText($passNoSpaces);
    };

    function greenText(control) {
        control.removeClass('red').addClass('green');
    };

    function redText(control) {
        control.removeClass('green').addClass('red');
    };

    function changePassword(login, id) {
        var html = $.tmpl('changeMailboxPasswordPopupTmpl',
        { login: login });

        $(html).find('.save').unbind('click').bind('click', function() {
            doChangePassword.apply(this, [login, id]);
        });

        $(html).find('.cancel').unbind('click').bind('click', function () {
            if ($(this).hasClass('disable')) {
                return false;
            }
            popup.hide();
            return false;
        });

        popup.hide();

        popup.addPopup(MailAdministrationResource.ChangeMailboxPasswordPopupInfo, html, 350);

        var cnt = $("#mail_server_change_mailbox_password_popup:visible");

        if (!cnt || !cnt.length) return;

        var $password = cnt.find("#passValue"),
            $passwordInfo = cnt.find("#passwordInfo");

        $password.on('input', checkPassword);
        $password.on('focus', function () { $passwordInfo.show(); });
        $password.on('blur', function () { $passwordInfo.hide(); });

        cnt.find('#passwordShow').on('click', showOrHidePassword);

        cnt.find('#passwordGen').unbind('click').bind('click', getRandomPwd);

        cnt.find('#copyValues').unbind('click').bind('click', copyToClipboard);

        PopupKeyUpActionProvider.EnterAction = "jq('#mail_server_change_mailbox_password_popup:visible .save').trigger('click');";

        $password.focus();
    }

    function doChangePassword(login, id) {
        if ($(this).hasClass('disable')) {
            return false;
        }

        window.LoadingBanner.hideLoading();

        var cnt = $("#mail_server_change_mailbox_password_popup");

        var pwd = cnt.find("#passValue").val();

        var isValid = passwordValidation(pwd);

        if (!isValid) {
            cnt.find("#passValue").focus();
            return false;
        }

        TMMail.setRequiredError('mailboxPwd', false);

        displayLoading(cnt, true);
        disablePopupControls(cnt, true);

        showLoader(window.MailScriptResource.MailboxCreation);

        serviceManager.changeMailboxPassword(id, pwd,
            null,
            {
                success: function () {
                    displayLoading(cnt, false);
                    disablePopupControls(cnt, false);

                    hide();
                    window.toastr.success(ASC.Mail.Resources.ChangePasswordSuccess);
                },
                error: function (ev, error) {
                    popup.error(error[0]);
                    displayLoading(cnt, false);
                    disablePopupControls(cnt, false);
                }
            });

        return false;
    }

    function blockUi(width, message) {
        StudioBlockUIManager.blockUI(message, width, { bindEvents: false });

        $('#manageWindow .cancelButton').css('cursor', 'pointer');
        $('.containerBodyBlock .buttons .cancel').unbind('click').bind('click', function() {
            $.unblockUI();
            return false;
        });
    }

    // Simple wizard window
    function showWizard(email, password) {
        oauthMailboxId = -1;

        var html = $.tmpl('accountWizardTmpl');

        $('#manageWindow').removeClass('show-error').attr('className', 'addInbox')
            .find('div.containerBodyBlock:first').html(html);

        $('#manageWindow div.containerHeaderBlock:first').find('td:first').html(window.MailScriptResource.NewAccount);

        if ($(html).find('#oauth_frame_blocker').length) {
            blockUi(626, $("#manageWindow"));

            $(".oauth-block").click(function () {
                var url = $(this).attr("data-url");
                var params = "height=600,width=1020,resizable=0,status=0,toolbar=0,menubar=0,location=1";
                window.open(url, "Authorization", params);
            });
        } else {
            blockUi(490, $("#manageWindow"));
        }

        $('.containerBodyBlock .buttons #save').unbind('click').bind('click', function() {
            if ($('.containerBodyBlock .buttons #save').attr('disabled')) {
                return false;
            }

            createMailBoxSimple();
            return false;
        });

        $('.containerBodyBlock .buttons #advancedLinkButton').unbind('click').bind('click', function() {
            if ($('.containerBodyBlock .buttons #advancedLinkButton').attr('disabled')) {
                return false;
            }

            switchToAdvanced("get_imap_pop_settings");
            return false;
        });

        $('.containerBodyBlock #password').keyup(setupPasswordView);
        $('.containerBodyBlock a.password-view').unbind('click').bind('click', togglePassword);

        window.PopupKeyUpActionProvider.EnterAction = "jq('.containerBodyBlock .buttons #save').click();";

        if (email) {
            setVal(ids.email, email);
        }

        if (password) {
            setVal(ids.password, password);
            $('.containerBodyBlock #password').keyup();
        }
    }

    function setupPasswordView() {
        var cnt = $(this).closest('.requiredField');
        if (!cnt || !cnt.length) return;

        var password = cnt.find("input.textEdit").val();
        if (password.length > 0) {
            TMMail.setRequiredError(cnt.attr('id'), false);
        }
        var passwordViewLink = cnt.find("a.password-view");
        passwordViewLink.toggleClass('off', password.length === 0);
    }

    function togglePassword() {
        var passwordInput = $(this).closest('.requiredField').find('input');
        if (passwordInput.attr('type') == "password") {
            passwordInput.attr('type', 'text');
            $(this).text(window.MailScriptResource.HidePasswordLinkLabel);
        } else {
            passwordInput.attr('type', 'password');
            $(this).text(window.MailScriptResource.ShowPasswordLinkLabel);
        }
    }

    function getRandomPwd() {

        TMMail.setRequiredError('mailboxPwd', false);

        serviceManager.getRandomPassword(
            null,
            {
                success: function (params, pwd) {
                    var cnt = $("#mail_server_change_mailbox_password_popup");

                    cnt.find("#passValue").attr('type', 'text').val(pwd);

                    cnt.find("#passwordShowLabel").removeClass('hide').addClass('show');

                    cnt.find("#passwordShow").prop('checked', true);

                    checkPassword();
                },
                error: function (params, error) {
                    popup.error(error[0]);
                }
            });
    }

    function viewMailboxSettings(account) {

        window.Teamlab.getMailMailbox({},
            account.email,
            {
                success: function (params, mailbox) {
                    showConnectionSettings(mailbox);
                },
                error: function(ev, error) {
                    window.toastr.error(error[0]);
                }
            });
    }

    function showConnectionSettings(mailbox, hideChangePasswordLink) {
        var html = $.tmpl('mailboxSettingsPopupTmpl', mailbox);

        $(html)
            .find('.cancel')
            .unbind('click')
            .bind('click',
                function () {
                    if ($(this).hasClass('disable')) {
                        return false;
                    }
                    popup.hide();
                    return false;
                });

        popup.hide();

        popup.addPopup(MailAdministrationResource.ViewMailboxConnectionSettingsPopupInfo, html, 350);

        var cnt = $("#mail_server_mailbox_settings_popup:visible");

        var changePasswordLink = cnt.find('#changePasswordLink');

        if (!hideChangePasswordLink) {
            changePasswordLink.show();

            changePasswordLink.unbind('click')
                .bind('click',
                    function() {
                        popup.hide();
                        changePassword(mailbox.email, mailbox.id);
                    });
        } else {
            changePasswordLink.hide();
        }

        PopupKeyUpActionProvider
            .EnterAction =
            "jq('#mail_server_change_mailbox_password_popup:visible .cancel').trigger('click');";
    }

    function onGetOAuthInfo(code, error) {

        if (oauthMailboxId > 0) {
            showLoader(window.MailScriptResource.MailBoxUpdate);

            var settings = getSettings();

            var account = accountsManager.getAccountById(oauthMailboxId);

            settings.id = account.id || account.mailbox_id;
            settings.is_oauth = true;

            var data = $.extend({ action: 'edit', activateOnSuccess: !account.enabled }, { settings: settings });

            if (error) {
                showErrorModal(data, [error]);
                return;
            }

            serviceManager.updateOAuthBox(code,
                1,
                oauthMailboxId,
                data,
                {
                    success: function () {
                        hide();
                        window.toastr.success(window.MailScriptResource.AccountGoogleReconnectSuccess);
                        if (!account.enabled)
                            accountsModal.activateAccount(account.email, true);
                    },
                    error: showErrorModal
                });
        } else {
            if (error) {
                showErrorModal({
                    oauth: true,
                    simple: true,
                    settings: {
                        name: ''
                    }
                }, [error]);
                return;
            }

            showLoader(window.MailScriptResource.MailboxCreation);
            serviceManager.createOAuthBox(code,
                1, //google service
                {
                    oauth: true,
                    settings: {
                        name: '',
                        enabled: true,
                        restrict: true
                    }
                },
                { error: showErrorModal });
        }
    }

    function switchToAdvanced(action) {
        var email = getVal(ids.email);
        var password = getVal(ids.password, false);

        var options = { action: action };

        // If the email entered is OK
        if (ASC.Mail.Utility.IsValidEmail(email)) {
            options.password = password;
            options.name = getVal(ids.name, true);
            serviceManager.getDefaultMailboxSettings(email, options,
                {
                    success: onGetDefaultMailboxSettings,
                    error: onErrorGetDefaultMailboxSettings
                },
                window.MailScriptResource.ObtainingDefaultDomainSettings);
        }
        else {
            // If nothing is entered as email or the email is wrong
            var data = {
                email: email,
                password: password,
                smtp_auth: true,
                imap: true,
                incoming_encryption_type: encriptionTypes.ssl,
                port: defaultPorts.imap_ssl,
                auth_type_in: authTypes.simple,
                restrict: true,
                outcoming_encryption_type: encriptionTypes.ssl,
                smtp_port: defaultPorts.smtp_ssl,
                smtp_password: password,
                auth_type_smtp: authTypes.simple
            };

            onGetBox(options, data);
        }
    }

    function showLoader(message) {
        $('.popupMailBox').find('div.error-popup').hide();
        $('.popupMailBox').find('div.progressContainer').show();
        $('.popupMailBox').find('div.progressContainer .loader').show().html(message || '');

        $('.containerBodyBlock .buttons #save').attr('disabled', 'true').removeClass("disable").addClass("disable");
        $('.containerBodyBlock .buttons #cancel').attr('disabled', 'true').removeClass("disable").addClass("disable");
        $('.popupMailBox #oauth_frame_blocker').show();
        $('.containerBodyBlock .buttons #getDefaultSettings').attr('disabled', 'true').removeClass("disable").addClass("disable");
        $('.containerBodyBlock .buttons #advancedLinkButton').attr('disabled', 'true').removeClass("disable").addClass("disable");

        $('#manageWindow .containerHeaderBlock').find('.popupCancel .cancelButton').css('cursor', 'default');

        disable(ids.name);
        disable(ids.mail_limit);
        disableControls();
    }

    function hideLoader(forceHideContainer) {
        if (forceHideContainer) {
            $('.popupMailBox').find('div.progressContainer').hide();
        }

        $('.popupMailBox').find('div.progressContainer .loader').hide();

        $('.containerBodyBlock .buttons #save').removeAttr('disabled').removeClass("disable");
        $('.containerBodyBlock .buttons #cancel').removeAttr('disabled').removeClass("disable");
        $('.popupMailBox #oauth_frame_blocker').hide();
        $('.containerBodyBlock .buttons #getDefaultSettings').removeAttr('disabled').removeClass("disable");
        $('.containerBodyBlock .buttons #advancedLinkButton').removeAttr('disabled').removeClass("disable");

        $('#manageWindow .containerHeaderBlock').find('.popupCancel .cancelButton').css('cursor', 'pointer');

        enableControls();
        if (getVal(ids.auth_type_smtp_sel, true) == 0) {
            enable(ids.smtp_account);
            enable(ids.smtp_password);
        }
    }

    function enableControls() {
        enable(ids.email);
        enable(ids.password);
        enable(ids.name);
        enable(ids.server_type);
        enable(ids.server);
        enable(ids.smtp_server);
        enable(ids.port);
        enable(ids.smtp_port);
        enable(ids.account);
        enable(ids.mail_limit);
        enable(ids.outcoming_encryption_type);
        enable(ids.incoming_encryption_type);
        enable(ids.auth_type_in_sel);
        enable(ids.auth_type_smtp_sel);
    }

    function disableControls() {
        disable(ids.email);
        disable(ids.password);
        disable(ids.server_type);
        disable(ids.server);
        disable(ids.smtp_server);
        disable(ids.port);
        disable(ids.smtp_port);
        disable(ids.account);
        disable(ids.smtp_account);
        disable(ids.smtp_password);
        disable(ids.outcoming_encryption_type);
        disable(ids.incoming_encryption_type);
        disable(ids.auth_type_in_sel);
        disable(ids.auth_type_smtp_sel);
    }

    function onGetBox(params, account) {
        oauthMailboxId = -1;

        if (params.action == "get_imap_server" ||
            params.action == "get_pop_server") {
            setVal(ids.account, account.account);
            setVal(ids.server, account.server);
            setVal(ids.port, account.port);
            $('.popupMailBox #ssl').prop('checked', account.ssl);
            return;
        }

        if ((params.action == 'get_imap_server_full' || params.action == 'get_pop_server_full') && $('#manageWindow').attr('classname') == 'editInbox') {
            params.action = 'edit';
        }

        var html = $.tmpl('accountTmpl', account);

        $('#manageWindow').removeClass('show-error').attr('className', params.action === 'edit' ? 'editInbox' : 'addInbox')
            .find('div.containerBodyBlock:first').html(html);
        $('#manageWindow div.containerHeaderBlock:first').find('td:first').html(params.action === 'edit' ? window.MailScriptResource.AccountEdit : window.MailScriptResource.NewAccount);

        blockUi(523, $("#manageWindow"));

        if ($(html).find('#oauth_frame_blocker').length) {
            $(".containerBodyBlock .buttons .oauth-block").click(function (e) {
                if (e.target && $(e.target).hasClass('oauth-help')) {
                    // skip help click
                    return;
                }

                if ("is_oauth" in account && account.is_oauth) {
                    oauthMailboxId = account.id;
                }

                var url = $(this).attr("data-url");
                var params = "height=600,width=1020,resizable=0,status=0,toolbar=0,menubar=0,location=1";
                window.open(url, "Authorization", params);
            });
        }

        if ($('#manageWindow').attr('className') != 'addInbox') {
            $('#smtp_password').attr('placeholder', '**********');
            $('#password').attr('placeholder', '**********');
            $('#smtp_password').placeholder();
            $('#password').placeholder();
        }

        if ("is_oauth" in account && account.is_oauth) {
            disableControls();
            $('.popupMailBox #getDefaultSettings').hide();
        }

        $('.containerBodyBlock .buttons #save').unbind('click').bind('click', function() {
            if ($('.containerBodyBlock .buttons #save').attr('disabled')) {
                return false;
            }

            $('.popupMailBox').find('div.progressContainer').show();
            $('.popupMailBox').find('div.error-popup').hide();
            if ($('#manageWindow').attr('className') == 'addInbox') {
                createMailbox();
            } else {
                updateMailbox(false, params.activateOnSuccess);
            }

            return false;
        });

        $('.popupMailBox .buttons #getDefaultSettings').unbind('click').bind('click', function() {
            if ($('.containerBodyBlock .buttons #getDefaultSettings').attr('disabled')) {
                return false;
            }

            var email = getVal(ids.email);

            var emailCorrect = isEmailCorrect(email);

            TMMail.setRequiredError("mail_EMailContainer", !emailCorrect);

            if (getVal(ids.server_type, true) == 'imap') {
                params.action = "get_imap_server_full";
            } else {
                params.action = "get_pop_server_full";
            }

            if (emailCorrect) {
                switchToAdvanced(params.action);
            }

            return false;
        });

        if (params.action == 'edit') {
            disable(ids.email);
            disable(ids.server_type);
        }

        $('.popupMailBox #auth_type_smtp_sel').unbind('change').bind('change', function() {
            if ($(this).val() != 0) {
                enable(ids.smtp_account);
                enable(ids.smtp_password);
                $("#mail_SMTPLoginContainer").addClass('requiredField');
                $("#mail_SMTPPasswordContainer").addClass('requiredField');
            } else {
                disable(ids.smtp_account);
                disable(ids.smtp_password);
                TMMail.setRequiredError("mail_SMTPLoginContainer", false);
                TMMail.setRequiredError("mail_SMTPPasswordContainer", false);

                $("#mail_SMTPLoginContainer").removeClass('requiredField');
                $("#mail_SMTPPasswordContainer").removeClass('requiredField');
            }
        });

        $('.popupMailBox #server').unbind('blur').bind('blur', function() {
            var addr = getVal(ids.server, true);
            if (addr.length > 0 && getVal(ids.smtp_server, true).length == 0) {
                setVal(ids.smtp_server, 'smtp' + addr.substring(addr.indexOf('.')));
            }
        });

        $('.popupMailBox #server-type').unbind('change').bind('change', function() {
            var email = getVal(ids.email);

            var emailCorrect = ASC.Mail.Utility.IsValidEmail(email);

            var action;
            if ($(this).val() == 'pop') {
                $('.popupMailBox #receive-server-header').html('POP ' + window.MailScriptResource.ServerLabel);
                $('.popupMailBox #use_incomming_ssl_label').html(window.MailResource.UsePOP3SSL);
                action = "get_pop_server";
            } else {
                $('.popupMailBox #receive-server-header').html('IMAP ' + window.MailScriptResource.ServerLabel);
                $('.popupMailBox #use_incomming_ssl_label').html(window.MailResource.UseImapSSL);
                action = "get_imap_server";
            }

            if (emailCorrect) {
                account.password = getVal(ids.password, true);
                account.smtp_password = getVal(ids.smtp_password, true);
                var data = $.extend({ action: action }, { settings: account });
                serviceManager.getDefaultMailboxSettings(email,
                    data,
                    {
                        success: onGetDefaultMailboxSettings,
                        error: onErrorGetDefaultMailboxSettings
                    },
                    window.MailScriptResource.ObtainingDefaultDomainSettings);
            }
        });

        $('.containerBodyBlock #password').keyup(setupPasswordView);
        $('.containerBodyBlock #smtp_password').keyup(setupPasswordView);
        $('.containerBodyBlock a.password-view').unbind('click').bind('click', togglePassword);

        if (params.error) {
            setErrorToPopupMailbox(params.error);
        }

        if (account.password) {
            $('.containerBodyBlock #password').keyup();
        }

        if (account.smtp_password) {
            $('.containerBodyBlock #smtp_password').keyup();
        }
    }

    function setErrorToPopupMailbox(errorText) {
        hideLoader(true);
        $('.popupMailBox').find('div.error-popup').show().find('.text').text(errorText);
    }

    function createMailbox() {
        return updateMailbox(true, false);
    }

    function createMailBoxSimple() {
        var email = getVal(ids.email),
            password = getVal(ids.password);

        var emailCorrect = false;
        var passwordCorrect = false;

        if (email.length === 0) {
            TMMail.setRequiredHint("mail_EMailContainer", window.MailScriptResource.ErrorEmptyField);
        } else if (!ASC.Mail.Utility.IsValidEmail(email)) {
            TMMail.setRequiredHint("mail_EMailContainer", window.MailScriptResource.ErrorIncorrectEmail);
        } else if (accountsPage.isContain(email.toLowerCase())) {
            TMMail.setRequiredHint("mail_EMailContainer", window.MailScriptResource.ErrorAccountAlreadyExists);
        } else {
            emailCorrect = true;
        }

        TMMail.setRequiredError("mail_EMailContainer", !emailCorrect);

        if (password.length !== 0) {
            passwordCorrect = true;
        }

        TMMail.setRequiredError("mail_PasswordContainer", !passwordCorrect);

        if (emailCorrect && passwordCorrect) {
            showLoader(window.MailScriptResource.MailboxCreation);

            var data = {
                oauth: false,
                simple: true,
                settings: { email: email, password: password, name: '', enabled: true, restrict: true }
            };

            serviceManager.createMinBox(email, password,
                data,
                { error: showErrorModal });
        }
    }

    function getSettings() {
        var settings = {
            email: getVal(ids.email),
            name: getVal(ids.name),
            account: getVal(ids.account),
            password: getVal(ids.password),
            server: getVal(ids.server),
            smtp_server: getVal(ids.smtp_server),
            smtp_port: getVal(ids.smtp_port),
            smtp_account: getVal(ids.smtp_account),
            smtp_password: getVal(ids.smtp_password),
            smtp_auth: $('.popupMailBox #auth_type_smtp_sel').val() != 0,
            port: getVal(ids.port),
            incoming_encryption_type: getVal(ids.incoming_encryption_type + ' option:selected', true),
            outcoming_encryption_type: getVal(ids.outcoming_encryption_type + ' option:selected', true),
            auth_type_in: getVal(ids.auth_type_in_sel + ' option:selected', true),
            auth_type_smtp: getVal(ids.auth_type_smtp_sel + ' option:selected', true),
            imap: (getVal(ids.server_type, true) == 'imap'),
            restrict: $('.popupMailBox #mail-limit').is(':checked')
        }

        return settings;
    }

    function updateMailbox(newFlag, activateOnSuccess) {
        var settings = getSettings();

        if (settings.password == $('#password').attr('placeholder')) {
            settings.password = '';
        }
        if (settings.smtp_password == $('#smtp_password').attr('placeholder')) {
            settings.smtp_password = '';
        }

        var emailIncorrect = true;
        var serverIncorrect = false;
        var portIncorrect = false;
        var accountIncorrect = false;
        var passwordIncorrect = false;
        var smtpServerIncorrect = false;
        var smtpPortIncorrect = false;
        var smtpAccountIncorrect = false;
        var smtpPasswordIncorrect = false;

        if (settings.email.length === 0) {
            $("#mail_EMailContainer.requiredField span").text(window.MailScriptResource.ErrorEmptyField);
        } else if (!ASC.Mail.Utility.IsValidEmail(settings.email)) {
            TMMail.setRequiredHint("mail_EMailContainer", window.MailScriptResource.ErrorIncorrectEmail);
        } else if (newFlag && accountsPage.isContain(settings.email.toLowerCase())) {
            TMMail.setRequiredHint("mail_EMailContainer", window.MailScriptResource.ErrorAccountAlreadyExists);
        } else {
            emailIncorrect = false;
        }

        TMMail.setRequiredError("mail_EMailContainer", emailIncorrect);
        TMMail.setRequiredError("mail_POPServerContainer", serverIncorrect = settings.server.length === 0);
        TMMail.setRequiredError("mail_POPPortContainer", portIncorrect = settings.port.length === 0);
        TMMail.setRequiredError("mail_POPLoginContainer", accountIncorrect = settings.account.length === 0);
        TMMail.setRequiredError("mail_POPPasswordContainer", passwordIncorrect = (settings.password.length === 0 && newFlag));

        TMMail.setRequiredError("mail_SMTPServerContainer", smtpServerIncorrect = settings.smtp_server.length === 0);
        TMMail.setRequiredError("mail_SMTPPortContainer", smtpPortIncorrect = settings.smtp_port.length === 0);

        if (settings.smtp_auth) {
            TMMail.setRequiredError("mail_SMTPLoginContainer", smtpAccountIncorrect = settings.smtp_account.length === 0);
            TMMail.setRequiredError("mail_SMTPPasswordContainer", smtpPasswordIncorrect = (settings.smtp_password.length === 0 && newFlag));
        }
        var data;
        if (!emailIncorrect &&
            !serverIncorrect &&
            !portIncorrect &&
            !accountIncorrect &&
            !passwordIncorrect &&
            !smtpServerIncorrect &&
            !smtpPortIncorrect &&
            !smtpAccountIncorrect &&
            !smtpPasswordIncorrect) {

            if (true === newFlag) {
                showLoader(window.MailScriptResource.MailboxCreation);

                data = $.extend({ oauth: false, action: 'add' }, { settings: settings });

                serviceManager.createBox(settings.name,
                    settings.email,
                    settings.account,
                    settings.password,
                    settings.port,
                    settings.server,
                    settings.smtp_account,
                    settings.smtp_password,
                    settings.smtp_port,
                    settings.smtp_server,
                    settings.smtp_auth,
                    settings.imap,
                    settings.restrict,
                    settings.incoming_encryption_type,
                    settings.outcoming_encryption_type,
                    settings.auth_type_in,
                    settings.auth_type_smtp,
                    data,
                    { error: showErrorModal });
            } else {

                showLoader(window.MailScriptResource.MailBoxUpdate);

                data = $.extend({ action: 'edit', activateOnSuccess: activateOnSuccess }, { settings: settings });

                serviceManager.updateBox(settings.name,
                    settings.email,
                    settings.account,
                    settings.password,
                    settings.port,
                    settings.server,
                    settings.smtp_account,
                    settings.smtp_password,
                    settings.smtp_port,
                    settings.smtp_server,
                    settings.smtp_auth,
                    settings.restrict,
                    settings.incoming_encryption_type,
                    settings.outcoming_encryption_type,
                    settings.auth_type_in,
                    settings.auth_type_smtp,
                    data,
                    {
                        success: function() {
                            window.toastr.success(window.MailActionCompleteResource.updateMailboxSuccess.format(settings.email));
                        },
                        error: showErrorModal
                    });
            }
        }
    }

    function questionBox(operation) {
        var header = '',
            question = '',
            option = '',
            accounts = accountsManager.getAccountList();

        wndQuestion.find('.activate').hide();
        wndQuestion.find('.deactivate').hide();
        wndQuestion.find('.remove').hide();

        switch (operation) {
            case 'remove':
                header = wndQuestion.attr('delete_header');
                wndQuestion.find('.remove').show();
                question = window.MailScriptResource.DeleteAccountShure;
                option = '<p>' + window.MailScriptResource.DeleteAccountOptionHead + '</p>\
                        <div class="reassignOption disabled"><input type="checkbox" class="needReassign"/> \
                        ' + window.MailScriptResource.DeleteAccountOptionText + ': <span id="reassignMessagesSelector" class="pointer">\
                        <span class="baseLinkAction"></span><div class="baseLinkArrowDown"></div></span></div>';
                break;
            case 'activate':
                header = wndQuestion.attr('activate_header');
                wndQuestion.find('.activate').show();
                question = window.MailScriptResource.ActivateAccountShure;
                break;
            case 'deactivate':
                header = wndQuestion.attr('deactivate_header');
                wndQuestion.find('.deactivate').show();
                question = window.MailScriptResource.DeactivateAccountShure;
                break;
        }

        wndQuestion.find('div.containerHeaderBlock:first td:first').html(header);
        question = question.replace(/%1/g, accountEmail);
        wndQuestion.find('.mail-confirmationAction p.questionText').text(question);

        if (accounts.filter(function (account) { return !(account.is_alias || account.is_group); }).length > 1) {
            wndQuestion.find('.mail-confirmationAction .optionText').html(option);

            createSetMailBoxSelector(accounts);
        }

        blockUi(523, wndQuestion);

        $('.needReassign').on('click', function () {
            ($(this).prop('checked'))
                ? $('.reassignOption').removeClass('disabled')
                : $('.reassignOption').addClass('disabled');
        });

        window.PopupKeyUpActionProvider.EnterAction = "jq('#questionWnd .containerBodyBlock .buttons .button.blue:visible').click();";
    }

    function createSetMailBoxSelector(accounts) {
        var complitedAccounts = [],
            $selector = $('#reassignMessagesSelector');

        complitedAccounts = accounts
            .filter(function (account) {
                return !(account.is_alias || account.is_group || account.email === accountEmail);
            })
            .map(function (account) {
                return {
                    text: (new ASC.Mail.Address(TMMail.htmlDecode(account.name), account.email)).ToString(true),
                    explanation: "",
                    handler: selectBoxForReassign,
                    account: account
                };
            });

        if (!complitedAccounts.length) return;

        $selector.actionPanel({ buttons: complitedAccounts, css: 'stick-over' });
        $selector.find('.baseLinkArrowDown').show();
        $selector.addClass('pointer');
        $selector.find('.baseLinkAction').addClass('baseLinkAction');

        selectBoxForReassign({}, {
            account: complitedAccounts[0].account
        });
    }

    function selectBoxForReassign(e, params) {
        var $selector = $('#reassignMessagesSelector'),
            text = (new ASC.Mail.Address(TMMail.htmlDecode(params.account.name), params.account.email)).ToString(true);

        $selector.attr('mailbox_email', params.account.email);
        $selector.find('span').text(text);
    }

    function informationBox(params) {
        var content = window.MailScriptResource.ImportAccountText;
        if (params.settings.restrict === true) {
            content += '<br><br>' + window.MailScriptResource.ImportAccountRestrictLabel;
        }

        var footer;
        if (/@gmail.com$/.test((params.settings.email || "").toLowerCase())) {
            footer = window.MailScriptResource.ImportGmailAttention;
        } else {
            footer = window.MailScriptResource.ImportProblemText;
        }

        footer = footer
            .replace('{0}', '<a href="{0}"class="linkDescribe" target="blank">'
                .format(TMMail.getFaqLink(params.settings.email)))
            .replace('{1}', '</a>');

        var body = $($.tmpl("accountSuccessTmpl", {
            errorBody: content,
            errorBodyFooter: footer
        }));

        body.find('.errorImg').toggleClass('errorImg', false).toggleClass('successImg', true);

        popup.addBig(window.MailScriptResource.DoneLabel, body);
    }

    function warningAlreadyExist() {
        html = $.tmpl('accountExistErrorTmpl', {});
        popup.addBig(window.MailScriptResource.ExistingAccountLabel, html);
    }

    function activateSelectedAccount(activated) {
        var account = $('#newmessageFromSelected').attr('mailbox_email');
        activateAccount(account, activated);
    }

    function activateAccount(account, activated, onSuccessCallback) {
        if (!account)
            return;

        onSuccessOperationCallback = onSuccessCallback;

        accountEmail = account;
        if (activated) {
            questionBox('activate');
        } else {
            questionBox('deactivate');
        }
    }

    function refreshAccount(account, activated) {
        accountsPage.activateAccount(account, activated);
    }

    function hide(stopOnSaving) {
        if (stopOnSaving) {
            var loader = $('.popupMailBox div.progressContainer div.loader');
            if (loader != undefined && loader.is(':visible')) {
                return;
            }
        }

        window.PopupKeyUpActionProvider.ClearActions();
        $.unblockUI();
    }

    function onError(error) {
        setErrorToPopupMailbox(error.message + (error.comment ? ': ' + error.comment : ''));
    }

    function onErrorGetDefaultMailboxSettings() {
        setErrorToPopupMailbox(window.MailScriptResource.ErrorNotification);
    }

    function onGetDefaultMailboxSettings(params, defaults) {
        if (params.password) {
            defaults.password = params.password;
            if (defaults.smtp_auth) {
                defaults.smtp_password = params.smtp_password != undefined ? params.smtp_password : params.password;
            }
        }
        if (params.name) {
            defaults.name = params.name;
        }

        onGetBox(params, defaults);
    }

    function onCreateAccount(params, account) {
        if (!accountsManager.getAccountByAddress(account.email)) {
            if (TMMail.pageIs('sysfolders') && accountsManager.getAccountList().length == 0) {
                blankPages.showEmptyFolder();
            }

            var accountData = {
                name: TMMail.ltgt(account.name),
                email: TMMail.ltgt(account.email),
                enabled: account.enabled,
                signature: account.signature,
                autoreply: account.autoreply,
                is_alias: account.isAlias,
                is_group: account.isGroup,
                oauth: account.oAuthConnection,
                emailInFolder: account.eMailInFolder,
                is_teamlab: account.isTeamlabMailbox,
                mailbox_id: account.mailboxId,
                is_default: account.isDefault,
                is_shared_domain: account.isSharedDomainMailbox,
                authError: account.authError,
                quotaError: account.quotaError
            };

            accountsPage.addAccount(accountData.email, account.autoreply, accountData.enabled, accountData.oauth);
            accountsManager.addAccount(accountData);
            hide();
            informationBox(params);
        } else {
            hide();
            warningAlreadyExist();
        }
    }

    function showErrorModal(params, error) {
        // ToDo: Reimplement to popup mechanism instead of #manageWindow
        hideLoader();
        var footer = TMMail.getAccountErrorFooter(params.settings.email),
            html = $.tmpl('accountErrorTmpl', {
                errorBodyFooter: footer,
                errorAdvancedInfo: error[0]
            });

        $('#manageWindow').removeClass('show-error').find('div.containerBodyBlock:first').html(html);
        $('#manageWindow div.containerHeaderBlock:first').find('td:first').html(window.MailScriptResource.AccountCreationErrorHeader);

        blockUi(523, $("#manageWindow"));

        $('#advancedErrorLinkButton').click(function() {
            $('#mail_advanced_error_container').slideToggle('slow');
        });

        $('#account_error_container .buttons .tryagain').click(function() {
            if (true === params.simple)
                showWizard(params.settings.email, params.settings.password);
            else
                onGetBox({ action: "get_pop_server_full", activateOnSuccess: params.activateOnSuccess }, params.settings);
        });

        $('#account_error_container .buttons .tryagain').keypress(function(event) {
            event.preventDefault();
        });

        window.PopupKeyUpActionProvider.EnterAction = "jq('#account_error_container .buttons #tryagain').click()";
    }

    function getVal(id, skipTrim) {
        var res = $('.popupMailBox #' + id).val();
        return skipTrim ? res : $.trim(res);
    }

    function setVal(id, v) {
        $('.popupMailBox #' + id).val(v);
    }

    function disable(id) {
        $('.popupMailBox #' + id).attr('disabled', 'true');
    }

    function enable(id) {
        $('.popupMailBox #' + id).removeAttr('disabled');
    }

    function isEmailCorrect(email) {
        var emailCorrect = false;

        if (email.length === 0) {
            TMMail.setRequiredHint("mail_EMailContainer", window.MailScriptResource.ErrorEmptyField);
        } else if (!ASC.Mail.Utility.IsValidEmail(email)) {
            TMMail.setRequiredHint("mail_EMailContainer", window.MailScriptResource.ErrorIncorrectEmail);
        } else {
            emailCorrect = true;
        }

        return emailCorrect;
    }

    function signatureBox(accountAddress) {
        var account = accountsManager.getAccountByAddress(accountAddress);
        if (account) {
            var isActive = (account.signature.html == "" && !account.signature.isActive) ? true : account.signature.isActive; // Default is true;

            var html = $.tmpl("manageSignatureTmpl", { 'isActive': isActive });

            var config = {
                toolbar: 'MailSignature',
                removePlugins: 'resize, magicline',
                filebrowserUploadUrl: 'fckuploader.ashx?newEditor=true&esid=mail',
                height: 200,
                startupFocus: true
            };

            ckeditorConnector.load(function () {
                var editor = html.find('#ckMailSignatureEditor').ckeditor(config).editor;
                editor.setData(account.signature.html);
            });

            html.find('.buttons .ok').unbind('click').bind('click', function () {
                updateSignature(account);
                return false;
            });
            popup.addBig(window.MailScriptResource.ManageSignatureLabel, html, undefined, false, { bindEvents: false });
        }
    }

    function updateSignature(account) {
        var html = $('#ckMailSignatureEditor').val();
        var isActive = $('#useSignatureFlag').is(':checked') ? true : false;

        if (html == "" && isActive) {
            isActive = false;
        }

        serviceManager.updateMailboxSignature(account.mailbox_id, html, isActive, { id: account.mailbox_id, html: html, is_active: isActive },
            { error: onErrorUpdateMailboxSignature }, ASC.Resources.Master.ResourceJS.LoadingProcessing);
    }

    function onErrorUpdateMailboxSignature() {
        hideLoader();
    }

    return {
        init: init,
        addBox: addBox,
        addMailbox: addMailbox,
        removeBox: removeBox,
        hideLoader: hideLoader,
        activateSelectedAccount: activateSelectedAccount,
        activateAccount: activateAccount,
        refreshAccount: refreshAccount,
        activateAccountWithoutQuestion: activateAccountWithoutQuestion,
        editBox: editBox,
        setDefaultAccount: setDefaultAccount,
        changePassword: <PASSWORD>,
        viewMailboxSettings: viewMailboxSettings,
        hide: hide,
        onError: onError,
        showInformationBox: informationBox,
        showSignatureBox: signatureBox,
        onGetOAuthInfo: onGetOAuthInfo,
        showConnectionSettings: showConnectionSettings
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/BookmarkingPagingUserControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web.UI;

using AjaxPro;

using ASC.Bookmarking;
using ASC.Bookmarking.Common;
using ASC.Web.Studio.Controls.Common;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;

namespace ASC.Web.UserControls.Bookmarking
{
    [AjaxNamespace("BookmarkPage")]
    public partial class BookmarkingPagingUserControl : UserControl
    {
        protected bool SingleBookmark { get; private set; }

        protected int ItemCounter { get; private set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            var pageCounter = string.IsNullOrEmpty(Request["size"]) ? 20 : Convert.ToInt32(Request["size"]);

            var helper = BookmarkingServiceHelper.GetCurrentInstanse();

            var bookmarks = helper.GetBookmarks(pageCounter);

            if (bookmarks == null || bookmarks.Count <= 0) return;

            var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

            if (BookmarkDisplayMode.SelectedBookmark.Equals(displayMode))
            {
                SingleBookmark = true;
            }
            else
            {
                SingleBookmark = false;

                var pageNavigator = new PageNavigator();

                helper.InitPageNavigator(pageNavigator, pageCounter);

                ItemCounter = pageNavigator.EntryCount;

                BookmarkingPaginationContainer.Controls.Add(pageNavigator);
            }
        }
    }
}

<|start_filename|>common/ASC.ActiveDirectory/BuiltIn/SystemLdapSettingsChecker.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.ActiveDirectory.DirectoryServices;
using System;
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
using System.Runtime.InteropServices;
using System.Linq;

namespace ASC.ActiveDirectory.BuiltIn
{
    public class SystemLdapSettingsChecker : LdapSettingsChecker
    {
        private readonly LdapHelper _ldapHelper = new SystemLdapHelper();

        public override byte CheckSettings(LDAPUserImporter importer,
                                           bool acceptCertificate = false)
        {
            var settings = importer.Settings;

            if (!settings.EnableLdapAuthentication)
                return OPERATION_OK;

            var password = GetPassword(settings.PasswordBytes);

            try
            {
                if (settings.Authentication)
                {
                    CheckCredentials(settings.Login, password, settings.Server, settings.PortNumber, settings.StartTls);
                }
                if (!CheckServerAndPort(settings.Server,
                                        settings.PortNumber, settings.Authentication, settings.Login, password))
                {
                    return WRONG_SERVER_OR_PORT;
                }
            }
            catch (DirectoryServicesCOMException)
            {
                return CREDENTIALS_NOT_VALID;
            }
            catch (COMException)
            {
                return WRONG_SERVER_OR_PORT;
            }

            if (!CheckUserDN(settings.UserDN, settings.Server, settings.PortNumber,
                             settings.Authentication, settings.Login, password, settings.StartTls))
            {
                return WRONG_USER_DN;
            }

            if (settings.GroupMembership)
            {
                if (!CheckGroupDN(settings.UserDN, settings.Server, settings.PortNumber,
                                  settings.Authentication, settings.Login, password, settings.StartTls))
                {
                    return WRONG_USER_DN;
                }

                if (!importer.TryLoadLDAPGroups())
                    return INCORRECT_GROUP_LDAP_FILTER;

                if (!importer.AllDomainGroups.Any())
                    return GROUPS_NOT_FOUND;

                foreach (var group in importer.AllDomainGroups)
                {
                    if (!CheckGroupAttribute(group, settings.GroupAttribute))
                        return WRONG_GROUP_ATTRIBUTE;

                    if (!CheckGroupNameAttribute(group, settings.GroupNameAttribute))
                        return WRONG_GROUP_NAME_ATTRIBUTE;

                    if (group.Sid == null)
                        return WRONG_SID_ATTRIBUTE;
                }
            }

            if (!importer.TryLoadLDAPDomain())
                return DOMAIN_NOT_FOUND;

            if (!importer.TryLoadLDAPUsers())
                return INCORRECT_LDAP_FILTER;

            if (!importer.AllDomainUsers.Any())
                return USERS_NOT_FOUND;

            foreach (var user in importer.AllDomainUsers)
            {
                if (!CheckLoginAttribute(user, settings.LoginAttribute))
                    return WRONG_LOGIN_ATTRIBUTE;

                if (user.Sid == null)
                    return WRONG_SID_ATTRIBUTE;

                if (settings.GroupMembership && !CheckUserAttribute(user, settings.UserAttribute))
                    return WRONG_USER_ATTRIBUTE;
            }

            return OPERATION_OK;
        }

        public override void CheckCredentials(string login, string password, string server, int portNumber, bool startTls)
        {
            try
            {
                _ldapHelper.CheckCredentials(login, password, server, portNumber, startTls);
            }
            catch (LdapException e)
            {
                if (e.ErrorCode != Constants.LDAP_ERROR_INVALID_CREDENTIALS)
                {
                    log.ErrorFormat("Internal LDAP authentication error: {0}.", e);
                    throw new COMException();
                }
                throw new DirectoryServicesCOMException();
            }
            catch (Exception e)
            {
                log.ErrorFormat("Internal AD authentication error: {0}.", e);
                throw new COMException();
            }
        }

        private bool CheckGroupDN(string groupDN, string server, int portNumber,
            bool authentication, string login, string password, bool startTls)
        {
            try
            {
                return _ldapHelper.CheckGroupDN(groupDN, server, portNumber, authentication, login, password, startTls);
            }
            catch (Exception e)
            {
                log.ErrorFormat("Wrong User DN parameter: {0}. {1}", groupDN, e);
                return false;
            }
        }

        private bool CheckUserDN(string userDN, string server, int portNumber,
            bool authentication, string login, string password, bool startTls)
        {
            try
            {
                return _ldapHelper.CheckUserDN(userDN, server, portNumber, authentication, login, password, startTls);
            }
            catch (Exception e)
            {
                log.ErrorFormat("Wrong User DN parameter: {0}. {1}", userDN, e);
                return false;
            }
        }

        private bool CheckServerAndPort(string server, int portNumber,
            bool authentication, string login, string password)
        {
            try
            {
                var type = AuthenticationTypes.ReadonlyServer | AuthenticationTypes.Secure;

                if (portNumber == Constants.SSL_LDAP_PORT)
                {
                    type |= AuthenticationTypes.SecureSocketsLayer;
                }

                var rootEntry = authentication ?
                    new DirectoryEntry(server + ":" + portNumber, login, password, type) :
                    new DirectoryEntry(server + ":" + portNumber);

                if (rootEntry.SchemaClassName != Constants.ObjectClassKnowedValues.DOMAIN_DNS)
                {
                    log.ErrorFormat("Wrong Server Address or Port: {0}:{1}", server, portNumber);
                    return false;
                }
            }
            catch (DirectoryServicesCOMException e)
            {
                log.ErrorFormat("Wrong login or password: {0}:{1}. {2}", login, password, e);
                throw new DirectoryServicesCOMException(e.Message);
            }
            catch (COMException e)
            {
                log.ErrorFormat("Wrong Server Address or Port: {0}:{1}. {2}", server, portNumber, e);
                throw new COMException(e.Message);
            }

            return true;
        }

        public override string GetDomain(LDAPSupportSettings settings)
        {
            var dataInfo = _ldapHelper.GetDomain(settings);

            var domainName = dataInfo != null && dataInfo.DistinguishedName != null
                                 ? dataInfo.DistinguishedName.Remove(0, 3).Replace(",DC=", ".").Replace(",dc=", ".")
                                 : null;

            return domainName;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_Join.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;
    using System.Text;

    #endregion

    /// <summary>
    /// Implements SIP "Join" value. Defined in RFC 3911.
    /// </summary>
    /// <remarks>
    /// <code>
    /// RFC 3911 Syntax:
    ///     Join       = callid *(SEMI join-param)
    ///     join-param = to-tag / from-tag / generic-param
    ///     to-tag     = "to-tag" EQUAL token
    ///     from-tag   = "from-tag" EQUAL token
    /// </code>
    /// </remarks>
    public class SIP_t_Join : SIP_t_ValueWithParams
    {
        #region Members

        private SIP_t_CallID m_pCallID;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets call ID value.
        /// </summary>
        /// <exception cref="ArgumentNullException">Is raised �when null value passed.</exception>
        public SIP_t_CallID CallID
        {
            get { return m_pCallID; }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("CallID");
                }

                m_pCallID = value;
            }
        }

        /// <summary>
        /// Gets or sets to-tag parameter value. This value is mandatory.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid ToTag value is passed.</exception>
        public string ToTag
        {
            get
            {
                SIP_Parameter parameter = Parameters["to-tag"];
                if (parameter != null)
                {
                    return parameter.Value;
                }
                else
                {
                    return null;
                }
            }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("ToTag is mandatory and cant be null or empty !");
                }
                else
                {
                    Parameters.Set("to-tag", value);
                }
            }
        }

        /// <summary>
        /// Gets or sets from-tag parameter value. This value is mandatory.
        /// </summary>
        /// <exception cref="ArgumentException">Is raised when invalid FromTag value is passed.</exception>
        public string FromTag
        {
            get
            {
                SIP_Parameter parameter = Parameters["from-tag"];
                if (parameter != null)
                {
                    return parameter.Value;
                }
                else
                {
                    return null;
                }
            }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("FromTag is mandatory and cant be null or empty !");
                }
                else
                {
                    Parameters.Set("from-tag", value);
                }
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="value">Join value.</param>
        public SIP_t_Join(string value)
        {
            Parse(value);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "Join" from specified value.
        /// </summary>
        /// <param name="value">SIP "Join" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>value</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "Join" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            /*
                Join       = callid *(SEMI join-param)
                join-param = to-tag / from-tag / generic-param
                to-tag     = "to-tag" EQUAL token
                from-tag   = "from-tag" EQUAL token
              
                A Join header MUST contain exactly one to-tag and exactly one from-
                tag, as they are required for unique dialog matching.
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // Parse address
            SIP_t_CallID callID = new SIP_t_CallID();
            callID.Parse(reader);
            m_pCallID = callID;

            // Parse parameters
            ParseParameters(reader);

            // Check that to and from tags exist.
            if (Parameters["to-tag"] == null)
            {
                throw new SIP_ParseException("Join value mandatory to-tag value is missing !");
            }
            if (Parameters["from-tag"] == null)
            {
                throw new SIP_ParseException("Join value mandatory from-tag value is missing !");
            }
        }

        /// <summary>
        /// Converts this to valid "Join" value.
        /// </summary>
        /// <returns>Returns "Join" value.</returns>
        public override string ToStringValue()
        {
            /*
                Join       = callid *(SEMI join-param)
                join-param = to-tag / from-tag / generic-param
                to-tag     = "to-tag" EQUAL token
                from-tag   = "from-tag" EQUAL token 
            */

            StringBuilder retVal = new StringBuilder();

            // Add address
            retVal.Append(m_pCallID.ToStringValue());

            // Add parameters
            retVal.Append(ParametersToString());

            return retVal.ToString();
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Core/Shared/Tag.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

namespace ASC.Forum
{
    public class Tag
    {
        public virtual int ID { get; set; }

        public virtual string Name { get; set; }

        public virtual bool IsApproved { get; set; }

        public virtual int TenantID { get; set; }
    }


    public class RankTag : Tag
    {


        public virtual int Rank { get; internal set; }

        public RankTag()
        {
            this.Rank = 0;
        }

        public RankTag(int id, string name)
        {
            this.ID = id;
            this.Name = name;
            this.IsApproved = false;
            this.Rank = 0;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Projects/ProjectApi.Reports.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Api.Attributes;
using ASC.Api.Documents;
using ASC.Api.Projects.Wrappers;
using ASC.Api.Utils;
using ASC.MessagingSystem;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Domain.Reports;
using ASC.Projects.Engine;
using ASC.Specific;
using ASC.Web.Core.Files;
using ASC.Web.Files.Services.DocumentService;
using ASC.Web.Projects.Classes;

namespace ASC.Api.Projects
{
    public partial class ProjectApi
    {
        [Create(@"report/create")]
        public ReportState CheckReportData(string uri)
        {
            ChechDocBuilder();

            ReportState state;

            Report.TryCreateReport(uri.Split('?')[1], out state);

            return state;
        }

        [Read(@"report/status")]
        public ReportState GetReportStatus()
        {
            ChechDocBuilder();

            return DocbuilderReportsUtility.Status(ReportOrigin.Projects);
        }

        [Read(@"report/terminate")]
        public void TerminateReport()
        {
            ChechDocBuilder();

            DocbuilderReportsUtility.Terminate(ReportOrigin.Projects);
        }

        ///<summary>
        ///Creates the project report template with the parameters specified in the request. Most of the parameters are optional and depend on the report type selected.
        ///</summary>
        ///<short>
        ///Create report template
        ///</short>
        ///<category>Report</category>         
        ///<param name="name">Report name</param>
        ///<param name="period" optional="true">Report template generation period. Can be one of the following: Day/Week/Month</param>
        ///<param name="periodItem" optional="true">Period item. Can be: weekday name (for weekly report, starting with Sunday), day of the month (for monthly report).</param>
        ///<param name="hour" optional="true">Send time (hour)</param>
        ///<param name="autoGenerated" optional="true">Automatically generated or not</param>
        ///<param name="reportType" optional="true">Report type</param>
        ///<param name="tag" optional="true">Tag</param>
        ///<param name="project" optional="true">Project</param>
        ///<param name="status" optional="true">Task status</param>       
        ///<param name="departament" optional="true">Department/Group</param>
        ///<param name="userId" optional="true">User GUID</param>
        ///<param name="reportTimeInterval" optional="true">Report time interval</param>
        ///<param name="fromDate" optional="true">Report period start date</param>
        ///<param name="toDate" optional="true">Report period end date</param>
        ///<param name="viewType" optional="true">View type: view by group or view by project</param>
        ///<param name="noResponsible" optional="true">Show or hide tasks without responsible</param>   
        ///<returns>Project report template</returns>
        [Create(@"report")]
        public ReportTemplateWrapper SaveReportTemplate(
            string name,
            string period,
            int periodItem,
            int hour,
            bool autoGenerated,
            ReportType reportType,
            int tag,
            int project,
            TaskStatus? status,
            Guid departament,
            Guid userId,
            ReportTimeInterval reportTimeInterval,
            ApiDateTime fromDate,
            ApiDateTime toDate,
            int viewType,
            bool noResponsible)
        {
            ProjectSecurity.DemandAuthentication();

            if (name == null || name.Trim().Length == 0) throw new ArgumentNullException("name");

            var filter = new TaskFilter
            {
                TagId = tag,
                DepartmentId = departament,
                UserId = userId,
                TimeInterval = reportTimeInterval,
                FromDate = fromDate,
                ToDate = toDate,
                ViewType = viewType,
                NoResponsible = noResponsible
            };

            if (project != 0)
            {
                filter.ProjectIds.Add(project);
            }

            if (status != null)
            {
                filter.TaskStatuses.Add((TaskStatus)status);
            }

            var template = new ReportTemplate(reportType) { Filter = filter };

            SaveOrUpdateTemplate(template, name, period, periodItem, hour, autoGenerated);
            MessageService.Send(Request, MessageAction.ReportTemplateCreated, MessageTarget.Create(template.Id), template.Name);

            return new ReportTemplateWrapper(template);
        }

        ///<summary>
        ///Updates the selected project report template with the parameters specified in the request
        ///</summary>
        ///<short>
        ///Update report template
        ///</short>
        ///<category>Report</category>           
        ///<param name="reportid">Report template ID</param>    
        ///<param name="name">Report name</param>
        ///<param name="period" optional="true">Report template generation period. Can be one of the following: Day/Week/Month</param>
        ///<param name="periodItem" optional="true">Period item. Can be: weekday name (for weekly report, starting with Sunday), day of the month (for monthly report).</param>
        ///<param name="hour" optional="true">Send time (hour)</param>
        ///<param name="autoGenerated" optional="true">Automatically generated or not</param>
        ///<param name="reportType" optional="true">Report type</param>
        ///<param name="tag" optional="true">Tag</param>
        ///<param name="project" optional="true">Project</param>
        ///<param name="status" optional="true">Task status</param>       
        ///<param name="departament" optional="true">Department/Group</param>
        ///<param name="userId" optional="true">User GUID</param>
        ///<param name="reportTimeInterval" optional="true">Report time interval</param>
        ///<param name="fromDate" optional="true">Report period start date</param>
        ///<param name="toDate" optional="true">Report period end date</param>
        ///<param name="viewType" optional="true">View type: view by group or view by project</param>
        ///<param name="noResponsible" optional="true">Show or hide tasks without responsible</param>   
        ///<returns>Project report template</returns>
        [Update(@"report/{reportid:[0-9]+}")]
        public ReportTemplateWrapper UpdateReportTemplate(
            int reportid,
            string name,
            string period,
            int periodItem,
            int hour,
            bool autoGenerated,
            ReportType reportType,
            int tag,
            int project,
            TaskStatus? status,
            Guid departament,
            Guid userId,
            ReportTimeInterval reportTimeInterval,
            ApiDateTime fromDate,
            ApiDateTime toDate,
            int viewType,
            bool noResponsible)
        {
            ProjectSecurity.DemandAuthentication();

            var filter = new TaskFilter
            {
                TagId = tag,
                DepartmentId = departament,
                UserId = userId,
                TimeInterval = reportTimeInterval,
                FromDate = fromDate,
                ToDate = toDate,
                ViewType = viewType,
                NoResponsible = noResponsible
            };

            if (project != 0)
            {
                filter.ProjectIds.Add(project);
            }

            if (status != null)
            {
                filter.TaskStatuses.Add((TaskStatus)status);
            }

            var template = EngineFactory.ReportEngine.GetTemplate(reportid);
            template.Filter = filter;

            SaveOrUpdateTemplate(template, name, period, periodItem, hour, autoGenerated);
            MessageService.Send(Request, MessageAction.ReportTemplateUpdated, MessageTarget.Create(template.Id), template.Name);

            return new ReportTemplateWrapper(template);
        }

        ///<summary>
        ///
        ///</summary>
        ///<category>Report</category>
        ///<param name="reportid"></param>
        ///<returns></returns>
        [Read(@"report/{reportid:[0-9]+}")]
        public ReportTemplateWrapper GetReportTemplate(int reportid)
        {
            ProjectSecurity.DemandAuthentication();
            return new ReportTemplateWrapper(EngineFactory.ReportEngine.GetTemplate(reportid).NotFoundIfNull());
        }

        ///<summary>
        ///Deletes the project report template with the ID specified in the request
        ///</summary>
        ///<short>
        ///Delete report template
        ///</short>
        ///<category>Report</category>   
        ///<param name="reportid">Report template ID</param>        
        ///<returns>Project report template</returns>
        [Delete(@"report/{reportid:[0-9]+}")]
        public ReportTemplateWrapper DeleteReportTemplate(int reportid)
        {
            ProjectSecurity.DemandAuthentication();

            var reportEngine = EngineFactory.ReportEngine;

            var reportTemplate = reportEngine.GetTemplate(reportid).NotFoundIfNull();

            reportEngine.DeleteTemplate(reportid);
            MessageService.Send(Request, MessageAction.ReportTemplateDeleted, MessageTarget.Create(reportTemplate.Id), reportTemplate.Name);

            return new ReportTemplateWrapper(reportTemplate);
        }

        [Read(@"report/files")]
        public IEnumerable<FileWrapper> GetGeneratedReports()
        {
            ChechDocBuilder();

            var fileIds = EngineFactory.ReportEngine.Get().Select(r => r.FileId).ToArray();

            return EngineFactory.FileEngine.GetFiles(fileIds).Select(r => new FileWrapper(r)).OrderByDescending(r => r.Id).ToList();
        }

        [Delete(@"report/files/{fileid:[0-9]+}")]
        public ReportFile RemoveGeneratedReport(int fileid)
        {
            ProjectSecurity.DemandAuthentication();

            var reportEngine = EngineFactory.ReportEngine;

            var report = reportEngine.GetByFileId(fileid).NotFoundIfNull();

            reportEngine.Remove(report);

            return report;
        }

        private void ChechDocBuilder()
        {
            ProjectSecurity.DemandAuthentication();
            if (string.IsNullOrEmpty(FilesLinkUtility.DocServiceDocbuilderUrl))
                throw ProjectSecurity.CreateSecurityException();
        }

        private void SaveOrUpdateTemplate(ReportTemplate template, string title, string period, int periodItem, int hour, bool autoGenerated)
        {
            template.Name = HttpUtility.HtmlEncode(title);
            switch (period)
            {
                case "day":
                    template.Cron = string.Format("0 0 {0} * * ?", hour);
                    break;
                case "week":
                    template.Cron = string.Format("0 0 {0} ? * {1}", hour, periodItem);
                    break;
                case "month":
                    template.Cron = string.Format("0 0 {0} {1} * ?", hour, periodItem);
                    break;
                default:
                    template.Cron = string.Format("0 0 {0} * * ?", 12);
                    break;
            }
            template.AutoGenerated = autoGenerated;
            EngineFactory.ReportEngine.SaveTemplate(template);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Contacts/ContactDetailsView.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;

using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.FederatedLogin.LoginProviders;
using ASC.Web.Core;
using ASC.Web.Core.Mobile;
using ASC.Web.CRM.Classes;
using ASC.Web.Studio.Utility;

namespace ASC.Web.CRM.Controls.Contacts
{
    public partial class ContactDetailsView : BaseUserControl
    {
        #region Properies

        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Contacts/ContactDetailsView.ascx"); }
        }

        public Contact TargetContact { get; set; }

        protected bool ShowEventLinkToPanel
        {
            get
            {
                var dealsCount = DaoFactory.DealDao.GetDealsCount();
                var casesCount = DaoFactory.CasesDao.GetCasesCount();

                return dealsCount + casesCount > 0;
            }
        }

        protected bool MobileVer = false;

        protected string HelpLink { get; set; }

        #endregion

        #region Events

        protected void Page_Load(object sender, EventArgs e)
        {
            MobileVer = MobileDetector.IsMobile;
            HelpLink = CommonLinkUtility.GetHelpLink();

            ExecFullCardView();
            ExecTasksView();
            ExecFilesView();
            ExecDealsView();

            if (TargetContact is Company)
                ExecPeopleContainerView();

            Page.RegisterStyle("~/Products/Projects/App_Themes/default/css/allprojects.less")
                .RegisterBodyScripts("~/Products/Projects/js/base.js")
                .RegisterBodyScripts("~/Products/Projects/js/projects.js");
            RegisterScript();
        }

        #endregion

        #region Methods

        protected void ExecDealsView()
        {
            Page.RegisterClientScript(new Masters.ClientScripts.ExchangeRateViewData());
        }

        protected void ExecPeopleContainerView()
        {
            RegisterClientScriptHelper.DataListContactTab(Page, TargetContact.ID, EntityType.Company);
        }

        protected void ExecFullCardView()
        {
            var contactFullCardControl = (ContactFullCardView)LoadControl(ContactFullCardView.Location);
            contactFullCardControl.TargetContact = TargetContact;

            _phProfileView.Controls.Add(contactFullCardControl);
        }

        protected void ExecFilesView()
        {
            var filesViewControl = (Studio.UserControls.Common.Attachments.Attachments)LoadControl(Studio.UserControls.Common.Attachments.Attachments.Location);
            filesViewControl.EntityType = "contact";
            filesViewControl.ModuleName = "crm";
            _phFilesView.Controls.Add(filesViewControl);
        }

        protected void ExecTasksView()
        {
            RegisterClientScriptHelper.DataContactDetailsViewForTaskAction(Page, TargetContact);
        }

        private void RegisterScript()
        {
            var sb = new StringBuilder();

            sb.AppendFormat(@"
                    ASC.CRM.ContactDetailsView.init({0},{1},{2},{3},{4},{5});
                    {6}",

                TargetContact.ID,
                (TargetContact is Company).ToString().ToLower(),
                WebItemSecurity.IsAvailableForMe(WebItemManager.ProjectsProductID).ToString().ToLower(),
                (!string.IsNullOrEmpty(TwitterLoginProvider.TwitterDefaultAccessToken)).ToString().ToLower(),
                (int)TargetContact.ShareType,
                CRMSecurity.CanEdit(TargetContact).ToString().ToLower(),
                ShowEventLinkToPanel ? "" : "jq('#eventLinkToPanel').hide();"
            );

            Page.RegisterInlineScript(sb.ToString());
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/FullTextSearch/FullTextSearch.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch;
using ASC.ElasticSearch.Service;
using ASC.MessagingSystem;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    [ManagementControl(ManagementType.FullTextSearch, "~/UserControls/Management/FullTextSearch/FullTextSearch.ascx")]
    [AjaxNamespace("FullTextSearch")]
    public partial class FullTextSearch : UserControl
    {
        protected Settings CurrentSettings
        {
            get
            {
                return CoreContext.Configuration.GetSection<Settings>(Tenant.DEFAULT_TENANT) ?? Settings.Default;
            }
        }

        protected string HelpLink { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!CoreContext.Configuration.Standalone)
                Response.Redirect("~/Management.aspx");

            AjaxPro.Utility.RegisterTypeForAjax(GetType(), Page);
            Page.RegisterBodyScripts("~/UserControls/Management/FullTextSearch/js/fulltextsearch.js")
                .RegisterStyle("~/UserControls/Management/FullTextSearch/css/fulltextsearch.css");

            HelpLink = CommonLinkUtility.GetHelpLink();
        }

        [AjaxMethod]
        public void Save(Settings settings)
        {
            SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
            CoreContext.Configuration.SaveSection(Tenant.DEFAULT_TENANT, settings);

            MessageService.Send(HttpContext.Current.Request, MessageAction.FullTextSearchSetting);
        }

        [AjaxMethod]
        public object Test()
        {
            return FactoryIndexer.CheckState() ?
                new { success = true, message = Resource.FullTextSearchServiceIsRunning } :
                new { success = false, message = Resource.FullTextSearchServiceIsNotRunning };
        }
    }
}

<|start_filename|>module/ASC.VoipService/VoipSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using ASC.Core;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;

namespace ASC.VoipService
{
    public class VoipSettings
    {
        public string VoiceUrl { get; set; }

        public string Name { get; set; }

        public List<Agent> Operators { get; set; }

        public Queue Queue { get; set; }

        public Agent Caller { get { return Operators.FirstOrDefault(r => r.Id == SecurityContext.CurrentAccount.ID); } }

        public WorkingHours WorkingHours { get; set; }

        public string VoiceMail { get; set; }

        public string GreetingAudio { get; set; }

        public string HoldAudio { get; set; }

        public bool AllowOutgoingCalls { get; set; }

        public bool Pause { get; set; }

        public bool Record { get; set; }

        internal string JsonSettings
        {
            get
            {
                return JsonConvert.SerializeObject(
                    new
                    {
                        Operators,
                        GreetingAudio,
                        Name,
                        Queue,
                        WorkingHours,
                        VoiceMail,
                        HoldAudio,
                        AllowOutgoingCalls,
                        Pause,
                        Record
                    },
                    new JsonSerializerSettings { ContractResolver = CustomSerializeContractResolver.Instance });
            }
            set
            {
                try
                {
                    var settings = JsonConvert.DeserializeObject<VoipSettings>(value, new JsonSerializerSettings { ContractResolver = CustomSerializeContractResolver.Instance });

                    Operators = settings.Operators ?? new List<Agent>();
                    Name = settings.Name;
                    Queue = settings.Queue;
                    WorkingHours = settings.WorkingHours;
                    GreetingAudio = settings.GreetingAudio;
                    VoiceMail = settings.VoiceMail;
                    HoldAudio = settings.HoldAudio;
                    AllowOutgoingCalls = settings.AllowOutgoingCalls;
                    Pause = settings.Pause;
                    Record = settings.Record;
                }
                catch (Exception)
                {

                }

            }
        }


        public VoipSettings()
        {
            Operators = new List<Agent>();
        }

        public VoipSettings(string settings)
        {
            JsonSettings = settings;
        }

        public virtual string Connect(bool user = true, string contactId = null)
        {
            throw new NotImplementedException();
        }

        public virtual string Redirect(string to)
        {
            throw new NotImplementedException();
        }

        public virtual string Dequeue(bool reject)
        {
            throw new NotImplementedException();
        }

        public override string ToString()
        {
            return JsonSettings;
        }

        public static VoipSettings GetSettings(string settings)
        {
            return new VoipSettings { JsonSettings = settings };
        }
    }

    class CustomSerializeContractResolver : CamelCasePropertyNamesContractResolver
    {
        public static readonly CustomSerializeContractResolver Instance = new CustomSerializeContractResolver();

        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);

            if (property.PropertyName == "voiceMail")
            {
                property.Converter = new VoiceMailConverter();
            }

            return property;
        }
    }

    class VoiceMailConverter : JsonConverter
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, value);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.ValueType != null && reader.ValueType.Name == "String")
            {
                return reader.Value;
            }

            var jObject = JObject.Load(reader);
            var url = jObject.Value<string>("url");

            return !string.IsNullOrEmpty(url) ? url : "";
        }

        public override bool CanConvert(Type objectType)
        {
            return true;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/calendar/Default.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Web.Calendar.UserControls;
using ASC.Web.Studio;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Calendar
{
    public partial class Default : MainPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Title = HeaderStringHelper.GetPageTitle(Resources.CalendarAddonResource.AddonName);

            CreateButtonContent.Controls.Add(LoadControl(ButtonSidePanel.Location));
            SidePanelContent.Controls.Add(LoadControl(SidePanel.Location));
            SidePanelContent.Controls.Add(LoadControl(CalendarSidePanel.Location));
            CalendarPageContent.Controls.Add(LoadControl(CalendarControl.Location));
        }
    }
}

<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/BoxLoginProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Core.Common.Configuration;

namespace ASC.FederatedLogin.LoginProviders
{
    public class BoxLoginProvider : Consumer, IOAuthProvider
    {
        public static BoxLoginProvider Instance
        {
            get
            {
                return ConsumerFactory.Get<BoxLoginProvider>();
            }
        }

        public string Scopes { get { return ""; } }
        public string CodeUrl { get { return "https://app.box.com/api/oauth2/authorize"; } }
        public string AccessTokenUrl { get { return "https://app.box.com/api/oauth2/token"; } }
        public string RedirectUri { get { return this["boxRedirectUrl"]; } }
        public string ClientID { get { return this["boxClientId"]; } }
        public string ClientSecret { get { return this["boxClientSecret"]; } }

        public bool IsEnabled
        {
            get
            {
                return !string.IsNullOrEmpty(ClientID) &&
                       !string.IsNullOrEmpty(ClientSecret) &&
                       !string.IsNullOrEmpty(RedirectUri);
            }
        }

        public BoxLoginProvider() { }

        public BoxLoginProvider(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
            : base(name, order, props, additional)
        {
        }
    }
}

<|start_filename|>common/ASC.Common/Data/DbRegistry.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Common;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Dialects;

namespace ASC.Common.Data
{
    public static class DbRegistry
    {
        private const string DEFAULT = "DEFAULT";
        private static readonly object syncRoot = new object();
        private static readonly IDictionary<string, DbProviderFactory> providers = new Dictionary<string, DbProviderFactory>(StringComparer.InvariantCultureIgnoreCase);
        private static readonly IDictionary<string, string> connnectionStrings = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
        private static readonly IDictionary<string, ISqlDialect> dialects = new Dictionary<string, ISqlDialect>(StringComparer.InvariantCultureIgnoreCase);
        private static volatile bool configured = false;

        static DbRegistry()
        {
            dialects["MySql.Data.MySqlClient.MySqlClientFactory"] = new MySQLDialect();
            dialects["System.Data.SQLite.SQLiteFactory"] = new SQLiteDialect();
        }

        internal static void RegisterDatabase(string databaseId, DbProviderFactory providerFactory, string connectionString)
        {
            if (string.IsNullOrEmpty(databaseId)) throw new ArgumentNullException("databaseId");
            if (providerFactory == null) throw new ArgumentNullException("providerFactory");

            if (!providers.ContainsKey(databaseId))
            {
                lock (syncRoot)
                {
                    if (!providers.ContainsKey(databaseId))
                    {
                        providers.Add(databaseId, providerFactory);
                        if (!string.IsNullOrEmpty(connectionString))
                        {
                            connnectionStrings.Add(databaseId, connectionString);
                        }
                    }
                }
            }
        }

        internal static void RegisterDatabase(string databaseId, string providerInvariantName, string connectionString)
        {
            RegisterDatabase(databaseId, DbProviderFactories.GetFactory(providerInvariantName), connectionString);
        }

        public static void RegisterDatabase(string databaseId, ConnectionStringSettings connectionString)
        {
            RegisterDatabase(databaseId, connectionString.ProviderName, connectionString.ConnectionString);
        }

        public static void UnRegisterDatabase(string databaseId)
        {
            if (string.IsNullOrEmpty(databaseId)) throw new ArgumentNullException("databaseId");

            if (providers.ContainsKey(databaseId))
            {
                lock (syncRoot)
                {
                    if (providers.ContainsKey(databaseId))
                    {
                        providers.Remove(databaseId);
                    }
                }
            }

            if (connnectionStrings.ContainsKey(databaseId))
            {
                lock (syncRoot)
                {
                    if (connnectionStrings.ContainsKey(databaseId))
                    {
                        connnectionStrings.Remove(databaseId);
                    }
                }
            }
        }

        public static bool IsDatabaseRegistered(string databaseId)
        {
            lock (syncRoot)
            {
                return providers.ContainsKey(databaseId);
            }
        }

        public static DbConnection CreateDbConnection(string databaseId)
        {
            Configure();

            if (!providers.ContainsKey(databaseId))
            {
                databaseId = DEFAULT;
            }

            var connection = providers[databaseId].CreateConnection();
            if (connnectionStrings.ContainsKey(databaseId))
            {
                connection.ConnectionString = connnectionStrings[databaseId];
            }
            return connection;
        }

        public static DbProviderFactory GetDbProviderFactory(string databaseId)
        {
            Configure();

            if (!providers.ContainsKey(databaseId))
            {
                databaseId = DEFAULT;
            }
            return providers.ContainsKey(databaseId) ? providers[databaseId] : null;
        }

        public static ConnectionStringSettings GetConnectionString(string databaseId)
        {
            Configure();

            if (!connnectionStrings.ContainsKey(databaseId))
            {
                databaseId = DEFAULT;
            }
            return connnectionStrings.ContainsKey(databaseId) ? new ConnectionStringSettings(databaseId, connnectionStrings[databaseId], providers[databaseId].GetType().Name) : null;
        }

        public static ISqlDialect GetSqlDialect(string databaseId)
        {
            var provider = GetDbProviderFactory(databaseId);
            if (provider != null && dialects.ContainsKey(provider.GetType().FullName))
            {
                return dialects[provider.GetType().FullName];
            }
            return SqlDialect.Default;
        }


        public static void Configure()
        {
            if (!configured)
            {
                lock (syncRoot)
                {
                    if (!configured)
                    {
                        var factories = DbProviderFactories.GetFactoryClasses();
                        AppDomain.CurrentDomain.SetData("DataDirectory", Environment.CurrentDirectory); //SQLite
                        foreach (ConnectionStringSettings cs in ConfigurationManagerExtension.ConnectionStrings)
                        {
                            var factory = factories.Rows.Find(cs.ProviderName);
                            if (factory == null)
                            {
                                throw new ConfigurationErrorsException("Db factory " + cs.ProviderName + " not found.");
                            }
                            RegisterDatabase(cs.Name, cs);
                        }
                        configured = true;
                    }
                }
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Product/CommunitySpaceUsageStatManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Web.Core;
using ASC.Web.Studio.UserControls.Statistics;

namespace ASC.Web.Community.Product
{
    public class CommunitySpaceUsageStatManager : SpaceUsageStatManager
    {
        public override List<UsageSpaceStatItem> GetStatData()
        {
            return WebItemManager.Instance.GetSubItems(CommunityProduct.ID, ItemAvailableState.All)
                .Select(webItem => new UsageSpaceStatItem
                {
                    Name = webItem.Name,
                    ImgUrl = webItem.GetIconAbsoluteURL(),
                    SpaceUsage = TenantStatisticsProvider.GetUsedSize(webItem.ID),
                    Url = VirtualPathUtility.ToAbsolute(webItem.StartURL)
                })
                .Where(statItem => statItem.SpaceUsage > 0)
                .ToList();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Classes/ResultsView.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Common.Utils;
using ASC.Projects.Core.Domain;
using ASC.Web.Core.ModuleManagement.Common;

namespace ASC.Web.Projects.Classes
{
    public sealed class ResultsView : ItemSearchControl
    {
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "tableBase");
            writer.AddAttribute("cellspacing", "0");
            writer.AddAttribute("cellpadding", "8");
            writer.RenderBeginTag(HtmlTextWriterTag.Table);

            writer.RenderBeginTag(HtmlTextWriterTag.Tbody);

            foreach (var srGroup in Items.GetRange(0, (MaxCount < Items.Count) ? MaxCount : Items.Count))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, "search-result-item");
                writer.RenderBeginTag(HtmlTextWriterTag.Tr);

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "borderBase left-column gray-text");
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.AddAttribute(HtmlTextWriterAttribute.Title, srGroup.Additional["Hint"].ToString());
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write(srGroup.Additional["Hint"].ToString());
                writer.RenderEndTag();
                writer.RenderEndTag();

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "borderBase center-column");
                writer.RenderBeginTag(HtmlTextWriterTag.Td);

                writer.AddAttribute(HtmlTextWriterAttribute.Href, srGroup.URL);
                writer.AddAttribute(HtmlTextWriterAttribute.Class, "link bold");
                writer.RenderBeginTag(HtmlTextWriterTag.A);
                writer.Write(HtmlUtil.SearchTextHighlight(Text, srGroup.Name.HtmlEncode()));
                writer.RenderEndTag();

                if ((EntityType)(Enum.Parse(typeof(EntityType), (srGroup.Additional["Type"]).ToString())) == EntityType.Project)
                {
                    if (!string.IsNullOrEmpty(srGroup.Description))
                    {
                        writer.WriteBreak();
                        writer.AddAttribute(HtmlTextWriterAttribute.Class, "describe-text");
                        writer.RenderBeginTag(HtmlTextWriterTag.Span);
                        writer.Write(CheckEmptyValue(HttpUtility.HtmlEncode(HtmlUtil.GetText(srGroup.Description, 100))));
                        writer.RenderEndTag();
                    }
                }
                else
                {
                    writer.WriteBreak();
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "describe-text");
                    writer.RenderBeginTag(HtmlTextWriterTag.Span);
                    writer.Write(srGroup.Additional["ContainerTitle"].ToString());
                    writer.RenderEndTag();
                    writer.Write("&nbsp;");

                    writer.AddAttribute(HtmlTextWriterAttribute.Href, srGroup.Additional["ContainerPath"].ToString());
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "link");
                    writer.RenderBeginTag(HtmlTextWriterTag.A);
                    writer.Write(srGroup.Additional["ContainerValue"].ToString().HtmlEncode());
                    writer.RenderEndTag();
                }

                writer.RenderEndTag();

                writer.AddAttribute(HtmlTextWriterAttribute.Class, "borderBase right-column gray-text");
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                if (srGroup.Date.HasValue)
                {
                    var srGroupDate = srGroup.Date.Value;
                    writer.AddAttribute(HtmlTextWriterAttribute.Title, srGroupDate.ToShortDateString());
                    writer.RenderBeginTag(HtmlTextWriterTag.Div);
                    writer.Write(srGroupDate.ToShortDateString());
                    writer.RenderEndTag();
                }

                writer.RenderEndTag();
                writer.RenderEndTag();
            }

            writer.RenderEndTag();
            writer.RenderEndTag();
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/plugins/progressdialog.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ProgressDialog = (function () {

    var progressStatus = {
        Queued: 0,
        Started: 1,
        Done: 2,
        Failed: 3
    };

    var loadingBanner,
        container,
        timeoutId;

    var resources, methods;

    function init(res, jqElement, met, mode) {

        if (jq("#progressDialog").length) return;
        loadingBanner = LoadingBanner;
        container = jqElement;
        resources = res;
        methods = met;

        if (mode && mode === 1) {
            jqElement.append(
                jq.tmpl("progressBarTmpl", {
                    header: resources.header || "",
                    percentage: resources.percentage || 0
                }));
        } else { // Default mode
            jqElement.append(
                jq.tmpl("progressDialogTmpl", {
                    header: resources.header || "",
                    footer: resources.footer || ""
                }));
        }

        jq("#bottomLoaderPanel").draggable(
            {
                axis: "x",
                handle: ".progress-dialog-header",
                containment: "body"
            }
        );

        jq("#progressDialog .actions-container.close").unbind("click").bind("click", terminate);

        jq("#progressDialog").off("click").on("click", ".progress-error", showErrorText);

        if (methods !== null) {
            getStatus();
        }
    }

    function showErrorText() {
        var rowIndex = jq(this).closest(".pd-row").index() + 1;

        jq(this).helper({
            BlockHelperID: "progressDialogBodyTable tr:nth-child(" + rowIndex + ") .popup_helper",
            position: "fixed"
        });
    }

    function setProgressValue(progressBar, value) {
        value = value | 0;
        progressBar = jq(progressBar);
        if (!progressBar.is("progress")) {
            progressBar = progressBar.find("progress");
        }

        var dt = 50;
        var timer = progressBar.data("timer");
        clearInterval(timer);

        var curValue = progressBar.val();
        if (!value || curValue > value) {
            progressBar.val(value);
        } else {
            var nextProgressValue = function (dValue, maxValue) {
                var v = Math.min(maxValue, progressBar.val() + dValue);
                progressBar.val(v);
                if (v == maxValue) {
                    clearInterval(timer);
                }
            };

            var dV = Math.max(1, (value - curValue) / dt);
            timer = setInterval(function () {
                nextProgressValue(dV, value);
            }, 1);
            progressBar.data("timer", timer);
        }

        var prValue = progressBar.find(".asc-progress-value");

        if (!value) {
            prValue.css("width", value + "%");
        } else {
            prValue.animate({ "width": value + "%" });
        }

        progressBar.next().text(value + "%");
    }

    function setProgress(percentage, status) {
        setProgressValue("#progressDialog progress", percentage);
        jq('#progressDialog').find('#progressDialogHeader').text(status);
    }

    function show() {
        jq("#progressDialog").show();
    }

    function close() {
        clearTimeout(timeoutId);
        jq("#progressDialog").hide();
        jq("#progressDialogBodyTable tbody").empty();
    }

    function changeHeaderText(text) {
        jq("#progressDialogHeader").text(text);
    };

    function renderRow(tmpl, data) {
        if (jq("#" + data.id).length) return;

        function replaceSpecCharacter(str) {
            var characterRegExp = new RegExp("[\t*\+:\"<>?|\\\\/]", "gim");
            return (str || "").trim().replace(characterRegExp, "_");
        }

        data.fileName = replaceSpecCharacter(data.fileName);
        data.fileTypeCssClass = ASC.Files.Utility.getCssClassByFileTitle(data.fileName, true);

        jq("#progressDialogBodyTable tbody").append(jq.tmpl(tmpl, data));
        jq("#progressDialogBodyTable").parent().scrollTo("#" + data.id);
    }

    function setRowProgress(id, percentage) {
        setProgressValue("#" + id + " progress", percentage);
    }

    function showRowStartedStatus(id) {
        jq("#" + id)
            .removeClass("done")
            .removeClass("error")
            .addClass("started");
    }

    function showRowFailedStatus(id, errorText) {
        jq("#" + id)
            .removeClass("started")
            .removeClass("done")
            .addClass("error")
            .removeAttr("id")
            .find(".popup_helper").text(errorText);
    }

    function showRowDoneStatus(id, url) {
        jq("#" + id)
            .removeClass("started")
            .removeClass("error")
            .addClass("done")
            .removeAttr("id")
            .find(".linkMedium").attr("href", url);
    }


    function terminate() {
        if (methods === null)  return close();

        if (methods.terminate) {
            methods.terminate(
            {
                success: function() {
                    hideLoader();
                    close();
                },
                error: generateErrorCallback
            });
        } else {
            close();
        }
    };

    function generate(data) {
        showLoader();
        methods.generate(data, {
            success: generateSuccessCallback,
            error: generateErrorCallback
        });
    }

    function generateSuccessCallback(params, response) {
        if (!response || typeof(response.id) === "undefined" || jq.isEmptyObject(response)) {
            hideLoader();
            return;
        }

        renderRow("progressDialogRowTmpl", response);
        show();

        switch (response.status) {
            case progressStatus.Queued:
            case progressStatus.Started:
                var progress = typeof(response.percentage) !== "undefined" ?
                    Math.round(response.percentage) :
                    response.status === progressStatus.Queued ? 10 : 60;

                changeHeaderText(progress > 0 ? resources.progress.format(progress) : resources.header);
                setRowProgress(response.id, progress);
                showRowStartedStatus(response.id);
                timeoutId = setTimeout(getStatus, 1600);
                break;
            case progressStatus.Done:
            case progressStatus.Failed:
                hideLoader();
                changeHeaderText(resources.header);
                setRowProgress(response.id, 100);

                if (response.exception) {
                    showRowFailedStatus(response.id, response.exception);
                    toastr.error(response.exception);
                } else {
                    showRowDoneStatus(response.id, response.fileUrl ? response.fileUrl : ASC.Files.Utility.GetFileWebEditorUrl(response.fileId));
                }
                break;
        }
    };

    function getStatus() {
        showLoader();

        methods.status(
            {
                success: generateSuccessCallback,
                error: generateErrorCallback
            });
    };

    function generateErrorCallback(params, errors) {
        hideLoader();
        toastr.error(errors[0]);
    };

    function showLoader() {
        loadingBanner.showLoaderBtn(container);
    }

    function hideLoader() {
        loadingBanner.hideLoaderBtn(container);
    }

    return {
        init: init,
        show: show,
        close: close,
        generate: generate,
        setProgress: setProgress
    };
})();

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileOperations/FileOperationsManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using ASC.Common.Threading;
using ASC.Core;
using ASC.Web.Files.Resources;

namespace ASC.Web.Files.Services.WCFService.FileOperations
{
    class FileOperationsManager
    {
        private readonly DistributedTaskQueue tasks = new DistributedTaskQueue("fileOperations", 10);


        public ItemList<FileOperationResult> GetOperationResults()
        {
            var operations = tasks.GetTasks();
            var processlist = Process.GetProcesses();

            foreach (var o in operations.Where(o => string.IsNullOrEmpty(o.InstanseId)
                                                    || processlist.All(p => p.Id != int.Parse(o.InstanseId))))
            {
                o.SetProperty(FileOperation.PROGRESS, 100);
                tasks.RemoveTask(o.Id);
            }

            operations = operations.Where(t => t.GetProperty<Guid>(FileOperation.OWNER) == SecurityContext.CurrentAccount.ID);
            foreach (var o in operations.Where(o => DistributedTaskStatus.Running < o.Status))
            {
                o.SetProperty(FileOperation.PROGRESS, 100);
                tasks.RemoveTask(o.Id);
            }

            var results = operations
                .Where(o => o.GetProperty<bool>(FileOperation.HOLD) || o.GetProperty<int>(FileOperation.PROGRESS) != 100)
                .Select(o => new FileOperationResult
                {
                    Id = o.Id,
                    OperationType = o.GetProperty<FileOperationType>(FileOperation.OPERATION_TYPE),
                    Source = o.GetProperty<string>(FileOperation.SOURCE),
                    Progress = o.GetProperty<int>(FileOperation.PROGRESS),
                    Processed = o.GetProperty<int>(FileOperation.PROCESSED).ToString(),
                    Result = o.GetProperty<string>(FileOperation.RESULT),
                    Error = o.GetProperty<string>(FileOperation.ERROR),
                    Finished = o.GetProperty<bool>(FileOperation.FINISHED),
                });

            return new ItemList<FileOperationResult>(results);
        }

        public ItemList<FileOperationResult> CancelOperations()
        {
            var operations = tasks.GetTasks()
                .Where(t => t.GetProperty<Guid>(FileOperation.OWNER) == SecurityContext.CurrentAccount.ID);

            foreach (var o in operations)
            {
                tasks.CancelTask(o.Id);
            }

            return GetOperationResults();
        }


        public ItemList<FileOperationResult> MarkAsRead(List<object> folderIds, List<object> fileIds)
        {
            var op = new FileMarkAsReadOperation(folderIds, fileIds);
            return QueueTask(op);
        }

        public ItemList<FileOperationResult> Download(Dictionary<object, string> folders, Dictionary<object, string> files, Dictionary<string, string> headers)
        {
            var operations = tasks.GetTasks()
                .Where(t => t.GetProperty<Guid>(FileOperation.OWNER) == SecurityContext.CurrentAccount.ID)
                .Where(t => t.GetProperty<FileOperationType>(FileOperation.OPERATION_TYPE) == FileOperationType.Download);

            if (operations.Any(o => o.Status <= DistributedTaskStatus.Running))
            {
                throw new InvalidOperationException(FilesCommonResource.ErrorMassage_ManyDownloads);
            }

            var op = new FileDownloadOperation(folders, files, headers);
            return QueueTask(op);
        }

        public ItemList<FileOperationResult> MoveOrCopy(List<object> folders, List<object> files, string destFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult, Dictionary<string, string> headers)
        {
            var op = new FileMoveCopyOperation(folders, files, destFolderId, copy, resolveType, holdResult, headers);
            return QueueTask(op);
        }

        public ItemList<FileOperationResult> Delete(List<object> folders, List<object> files, bool ignoreException, bool holdResult, bool immediately, Dictionary<string, string> headers)
        {
            var op = new FileDeleteOperation(folders, files, ignoreException, holdResult, immediately, headers);
            return QueueTask(op);
        }


        private ItemList<FileOperationResult> QueueTask(FileOperation op)
        {
            tasks.QueueTask(op.RunJob, op.GetDistributedTask());
            return GetOperationResults();
        }
    }
}

<|start_filename|>module/ASC.Feed.Aggregator/Modules/Projects/ParticipantsModule.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Users;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Projects.Core;
using ASC.Web.Studio.Utility;

using Autofac;

namespace ASC.Feed.Aggregator.Modules.Projects
{
    internal class ParticipantsModule : FeedModule
    {
        private const string item = "participant";

        public override string Name
        {
            get { return Constants.ProjectsModule; }
        }

        public override string Product
        {
            get { return ModulesHelper.ProjectsProductName; }
        }

        public override Guid ProductID
        {
            get { return ModulesHelper.ProjectsProductID; }
        }

        protected override string Table
        {
            get { return "projects_project_participant"; }
        }

        protected override string LastUpdatedColumn
        {
            get { return "created"; }
        }

        protected override string TenantColumn
        {
            get { return "tenant"; }
        }

        protected override string DbId
        {
            get { return Constants.ProjectsDbId; }
        }

        public override bool VisibleFor(Feed feed, object data, Guid userId)
        {
            using (var scope = DIHelper.Resolve())
            {
                return base.VisibleFor(feed, data, userId) && scope.Resolve<ProjectSecurity>().CanGoToFeed((ParticipantFull)data, userId);
            }
        }

        public override IEnumerable<Tuple<Feed, object>> GetFeeds(FeedFilter filter)
        {
            var filterTimeInterval = TimeSpan.FromTicks(filter.Time.To.Ticks - filter.Time.From.Ticks).TotalMinutes;

            var q = new SqlQuery("projects_project_participant" + " pp")
                .Select("pp.participant_id", "pp.created", "pp.updated")
                .InnerJoin("projects_projects" + " p",
                           Exp.EqColumns("p.id", "pp.project_id") & Exp.Eq("p.tenant_id", filter.Tenant))
                .Select("p.id", "p.title", "p.description", "p.status", "p.status_changed", "p.responsible_id")
                .Select("p.private", "p.create_by", "p.create_on", "p.last_modified_by", "p.last_modified_on")
                .Where("pp.removed", 0)
                .Where("pp.tenant", filter.Tenant)
                .Where(Exp.Between("pp.created", filter.Time.From, filter.Time.To) &
                       !Exp.Between("TIMESTAMPDIFF(MINUTE,p.create_on, pp.created)", -filterTimeInterval, filterTimeInterval));

            using (var db = new DbManager(DbId))
            {
                var participants = db.ExecuteList(q).ConvertAll(ToParticipant);
                return participants.Select(p => new Tuple<Feed, object>(ToFeed(p), p));
            }
        }

        private static ParticipantFull ToParticipant(object[] r)
        {
            var participantId = new Guid(Convert.ToString(r[0]));
            return new ParticipantFull(participantId)
            {
                Created = Convert.ToDateTime(r[1]),
                Updated = Convert.ToDateTime(r[2]),
                Project = new Project
                {
                    ID = Convert.ToInt32(r[3]),
                    Title = Convert.ToString(r[4]),
                    Description = Convert.ToString(r[5]),
                    Status = (ProjectStatus)Convert.ToInt32(6),
                    StatusChangedOn = Convert.ToDateTime(r[7]),
                    Responsible = new Guid(Convert.ToString(r[8])),
                    Private = Convert.ToBoolean(r[9]),
                    CreateBy = new Guid(Convert.ToString(r[10])),
                    CreateOn = Convert.ToDateTime(r[11]),
                    LastModifiedBy = ToGuid(r[12]),
                    LastModifiedOn = Convert.ToDateTime(r[13])
                }
            };
        }

        private Feed ToFeed(ParticipantFull participant)
        {
            var projectUrl = "/Products/Projects/Tasks.aspx?prjID=" + participant.Project.ID;
            var feed = new Feed(participant.ID, participant.Created)
            {
                Item = item,
                ItemId = string.Format("{0}_{1}", participant.ID, participant.Project.ID),
                ItemUrl = CommonLinkUtility.ToAbsolute(projectUrl),
                Product = Product,
                Module = Name,
                Title = participant.Project.Title,
                ExtraLocation = participant.Project.Title,
                ExtraLocationUrl = CommonLinkUtility.ToAbsolute(projectUrl),
                HasPreview = false,
                CanComment = false,
                GroupId = GetGroupId(item, Guid.Empty, participant.Project.ID.ToString(CultureInfo.InvariantCulture)),
                Keywords = CoreContext.UserManager.GetUsers(participant.ID).DisplayUserName(false)
            };
            return feed;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/Masters/ClientScripts/ClientSettingsResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Web;

using ASC.Core.Users;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Core.Utility.Skins;

namespace ASC.Web.People.Masters.ClientScripts
{
    public class ClientSettingsResources : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.People.Data"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            return new List<KeyValuePair<string, object>>(1)
            {
                RegisterObject(new
                {
                    emptyScreenPeopleFilter = WebImageSupplier.GetAbsoluteWebPath("empty_screen_filter.png"),
                    userDisplayFormat = (int) UserFormatter.GetUserDisplayDefaultOrder()
                })
            };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_SingleValueHF.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements single value header field.
    /// Used by header fields like To:,From:,CSeq:, ... .
    /// </summary>
    public class SIP_SingleValueHF<T> : SIP_HeaderField where T : SIP_t_Value
    {
        #region Members

        private T m_pValue;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets header field value.
        /// </summary>
        public override string Value
        {
            get { return ToStringValue(); }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("Property Value value may not be null !");
                }

                Parse(new StringReader(value));
            }
        }

        /// <summary>
        /// Gets or sets header field value.
        /// </summary>
        public T ValueX
        {
            get { return m_pValue; }

            set { m_pValue = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="name">Header field name.</param>
        /// <param name="value">Header field value.</param>
        public SIP_SingleValueHF(string name, T value) : base(name, "")
        {
            m_pValue = value;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses single value from specified reader.
        /// </summary>
        /// <param name="reader">Reader what contains </param>
        public void Parse(StringReader reader)
        {
            m_pValue.Parse(reader);
        }

        /// <summary>
        /// Convert this to string value.
        /// </summary>
        /// <returns>Returns this as string value.</returns>
        public string ToStringValue()
        {
            return m_pValue.ToStringValue();
        }

        #endregion

        // FIX ME: Change base class Value property or this to new name
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/GreetingSettings/LogoUploader.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Web;

using ASC.Core;
using ASC.Web.Core.Users;
using ASC.Web.Core.Utility;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;

namespace ASC.Web.Studio.UserControls.Management
{
    internal class LogoUploader : IFileUploadHandler
    {
        #region IFileUploadHandler Members

        public FileUploadResult ProcessUpload(HttpContext context)
        {
            var result = new FileUploadResult();
            try
            {
                SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

                if (context.Request.Files.Count != 0)
                {
                    var logo = context.Request.Files[0];
                    var data = new byte[logo.InputStream.Length];

                    var br = new BinaryReader(logo.InputStream);
                    br.Read(data, 0, (int)logo.InputStream.Length);
                    br.Close();

                    var ap = UserPhotoManager.SaveTempPhoto(data, SetupInfo.MaxImageUploadSize, 250, 100);

                    result.Success = true;
                    result.Message = ap;
                }
                else
                {
                    result.Success = false;
                    result.Message = Resource.ErrorEmptyUploadFileSelected;
                }
            }
            catch (ImageWeightLimitException)
            {
                result.Success = false;
                result.Message = Resource.ErrorImageWeightLimit;
            }
            catch (ImageSizeLimitException)
            {
                result.Success = false;
                result.Message = Resource.ErrorImageSizetLimit;
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.Message = ex.Message.HtmlEncode();
            }

            return result;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/ViewSwitcher/ViewSwitcherTabItem.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web.UI;

namespace ASC.Web.Studio.UserControls.Common.ViewSwitcher
{
    public class ViewSwitcherTabItem : Control
    {
        public string OnClickText { get; set; }

        public string TabName { get; set; }

        public string TabAnchorName { get; set; }

        public bool IsSelected { get; set; }

        public bool SkipRender { get; set; }

        public string SortItemsDivID { get; set; }

        public bool HideSortItems { get; set; }

        public string DivID = Guid.NewGuid().ToString();

        public string GetSortLink(bool renderAllTabs)
        {
            var tabCssName = String.IsNullOrEmpty(TabAnchorName)
                                 ? (IsSelected ? "viewSwitcherTabSelected" : "viewSwitcherTab")
                                 : String.Format("{0} viewSwitcherTab_{1}",
                                                 IsSelected ? "viewSwitcherTabSelected" : "viewSwitcherTab",
                                                 TabAnchorName);

            var javascriptText = string.Format(@" onclick=""{0} {1} viewSwitcherToggleTabs(this.id);"" ",
                                               String.IsNullOrEmpty(OnClickText) ? String.Empty : OnClickText + ";",
                                               renderAllTabs && !String.IsNullOrEmpty(TabAnchorName)
                                                   ? String.Format("ASC.Controls.AnchorController.move('{0}');", TabAnchorName)
                                                   : "");

            var sb = new StringBuilder();
            sb.AppendFormat(@"<li id='{0}_ViewSwitcherTab' class='{1}' {2}>{3}</li>", DivID, tabCssName, javascriptText, TabName.HtmlEncode());
            return sb.ToString();
        }

        public void RenderTabContent(HtmlTextWriter writer)
        {
            if (SkipRender) return;
            writer.Write("<div id='{0}'{1}>", DivID, IsSelected ? string.Empty : " style='display: none;'");
            RenderControl(writer);
            writer.Write("</div>");
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/Log/LogEntry.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Log
{
    #region usings

    using System;
    using System.Net;
    using System.Security.Principal;

    #endregion

    /// <summary>
    /// Implements log entry.
    /// </summary>
    public class LogEntry
    {
        #region Members

        private readonly string m_ID = "";
        private readonly byte[] m_pData;
        private readonly Exception m_pException;
        private readonly IPEndPoint m_pLocalEP;
        private readonly IPEndPoint m_pRemoteEP;
        private readonly GenericIdentity m_pUserIdentity;
        private readonly long m_Size;
        private readonly string m_Text = "";
        private readonly DateTime m_Time;
        private readonly LogEntryType m_Type = LogEntryType.Text;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="type">Log entry type.</param>
        /// <param name="id">Log entry ID.</param>
        /// <param name="size">Specified how much data was readed or written.</param>
        /// <param name="text">Description text.</param>
        public LogEntry(LogEntryType type, string id, long size, string text)
        {
            m_Type = type;
            m_ID = id;
            m_Size = size;
            m_Text = text;

            m_Time = DateTime.Now;
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="type">Log entry type.</param>
        /// <param name="id">Log entry ID.</param>
        /// <param name="userIdentity">Log entry owner user or null if none.</param>
        /// <param name="size">Log entry read/write size in bytes.</param>
        /// <param name="text">Log text.</param>
        /// <param name="localEP">Local IP end point.</param>
        /// <param name="remoteEP">Remote IP end point.</param>
        /// <param name="data">Log data.</param>
        public LogEntry(LogEntryType type,
                        string id,
                        GenericIdentity userIdentity,
                        long size,
                        string text,
                        IPEndPoint localEP,
                        IPEndPoint remoteEP,
                        byte[] data)
        {
            m_Type = type;
            m_ID = id;
            m_pUserIdentity = userIdentity;
            m_Size = size;
            m_Text = text;
            m_pLocalEP = localEP;
            m_pRemoteEP = remoteEP;
            m_pData = data;

            m_Time = DateTime.Now;
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="type">Log entry type.</param>
        /// <param name="id">Log entry ID.</param>
        /// <param name="userIdentity">Log entry owner user or null if none.</param>
        /// <param name="size">Log entry read/write size in bytes.</param>
        /// <param name="text">Log text.</param>
        /// <param name="localEP">Local IP end point.</param>
        /// <param name="remoteEP">Remote IP end point.</param>
        /// <param name="exception">Exception happened. Can be null.</param>
        public LogEntry(LogEntryType type,
                        string id,
                        GenericIdentity userIdentity,
                        long size,
                        string text,
                        IPEndPoint localEP,
                        IPEndPoint remoteEP,
                        Exception exception)
        {
            m_Type = type;
            m_ID = id;
            m_pUserIdentity = userIdentity;
            m_Size = size;
            m_Text = text;
            m_pLocalEP = localEP;
            m_pRemoteEP = remoteEP;
            m_pException = exception;

            m_Time = DateTime.Now;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gest log data. Value null means no log data.
        /// </summary>
        public byte[] Data
        {
            get { return m_pData; }
        }

        /// <summary>
        /// Gets log entry type.
        /// </summary>
        public LogEntryType EntryType
        {
            get { return m_Type; }
        }

        /// <summary>
        /// Gets exception happened. This property is available only if LogEntryType.Exception.
        /// </summary>
        public Exception Exception
        {
            get { return m_pException; }
        }

        /// <summary>
        /// Gets log entry ID.
        /// </summary>
        public string ID
        {
            get { return m_ID; }
        }

        /// <summary>
        /// Gets local IP end point. Value null means no local end point.
        /// </summary>
        public IPEndPoint LocalEndPoint
        {
            get { return m_pLocalEP; }
        }

        /// <summary>
        /// Gets remote IP end point. Value null means no remote end point.
        /// </summary>
        public IPEndPoint RemoteEndPoint
        {
            get { return m_pRemoteEP; }
        }

        /// <summary>
        /// Gets how much data was readed or written, depends on <b>LogEntryType</b>.
        /// </summary>
        public long Size
        {
            get { return m_Size; }
        }

        /// <summary>
        /// Gets describing text.
        /// </summary>
        public string Text
        {
            get { return m_Text; }
        }

        /// <summary>
        /// Gets time when log entry was created.
        /// </summary>
        public DateTime Time
        {
            get { return m_Time; }
        }

        /// <summary>
        /// Gets log entry related user identity.
        /// </summary>
        public GenericIdentity UserIdentity
        {
            get { return m_pUserIdentity; }
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Community/Forums/ForumTopicPostWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Api.Employee;
using ASC.Forum;
using ASC.Specific;

namespace ASC.Api.Forums
{
    [DataContract(Name = "post", Namespace = "")]
    public class ForumTopicPostWrapper : IApiSortableDate
    {
        [DataMember(Order = 1)]
        public int Id { get; set; }

        [DataMember(Order = 2)]
        public string Subject { get; set; }

        [DataMember(Order = 2)]
        public string Text { get; set; }

        [DataMember(Order = 3)]
        public ApiDateTime Created { get; set; }

        private ApiDateTime updated;

        [DataMember(Order = 3)]
        public ApiDateTime Updated
        {
            get { return updated >= Created ? updated : Created; }
            set { updated = value; }
        }

        [DataMember(Order = 9)]
        public EmployeeWraper CreatedBy { get; set; }

        [DataMember(Order = 10)]
        public string ThreadTitle { get; set; }

        [DataMember(Order = 100, EmitDefaultValue = false)]
        public List<ForumTopicPostAttachmentWrapper> Attachments { get; set; }

        public ForumTopicPostWrapper(Post post)
        {
            Id = post.ID;
            Text = post.Text;
            Created = (ApiDateTime)post.CreateDate;
            Updated = (ApiDateTime)post.EditDate;
            Subject = post.Subject;
            CreatedBy = EmployeeWraper.Get(Core.CoreContext.UserManager.GetUsers(post.PosterID));
            Attachments = post.Attachments.Select(x => new ForumTopicPostAttachmentWrapper(x)).ToList();
        }

        private ForumTopicPostWrapper()
        {
        }

        public static ForumTopicPostWrapper GetSample()
        {
            return new ForumTopicPostWrapper
            {
                Id = 123,
                CreatedBy = EmployeeWraper.GetSample(),
                Created = ApiDateTime.GetSample(),
                Updated = ApiDateTime.GetSample(),
                Subject = "Sample subject",
                Text = "Post text",
                Attachments = new List<ForumTopicPostAttachmentWrapper> { ForumTopicPostAttachmentWrapper.GetSample() }
            };
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/MailboxDomainDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao
{
    public class MailboxDomainDao : BaseDao, IMailboxDomainDao
    {
        protected static ITable table = new MailTableFactory().Create<MailboxDomainTable>();

        public MailboxDomainDao(IDbManager dbManager)
            : base(table, dbManager, -1)
        {
        }

        public MailboxDomain GetDomain(string domainName)
        {
            var query = Query()
                .Where(MailboxDomainTable.Columns.DomainName, domainName);

            return Db.ExecuteList(query)
                .ConvertAll(ToMailboxDomain)
                .FirstOrDefault();
        }

        public int SaveDomain(MailboxDomain domain)
        {
            var query = new SqlInsert(MailboxDomainTable.TABLE_NAME, true)
                .InColumnValue(MailboxDomainTable.Columns.Id, domain.Id)
                .InColumnValue(MailboxDomainTable.Columns.ProviderId, domain.ProviderId)
                .InColumnValue(MailboxDomainTable.Columns.DomainName, domain.Name)
                .Identity(0, 0, true);

            var id = Db.ExecuteScalar<int>(query);

            return id;
        }

        protected MailboxDomain ToMailboxDomain(object[] r)
        {
            var d = new MailboxDomain
            {
                Id = Convert.ToInt32(r[0]),
                ProviderId = Convert.ToInt32(r[1]),
                Name = Convert.ToString(r[2])
            };

            return d;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Interfaces/IFolderDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Core.Entities;
using ASC.Mail.Enums;

namespace ASC.Mail.Core.Dao.Interfaces
{
    public interface IFolderDao
    {
        /// <summary>
        ///     Get folder by id.
        /// </summary>
        Folder GetFolder(FolderType folder);

        /// <summary>
        ///     Get a list of folders.
        /// </summary>
        List<Folder> GetFolders();

        /// <summary>
        ///     Save folder
        /// </summary>
        int Save(Folder folder);

        /// <summary>
        ///     Update folder counters
        /// </summary>
        int ChangeFolderCounters(FolderType folder, int? unreadMessDiff = null, int? totalMessDiff = null,
            int? unreadConvDiff = null, int? totalConvDiff = null);

        int Delete();
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Controls/Reports/ReportTemplateView.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Projects.Core.Domain.Reports;
using ASC.Web.Projects.Classes;
using ASC.Web.Projects.Resources;
using ASC.Web.Studio.Utility;

using Report = ASC.Web.Projects.Classes.Report;

namespace ASC.Web.Projects.Controls.Reports
{
    public partial class ReportTemplateView : BaseUserControl
    {
        public ReportTemplate Template { get; set; }

        public string TmplParamHour { get; set; }
        public int TmplParamMonth { get; set; }
        public int TmplParamWeek { get; set; }
        public string TmplParamPeriod { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            Template = Page.EngineFactory.ReportEngine.GetTemplate(int.Parse(Request["tmplId"]));
            if (Template == null)
            {
                Page.RedirectNotFound("Reports.aspx");
            }
            else
            {
                var filters = (ReportFilters)LoadControl(PathProvider.GetFileStaticRelativePath("Reports/ReportFilters.ascx"));
                filters.Report = Report.CreateNewReport(Template.ReportType, Template.Filter);
                _filter.Controls.Add(filters);
                InitTmplParam();

                Page.Title = HeaderStringHelper.GetPageTitle(string.Format(ReportResource.ReportPageTitle, HttpUtility.HtmlDecode(Template.Name)));
            }
        }

        private void InitTmplParam()
        {
            var cron = Template.Cron.Split(' ');

            try
            {
                TmplParamWeek = Int32.Parse(cron[5]);
                TmplParamPeriod = "week";
            }
            catch (FormatException)
            {
                try
                {
                    TmplParamMonth = Int32.Parse(cron[3]);
                    TmplParamPeriod = "month";
                }
                catch (FormatException)
                {
                    TmplParamPeriod = "day";
                }
            }

            TmplParamHour = cron[2];

        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/autocomplete/crmautocomplete.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function (jq) {

    var instances = [];

    function removeInstance(obj) {
        jq.each(instances, function (index, item) {
            if (obj.is(item.obj)) {
                instances.splice(index, 1);
                return false;
            }
            return true;
        });
    }

    function crmSelector(obj, options) {
        var self = this;

        this.input = obj;
        this.settings = options || {};
        this.container = options.container || null;
        this.getEntityType = options.getEntityType || null;
        this.onSelectItem = options.onSelectItem || null;
        this.isExists = options.isExists || null;
        this.cache = [];
        this.firstFailTerm = "";

        this.closeSelector = function() {
            var uiAutocomplete = self.input.data("ui-autocomplete");
            if (uiAutocomplete) {
                uiAutocomplete.close();
            }
        };

        this.addItem = function (item) {
            self.onSelectItem(item);
            self.closeSelector();
        };

        this.initAutocomplete = function () {
            self.input.autocomplete({
                minLength: 1,
                delay: 500,

                position: {my: "left top", at: "left bottom+2", collision: "none"},

                select: function (event, ui) {
                    if (ui.item) {
                        self.input.val("");
                        self.addItem(ui.item);
                    }
                    return false;
                },

                search: function () {
                    return self.input.is(":visible");
                },

                source: function (request, response) {
                    var entityType = +self.getEntityType();
                    var params = { searchText: request.term, entityType: entityType };

                    if (self.settings.isInPopup) {
                        var ul = this.menu.element;
                        var popupParent = self.input.parents(".blockUI.blockPage:first");

                        if (popupParent.length !== 0) {
                            if (popupParent.css("position") === "fixed") {
                                ul.css("position", "fixed");
                            } else {
                                ul.css("position", "absolute");
                            }
                        }
                    }

                    var cacheKey = request.term + '|' + entityType;

                    if (cacheKey in self.cache) {
                        var cachedItems = self.cache[cacheKey];
                        params.skipCache = true;
                        return onGetCrmContactsByPrefix(params, cachedItems);
                    }

                    if (!request.term) {
                        self.firstFailTerm = "";
                        return response([]);
                    }

                    if (self.firstFailTerm) {
                        if (request.term.indexOf(self.firstFailTerm) === 0) {
                            return response([]);
                        } else
                            self.firstFailTerm = "";
                    }

                    if (!self.getEntityType) {
                        console.error("No set getEntityType function");
                        return response([]);
                    }

                    function onGetCrmContactsByPrefix(params, contacts) {
                        if (!contacts || contacts.length === 0) {
                            self.firstFailTerm = request.term;
                            return response([]);
                        }

                        var items = contacts.map(function (contact) {
                            if (!self.isExists(params.entityType, contact.id)) {

                                var contactInfo = {
                                    id: contact.id,
                                    entityType: params.entityType,
                                    displayName: contact.displayName || contact.title
                                };

                                if (contact.smallFotoUrl) {
                                    contactInfo.smallFotoUrl = contact.smallFotoUrl;
                                }

                                return contactInfo;
                            }
                            return undefined;
                        }).filter(function (val) { return val != undefined; });

                        if (!params.skipCache) {
                            var cacheKey = request.term + '|' + params.entityType;
                            self.cache[cacheKey] = items;
                        }

                        return response(items);
                    }

                    switch (entityType) {
                        case 1: // contactType
                            window.Teamlab.getCrmContactsByPrefix(params, {
                                filter: { prefix: request.term, searchType: -1 },
                                success: onGetCrmContactsByPrefix,
                                error: function (params, error) {
                                    console.log(error);
                                }
                            });
                            break;
                        case 2: // caseType
                            window.Teamlab.getCrmCasesByPrefix(params, {
                                filter: { prefix: request.term, searchType: -1 },
                                success: onGetCrmContactsByPrefix,
                                error: function (params, error) {
                                    console.log(error);
                                }
                            });
                            break;
                        case 3: // opportunityType
                            window.Teamlab.getCrmOpportunitiesByPrefix(params, {
                                filter: { prefix: request.term },
                                success: onGetCrmContactsByPrefix,
                                error: function (params, error) {
                                    console.log(error);
                                }
                            });
                            break;
                        default:
                            return response([]);
                    }
                },
                focus: function () {
                    return false;
                },
                create: function() {
                    jq(window).resize(function () {
                        self.closeSelector();
                    });
                },
                open: function () {
                    var e = jq.Event("keydown", { keyCode: 40 });
                    jq(self.input).trigger(e);
                    return false;
                }
            });

            self.input.data("ui-autocomplete")._renderMenu = function (ul, items) {
                var target = this;

                jq.each(items, function (index, item) {
                    target._renderItemData(ul, item);
                });

                if (self.settings.isInPopup && jq.browser.mobile && ul.parents(".blockUI.blockPage:first").length === 0) {
                    var popupParent = self.input.parents(".blockUI.blockPage:first");
                    if (popupParent.length !== 0) {
                        ul.appendTo(popupParent.children());
                    }
                }
            };

           self.input.data("ui-autocomplete")._renderItem = function (ul, item) {
               return jq.tmpl("template-emailselector-autocomplete", { name: null, email: item.displayName }).appendTo(ul);
           };

            self.input.data("ui-autocomplete")._resizeMenu = function () {
                this.menu.element.outerWidth(self.input.outerWidth());
            };

            self.input.data("ui-autocomplete")._suggest = function (items) {
                var ul = this.menu.element.empty().zIndex(this.element.zIndex() + 1);
                this._renderMenu(ul, items);
                this.menu.refresh();
                ul.show();
                this._resizeMenu();
                var position = jq.extend({ of: jq(this.element).parent() }, this.options.position);
                ul.position(position);
            };
        };

        this.init = function () {
            self.initAutocomplete();
            self.input.val("");
        };

    }

    var methods = {
        init: function (options) {
            var obj = jq(this);
            removeInstance(obj);
            var instance = new crmSelector(obj, options);
            instances.push(instance);
            instance.init();
            return this;
        }
    };

    jq.fn.CrmSelector = function (method) {
        if (this.length && methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        }

        return this;
    };

})(jQuery);




<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/ContactDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao
{
    public class ContactDao : BaseDao, IContactDao
    {
        protected static ITable table = new MailTableFactory().Create<ContactsTable>();

        protected string CurrentUserId { get; private set; }

        public ContactDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public int SaveContact(Contact contact)
        {
            var queryContact = new SqlInsert(ContactsTable.TABLE_NAME, true)
                .InColumnValue(ContactsTable.Columns.Id, contact.Id)
                .InColumnValue(ContactsTable.Columns.User, contact.User)
                .InColumnValue(ContactsTable.Columns.Tenant, contact.Tenant)
                .InColumnValue(ContactsTable.Columns.ContactName, contact.ContactName)
                .InColumnValue(ContactsTable.Columns.Address, contact.Address)
                .InColumnValue(ContactsTable.Columns.Description, contact.Description)
                .InColumnValue(ContactsTable.Columns.Type, contact.Type)
                .InColumnValue(ContactsTable.Columns.HasPhoto, contact.HasPhoto)
                .Identity(0, 0, true);

            return Db.ExecuteScalar<int>(queryContact);
        }

        public int RemoveContacts(List<int> ids)
        {
            var query = new SqlDelete(ContactInfoTable.TABLE_NAME)
                .Where(Exp.In(ContactInfoTable.Columns.ContactId, ids))
                .Where(ContactInfoTable.Columns.Tenant, Tenant)
                .Where(ContactInfoTable.Columns.User, CurrentUserId);

            return Db.ExecuteNonQuery(query);
        }
    }
}

<|start_filename|>common/ASC.ActiveDirectory/Novell/NovellLdapHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

using ASC.ActiveDirectory.Base;
using ASC.ActiveDirectory.Base.Data;
using ASC.ActiveDirectory.Base.Expressions;
using ASC.ActiveDirectory.Base.Settings;

namespace ASC.ActiveDirectory.Novell
{
    public class NovellLdapHelper : LdapHelper
    {
        public NovellLdapSearcher LDAPSearcher { get; private set; }

        public NovellLdapHelper(LdapSettings settings) :
            base(settings)
        {
            var password = string.IsNullOrEmpty(settings.Password)
                ? GetPassword(settings.PasswordBytes)
                : settings.Password;

            LDAPSearcher = new NovellLdapSearcher(settings.Login, password, settings.Server, settings.PortNumber,
                settings.StartTls, settings.Ssl, settings.AcceptCertificate, settings.AcceptCertificateHash);
        }

        public override bool IsConnected
        {
            get { return LDAPSearcher.IsConnected; }
        }

        public override void Connect()
        {
            LDAPSearcher.Connect();

            Settings.AcceptCertificate = LDAPSearcher.AcceptCertificate;
            Settings.AcceptCertificateHash = LDAPSearcher.AcceptCertificateHash;
        }

        public override Dictionary<string, string[]> GetCapabilities()
        {
            return LDAPSearcher.GetCapabilities();
        }

        public override string SearchDomain()
        {
            try
            {
                var capabilities = GetCapabilities();

                if (capabilities.Any())
                {
                    if (capabilities.ContainsKey("defaultNamingContext"))
                    {
                        var dnList = capabilities["defaultNamingContext"];

                        var dn = dnList.FirstOrDefault(dc =>
                            !string.IsNullOrEmpty(dc) &&
                            dc.IndexOf("dc=", StringComparison.InvariantCultureIgnoreCase) != -1);

                        var domain = LdapUtils.DistinguishedNameToDomain(dn);

                        if (!string.IsNullOrEmpty(domain))
                            return domain;
                    }

                    if (capabilities.ContainsKey("rootDomainNamingContext"))
                    {
                        var dnList = capabilities["rootDomainNamingContext"];

                        var dn = dnList.FirstOrDefault(dc =>
                            !string.IsNullOrEmpty(dc) &&
                            dc.IndexOf("dc=", StringComparison.InvariantCultureIgnoreCase) != -1);

                        var domain = LdapUtils.DistinguishedNameToDomain(dn);

                        if (!string.IsNullOrEmpty(domain))
                            return domain;
                    }

                    if (capabilities.ContainsKey("namingContexts"))
                    {
                        var dnList = capabilities["namingContexts"];

                        var dn = dnList.FirstOrDefault(dc =>
                            !string.IsNullOrEmpty(dc) &&
                            dc.IndexOf("dc=", StringComparison.InvariantCultureIgnoreCase) != -1);

                        var domain = LdapUtils.DistinguishedNameToDomain(dn);

                        if (!string.IsNullOrEmpty(domain))
                            return domain;
                    }
                }
            }
            catch (Exception e)
            {
                Log.WarnFormat("NovellLdapHelper->SearchDomain() failed. Error: {0}", e);
            }

            try
            {
                var searchResult =
                    LDAPSearcher.Search(Settings.UserDN, NovellLdapSearcher.LdapScope.Sub, Settings.UserFilter, limit: 1)
                        .FirstOrDefault();

                return searchResult != null ? searchResult.GetDomainFromDn() : null;
            }
            catch (Exception e)
            {
                Log.WarnFormat("NovellLdapHelper->SearchDomain() failed. Error: {0}", e);
            }

            return null;
        }

        public override void CheckCredentials(string login, string password, string server, int portNumber,
            bool startTls, bool ssl, bool acceptCertificate, string acceptCertificateHash)
        {
            using (var novellLdapSearcher = new NovellLdapSearcher(login, password, server, portNumber,
                startTls, ssl, acceptCertificate, acceptCertificateHash))
            {
                novellLdapSearcher.Connect();
            }
        }

        public override bool CheckUserDn(string userDn)
        {
            string[] attributes = { LdapConstants.ADSchemaAttributes.OBJECT_CLASS };

            var searchResult = LDAPSearcher.Search(userDn, NovellLdapSearcher.LdapScope.Base,
                LdapConstants.OBJECT_FILTER, attributes, 1);

            if (searchResult.Any())
                return true;

            Log.ErrorFormat("NovellLdapHelper->CheckUserDn(userDn: {0}) Wrong User DN parameter", userDn);
            return false;
        }

        public override bool CheckGroupDn(string groupDn)
        {
            string[] attributes = { LdapConstants.ADSchemaAttributes.OBJECT_CLASS };

            var searchResult = LDAPSearcher.Search(groupDn, NovellLdapSearcher.LdapScope.Base,
                LdapConstants.OBJECT_FILTER, attributes, 1);

            if (searchResult.Any())
                return true;

            Log.ErrorFormat("NovellLdapHelper->CheckGroupDn(groupDn: {0}): Wrong Group DN parameter", groupDn);
            return false;
        }

        public override List<LdapObject> GetUsers(string filter = null, int limit = -1)
        {
            var list = new List<LdapObject>();

            try
            {
                if (!string.IsNullOrEmpty(Settings.UserFilter) && !Settings.UserFilter.StartsWith("(") &&
                    !Settings.UserFilter.EndsWith(")"))
                {
                    Settings.UserFilter = string.Format("({0})", Settings.UserFilter);
                }

                if (!string.IsNullOrEmpty(filter) && !filter.StartsWith("(") &&
                    !filter.EndsWith(")"))
                {
                    filter = string.Format("({0})", Settings.UserFilter);
                }

                var searchfilter = string.IsNullOrEmpty(filter)
                    ? Settings.UserFilter
                    : string.Format("(&{0}{1})", Settings.UserFilter, filter);

                list = LDAPSearcher.Search(Settings.UserDN, NovellLdapSearcher.LdapScope.Sub, searchfilter, limit: limit);

                return list;
            }
            catch (Exception e)
            {
                Log.ErrorFormat("NovellLdapHelper->GetUsers(filter: '{0}' limit: {1}) failed. Error: {2}",
                    filter, limit, e);
            }

            return list;
        }

        public override LdapObject GetUserBySid(string sid)
        {
            try
            {
                var ldapUniqueIdAttribute = ConfigurationManagerExtension.AppSettings["ldap.unique.id"];

                Criteria criteria;

                if (ldapUniqueIdAttribute == null)
                {
                    criteria = Criteria.Any(
                        Expression.Equal(LdapConstants.RfcLDAPAttributes.ENTRY_UUID, sid),
                        Expression.Equal(LdapConstants.RfcLDAPAttributes.NS_UNIQUE_ID, sid),
                        Expression.Equal(LdapConstants.RfcLDAPAttributes.GUID, sid),
                        Expression.Equal(LdapConstants.ADSchemaAttributes.OBJECT_SID, sid)
                        );
                }
                else
                {
                    criteria = Criteria.All(Expression.Equal(ldapUniqueIdAttribute, sid));
                }

                var searchfilter = string.Format("(&{0}{1})", Settings.UserFilter, criteria);

                var list = LDAPSearcher.Search(Settings.UserDN, NovellLdapSearcher.LdapScope.Sub, searchfilter, limit: 1);

                return list.FirstOrDefault();
            }
            catch (Exception e)
            {
                Log.ErrorFormat("NovellLdapHelper->GetUserBySid(sid: '{0}') failed. Error: {1}", sid, e);
            }

            return null;
        }

        public override List<LdapObject> GetGroups(Criteria criteria = null)
        {
            var list = new List<LdapObject>();

            try
            {
                if (!string.IsNullOrEmpty(Settings.GroupFilter) && !Settings.GroupFilter.StartsWith("(") &&
                    !Settings.GroupFilter.EndsWith(")"))
                {
                    Settings.GroupFilter = string.Format("({0})", Settings.GroupFilter);
                }

                var searchfilter = criteria == null
                    ? Settings.GroupFilter
                    : string.Format("(&{0}{1})", Settings.GroupFilter, criteria);


                list = LDAPSearcher.Search(Settings.GroupDN, NovellLdapSearcher.LdapScope.Sub, searchfilter);
            }
            catch (Exception e)
            {
                Log.ErrorFormat("NovellLdapHelper->GetGroups(criteria: '{0}') failed. Error: {1}", criteria, e);
            }

            return list;
        }

        public override void Dispose()
        {
            LDAPSearcher.Dispose();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Utils/FileTracker.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Common.Caching;
using ASC.Core;

namespace ASC.Web.Files.Utils
{
    [DataContract]
    public class FileTracker
    {
        private const string TRACKER = "filesTracker";
        private static readonly ICache cache = AscCache.Default;

        public static readonly TimeSpan TrackTimeout = TimeSpan.FromSeconds(12);
        public static readonly TimeSpan CacheTimeout = TimeSpan.FromSeconds(60);
        public static readonly TimeSpan CheckRightTimeout = TimeSpan.FromMinutes(1);

        [DataMember] private readonly Dictionary<Guid, TrackInfo> _editingBy;


        private FileTracker()
        {
        }

        private FileTracker(Guid tabId, Guid userId, bool newScheme, bool editingAlone)
        {
            _editingBy = new Dictionary<Guid, TrackInfo> { { tabId, new TrackInfo(userId, newScheme, editingAlone) } };
        }


        public static Guid Add(object fileId)
        {
            var tabId = Guid.NewGuid();
            ProlongEditing(fileId, tabId, SecurityContext.CurrentAccount.ID);
            return tabId;
        }

        public static bool ProlongEditing(object fileId, Guid tabId, Guid userId, bool editingAlone = false)
        {
            var checkRight = true;
            var tracker = GetTracker(fileId);
            if (tracker != null && IsEditing(fileId))
            {
                if (tracker._editingBy.Keys.Contains(tabId))
                {
                    tracker._editingBy[tabId].TrackTime = DateTime.UtcNow;
                    checkRight = (DateTime.UtcNow - tracker._editingBy[tabId].CheckRightTime > CheckRightTimeout);
                }
                else
                {
                    tracker._editingBy.Add(tabId, new TrackInfo(userId, tabId == userId, editingAlone));
                }
            }
            else
            {
                tracker = new FileTracker(tabId, userId, tabId == userId, editingAlone);
            }

            SetTracker(fileId, tracker);

            return checkRight;
        }

        public static void Remove(object fileId, Guid tabId = default(Guid), Guid userId = default(Guid))
        {
            var tracker = GetTracker(fileId);
            if (tracker != null)
            {
                if (tabId != default(Guid))
                {
                    tracker._editingBy.Remove(tabId);
                    SetTracker(fileId, tracker);
                    return;
                }
                if (userId != default(Guid))
                {
                    var listForRemove = tracker._editingBy
                                               .Where(b => tracker._editingBy[b.Key].UserId == userId)
                                               .ToList();
                    foreach (var editTab in listForRemove)
                    {
                        tracker._editingBy.Remove(editTab.Key);
                    }
                    SetTracker(fileId, tracker);
                    return;
                }
            }

            SetTracker(fileId, null);
        }

        public static void RemoveAllOther(object fileId)
        {
            var tracker = GetTracker(fileId);
            if (tracker != null)
            {
                var listForRemove = tracker._editingBy
                                           .Where(b => b.Value.UserId != SecurityContext.CurrentAccount.ID)
                                           .ToList();
                if (listForRemove.Count() != tracker._editingBy.Count)
                {
                    foreach (var forRemove in listForRemove)
                    {
                        tracker._editingBy.Remove(forRemove.Key);
                    }
                    SetTracker(fileId, tracker);
                    return;
                }
            }
            SetTracker(fileId, null);
        }

        public static bool IsEditing(object fileId)
        {
            var tracker = GetTracker(fileId);
            if (tracker != null)
            {
                var listForRemove = tracker._editingBy
                                           .Where(e => !e.Value.NewScheme && (DateTime.UtcNow - e.Value.TrackTime).Duration() > TrackTimeout)
                                           .ToList();
                foreach (var editTab in listForRemove)
                {
                    tracker._editingBy.Remove(editTab.Key);
                }

                if (tracker._editingBy.Count == 0)
                {
                    SetTracker(fileId, null);
                    return false;
                }

                SetTracker(fileId, tracker);
                return true;
            }
            SetTracker(fileId, null);
            return false;
        }

        public static bool IsEditingAlone(object fileId)
        {
            var tracker = GetTracker(fileId);
            return tracker != null && tracker._editingBy.Count == 1 && tracker._editingBy.FirstOrDefault().Value.EditingAlone;
        }

        public static void ChangeRight(object fileId, Guid userId, bool check)
        {
            var tracker = GetTracker(fileId);
            if (tracker != null)
            {

                tracker._editingBy.Values
                       .ToList()
                       .ForEach(i =>
                           {
                               if (i.UserId == userId || userId == Guid.Empty)
                               {
                                   i.CheckRightTime = check ? DateTime.MinValue : DateTime.UtcNow;
                               }
                           });
                SetTracker(fileId, tracker);
            }
            else
            {
                SetTracker(fileId, null);
            }
        }

        public static List<Guid> GetEditingBy(object fileId)
        {
            var tracker = GetTracker(fileId);
            return tracker != null && IsEditing(fileId) ? tracker._editingBy.Values.Select(i => i.UserId).Distinct().ToList() : new List<Guid>();
        }

        private static FileTracker GetTracker(object fileId)
        {
            if (fileId != null)
            {
                return cache.Get<FileTracker>(TRACKER + fileId);
            }
            return null;
        }

        private static void SetTracker(object fileId, FileTracker tracker)
        {
            if (fileId != null)
            {
                if (tracker != null)
                {
                    cache.Insert(TRACKER + fileId, tracker, CacheTimeout);
                }
                else
                {
                    cache.Remove(TRACKER + fileId);
                }
            }
        }


        [DataContract]
        internal class TrackInfo
        {
            [DataMember] public DateTime CheckRightTime;

            [DataMember] public DateTime TrackTime;

            [DataMember] public Guid UserId;

            [DataMember] public bool NewScheme;

            [DataMember] public bool EditingAlone;

            public TrackInfo()
            {
            }

            public TrackInfo(Guid userId, bool newScheme, bool editingAlone)
            {
                CheckRightTime = DateTime.UtcNow;
                TrackTime = DateTime.UtcNow;
                NewScheme = newScheme;
                UserId = userId;
                EditingAlone = editingAlone;
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Utils/CryptoUtil.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Security.Cryptography;

namespace ASC.Mail.Utils
{
    public static class CryptoUtil
    {
        private static readonly byte[] RsaOid = { 0x30, 0xD, 0x6, 0x9, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0xD, 0x1, 0x1, 0x1, 0x5, 0x0 }; // Object ID for RSA

        private const byte INTEGER = 0x2;
        private const byte SEQUENCE = 0x30;
        private const byte BIT_STRING = 0x3;

        public static void GenerateDkimKeys(out string privateKey, out string publicKey)
        {
            var rsa = new RSACryptoServiceProvider();
            var rsaKeyInfo = rsa.ExportParameters(true);
            publicKey = "k=rsa; p=" + ConvertPublicKey(rsaKeyInfo);
            privateKey = ConvertPrivateKey(rsaKeyInfo);
        }

        private static string ConvertPublicKey(RSAParameters param)
        {
            var arrBinaryPublicKey = new List<byte>();

            arrBinaryPublicKey.InsertRange(0, param.Exponent);
            arrBinaryPublicKey.Insert(0, (byte)arrBinaryPublicKey.Count);
            arrBinaryPublicKey.Insert(0, INTEGER);

            arrBinaryPublicKey.InsertRange(0, param.Modulus);
            AppendLength(ref arrBinaryPublicKey, param.Modulus.Length);
            arrBinaryPublicKey.Insert(0, INTEGER);

            AppendLength(ref arrBinaryPublicKey, arrBinaryPublicKey.Count);
            arrBinaryPublicKey.Insert(0, SEQUENCE);

            arrBinaryPublicKey.Insert(0, 0x0); // Add NULL value

            AppendLength(ref arrBinaryPublicKey, arrBinaryPublicKey.Count);

            arrBinaryPublicKey.Insert(0, BIT_STRING);
            arrBinaryPublicKey.InsertRange(0, RsaOid);

            AppendLength(ref arrBinaryPublicKey, arrBinaryPublicKey.Count);

            arrBinaryPublicKey.Insert(0, SEQUENCE);

            return Convert.ToBase64String(arrBinaryPublicKey.ToArray());
        }

        private static string ConvertPrivateKey(RSAParameters param)
        {
            var arrBinaryPrivateKey = new List<byte>();

            arrBinaryPrivateKey.InsertRange(0, param.InverseQ);
            AppendLength(ref arrBinaryPrivateKey, param.InverseQ.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.InsertRange(0, param.DQ);
            AppendLength(ref arrBinaryPrivateKey, param.DQ.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.InsertRange(0, param.DP);
            AppendLength(ref arrBinaryPrivateKey, param.DP.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.InsertRange(0, param.Q);
            AppendLength(ref arrBinaryPrivateKey, param.Q.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.InsertRange(0, param.P);
            AppendLength(ref arrBinaryPrivateKey, param.P.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.InsertRange(0, param.D);
            AppendLength(ref arrBinaryPrivateKey, param.D.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.InsertRange(0, param.Exponent);
            AppendLength(ref arrBinaryPrivateKey, param.Exponent.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.InsertRange(0, param.Modulus);
            AppendLength(ref arrBinaryPrivateKey, param.Modulus.Length);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            arrBinaryPrivateKey.Insert(0, 0x00);
            AppendLength(ref arrBinaryPrivateKey, 1);
            arrBinaryPrivateKey.Insert(0, INTEGER);

            AppendLength(ref arrBinaryPrivateKey, arrBinaryPrivateKey.Count);
            arrBinaryPrivateKey.Insert(0, SEQUENCE);

            return Convert.ToBase64String(arrBinaryPrivateKey.ToArray());
        }

        private static void AppendLength(ref List<byte> arrBinaryData, int len)
        {
            if (len <= byte.MaxValue)
            {
                arrBinaryData.Insert(0, Convert.ToByte(len));
                arrBinaryData.Insert(0, 0x81);  //This byte means that the length fits in one byte
            }
            else
            {
                arrBinaryData.Insert(0, Convert.ToByte(len % (byte.MaxValue + 1)));
                arrBinaryData.Insert(0, Convert.ToByte(len / (byte.MaxValue + 1)));
                arrBinaryData.Insert(0, 0x82);  //This byte means that the length fits in two byte
            }

        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Calendar/Wrappers/EventHistoryWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Linq;
using System.Runtime.Serialization;

using ASC.Api.Calendar.BusinessObjects;
using ASC.Api.Calendar.iCalParser;

namespace ASC.Api.Calendar.Wrappers
{
    [DataContract(Name = "eventHistory", Namespace = "")]
    public class EventHistoryWrapper
    {
        public EventHistoryWrapper(EventHistory eventHistory, bool canEdit, bool canNotify, BusinessObjects.Calendar cal, bool fullHistory = true)
        {
            CalendarId = eventHistory.CalendarId;
            EventUid = eventHistory.EventUid;
            EventId = eventHistory.EventId;

            if (fullHistory)
            {
                Ics = eventHistory.Ics;
            }
            else
            {
                var mergedCalendar = eventHistory.GetMerged();
                MergedIcs = mergedCalendar == null ? string.Empty : DDayICalParser.SerializeCalendar(mergedCalendar);
            }

            CanEdit = canEdit;
            CanNotify = canNotify;

            CalendarName = cal.Name;

            TimeZoneInfo = new TimeZoneWrapper(cal.ViewSettings.Any() && cal.ViewSettings.First().TimeZone != null
                                                   ? cal.ViewSettings.First().TimeZone
                                                   : cal.TimeZone);
        }

        [DataMember(Name = "calendarId", Order = 0)]
        public int CalendarId { get; set; }

        [DataMember(Name = "eventUid", Order = 10)]
        public string EventUid { get; set; }

        [DataMember(Name = "eventId", Order = 20)]
        public int EventId { get; set; }

        [DataMember(Name = "mergedIcs", Order = 30)]
        public string MergedIcs { get; set; }

        [DataMember(Name = "canEdit", Order = 40)]
        public bool CanEdit { get; set; }

        [DataMember(Name = "canNotify", Order = 50)]
        public bool CanNotify { get; set; }

        [DataMember(Name = "ics", Order = 60)]
        public string Ics { get; set; }

        [DataMember(Name = "timeZone", Order = 70)]
        public TimeZoneWrapper TimeZoneInfo { get; set; }

        [DataMember(Name = "calendarName", Order = 80)]
        public string CalendarName { get; set; }

        public static object GetSample()
        {
            return new
            {
                calendarId = 1,
                eventUid = "<EMAIL>",
                eventId = 1,
                mergedIcs = "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:onlyoffice.com\r\nBEGIN:VEVENT\r\nUID:uid1@onlyoffice.com\r\nDTSTAMP:19970714T170000Z\r\nORGANIZER;CN=<NAME>:MAILTO:<EMAIL>\r\nDTSTART:19970714T170000Z\r\nDTEND:19970715T035959Z\r\nSUMMARY:Bastille Day Party\r\nEND:VEVENT\r\nEND:VCALENDAR",
                canEdit = true,
                canNotify = true
            };
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SMTP/Server/SMTP_Server.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SMTP.Server
{
    #region usings

    using System;
    using System.Collections.Generic;
    using TCP;

    #endregion

    /// <summary>
    /// This class implements SMTP server.  Defined RFC 5321.
    /// </summary>
    public class SMTP_Server : TCP_Server<SMTP_Session>
    {
        #region Members

        private readonly List<string> m_pServiceExtentions;
        private string m_GreetingText = "";
        private int m_MaxBadCommands = 30;
        private int m_MaxMessageSize = 10000000;
        private int m_MaxRecipients = 100;
        private int m_MaxTransactions = 10;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SMTP_Server()
        {
            m_pServiceExtentions = new List<string>();
            m_pServiceExtentions.Add(SMTP_ServiceExtensions.PIPELINING);
            m_pServiceExtentions.Add(SMTP_ServiceExtensions.SIZE);
            m_pServiceExtentions.Add(SMTP_ServiceExtensions.STARTTLS);
            m_pServiceExtentions.Add(SMTP_ServiceExtensions._8BITMIME);
            m_pServiceExtentions.Add(SMTP_ServiceExtensions.BINARYMIME);
            m_pServiceExtentions.Add(SMTP_ServiceExtensions.CHUNKING);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets server greeting text.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public string GreetingText
        {
            get
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_GreetingText;
            }

            set
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                m_GreetingText = value;
            }
        }

        /// <summary>
        /// Gets or sets how many bad commands session can have before it's terminated. Value 0 means unlimited.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public int MaxBadCommands
        {
            get
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_MaxBadCommands;
            }

            set
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (value < 0)
                {
                    throw new ArgumentException("Property 'MaxBadCommands' value must be >= 0.");
                }

                m_MaxBadCommands = value;
            }
        }

        /// <summary>
        /// Gets or sets maximum message size in bytes.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public int MaxMessageSize
        {
            get
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_MaxMessageSize;
            }

            set
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                if (value < 500)
                {
                    throw new ArgumentException("Property 'MaxMessageSize' value must be >= 500.");
                }

                m_MaxMessageSize = value;
            }
        }

        /// <summary>
        /// Gets or sets maximum allowed recipients per SMTP transaction.
        /// </summary>
        /// <remarks>According RFC 5321 this value SHOULD NOT be less than 100.</remarks>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public int MaxRecipients
        {
            get
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_MaxRecipients;
            }

            set
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (value < 1)
                {
                    throw new ArgumentException("Property 'MaxRecipients' value must be >= 1.");
                }

                m_MaxRecipients = value;
            }
        }

        /// <summary>
        /// Gets or sets maximum mail transactions per session. Value 0 means unlimited.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentException">Is raised when invalid value is passed.</exception>
        public int MaxTransactions
        {
            get
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_MaxTransactions;
            }

            set
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (value < 0)
                {
                    throw new ArgumentException("Property 'MaxTransactions' value must be >= 0.");
                }

                m_MaxTransactions = value;
            }
        }

        /// <summary>
        /// Gets or sets SMTP server supported service extentions.
        /// Supported values: PIPELINING,SIZE,STARTTLS,8BITMIME,BINARYMIME,CHUNKING,DSN.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when null reference passed.</exception>
        public string[] ServiceExtentions
        {
            get
            {
                if (IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pServiceExtentions.ToArray();
            }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("ServiceExtentions");
                }

                m_pServiceExtentions.Clear();

                foreach (string extention in value)
                {
                    if (extention.ToUpper() == SMTP_ServiceExtensions.PIPELINING)
                    {
                        m_pServiceExtentions.Add(SMTP_ServiceExtensions.PIPELINING);
                    }
                    else if (extention.ToUpper() == SMTP_ServiceExtensions.SIZE)
                    {
                        m_pServiceExtentions.Add(SMTP_ServiceExtensions.SIZE);
                    }
                    else if (extention.ToUpper() == SMTP_ServiceExtensions.STARTTLS)
                    {
                        m_pServiceExtentions.Add(SMTP_ServiceExtensions.STARTTLS);
                    }
                    else if (extention.ToUpper() == SMTP_ServiceExtensions._8BITMIME)
                    {
                        m_pServiceExtentions.Add(SMTP_ServiceExtensions._8BITMIME);
                    }
                    else if (extention.ToUpper() == SMTP_ServiceExtensions.BINARYMIME)
                    {
                        m_pServiceExtentions.Add(SMTP_ServiceExtensions.BINARYMIME);
                    }
                    else if (extention.ToUpper() == SMTP_ServiceExtensions.CHUNKING)
                    {
                        m_pServiceExtentions.Add(SMTP_ServiceExtensions.CHUNKING);
                    }
                    else if (extention.ToUpper() == SMTP_ServiceExtensions.DSN)
                    {
                        m_pServiceExtentions.Add(SMTP_ServiceExtensions.DSN);
                    }
                }
            }
        }

        /// <summary>
        /// Gets SMTP service extentions list.
        /// </summary>
        internal List<string> Extentions
        {
            get { return m_pServiceExtentions; }
        }

        #endregion

        // TODO:

        //public override Dispose

        #region Overrides

        /// <summary>
        /// Is called when new incoming session and server maximum allowed connections exceeded.
        /// </summary>
        /// <param name="session">Incoming session.</param>
        /// <remarks>This method allows inhereted classes to report error message to connected client.
        /// Session will be disconnected after this method completes.
        /// </remarks>
        protected override void OnMaxConnectionsExceeded(SMTP_Session session)
        {
            session.TcpStream.WriteLine(
                "421 Client host rejected: too many connections, please try again later.");
        }

        /// <summary>
        /// Is called when new incoming session and server maximum allowed connections per connected IP exceeded.
        /// </summary>
        /// <param name="session">Incoming session.</param>
        /// <remarks>This method allows inhereted classes to report error message to connected client.
        /// Session will be disconnected after this method completes.
        /// </remarks>
        protected override void OnMaxConnectionsPerIPExceeded(SMTP_Session session)
        {
            session.TcpStream.WriteLine("421 Client host rejected: too many connections from your IP(" +
                                        session.RemoteEndPoint.Address + "), please try again later.");
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/Services/ASC.Mail.Reloader/Program.Options.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using CommandLine;
using CommandLine.Text;

namespace ASC.Mail.Reloader
{
    internal partial class Program
    {
        private sealed class Options
        {
            [Option('i', "id", Required = false, DefaultValue = -1, HelpText = "Id mailbox from MySQL DB.")]
            public int MailboxId { get; set; }

            [Option('m', "mid", Required = false, DefaultValue = -1, HelpText = "Message id for reload.")]
            public int MessageId { get; set; }

            [Option('j', "json_path", Required = false, DefaultValue = null, HelpText = "Path to json file (ex. { \"data\": [ { \"id_mailbox\": 2649,\"id\": 27325207 } ] } ).")]
            public string PathToJson { get; set; }

            [ParserState]
            public IParserState LastParserState { get; set; }

            [HelpOption]
            public string GetUsage()
            {
                return HelpText.AutoBuild(this, current => HelpText.DefaultParsingErrorsHandler(this, current));
            }
        }
    }
}


<|start_filename|>common/ASC.Data.Storage/Encryption/IEncryptionService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.ServiceModel;

using ASC.Core.Encryption;

namespace ASC.Data.Storage.Encryption
{
    [ServiceContract]
    public interface IEncryptionService
    {
        [OperationContract]
        void Start(EncryptionSettings encryptionSettings, string serverRootPath);

        [OperationContract]
        double GetProgress();

        [OperationContract]
        void Stop();
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Helpers/EasyBibHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Logging;
using ASC.Core.Common.Configuration;
using ASC.FederatedLogin.Helpers;
using ASC.Web.Files.Classes;

using Newtonsoft.Json.Linq;

namespace ASC.Web.Files.Helpers
{
    public class EasyBibHelper : Consumer
    {
        public static ILog Log = Global.Logger;

        static readonly string searchBookUrl = "https://worldcat.citation-api.com/query?search=",
                        searchJournalUrl = "https://crossref.citation-api.com/query?search=",
                        searchWebSiteUrl = "https://web.citation-api.com/query?search=",
                        easyBibStyles = "https://api.citation-api.com/2.1/rest/styles";

        public enum EasyBibSource
        {
            book = 0,
            journal = 1,
            website = 2
        }

        public string AppKey
        {
            get { return this["easyBibappkey"]; }
        }

        public EasyBibHelper()
        {

        }

        public EasyBibHelper(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
            : base(name, order, props, additional)
        {
        }

        public static string GetEasyBibCitationsList(int source, string data)
        {
            var uri = "";
            switch (source)
            {
                case 0:
                    uri = searchBookUrl;
                    break;
                case 1:
                    uri = searchJournalUrl;
                    break;
                case 2:
                    uri = searchWebSiteUrl;
                    break;
                default:
                    break;
            }
            uri += data;

            const string method = "GET";
            var headers = new Dictionary<string, string>() { };
            try
            {
                return RequestHelper.PerformRequest(uri, "", method, "", headers);
            }
            catch (Exception)
            {
                return "error";
            }

        }

        public static string GetEasyBibStyles()
        {

            const string method = "GET";
            var headers = new Dictionary<string, string>() { };
            try
            {
                return RequestHelper.PerformRequest(easyBibStyles, "", method, "", headers);
            }
            catch (Exception)
            {
                return "error";
            }
        }
        public static object GetEasyBibCitation(string data)
        {
            try
            {
                var easyBibappkey = ConsumerFactory.Get<EasyBibHelper>().AppKey;

                var jsonBlogInfo = JObject.Parse(data);
                jsonBlogInfo.Add("key", easyBibappkey);
                var citationData = jsonBlogInfo.ToString();

                var uri = "https://api.citation-api.com/2.0/rest/cite";
                const string contentType = "application/json";
                const string method = "POST";
                var body = citationData;
                var headers = new Dictionary<string, string>() { };

                return RequestHelper.PerformRequest(uri, contentType, method, body, headers);

            }
            catch (Exception)
            {
                return null;
                throw;
            }

        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Helpers/ApiSystemHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Web;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.Security.Cryptography;
using ASC.Web.Studio.Utility;

using Newtonsoft.Json.Linq;

namespace ASC.Web.Core.Helpers
{
    public class ApiSystemHelper
    {
        public static string ApiSystemUrl { get; private set; }

        public static string ApiCacheUrl { get; private set; }

        private static byte[] Skey { get; set; }

        static ApiSystemHelper()
        {
            ApiSystemUrl = ConfigurationManagerExtension.AppSettings["web.api-system"];
            ApiCacheUrl = ConfigurationManagerExtension.AppSettings["web.api-cache"];
            Skey = MachinePseudoKeys.GetMachineConstant();
        }


        public static string CreateAuthToken(string pkey)
        {
            using (var hasher = new HMACSHA1(Skey))
            {
                var now = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
                var hash = HttpServerUtility.UrlTokenEncode(hasher.ComputeHash(Encoding.UTF8.GetBytes(string.Join("\n", now, pkey))));
                return string.Format("ASC {0}:{1}:{2}", pkey, now, hash);
            }
        }

        #region system

        public static void ValidatePortalName(string domain)
        {
            try
            {
                var data = string.Format("portalName={0}", HttpUtility.UrlEncode(domain));
                SendToApi(ApiSystemUrl, "portal/validateportalname", WebRequestMethods.Http.Post, data);
            }
            catch (WebException exception)
            {
                if (exception.Status != WebExceptionStatus.ProtocolError || exception.Response == null) return;

                var response = exception.Response;
                try
                {
                    using (var stream = response.GetResponseStream())
                    using (var reader = new StreamReader(stream, Encoding.UTF8))
                    {
                        var result = reader.ReadToEnd();

                        var resObj = JObject.Parse(result);
                        if (resObj["error"] != null)
                        {
                            if (resObj["error"].ToString() == "portalNameExist")
                            {
                                var varians = resObj.Value<JArray>("variants").Select(jv => jv.Value<String>());
                                throw new TenantAlreadyExistsException("Address busy.", varians);
                            }

                            throw new Exception(resObj["error"].ToString());
                        }
                    }
                }
                finally
                {
                    if (response != null)
                    {
                        response.Close();
                    }
                }
            }
        }

        #endregion

        #region cache

        public static void AddTenantToCache(string domain)
        {
            var data = string.Format("portalName={0}", HttpUtility.UrlEncode(domain));
            SendToApi(ApiCacheUrl, "portal/add", WebRequestMethods.Http.Post, data);
        }

        public static void RemoveTenantFromCache(string domain)
        {
            SendToApi(ApiCacheUrl, "portal/remove?portalname=" + HttpUtility.UrlEncode(domain), "DELETE");
        }

        public static IEnumerable<string> FindTenantsInCache(string domain)
        {
            var result = SendToApi(ApiCacheUrl, "portal/find?portalname=" + HttpUtility.UrlEncode(domain), WebRequestMethods.Http.Get);
            var resObj = JObject.Parse(result);

            var variants = resObj.Value<JArray>("variants");
            return variants == null
                       ? null
                       : variants.Select(jv => jv.Value<String>()).ToList();
        }

        #endregion

        private static string SendToApi(string absoluteApiUrl, string apiPath, string httpMethod, string data = null)
        {
            Uri uri;
            if (!Uri.TryCreate(absoluteApiUrl, UriKind.Absolute, out uri))
            {
                var appUrl = CommonLinkUtility.GetFullAbsolutePath("/");
                absoluteApiUrl = string.Format("{0}/{1}", appUrl.TrimEnd('/'), absoluteApiUrl.TrimStart('/')).TrimEnd('/');
            }

            var url = String.Format("{0}/{1}", absoluteApiUrl, apiPath);

            var webRequest = (HttpWebRequest)WebRequest.Create(url);
            webRequest.Method = httpMethod;
            webRequest.Accept = "application/json";
            webRequest.Headers.Add(HttpRequestHeader.Authorization, CreateAuthToken(SecurityContext.CurrentAccount.ID.ToString()));
            webRequest.ContentType = "application/x-www-form-urlencoded";
            webRequest.ContentLength = 0;

            if (data != null)
            {
                webRequest.ContentLength = data.Length;

                using (var writer = new StreamWriter(webRequest.GetRequestStream()))
                {
                    writer.Write(data);
                }
            }

            using (var response = webRequest.GetResponse())
            using (var stream = response.GetResponseStream())
            using (var reader = new StreamReader(stream, Encoding.UTF8))
            {
                return reader.ReadToEnd();
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/js/taskdescription.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.Projects.TaskDescriptionPage = (function() {
    var currentTask = {},
        tasks = [],
        taskId = undefined,
        projId = undefined,
        currentUserId,
        commentIsEdit = false,
        listAllProjectTasks = {},
        listOpenTasks = [],
        listValidTaskForLink = [],
        linkedTasksIds = [],
        relatedTasks = {},
        editedLink = null,
        reloadedTaskListFlag = false,
        overInvalidLinkHint = false,
        projectFolderId;

    var
        overViewTab,
        subtaskTab,
        documentsTab,
        linksTab,
        commentsTab,
        ganttTab,
        timeTrackingTab;

    var $editLinkBox,
        $relatedTasksCont,
        $taskSelector,
        $linkTypeSelector,
        $addTaskLinkButton,
        $createAddTaskLinkButton,
        $hintInvalidLink,
        $subtaskContainer,
        $filesContainer,
        $commentContainer,
        $mainCommentContainer,
        $subtasks,
        $linkedTasksContainer,
        $linkedTasksButtons;

    var baseObject = ASC.Projects,
        resources = baseObject.Resources,
        projectsJsResource = resources.ProjectsJSResource,
        TaskResource = resources.TaskResource,
        common = baseObject.Common,
        master = baseObject.Master,
        teamlab,
        attachments,
        loadingBanner,
        handlers = [];

    var displayNoneClass = "display-none",
        clickEventName = "click";

    var init = function () {
        baseObject.Base.clearTables();
        jq("#filterContainer").hide();
        $subtaskContainer = jq("#subtaskContainer");
        $filesContainer = jq("#filesContainer");
        $commentContainer = jq("#commonCommentsContainer");
        $mainCommentContainer = $commentContainer.find("#mainCommentsContainer");
        $subtasks = $subtaskContainer.find(".subtasks");

        jq(".tab1").html(jq.tmpl("projects_taskLinksContainer", { canEdit: false, tasks: [] }));
        $linkedTasksContainer = jq("#linkedTasksContainer");

        teamlab = Teamlab;

        loadingBanner = LoadingBanner;
        loadingBanner.displayLoading();

        currentUserId = Teamlab.profile.id;
        jq("#CommonListContainer").show();

        var events = teamlab.events;
        bind(events.addSubtask, onAddSubtask);
        bind(events.removeSubtask, onRemoveSubtask);
        bind(events.updateSubtask, onUpdateSubtaskStatus);
        //bind(events.addPrjTask, onAddTask);
        bind(events.updatePrjTask, onUpdateTask);
        bind(events.removePrjTask, onRemoveTask);
        bind(events.addPrjComment, function () {
            if (!commentIsEdit) {
                if (CommentsManagerObj.editorInstance.getData()) {
                    currentTask.commentsCount++;
                    commentsTab.rewrite();
                }
            }
            else {
                commentIsEdit = false;
            }
        });

        baseObject.SubtasksManager.init();
        ASC.Projects.Base.initActionPanel(baseObject.SubtasksManager.showEntityMenu, $subtasks);


        projId = jq.getURLParam("prjID");

        var id = jq.getURLParam("id");

        common.initCustomStatuses(function () {
            if (id != null) {
                teamlab.getPrjTask({},
                    id,
                    {
                        success: onGetTaskDescription,
                        error: function (params, errors) {
                            if (errors[0] === "Item not found") {
                                ASC.Projects.Base.setElementNotFound();
                            }
                        }
                    });
            } else {
                loadingBanner.hideLoading();
            }
        });
    };

    function initAttachmentsControl() {
        projectFolderId = currentTask.project.projectFolder;

        var entityType = "task";
        attachments = Attachments;

        if (!currentTask.canEdit) {
            attachments.banOnEditing();
        }

        ProjectDocumentsPopup.init(projectFolderId, attachments.isAddedFile, attachments.appendToListAttachFiles);
        attachments.isLoaded = false;
        attachments.init(entityType, function() { return currentTask.id });
        attachments.setFolderId(projectFolderId);
        attachments.loadFiles(currentTask.files);

        function addFileSuccess(file) {
            currentTask.files.push(file);
            documentsTab.rewrite();
        }

        attachments.bind("addFile", function (ev, file) {
            if (file.attachFromPrjDocFlag || file.isNewFile) {
                teamlab.addPrjEntityFiles(null,
                    taskId,
                    entityType,
                    [file.id],
                    { success: function() { addFileSuccess(file); } });
            } else {
                addFileSuccess(file);
            }
        });

        attachments.bind("deleteFile", function (ev, fileId) {
            teamlab.removePrjEntityFiles({}, taskId, entityType, fileId, {
                success: function () {
                currentTask.files = currentTask.files.filter(function (item) { return item.id != fileId; });
                attachments.deleteFileFromLayout(fileId);
                documentsTab.rewrite();
            }});
        });

        attachments.bind("loadAttachments", function (ev, count) {
            if (count < 1) {
                $filesContainer.show();
            }
        });
    };

    function hideRemovedComments(comments) {
        comments.forEach(function (item) {
            if (item.commentList.length) {
                item.commentList = hideRemovedComments(item.commentList);
            }
        });

        comments = comments.filter(function (item) {
            return !(item.inactive && item.commentList.length === 0);
        });

        return comments;
    }

    function getProjectTasks() {
        linkedTasksIds = [];
        var filter = common.filterParamsForListTasks;
        filter.projectId = projId;
        filter.status = 1;
        filter.milestone = currentTask.milestone ? currentTask.milestoneId : 0;

        if (currentTask.links) {
            for (var i = 0; i < currentTask.links.length; i++) {
                var linkTaskId;
                if (currentTask.links[i].parentTaskId == currentTask.id) {
                    linkTaskId = currentTask.links[i].dependenceTaskId;
                } else {
                    linkTaskId = currentTask.links[i].parentTaskId;
                }
                linkedTasksIds.push(linkTaskId);
                relatedTasks[linkTaskId] = currentTask.links[i];
            }
        }

        teamlab.getPrjTasks({}, { success: onGetOpenTask, filter: filter });
    };

    function hideHintInvalidLink() {
        setTimeout(function () {
            if (!overInvalidLinkHint) $hintInvalidLink.hide(100);
        }, 200);
    };

    function initCommentsBlock(task) {
        CommentsManagerObj.isShowAddCommentBtn = task.canCreateComment;
        CommentsManagerObj.total = task.comments.length;
        CommentsManagerObj.isEmpty = task.comments.length === 0;
        CommentsManagerObj.moduleName = "projects_Task";
        CommentsManagerObj.comments = jq.base64.encode(JSON.stringify(task.comments));
        CommentsManagerObj.objectID = "common";
        CommentsManagerObj.Init();
        CommentsManagerObj.objectID = task.id;
        jq("#hdnObjectID").val(task.id);

        jq("#commentsTitle").remove();
        $mainCommentContainer.css("width", 100 + "%");

        //-------------Comments-------------//
        var commentsClick = clickEventName + ".comments";
        jq("#btnCancel").off(commentsClick).on(commentsClick, function () {
            commentIsEdit = false;
            commentsTab.select();
        });

        jq("#mainCommentsContainer div[id^='container_'] a[id^='edit_']").off(commentsClick).on(commentsClick, function () {
            commentIsEdit = true;
        });


        jq(document).off("keydown.taskdescr").on("keydown.taskdescr", function (e) {
            if (e.keyCode == 27) {
                hideEditBox(true);
                $linkedTasksButtons.show();
            }
        });
    };

    function displaySubtasks(task) {
        $subtasks.empty();
        $subtasks.attr("taskid", task.id);
        var projectsTaskDescriptionSubtasksContainerTmplName = "projects_taskDescriptionSubtasksContainerTmpl";
        if (task.subtasks.length == 0) {
            jq.tmpl(projectsTaskDescriptionSubtasksContainerTmplName, task).prependTo($subtasks);
        }
        else {
            jq.tmpl(projectsTaskDescriptionSubtasksContainerTmplName, task).prependTo($subtasks);
            $subtasks.find(".st_separater").after($subtasks.find('.closed'));

            if (task.status == 2) {
                $subtasks.find(".quickAddSubTaskLink").remove();
                $subtasks.find(".subtask .check input").attr('disabled', true);
            }
            if (subtaskTab.selected) {
                $subtasks.show();
            }
        }

        jq(document).off("keydown.description").on("keydown.description", ".subtask-name-input", function (e) {
            switch (e.which) {
                case 27:
                    subtaskTab.select();
                    break;
            }
        });
    };
    
    function taAcceptHandler() {
        var data = {
            title: currentTask.title,
            responsibles: [currentUserId],
            description: currentTask.description,
            priority: currentTask.priority
        };

        if (currentTask.deadline) {
            data.deadline = currentTask.deadline;
        }

        if (currentTask.milestoneId) {
            data.milestoneid = currentTask.milestoneId;
        }

        teamlab.updatePrjTask({}, taskId, data);

        return false;
    };

    // task actions
    function taCloseHandler() {
        if ($subtasks.find(".subtask").length != $subtasks.find(".subtask.closed").length) {
            showQuestionWindow.call(this);
        }
        else {
            closeTask.call(this);
        }
    };

    function taResumeHandler() {
        jq("body").css("cursor", "wait");

        teamlab.updatePrjTask({}, taskId, { 'status': 1, "statusId": this.id }, { success: onChangeTaskStatus });

        jq(".pm_taskTitleClosedByPanel").hide();
    };

    function taEditHandler() {
        baseObject.TaskAction.showUpdateTaskForm(currentTask);
    };

    function taRemoveHandler() {
        ASC.Projects.Base.showCommonPopup("taskRemoveWarning", function () {
            teamlab.removePrjTask({}, taskId);
        });
    };

    function taStartTimerHandler() {
        common.showTimer(currentTask.projectId, currentTask.id);
    };


    function ltaEditHandler(taskid) {
        showEditLinkBox(true, taskid);
    };

    function ltaRemoveHandler(taskid) {
        removeTaskLink(taskid, true);
    };

    function displayTotalInfo(task) {
        var closedBy = "";

        var time = jq.timeFormat(task.timeSpend).split(":");
        var timeSpend = {
            hours: time[0],
            minutes: time[1]
        };

        if (task.status == 2) {
            if (task.updatedBy != undefined)
                closedBy = task.updatedBy.displayName;
            else
                closedBy = task.createdBy.displayName;
        }

        var statusAvailable = task.createdBy.id === currentUserId ||
            master.IsModuleAdmin ||
            task.project.responsible.id === currentUserId;

        var statuses = master.customStatuses
            .filter(function (item) {
                return statusAvailable || item.available;
            })
            .map(function(item) {
                return {
                    title: item.title,
                    handler: item.statusType === 1 ? taResumeHandler : taCloseHandler,
                    id: (Math.abs(item.id)).toString()
                };
            });

        var currentStatus = master.customStatuses.find(function (item) {
            if (task.customTaskStatus) {
                return item.id === task.customTaskStatus;
            }

            return item.statusType === task.status;
        });
        var descriptionTab = ASC.Projects.DescriptionTab;
        
        descriptionTab.init()
            .push(resources.ProjectResource.Project, formatDescription(task.projectOwner.title), "Tasks.aspx?prjID=" + task.projectOwner.id)
            .push(resources.MilestoneResource.Milestone, task.milestone ? jq.format('[{0}] {1}', task.milestone.displayDateDeadline, task.milestone.title) : '')
            .push(TaskResource.TaskStartDate, task.displayDateStart)
            .push(TaskResource.EndDate, task.displayDateDeadline, undefined, ASC.Projects.TasksManager.compareDates(task.deadline) ? "<span class='deadlineLate'>{0}</span>" : undefined)
            .push(TaskResource.Priority, task.priority === 1 ? TaskResource.HighPriority : undefined, undefined, '<span class="colorPriority high"><span>{0}</span></span>')
            .push(TaskResource.AssignedTo, task.responsibles.length === 0 ? TaskResource.WithoutResponsible : task.responsibles.map(function (item) { return item.displayName }).join(', '))
            .push(resources.ProjectsCommonResource.SpentTotally, task.canCreateTimeSpend && task.timeSpend ? jq.format("{0} {1}", timeSpend.hours + resources.TimeTrackingResource.ShortHours, timeSpend.minutes + resources.TimeTrackingResource.ShortMinutes) : '', "TimeTracking.aspx?prjID=" + task.projectOwner.id + "&id=" + task.id)
            .push(TaskResource.CreatingDate, task.displayDateCrtdate)
            .push(TaskResource.TaskProducer, task.createdBy.displayName)
            .push(TaskResource.ClosingDate, task.status === 2 ? task.displayDateUptdate : '')
            .push(TaskResource.ClosedBy, closedBy)
            .push(resources.ProjectsCommonResource.Description, jq.linksParser(formatDescription(task.description)))
            .setStatuses(statuses)
            .setCurrentStatus(currentStatus)
            .setStatusRight(currentTask.canEdit)
            .tmpl();

        if (overViewTab.selected) {
            descriptionTab.show();
        } else {
            descriptionTab.hide();
        }

        if (!task.canEdit) {
            jq("div.buttonContainer").remove();
        }

        if (task.timeSpend) {
            jq(".timeSpend").show();
        }
        jq(".subscribeLink").show();
    };

    function checkValidLinkTypeForTask(taskId){
        var task = listAllProjectTasks[taskId];

        var currentTaskStart = currentTask.startDate ? currentTask.startDate : currentTask.crtdate;
        var taskStart = task.startDate ? task.startDate : task.crtdate;

        var currentTaskDeadline = currentTask.deadline ? currentTask.deadline : undefined;
        var taskDeadline = task.deadline ? task.deadline : undefined;

        var validLinkFlag = true;
        var possibleLinkTypes = common.getPossibleTypeLink(currentTaskStart, currentTaskDeadline, taskStart, taskDeadline, validLinkFlag);

        if (possibleLinkTypes[2] == common.linkTypeEnum.start_end) {
            $linkTypeSelector.text(projectsJsResource.RelatedLinkTypeSE).data("value", common.linkTypeEnum.start_end);
        } else {
            $linkTypeSelector.text(projectsJsResource.RelatedLinkTypeES).data("value", common.linkTypeEnum.end_start);
        }
    };

    function getDelay(firstDate, secondDate){
        var delay = Math.abs(firstDate.getTime() - secondDate.getTime());
        delay = Math.floor(delay / 1000 / 60 / 60 / 24);
        if(delay == 0) return 0;
        if (delay == 1) {
            return delay + " " + projectsJsResource.DelayDay;
        } else {
            return delay + " " + projectsJsResource.DelayDays;
        }
    };

    function getRelatedTaskObject(firstTask, secondTask, link) {

        var firstTaskStart = firstTask.startDate ? firstTask.startDate : firstTask.crtdate;
        var secondTaskStart = secondTask.startDate ? secondTask.startDate : secondTask.crtdate;
        var firstTaskDeadline = firstTask.deadline ? firstTask.deadline : firstTask.milestone ? firstTask.milestone.deadline : undefined;
        var secondTaskDeadline = secondTask.deadline ? secondTask.deadline : secondTask.milestone ? secondTask.milestone.deadline : undefined;

        var relatedTaskObject = {};
        relatedTaskObject.invalidLink = false;
        relatedTaskObject.delay = 0;
        relatedTaskObject.possibleLinkType = common.getPossibleTypeLink(firstTaskStart, firstTaskDeadline, secondTaskStart, secondTaskDeadline, relatedTaskObject);


        relatedTaskObject.linkType = link.linkType;

        if (link.linkType == 2) {
            if (link.parentTaskId == currentTask.id) {
                relatedTaskObject.linkType = common.linkTypeEnum.end_start;
                if (relatedTaskObject.possibleLinkType[3] != common.linkTypeEnum.end_start) {
                    relatedTaskObject.invalidLink = true;
                }
            } else {
                relatedTaskObject.linkType = common.linkTypeEnum.start_end;
                if (relatedTaskObject.possibleLinkType[2] != common.linkTypeEnum.start_end) {
                    relatedTaskObject.invalidLink = true;
                }
            }
        }

        switch (relatedTaskObject.linkType) {
            case common.linkTypeEnum.start_start:
                relatedTaskObject.linkTypeText = projectsJsResource.RelatedLinkTypeSS;
                relatedTaskObject.delay = getDelay(firstTaskStart, secondTaskStart);
                relatedTaskObject.invalidLink = false;
                break;
            case common.linkTypeEnum.end_end:
                relatedTaskObject.linkTypeText = projectsJsResource.RelatedLinkTypeEE;
                relatedTaskObject.delay = getDelay(firstTaskDeadline, secondTaskDeadline);
                relatedTaskObject.invalidLink = false;
                break;
            case common.linkTypeEnum.start_end:
                relatedTaskObject.linkTypeText = projectsJsResource.RelatedLinkTypeSE;
                relatedTaskObject.delay = getDelay(secondTaskDeadline, firstTaskStart);
                break;
            case common.linkTypeEnum.end_start:
                relatedTaskObject.linkTypeText = projectsJsResource.RelatedLinkTypeES;
                relatedTaskObject.delay = getDelay(firstTaskDeadline, secondTaskStart);
                break;
            default: break;
        }

        return relatedTaskObject;
    };

    function getRelatedTaskTmpl(taskId, link) {
        var task = listAllProjectTasks[taskId];
        
        if (task) {
            task.relatedTaskObject = getRelatedTaskObject(currentTask, task, link);
            return task;
        } else {
            return null;
        }
    };

    function showEditLinkBox(editFlag, taskId) {
        if (editFlag) {
            var taskCont = $relatedTasksCont.find("tr[data-taskid="+taskId+"]");
            $editLinkBox.css("position", "absolute");

            var marginTop = taskCont.offset().top - jq("#linkedTasksContainer").offset().top - 1 + "px";
            $editLinkBox.css("top", marginTop);
            $editLinkBox.attr("data-edit", "edit");

            var option = $taskSelector.find("option[value="+taskId+"]");
            option.removeClass(displayNoneClass);
            option.prop("selected", true);
            $taskSelector.change();

            var link = relatedTasks[taskId];
            editedLink = link;
            editedLink.targetTaskId = taskId;

            var linkType = parseInt(taskCont.find(".link-type").data("type"));
            $linkTypeSelector.data("value", linkType);
            //linkTypeSelector.val(linkType);
        } else {
            if ($editLinkBox.is(":visible")) {
                hideEditBox(true);
            }
            $editLinkBox.addClass("border-top");
            $editLinkBox.addClass("border-bottom");
            $relatedTasksCont.css("marginTop", "0");
            $taskSelector.val("-1");
            $linkTypeSelector.text("");
            //linkTypeSelector.prop("disabled", true);
        }
        $editLinkBox.removeClass(displayNoneClass);
    };

    function hideEditBox(escapeFlag){
        if (editedLink) {
            if(escapeFlag){
                $taskSelector.find("option[value=" + editedLink.targetTaskId + "]").addClass(displayNoneClass);
            }
            editedLink = null;
        }
        $taskSelector.val("-1");
        //linkTypeSelector.val("-1");
        //linkTypeSelector.find("option").prop("disabled", false);
        $editLinkBox.css("position", "static");
        $editLinkBox.removeClass("border-top");
        $editLinkBox.removeClass("border-bottom");
        $editLinkBox.addClass(displayNoneClass);

        if (linksTab.selected) {
            linksTab.select();
        }
    };

    function initTaskLinkSelect(){
        var option = $taskSelector.find("option:first");
        $taskSelector.empty();
        $taskSelector.append(option);
        for (var i = 0, max = listValidTaskForLink.length; i < max; i++) {
            option = document.createElement('option');
            option.setAttribute("value", listValidTaskForLink[i].id);
            if (relatedTasks[listValidTaskForLink[i].id]) {
                option.setAttribute("class", displayNoneClass);
            }
            option.appendChild(document.createTextNode(listValidTaskForLink[i].title));
            $taskSelector.append(option);
        }
    };
    
    function disableCreateLinkButton() {
        if ($taskSelector.find("." + displayNoneClass).length == $taskSelector.find("option").length - 1 || currentTask.status == 2) {
            $createAddTaskLinkButton.addClass("disabled");
        } else {
            $createAddTaskLinkButton.removeClass("disabled");
        }
    };

    function displayRelatedTasks() {
        var tasksForTmpl = [];
        var linksCount = currentTask.links.length;
        for (var i = 0; i < linksCount; i++) {          //TODO: rewrite for relatedTasks
            var linkTaskId;
            if (currentTask.links[i].parentTaskId == currentTask.id) {
                linkTaskId = currentTask.links[i].dependenceTaskId;
            } else {
                linkTaskId = currentTask.links[i].parentTaskId;
            }
            tasksForTmpl.push(getRelatedTaskTmpl(linkTaskId, currentTask.links[i]));
        }

        jq(".tab1").html(jq.tmpl("projects_taskLinksContainer", { canEdit: currentTask.canEdit, tasks: tasksForTmpl })).show();
        $linkedTasksContainer = jq("#linkedTasksContainer");
        linksTab.$container = $linkedTasksContainer;

        $editLinkBox = jq("#editTable");
        $relatedTasksCont = jq("#relatedTasks");
        $taskSelector = jq("#taskSelector");
        $linkTypeSelector = jq("#linkTypeSelector");
        $addTaskLinkButton = jq("#addLink");
        $createAddTaskLinkButton = jq("#addNewLink");
        $hintInvalidLink = jq("#hintInvalidLink");
        $linkedTasksButtons = jq(".linked-tasks-buttons");

        ASC.Projects.Base.initActionPanel(showLinkEntityMenu, $linkedTasksContainer);

        $relatedTasksCont.on("mouseenter", ".invalid-link", function () {
            overInvalidLinkHint = true;
            var elem = this;
            setTimeout(function () {
                if (!overInvalidLinkHint) return;
                jq(elem).helper({
                    BlockHelperID: "hintInvalidLink",
                    addLeft: 8,
                    addTop: 14
                });
            }, 1000);
        });

        $relatedTasksCont.on("mouseleave", ".invalid-link", function () {
            overInvalidLinkHint = false;
            hideHintInvalidLink();
        });

        $hintInvalidLink.mouseenter(function () {
            overInvalidLinkHint = true;
        });

        $hintInvalidLink.mouseleave(function () {
            overInvalidLinkHint = false;
            hideHintInvalidLink();
        });

        $createAddTaskLinkButton.on(clickEventName, function () {
            if ($createAddTaskLinkButton.hasClass("disabled")) return;
            $linkedTasksButtons.hide();
            showEditLinkBox(false, {});
        });

        $addTaskLinkButton.on(clickEventName, function () {
            var link = {};
            var linkType = parseInt($linkTypeSelector.data("value"));//linkTypeSelector.val()

            if (linkType == "-1" || $taskSelector.val() == "-1") {
                hideEditBox();
                $linkedTasksButtons.show();
                return;
            }

            if (linkType == 2) {
                link = { parentTaskId: $taskSelector.val(), dependenceTaskId: currentTask.id, linkType: linkType };
            } else {
                link = { parentTaskId: currentTask.id, dependenceTaskId: $taskSelector.val(), linkType: linkType };
            }

            if (linkType == 3) {
                link.linkType = 2;
            }

            loadingBanner.displayLoading();
            if (!editedLink) {
                addTaskLink(link);
            } else {
                removeTaskLink(editedLink.targetTaskId, false);
                addTaskLink(link, editedLink.targetTaskId);
            }
        });
        $taskSelector.change(function () {
            var taskId = $taskSelector.val();
            if (taskId != "-1") {
                checkValidLinkTypeForTask(taskId);
                //linkTypeSelector.prop("disabled", false);
            }
        });

        if (linksTab.selected) {
            linksTab.select();
        }
    }


    function displayNewRelatedTask(link, element){
        if (currentTask.links) {
            currentTask.links.push(link);
        } else {
            currentTask.links = [];
            currentTask.links.push(link);
        }
        var linkTaskId;
        if (link.parentTaskId == currentTask.id) {
            linkTaskId = link.dependenceTaskId;
        } else {
            linkTaskId = link.parentTaskId;
        }
        relatedTasks[linkTaskId] = link;
        var taskForTmpl = getRelatedTaskTmpl(linkTaskId, link);
        if (element) {
            element.after(jq.tmpl("projects_taskLinks", [taskForTmpl]));
        } else {
            jq.tmpl("projects_taskLinks", [taskForTmpl]).prependTo($relatedTasksCont);
        }
        $taskSelector.find("option[value=" + linkTaskId + "]").addClass(displayNoneClass);
    }

    function displayTaskDescription(task) {
        displayTotalInfo(task);
        displaySubtasks(task);
        initCommentsBlock(task);
    }

    function showQuestionWindow() {
        ASC.Projects.Base.showCommonPopup("closedTaskQuestion", closeTask.bind(this), cancelCloseTask);
    }

    function subscribeTask() {
        teamlab.subscribeToPrjTask({}, taskId, { success: function() {
            currentTask.isSubscribed = !currentTask.isSubscribed;
        }});
    };

    function addTaskLink(link, removedLinkTaskId){
        teamlab.addPrjTaskLink({link: link, removedLinkTaskId: removedLinkTaskId }, link.parentTaskId, link, { success: onAddTaskLink, error: onAddTaskLinkError });
    };

    function removeTaskLink(taskId, removeElemFlag) {
        var link = relatedTasks[taskId];
        teamlab.removePrjTaskLink({ taskId: taskId, removeElemFlag: removeElemFlag }, link.dependenceTaskId, { dependenceTaskId: link.dependenceTaskId, parentTaskId: link.parentTaskId }, { success: onRemoveTaskLink, error: function (params, error) { } });
    };

    function notifyTaskResponsible() {
        teamlab.notifyPrjTaskResponsible({}, taskId, { success: function () {
            common.displayInfoPanel(TaskResource.MessageSend);
        }});
    };

    function showEntityMenu() {
        var menuItems = [],
            ActionMenuItem = ASC.Projects.ActionMenuItem;

        if (currentTask.status !== 2 && currentTask.canEdit) {
            if (currentTask.responsibles.length === 0) {
                menuItems.push(new ActionMenuItem("ta_accept", TaskResource.Accept, taAcceptHandler));
            }

            menuItems.push(new ActionMenuItem("ta_edit", TaskResource.EditTask, taEditHandler));

            if (currentTask.responsibles.length && currentTask.responsibles.some(function (item) { return item.id != currentUserId; })) {
                menuItems.push(new ActionMenuItem("ta_mesres", TaskResource.MessageResponsible, notifyTaskResponsible));
            }
        }

        if (currentTask.canCreateTimeSpend) {
            menuItems.push(new ActionMenuItem("ta_startTimer", resources.ProjectsCommonResource.AutoTimer, taStartTimerHandler));
        }

        if (typeof (currentTask.isSubscribed) !== "undefined") {
            menuItems.push(new ActionMenuItem("ta_follow", currentTask.isSubscribed ? TaskResource.UnfollowTask : TaskResource.FollowTask, subscribeTask));
        }

        if (currentTask.canDelete) {
            menuItems.push(new ActionMenuItem("ta_remove", TaskResource.RemoveTask, taRemoveHandler));
        }

        return { menuItems: menuItems };
    }

    function showLinkEntityMenu(selectedActionCombobox) {
        var taskid = selectedActionCombobox.data("taskid");

        var menuItems = [
            new ASC.Projects.ActionMenuItem("lta_edit", TaskResource.Edit, ltaEditHandler.bind(null, taskid), "edit"),
            new ASC.Projects.ActionMenuItem("lta_remove", resources.ProjectsCommonResource.Delete, ltaRemoveHandler.bind(null, taskid), "delete")
        ];

        return { menuItems: menuItems };
    }

    /*--------event handlers--------*/

    function onRemoveTaskLink(params, task) {
        if (params.removeElemFlag) {
            $relatedTasksCont.find("tr[data-taskid=" + params.taskId + "]").remove();
            loadingBanner.hideLoading();
        }

        currentTask.links = currentTask.links.filter(function(item) {
            return item.dependenceTaskId != params.taskId && item.parentTaskId != params.taskId;
        });
        if (params.removeElemFlag) {
            linksTab.select();
        }

        delete relatedTasks[params.taskId];
        editedLink = null;
        $taskSelector.find("option[value=" + params.taskId + "]").removeClass(displayNoneClass);
        disableCreateLinkButton();
    };

    function onAddTaskLink(params, task) {
        hideEditBox();
        
        if (params.removedLinkTaskId) {
            var removeElem = $relatedTasksCont.find("tr[data-taskid=" + params.removedLinkTaskId + "]");
            displayNewRelatedTask(params.link, removeElem);
            removeElem.remove();
        } else {
            displayNewRelatedTask(params.link);
        }

        $linkedTasksButtons.show();
        disableCreateLinkButton();
        linksTab.select();
        loadingBanner.hideLoading();
    };

    function onAddTaskLinkError(params, error) {
        loadingBanner.hideLoading();

        ASC.Projects.Base.showCommonPopup("createNewLinkError");

        hideEditBox();
        reloadedTaskListFlag = true;
        getProjectTasks();
    };

    function onGetTaskDescription(params, task) {
        currentTask = task;

        getProjectTasks();

        taskId = task.id;

        initAttachmentsControl();

        task.comments = hideRemovedComments(task.comments);

        var subtasksEmpty = 
        {
            img: "subtasks",
            header: TaskResource.SubtasksEmptyScreen_Header,
            description: TaskResource.SubtasksEmptyScreen_Describe,
            button: {
                title: TaskResource.AddNewSubtask,
                onclick: function () {
                    $subtaskContainer.find(".quickAddSubTaskLink .link").click();
                },
                canCreate: function () {
                    return currentTask.status !== 2 && currentTask.canCreateSubtask;
                }
            }
        };

        var linksEmpty = 
        {
            img: "relatedtasks",
            header: TaskResource.RelatedTasksEmptyScreen_Header,
            description: TaskResource.RelatedTasksEmptyScreen_Describe,
            button: {
                title: TaskResource.CreateNewLink,
                onclick: function () {
                    if (!$editLinkBox.is(":visible")) {
                        $createAddTaskLinkButton.click();
                    }
                },
                canCreate: function () {
                    return currentTask.status === 1 && currentTask.canEdit && listValidTaskForLink.length;
                }
            }
        };

        var commentsEmpty = 
        {
            img: "comments",
            header: TaskResource.CommentsEmptyScreen_Header,
            description: TaskResource.CommentsEmptyScreen_Describe,
            button: {
                title: ASC.Resources.Master.TemplateResource.AddNewCommentButton,
                onclick: function () {
                    jq("#add_comment_btn").click();
                },
                canCreate: function () {
                    return currentTask.canCreateComment;
                }
            }
        };

        var Tab = ASC.Projects.Tab;
        overViewTab = new Tab(resources.ProjectsJSResource.OverviewModule,
            function() { return 0; },
            "overViewModule",
            jq(".tab"),
            '#');
        subtaskTab = new Tab(TaskResource.Subtasks,
            function() { return currentTask.subtasks.length; },
            "subtasksModule",
            $subtaskContainer,
            '#subtasks',
            function() { return currentTask.canEdit || currentTask.subtasks.length },
            subtasksEmpty);
        documentsTab = new Tab(ASC.Projects.Resources.ProjectsCommonResource.DocsModuleTitle,
            function() { return currentTask.files.length; },
            "documentsModule",
            $filesContainer,
            '#documents',
            function() { return currentTask.canReadFiles && (currentTask.canEditFiles || currentTask.files.length) });
        linksTab = new Tab(TaskResource.RelatedTask,
            function() { return currentTask.links.length; },
            "linksModule",
            $linkedTasksContainer,
            '#links',
            function() { return currentTask.canEdit || currentTask.links.length },
            linksEmpty);
        commentsTab = new Tab(resources.MessageResource.Comments,
            function() { return currentTask.commentsCount; },
            "commentsModule",
            $commentContainer,
            '#comments',
            function() { return true },
            commentsEmpty,
            '#comment_');
        ganttTab = new Tab(resources.ProjectResource.GanttGart,
            function () { return 0; },
            "ganttchartModule",
            null,
            "GanttChart.aspx",
            function () { return !jq.browser.mobile && task.projectOwner.status === 0 });

        ganttTab.href = "GanttChart.aspx?prjID=" + task.projectId;

        timeTrackingTab = new Tab(resources.ProjectsJSResource.TimeTrackingModule,
            function () {
                var time = jq.timeFormat(task.timeSpend).split(":");
                var timeSpend = {
                    hours: time[0],
                    minutes: time[1]
                };
                 return jq.format("{0}:{1}", timeSpend.hours, timeSpend.minutes);
            },
            "timetrackingModule",
            null,
            "TimeTracking.aspx",
            function () { return task.canCreateTimeSpend && task.timeSpend; });

        timeTrackingTab.href = "TimeTracking.aspx?prjID=" + task.projectOwner.id + "&id=" + task.id;

        var data = {
            icon: "tasks",
            title: task.title
        };

        baseObject.InfoContainer.init(data, showEntityMenu, [overViewTab, subtaskTab, documentsTab, linksTab, commentsTab, timeTrackingTab, ganttTab]);

        jq("#descriptionTab").show();
        loadingBanner.hideLoading();

        tasks = [currentTask];
        baseObject.SubtasksManager.setTasks(tasks);

        displayTaskDescription(task);
    };

    function onUpdateTask(params, task) {
        currentTask = task;
        if (!task.canEdit && attachments) {
            attachments.banOnEditing();
        }

        baseObject.InfoContainer.updateTitle(task.title);
        displayTaskDescription(task);

        jq.unblockUI();
        common.displayInfoPanel(projectsJsResource.TaskUpdated);
    };

    function onRemoveTask() {
        jq.unblockUI();
        var newUrl = "Tasks.aspx?prjID=" + projId;
        window.location.replace(newUrl);
    };

    function onRemoveSubtask(params, subtask) {
        tasks[0].subtasks = tasks[0].subtasks.filter(function (t) { return t.id !== subtask.id });
        subtaskTab.select();
    };

    function onAddSubtask(params, subtask) {
        tasks[0].subtasks.push(subtask);
        subtaskTab.rewrite();
    };

    function onUpdateSubtaskStatus(params, subtask) {
        for (var i = 0, max = tasks[0].subtasks.length; i < max; i++) {
            if (tasks[0].subtasks[i].id === subtask.id) {
                tasks[0].subtasks[i] = subtask;
                break;
            }
        }
        subtaskTab.rewrite();
    };

    function onChangeTaskStatus(params, task) {
        currentTask = task;
        tasks[0].subtasks = currentTask.subtasks;
        subtaskTab.rewrite();

        displayTaskDescription(task);

        jq("body").css("cursor", "default");
        disableCreateLinkButton();
        jq.unblockUI();
    }

    function onGetRelatedTasks(params, tasks){
        var taskCount = tasks.length;

        if (taskCount) {
            for (var i = 0; i < taskCount; i++) {
                if (tasks[i].status == 2) {
                    listAllProjectTasks[tasks[i].id] = tasks[i];
                }
            }
        }

        displayRelatedTasks();
        initTaskLinkSelect();
        disableCreateLinkButton();
    };

    function onGetOpenTask(params, tasks) {
        listOpenTasks = [];
        listValidTaskForLink = [];
        var taskCount = tasks.length;
        if (taskCount) {
            for (var i = 0; i < taskCount; i++) {
                if (tasks[i].id == currentTask.id) {
                    if (reloadedTaskListFlag) {
                        //displayTotalInfo(currentTask);
                        reloadedTaskListFlag = false;
                    }
                }
                if (tasks[i].status == 1 && tasks[i].id != currentTask.id) {
                    listOpenTasks.push(tasks[i]);
                    if (tasks[i].deadline || currentTask.deadline) { // rewrite use possible link types
                        listValidTaskForLink.push(tasks[i]);
                    }
                }                
                listAllProjectTasks[tasks[i].id] = tasks[i];
            }
        }

        teamlab.getPrjTasksById({}, { taskid: linkedTasksIds }, { success: onGetRelatedTasks });
    };

    function onDeleteComment() {
        currentTask.commentsCount--;
        commentsTab.select();

        if (currentTask.commentsCount === 0) {
            commentsTab.select();
        }
    };

    /*---------actions--------*/
    function closeTask() {
        jq("body").css("cursor", "wait");

        teamlab.updatePrjTask({}, taskId, { 'status': 2, 'statusId': this.id }, { success: onChangeTaskStatus });
    };

    function cancelCloseTask() {
        ASC.Projects.DescriptionTab.resetStatus(currentTask.status);
        jq.unblockUI();
    }

    function formatDescription(descr) {
        var formatDescr = descr.replace(/</ig, '&lt;').replace(/>/ig, '&gt;').replace(/\n/ig, '<br/>');
        return formatDescr.replace('&amp;', '&');
    };

    function compareDates(data) {
        var currentDate = new Date();
        if (currentDate > data) {
            return true;
        }
        if (currentDate <= data) {
            return false;
        }
    };

    function unbindListEvents() {
        jq(".project-info-container").hide();
        jq("#descriptionTab").hide();
        jq(document).off("keydown.taskdescr");
        jq(document).off("keydown.description");
        attachments.unbind();
        unbind();
    }

    function bind(event, handler) {
        handlers.push(teamlab.bind(event, handler));
    }

    function unbind() {
        while (handlers.length) {
            var handler = handlers.shift();
            teamlab.unbind(handler);
        }
    }

    return {
        init: init,
        onDeleteComment: onDeleteComment,
        compareDates: compareDates,
        unbindListEvents: unbindListEvents
    };
})(jQuery);


<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Settings/HealthCheckCfgSectionHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using ASC.HealthCheck.Models;

namespace ASC.HealthCheck.Settings
{
    class HealthCheckCfgSectionHandler : ConfigurationSection
    {
        private static HealthCheckCfgSectionHandler instance;
        public static HealthCheckCfgSectionHandler Instance
        {
            get
            {
                return instance ?? (instance = (HealthCheckCfgSectionHandler)ConfigurationManager.GetSection("healthCheck"));
            }
        }

        [ConfigurationProperty("", IsDefaultCollection = true)]
        public KeyValueConfigurationCollection Settings
        {
            get
            {
                return (KeyValueConfigurationCollection)this[new ConfigurationProperty("", typeof(KeyValueConfigurationCollection), null, ConfigurationPropertyOptions.IsDefaultCollection)];
            }
        }

        private string GetValue(string key, string defaultValue = "")
        {
            return Settings.AllKeys.Contains(key) ? Settings[key].Value : defaultValue;
        }

        public TimeSpan MainLoopPeriod
        {
            get { return TimeSpan.FromSeconds(Convert.ToInt32(GetValue("mainLoopPeriod", "60"))); }
        }

        public List<ServiceEnum> ServiceNames
        {
            get
            {
                var configValue = GetValue("service-names").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                return configValue.Select(r =>(ServiceEnum)Enum.Parse(typeof(ServiceEnum), r, true)).ToList();
            }
        }

        public int DriveSpaceThreashold
        {
            get { return Convert.ToInt32(GetValue("drive-space-threashold", "104857600")); }
        }

        public string LogFolders
        {
            get { return GetValue("log-folders", "/var/log/onlyoffice/"); }
        }

        public string SMSUSAregex
        {
            get { return GetValue("sms-USAregex"); }
        }

        public string SMSCISregex
        {
            get { return GetValue("sms-CISregex"); }
        }

        public string SupportEmails
        {
            get { return GetValue("support-emails"); }
        }

        public string Url
        {
            get { return GetValue("url", "http://localhost:9810/"); }
        }

        public string PortalsWebConfigPath
        {
            get { return GetValue("portals-web-config-path", "/var/www/onlyoffice/WebStudio{0}/Web.config"); }
        }

        public int WebInstanceCount
        {
            get { return Convert.ToInt32(GetValue("portals-web-count", "2")); }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Stack/SIP_TransportLayer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Stack
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Timers;
    using Dns.Client;
    using Message;
    using TCP;
    using UDP;

    #endregion

    /// <summary>
    /// Implements SIP transport layer. Defined in RFC 3261.
    /// </summary>
    public class SIP_TransportLayer
    {
        #region Members

        private readonly SIP_FlowManager m_pFlowManager;
        private readonly CircleCollection<IPAddress> m_pLocalIPv4;
        private readonly CircleCollection<IPAddress> m_pLocalIPv6;
        private readonly SIP_Stack m_pStack;
        private bool m_IsDisposed;
        private bool m_IsRunning;
        private IPBindInfo[] m_pBinds;
        private Random m_pRandom;
        private TCP_Server<TCP_ServerSession> m_pTcpServer;
        private UDP_Server m_pUdpServer;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stack">Owner SIP stack.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stack</b> is null reference.</exception>
        internal SIP_TransportLayer(SIP_Stack stack)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }

            m_pStack = stack;

            m_pUdpServer = new UDP_Server();
            m_pUdpServer.ProcessMode = UDP_ProcessMode.Parallel;
            m_pUdpServer.PacketReceived += m_pUdpServer_PacketReceived;
            m_pUdpServer.Error += m_pUdpServer_Error;

            m_pTcpServer = new TCP_Server<TCP_ServerSession>();
            m_pTcpServer.SessionCreated += m_pTcpServer_SessionCreated;

            m_pFlowManager = new SIP_FlowManager(this);

            m_pBinds = new IPBindInfo[] {};

            m_pRandom = new Random();

            m_pLocalIPv4 = new CircleCollection<IPAddress>();
            m_pLocalIPv6 = new CircleCollection<IPAddress>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets socket bind info. Use this property to specify on which protocol,IP,port server 
        /// listnes and also if connections is SSL.
        /// </summary>
        public IPBindInfo[] BindInfo
        {
            get { return m_pBinds; }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("BindInfo");
                }

                //--- See binds has changed --------------
                bool changed = false;
                if (m_pBinds.Length != value.Length)
                {
                    changed = true;
                }
                else
                {
                    for (int i = 0; i < m_pBinds.Length; i++)
                    {
                        if (!m_pBinds[i].Equals(value[i]))
                        {
                            changed = true;
                            break;
                        }
                    }
                }

                if (changed)
                {
                    m_pBinds = value;

                    // Create listening points.
                    List<IPEndPoint> udpListeningPoints = new List<IPEndPoint>();
                    List<IPBindInfo> tcpListeningPoints = new List<IPBindInfo>();
                    foreach (IPBindInfo bindInfo in m_pBinds)
                    {
                        if (bindInfo.Protocol == BindInfoProtocol.UDP)
                        {
                            udpListeningPoints.Add(new IPEndPoint(bindInfo.IP, bindInfo.Port));
                        }
                        else
                        {
                            tcpListeningPoints.Add(bindInfo);
                        }
                    }
                    m_pUdpServer.Bindings = udpListeningPoints.ToArray();
                    m_pTcpServer.Bindings = tcpListeningPoints.ToArray();

                    // Build possible local TCP/TLS IP addresses.
                    foreach (IPEndPoint ep in m_pTcpServer.LocalEndPoints)
                    {
                        if (ep.AddressFamily == AddressFamily.InterNetwork)
                        {
                            m_pLocalIPv4.Add(ep.Address);
                        }
                        else if (ep.AddressFamily == AddressFamily.InterNetwork)
                        {
                            m_pLocalIPv6.Add(ep.Address);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Gets currently active flows.
        /// </summary>
        public SIP_Flow[] Flows
        {
            get { return m_pFlowManager.Flows; }
        }

        /// <summary>
        /// Gets if transport layer is running.
        /// </summary>
        public bool IsRunning
        {
            get { return m_IsRunning; }
        }

        /// <summary>
        /// Gets owner SIP stack.
        /// </summary>
        public SIP_Stack Stack
        {
            get { return m_pStack; }
        }

        /// <summary>
        /// Gets or sets STUN server name or IP address. This value must be filled if SIP stack is running behind a NAT.
        /// </summary>
        internal string StunServer { get; set; }

        /// <summary>
        /// Gets UDP server.
        /// </summary>
        internal UDP_Server UdpServer
        {
            get { return m_pUdpServer; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets existing flow or if flow doesn't exist, new one is created and returned.
        /// </summary>
        /// <param name="transport">SIP transport.</param>
        /// <param name="localEP">Local end point. Value null means system will allocate it.</param>
        /// <param name="remoteEP">Remote end point.</param>
        /// <returns>Returns data flow.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>remoteEP</b>.</exception>
        public SIP_Flow GetOrCreateFlow(string transport, IPEndPoint localEP, IPEndPoint remoteEP)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (remoteEP == null)
            {
                throw new ArgumentNullException("remoteEP");
            }

            if (localEP == null)
            {
                if (transport == SIP_Transport.UDP)
                {
                    //  Get load-balanched local endpoint.
                    localEP = m_pUdpServer.GetLocalEndPoint(remoteEP);
                }
                else if (transport == SIP_Transport.TCP)
                {
                    // Get load-balanched local IP for TCP and create random port.
                    if (remoteEP.AddressFamily == AddressFamily.InterNetwork)
                    {
                        localEP = new IPEndPoint(m_pLocalIPv4.Next(), m_pRandom.Next(10000, 65000));
                    }
                    else
                    {
                        localEP = new IPEndPoint(m_pLocalIPv4.Next(), m_pRandom.Next(10000, 65000));
                    }
                }
                else if (transport == SIP_Transport.TLS)
                {
                    // Get load-balanched local IP for TLS and create random port.
                    if (remoteEP.AddressFamily == AddressFamily.InterNetwork)
                    {
                        localEP = new IPEndPoint(m_pLocalIPv4.Next(), m_pRandom.Next(10000, 65000));
                    }
                    else
                    {
                        localEP = new IPEndPoint(m_pLocalIPv4.Next(), m_pRandom.Next(10000, 65000));
                    }
                }
            }

            return m_pFlowManager.GetOrCreateFlow(false, localEP, remoteEP, transport);
        }

        /// <summary>
        /// Returns specified flow or null if no such flow.
        /// </summary>
        /// <param name="flowID">Data flow ID.</param>
        /// <returns>Returns specified flow or null if no such flow.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flowID</b> is null reference.</exception>
        public SIP_Flow GetFlow(string flowID)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (flowID == null)
            {
                throw new ArgumentNullException("flowID");
            }

            return m_pFlowManager.GetFlow(flowID);
        }

        /// <summary>
        /// Sends request using methods as described in RFC 3261 [4](RFC 3263).
        /// </summary>
        /// <param name="request">SIP request to send.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>request</b> is null.</exception>
        /// <exception cref="SIP_TransportException">Is raised when transport error happens.</exception>
        public void SendRequest(SIP_Request request)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            SIP_Hop[] hops = m_pStack.GetHops((SIP_Uri) request.RequestLine.Uri,
                                              request.ToByteData().Length,
                                              false);
            if (hops.Length == 0)
            {
                throw new SIP_TransportException("No target hops for URI '" + request.RequestLine.Uri + "'.");
            }

            SIP_TransportException lastException = null;
            foreach (SIP_Hop hop in hops)
            {
                try
                {
                    SendRequest(request, null, hop);

                    return;
                }
                catch (SIP_TransportException x)
                {
                    lastException = x;
                }
            }

            // If we reach so far, send failed, return last error.
            throw lastException;
        }

        /// <summary>
        /// Sends request to the specified hop.
        /// </summary>
        /// <param name="request">SIP request.</param>
        /// <param name="localEP">Local end point. Value null means system will allocate it.</param>
        /// <param name="hop">Target hop.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>request</b> or <b>hop</b> is null reference.</exception>
        public void SendRequest(SIP_Request request, IPEndPoint localEP, SIP_Hop hop)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (hop == null)
            {
                throw new ArgumentNullException("hop");
            }

            SendRequest(GetOrCreateFlow(hop.Transport, localEP, hop.EndPoint), request);
        }

        /// <summary>
        /// Sends request to the specified flow.
        /// </summary>
        /// <param name="flow">Data flow.</param>
        /// <param name="request">SIP request.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments contains invalid value.</exception>
        public void SendRequest(SIP_Flow flow, SIP_Request request)
        {
            SendRequest(flow, request, null);
        }

        /// <summary>
        /// Sends specified response back to request maker using RFC 3261 18. rules.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        /// <remarks>Use this method to send SIP responses from stateless SIP elements, like stateless proxy. 
        /// Otherwise SIP_ServerTransaction.SendResponse method should be used.</remarks>
        public void SendResponse(SIP_Response response)
        {
            SendResponse(response, null);
        }

        /// <summary>
        /// Sends specified response back to request maker using RFC 3261 18. rules.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <param name="localEP">Local IP end point to use for sending resposne. Value null means system will allocate it.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        /// <remarks>Use this method to send SIP responses from stateless SIP elements, like stateless proxy. 
        /// Otherwise SIP_ServerTransaction.SendResponse method should be used.</remarks>
        public void SendResponse(SIP_Response response, IPEndPoint localEP)
        {
            // NOTE: all  paramter / state validations are done in SendResponseInternal.

            SendResponseInternal(null, response, localEP);
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        internal void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            m_IsDisposed = true;

            Stop();

            m_IsRunning = false;
            m_pBinds = null;
            m_pRandom = null;

            m_pTcpServer.Dispose();
            m_pTcpServer = null;

            m_pUdpServer.Dispose();
            m_pUdpServer = null;
        }

        /// <summary>
        /// Starts listening incoming requests and responses.
        /// </summary>
        internal void Start()
        {
            if (m_IsRunning)
            {
                return;
            }
            // Set this flag before running thread, otherwise thead may exist before you set this flag.
            m_IsRunning = true;

            m_pUdpServer.Start();
            m_pTcpServer.Start();
        }

        /// <summary>
        /// Stops listening incoming requests and responses.
        /// </summary>
        internal void Stop()
        {
            if (!m_IsRunning)
            {
                return;
            }
            m_IsRunning = false;

            m_pUdpServer.Stop();
            m_pTcpServer.Stop();
        }

        /// <summary>
        /// Is called when specified SIP flow has got new SIP message.
        /// </summary>
        /// <param name="flow">SIP flow.</param>
        /// <param name="message">Received message.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>message</b> is null reference.</exception>
        internal void OnMessageReceived(SIP_Flow flow, byte[] message)
        {
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            // TODO: Log

            try
            {
                #region Ping / pong

                // We have "ping"(CRLFCRLF) request, response with "pong".
                if (message.Length == 4)
                {
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddRead("",
                                             null,
                                             2,
                                             "Flow [id='" + flow.ID + "'] received \"ping\"",
                                             flow.LocalEP,
                                             flow.RemoteEP);
                    }

                    // Send "pong".
                    flow.SendInternal(new[] {(byte) '\r', (byte) '\n'});

                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddWrite("",
                                              null,
                                              2,
                                              "Flow [id='" + flow.ID + "'] sent \"pong\"",
                                              flow.LocalEP,
                                              flow.RemoteEP);
                    }

                    return;
                }
                    // We have pong(CRLF), do nothing.
                else if (message.Length == 2)
                {
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddRead("",
                                             null,
                                             2,
                                             "Flow [id='" + flow.ID + "'] received \"pong\"",
                                             flow.LocalEP,
                                             flow.RemoteEP);
                    }

                    return;
                }

                #endregion

                #region Response

                if (Encoding.UTF8.GetString(message, 0, 3).ToUpper().StartsWith("SIP"))
                {
                    #region Parse and validate response

                    SIP_Response response = null;
                    try
                    {
                        response = SIP_Response.Parse(message);
                    }
                    catch (Exception x)
                    {
                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddText("Skipping message, parse error: " + x);
                        }

                        return;
                    }

                    try
                    {
                        response.Validate();
                    }
                    catch (Exception x)
                    {
                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddText("Response validation failed: " + x);
                        }

                        return;
                    }

                    #endregion

                    /* RFC 3261 18.1.2 Receiving Responses.
                        When a response is received, the client transport examines the top
                        Via header field value.  If the value of the "sent-by" parameter in
                        that header field value does not correspond to a value that the
                        client transport is configured to insert into requests, the response
                        MUST be silently discarded.

                        If there are any client transactions in existence, the client
                        transport uses the matching procedures of Section 17.1.3 to attempt
                        to match the response to an existing transaction.  If there is a
                        match, the response MUST be passed to that transaction.  Otherwise,
                        the response MUST be passed to the core (whether it be stateless
                        proxy, stateful proxy, or UA) for further processing.  Handling of
                        these "stray" responses is dependent on the core (a proxy will
                        forward them, while a UA will discard, for example).
                    */

                    SIP_ClientTransaction transaction =
                        m_pStack.TransactionLayer.MatchClientTransaction(response);
                    // Allow client transaction to process response.
                    if (transaction != null)
                    {
                        transaction.ProcessResponse(flow, response);
                    }
                    else
                    {
                        // Pass response to dialog.
                        SIP_Dialog dialog = m_pStack.TransactionLayer.MatchDialog(response);
                        if (dialog != null)
                        {
                            dialog.ProcessResponse(response);
                        }
                            // Pass response to core.
                        else
                        {
                            m_pStack.OnResponseReceived(new SIP_ResponseReceivedEventArgs(m_pStack,
                                                                                          null,
                                                                                          response));
                        }
                    }
                }

                    #endregion

                    #region Request

                    // SIP request.
                else
                {
                    #region Parse and validate request

                    SIP_Request request = null;
                    try
                    {
                        request = SIP_Request.Parse(message);
                    }
                    catch (Exception x)
                    {
                        // Log
                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddText("Skipping message, parse error: " + x.Message);
                        }

                        return;
                    }

                    try
                    {
                        request.Validate();
                    }
                    catch (Exception x)
                    {
                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddText("Request validation failed: " + x);
                        }

                        // Bad request, send error to request maker.
                        SendResponse(
                            m_pStack.CreateResponse(SIP_ResponseCodes.x400_Bad_Request + ". " + x.Message,
                                                    request));

                        return;
                    }

                    #endregion

                    // TODO: Is that needed, core can reject message as it would like.
                    SIP_ValidateRequestEventArgs eArgs = m_pStack.OnValidateRequest(request, flow.RemoteEP);
                    // Request rejected, return response.
                    if (eArgs.ResponseCode != null)
                    {
                        SendResponse(m_pStack.CreateResponse(eArgs.ResponseCode, request));

                        return;
                    }

                    request.Flow = flow;
                    request.LocalEndPoint = flow.LocalEP;
                    request.RemoteEndPoint = flow.RemoteEP;

                    /* RFC 3261 18.2.1.
                        When the server transport receives a request over any transport, it
                        MUST examine the value of the "sent-by" parameter in the top Via
                        header field value.  If the host portion of the "sent-by" parameter
                        contains a domain name, or if it contains an IP address that differs
                        from the packet source address, the server MUST add a "received"
                        parameter to that Via header field value.  This parameter MUST
                        contain the source address from which the packet was received.  This
                        is to assist the server transport layer in sending the response,
                        since it must be sent to the source IP address from which the request
                        came.

                        Next, the server transport attempts to match the request to a server
                        transaction.  It does so using the matching rules described in
                        Section 17.2.3.  If a matching server transaction is found, the
                        request is passed to that transaction for processing.  If no match is
                        found, the request is passed to the core, which may decide to
                        construct a new server transaction for that request.  Note that when
                        a UAS core sends a 2xx response to INVITE, the server transaction is
                        destroyed.  This means that when the ACK arrives, there will be no
                        matching server transaction, and based on this rule, the ACK is
                        passed to the UAS core, where it is processed.
                    */

                    /* RFC 3581 4. 
                        When a server compliant to this specification (which can be a proxy
                        or UAS) receives a request, it examines the topmost Via header field
                        value.  If this Via header field value contains an "rport" parameter
                        with no value, it MUST set the value of the parameter to the source
                        port of the request.  This is analogous to the way in which a server
                        will insert the "received" parameter into the topmost Via header
                        field value.  In fact, the server MUST insert a "received" parameter
                        containing the source IP address that the request came from, even if
                        it is identical to the value of the "sent-by" component.  Note that
                        this processing takes place independent of the transport protocol.
                    */

                    SIP_t_ViaParm via = request.Via.GetTopMostValue();
                    via.Received = flow.RemoteEP.Address;
                    if (via.RPort == 0)
                    {
                        via.RPort = flow.RemoteEP.Port;
                    }

                    bool processed = false;
                    SIP_ServerTransaction transaction =
                        m_pStack.TransactionLayer.MatchServerTransaction(request);
                    // Pass request to matched server transaction.
                    if (transaction != null)
                    {
                        transaction.ProcessRequest(flow, request);

                        processed = true;
                    }
                    else
                    {
                        SIP_Dialog dialog = m_pStack.TransactionLayer.MatchDialog(request);
                        // Pass request to dialog.
                        if (dialog != null)
                        {
                            processed =
                                dialog.ProcessRequest(new SIP_RequestReceivedEventArgs(m_pStack, flow, request));
                        }
                    }

                    // Request not proecced by dialog or transaction, pass request to TU.
                    if (!processed)
                    {
                        // Log
                        if (m_pStack.Logger != null)
                        {
                            byte[] requestData = request.ToByteData();

                            m_pStack.Logger.AddRead(Guid.NewGuid().ToString(),
                                                    null,
                                                    0,
                                                    "Request [method='" + request.RequestLine.Method +
                                                    "'; cseq='" + request.CSeq.SequenceNumber + "'; " +
                                                    "transport='" + flow.Transport + "'; size='" +
                                                    requestData.Length + "'; " + "received '" + flow.RemoteEP +
                                                    "' -> '" + flow.LocalEP + "'.",
                                                    flow.LocalEP,
                                                    flow.RemoteEP,
                                                    requestData);
                        }

                        m_pStack.OnRequestReceived(new SIP_RequestReceivedEventArgs(m_pStack, flow, request));
                    }
                }

                #endregion
            }
            catch (SocketException s)
            {
                // Skip all socket errors here
                string dummy = s.Message;
            }
                //catch(ArgumentException x){
                //    m_pStack.OnError(x);
                //}
            catch (Exception x)
            {
                m_pStack.OnError(x);
            }
        }

        /// <summary>
        /// Sends request to the specified flow.
        /// </summary>
        /// <param name="flow">Data flow.</param>
        /// <param name="request">SIP request.</param>
        /// <param name="transaction">Owner client transaction or null if stateless sending.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments contains invalid value.</exception>
        internal void SendRequest(SIP_Flow flow, SIP_Request request, SIP_ClientTransaction transaction)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (request.Via.GetTopMostValue() == null)
            {
                throw new ArgumentException("Argument 'request' doesn't contain required Via: header field.");
            }

            // Set sent-by
            SIP_t_ViaParm via = request.Via.GetTopMostValue();
            via.ProtocolTransport = flow.Transport;
            // Via sent-by is used only to send responses when request maker data flow is not active.
            // Normally this never used, so just report first local listening point as sent-by.
            HostEndPoint sentBy = null;
            foreach (IPBindInfo bind in BindInfo)
            {
                if (flow.Transport == SIP_Transport.UDP && bind.Protocol == BindInfoProtocol.UDP)
                {
                    if (!string.IsNullOrEmpty(bind.HostName))
                    {
                        sentBy = new HostEndPoint(bind.HostName, bind.Port);
                    }
                    else
                    {
                        sentBy = new HostEndPoint(flow.LocalEP.Address.ToString(), bind.Port);
                    }
                    break;
                }
                else if (flow.Transport == SIP_Transport.TLS && bind.Protocol == BindInfoProtocol.TCP &&
                         bind.SslMode == SslMode.SSL)
                {
                    if (!string.IsNullOrEmpty(bind.HostName))
                    {
                        sentBy = new HostEndPoint(bind.HostName, bind.Port);
                    }
                    else
                    {
                        sentBy = new HostEndPoint(flow.LocalEP.Address.ToString(), bind.Port);
                    }
                    break;
                }
                else if (flow.Transport == SIP_Transport.TCP && bind.Protocol == BindInfoProtocol.TCP)
                {
                    if (!string.IsNullOrEmpty(bind.HostName))
                    {
                        sentBy = new HostEndPoint(bind.HostName, bind.Port);
                    }
                    else
                    {
                        sentBy = new HostEndPoint(flow.LocalEP.Address.ToString(), bind.Port);
                    }
                    break;
                }
            }
            // No local end point for sent-by, just use flow local end point for it.
            if (sentBy == null)
            {
                via.SentBy = new HostEndPoint(flow.LocalEP);
            }
            else
            {
                via.SentBy = sentBy;
            }

            // Send request.
            flow.Send(request);

            // Log.
            if (m_pStack.Logger != null)
            {
                byte[] requestData = request.ToByteData();

                m_pStack.Logger.AddWrite(Guid.NewGuid().ToString(),
                                         null,
                                         0,
                                         "Request [" +
                                         (transaction == null ? "" : "transactionID='" + transaction.ID + "';") +
                                         "method='" + request.RequestLine.Method + "'; cseq='" +
                                         request.CSeq.SequenceNumber + "'; " + "transport='" + flow.Transport +
                                         "'; size='" + requestData.Length + "'; sent '" + flow.LocalEP +
                                         "' -> '" + flow.RemoteEP + "'.",
                                         flow.LocalEP,
                                         flow.RemoteEP,
                                         requestData);
            }
        }

        /// <summary>
        /// Sends specified response back to request maker using RFC 3261 18. rules.
        /// </summary>
        /// <param name="transaction">SIP server transaction which response to send.</param>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>transaction</b> or <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        internal void SendResponse(SIP_ServerTransaction transaction, SIP_Response response)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            // NOTE: all other paramter / state validations are done in SendResponseInternal.

            SendResponseInternal(transaction, response, null);
        }

        /// <summary>
        /// Resolves data flow local NATed IP end point to public IP end point.
        /// </summary>
        /// <param name="flow">Data flow.</param>
        /// <returns>Returns public IP end point of local NATed IP end point.</returns>
        /// <exception cref="ArgumentNullException">Is raised <b>flow</b> is null reference.</exception>
        internal IPEndPoint Resolve(SIP_Flow flow)
        {
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }

            IPEndPoint resolvedEP = null;
            AutoResetEvent completionWaiter = new AutoResetEvent(false);
            // Create OPTIONS request
            SIP_Request optionsRequest = m_pStack.CreateRequest(SIP_Methods.OPTIONS,
                                                                new SIP_t_NameAddress("sip:<EMAIL>"),
                                                                new SIP_t_NameAddress("sip:<EMAIL>"));
            SIP_ClientTransaction optionsTransaction = m_pStack.TransactionLayer.CreateClientTransaction(
                flow, optionsRequest, true);
            optionsTransaction.ResponseReceived += delegate(object s, SIP_ResponseReceivedEventArgs e)
                                                       {
                                                           SIP_t_ViaParm via =
                                                               e.Response.Via.GetTopMostValue();

                                                           resolvedEP =
                                                               new IPEndPoint(
                                                                   via.Received == null
                                                                       ? flow.LocalEP.Address
                                                                       : via.Received,
                                                                   via.RPort > 0
                                                                       ? via.RPort
                                                                       : flow.LocalEP.Port);

                                                           completionWaiter.Set();
                                                       };
            optionsTransaction.StateChanged += delegate
                                                   {
                                                       if (optionsTransaction.State ==
                                                           SIP_TransactionState.Terminated)
                                                       {
                                                           completionWaiter.Set();
                                                       }
                                                   };
            optionsTransaction.Start();

            // Wait OPTIONS request to complete.
            completionWaiter.WaitOne();

            if (resolvedEP != null)
            {
                return resolvedEP;
            }
            else
            {
                return flow.LocalEP;
            }
        }

        /// <summary>
        /// Gets contact URI <b>host</b> parameter suitable to the specified flow.
        /// </summary>
        /// <param name="flow">Data flow.</param>
        /// <returns>Returns contact URI <b>host</b> parameter suitable to the specified flow.</returns>
        internal HostEndPoint GetContactHost(SIP_Flow flow)
        {
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }

            HostEndPoint retVal = null;

            // Find suitable listening point for flow.
            foreach (IPBindInfo bind in BindInfo)
            {
                if (bind.Protocol == BindInfoProtocol.UDP && flow.Transport == SIP_Transport.UDP)
                {
                    // For UDP flow localEP is also listeining EP, so use it.
                    if (bind.IP.AddressFamily == flow.LocalEP.AddressFamily && bind.Port == flow.LocalEP.Port)
                    {
                        retVal =
                            new HostEndPoint(
                                (string.IsNullOrEmpty(bind.HostName)
                                     ? flow.LocalEP.Address.ToString()
                                     : bind.HostName),
                                bind.Port);
                        break;
                    }
                }
                else if (bind.Protocol == BindInfoProtocol.TCP && bind.SslMode == SslMode.SSL &&
                         flow.Transport == SIP_Transport.TLS)
                {
                    // Just use first matching listening point.
                    //   TODO: Probably we should imporve it with load-balanched local end point.
                    if (bind.IP.AddressFamily == flow.LocalEP.AddressFamily)
                    {
                        if (bind.IP == IPAddress.Any || bind.IP == IPAddress.IPv6Any)
                        {
                            retVal =
                                new HostEndPoint(
                                    (string.IsNullOrEmpty(bind.HostName)
                                         ? flow.LocalEP.Address.ToString()
                                         : bind.HostName),
                                    bind.Port);
                        }
                        else
                        {
                            retVal =
                                new HostEndPoint(
                                    (string.IsNullOrEmpty(bind.HostName)
                                         ? bind.IP.ToString()
                                         : bind.HostName),
                                    bind.Port);
                        }
                        break;
                    }
                }
                else if (bind.Protocol == BindInfoProtocol.TCP && flow.Transport == SIP_Transport.TCP)
                {
                    // Just use first matching listening point.
                    //   TODO: Probably we should imporve it with load-balanched local end point.
                    if (bind.IP.AddressFamily == flow.LocalEP.AddressFamily)
                    {
                        if (bind.IP.Equals(IPAddress.Any) || bind.IP.Equals(IPAddress.IPv6Any))
                        {
                            retVal =
                                new HostEndPoint(
                                    (string.IsNullOrEmpty(bind.HostName)
                                         ? flow.LocalEP.Address.ToString()
                                         : bind.HostName),
                                    bind.Port);
                        }
                        else
                        {
                            retVal =
                                new HostEndPoint(
                                    (string.IsNullOrEmpty(bind.HostName)
                                         ? bind.IP.ToString()
                                         : bind.HostName),
                                    bind.Port);
                        }
                        break;
                    }
                }
            }

            // We don't have suitable listening point for active flow.
            // RFC 3261 forces to have, but for TCP based protocls + NAT, server can't connect to use anyway, 
            // so just ignore it and report flow local EP.
            if (retVal == null)
            {
                retVal = new HostEndPoint(flow.LocalEP);
            }

            // If flow remoteEP is public IP and our localEP is private IP, resolve localEP to public.
            if (retVal.IsIPAddress && Core.IsPrivateIP(IPAddress.Parse(retVal.Host)) &&
                !Core.IsPrivateIP(flow.RemoteEP.Address))
            {
                retVal = new HostEndPoint(Resolve(flow));
            }

            return retVal;
        }

        /// <summary>
        /// Gets Record-Route for the specified transport.
        /// </summary>
        /// <param name="transport">SIP transport.</param>
        /// <returns>Returns Record-Route ro or null if no record route possible.</returns>
        internal string GetRecordRoute(string transport)
        {
            foreach (IPBindInfo bind in m_pBinds)
            {
                if (!string.IsNullOrEmpty(bind.HostName))
                {
                    if (bind.Protocol == BindInfoProtocol.TCP && bind.SslMode != SslMode.None &&
                        transport == SIP_Transport.TLS)
                    {
                        return "<sips:" + bind.HostName + ":" + bind.Port + ";lr>";
                    }
                    else if (bind.Protocol == BindInfoProtocol.TCP && transport == SIP_Transport.TCP)
                    {
                        return "<sip:" + bind.HostName + ":" + bind.Port + ";lr>";
                    }
                    else if (bind.Protocol == BindInfoProtocol.UDP && transport == SIP_Transport.UDP)
                    {
                        return "<sip:" + bind.HostName + ":" + bind.Port + ";lr>";
                    }
                }
            }

            return null;
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// This method is called when new SIP UDP packet has received.
        /// </summary>
        /// <param name="e">Event data.</param>
        private void m_pUdpServer_PacketReceived(UDP_PacketEventArgs e)
        {
            try
            {
                SIP_Flow flow = m_pFlowManager.GetOrCreateFlow(true,
                                                               e.LocalEndPoint,
                                                               e.RemoteEndPoint,
                                                               SIP_Transport.UDP);
                flow.OnUdpPacketReceived(e);
            }
            catch (Exception x)
            {
                m_pStack.OnError(x);
            }
        }

        /// <summary>
        /// This method is called when UDP server unknown error.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pUdpServer_Error(object sender, Error_EventArgs e)
        {
            m_pStack.OnError(e.Exception);
        }

        /// <summary>
        /// This method is called when SIP stack has got new incoming connection.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTcpServer_SessionCreated(object sender,
                                                 TCP_ServerSessionEventArgs<TCP_ServerSession> e)
        {
            m_pFlowManager.CreateFromSession(e.Session);
        }

        /// <summary>
        /// Sends response to request maker using RFC 3261 18. rules.
        /// </summary>
        /// <param name="transaction">Owner server transaction. Can be null if stateless response sending.</param>
        /// <param name="response">SIP response to send.</param>
        /// <param name="localEP">Local IP end point to use for sending resposne. Value null means system will allocate it.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        private void SendResponseInternal(SIP_ServerTransaction transaction,
                                          SIP_Response response,
                                          IPEndPoint localEP)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (!m_IsRunning)
            {
                throw new InvalidOperationException("Stack has not been started.");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            /* RFC 3261 18.2.2.
                The server transport uses the value of the top Via header field in
                order to determine where to send a response.  It MUST follow the
                following process:

                    o  If the "sent-protocol" is a reliable transport protocol such as
                       TCP or SCTP, or TLS over those, the response MUST be sent using
                       the existing connection to the source of the original request
                       that created the transaction, if that connection is still open.
                       This requires the server transport to maintain an association
                       between server transactions and transport connections.  If that
                       connection is no longer open, the server SHOULD open a
                       connection to the IP address in the "received" parameter, if
                       present, using the port in the "sent-by" value, or the default
                       port for that transport, if no port is specified.  If that
                       connection attempt fails, the server SHOULD use the procedures
                       in [4] for servers in order to determine the IP address and
                       port to open the connection and send the response to.

                    o  Otherwise, if the Via header field value contains a "maddr"
                       parameter, the response MUST be forwarded to the address listed
                       there, using the port indicated in "sent-by", or port 5060 if
                       none is present.  If the address is a multicast address, the
                       response SHOULD be sent using the TTL indicated in the "ttl"
                       parameter, or with a TTL of 1 if that parameter is not present.

                    o  Otherwise (for unreliable unicast transports), if the top Via
                       has a "received" parameter, the response MUST be sent to the
                       address in the "received" parameter, using the port indicated
                       in the "sent-by" value, or using port 5060 if none is specified
                       explicitly.  If this fails, for example, elicits an ICMP "port
                       unreachable" response, the procedures of Section 5 of [4]
                       SHOULD be used to determine where to send the response.
                  
                    o  Otherwise, if it is not receiver-tagged, the response MUST be
                       sent to the address indicated by the "sent-by" value, using the
                       procedures in Section 5 of [4].
            */

            /* RFC 3581 4. (Adds new processing between RFC 3261 18.2.2. bullet 2 and 3)
                When a server attempts to send a response, it examines the topmost
                Via header field value of that response.  If the "sent-protocol"
                component indicates an unreliable unicast transport protocol, such as
                UDP, and there is no "maddr" parameter, but there is both a
                "received" parameter and an "rport" parameter, the response MUST be
                sent to the IP address listed in the "received" parameter, and the
                port in the "rport" parameter.  The response MUST be sent from the
                same address and port that the corresponding request was received on.
                This effectively adds a new processing step between bullets two and
                three in Section 18.2.2 of SIP [1].

                The response must be sent from the same address and port that the
                request was received on in order to traverse symmetric NATs.  When a
                server is listening for requests on multiple ports or interfaces, it
                will need to remember the one on which the request was received.  For
                a stateful proxy, storing this information for the duration of the
                transaction is not an issue.  However, a stateless proxy does not
                store state between a request and its response, and therefore cannot
                remember the address and port on which a request was received.  To
                properly implement this specification, a stateless proxy can encode
                the destination address and port of a request into the Via header
                field value that it inserts.  When the response arrives, it can
                extract this information and use it to forward the response.
            */

            SIP_t_ViaParm via = response.Via.GetTopMostValue();
            if (via == null)
            {
                throw new ArgumentException("Argument 'response' does not contain required Via: header field.");
            }

            // TODO: If transport is not supported.            
            //throw new SIP_TransportException("Not supported transport '" + via.ProtocolTransport + "'.");

            string logID = Guid.NewGuid().ToString();
            string transactionID = transaction == null ? "" : transaction.ID;

            // Try to get local IP end point which we should use to send response back.            
            if (transaction != null && transaction.Request.LocalEndPoint != null)
            {
                localEP = transaction.Request.LocalEndPoint;
            }

                // TODO: no "localEP" at moment

                // TODO: Stateless should use flowID instead.

                // Our stateless proxy add 'localEP' parameter to Via: if so normally we can get it from there.
            else if (via.Parameters["localEP"] != null)
            {
                localEP = Net_Utils.ParseIPEndPoint(via.Parameters["localEP"].Value);
            }

            byte[] responseData = response.ToByteData();

            #region Try existing flow first

            /* First try active flow to send response, thats not 100% as RFC says, but works better in any case.
               RFC says that for TCP and TLS only, we do it for any transport.
            */

            if (transaction != null)
            {
                try
                {
                    SIP_Flow flow = transaction.Flow;
                    flow.Send(response);

                    if (m_pStack.Logger != null)
                    {
                        m_pStack.Logger.AddWrite(logID,
                                                 null,
                                                 0,
                                                 "Response [flowReuse=true; transactionID='" + transactionID +
                                                 "'; method='" + response.CSeq.RequestMethod + "'; cseq='" +
                                                 response.CSeq.SequenceNumber + "'; " + "transport='" +
                                                 flow.Transport + "'; size='" + responseData.Length +
                                                 "'; statusCode='" + response.StatusCode + "'; " + "reason='" +
                                                 response.ReasonPhrase + "'; sent '" + flow.LocalEP + "' -> '" +
                                                 flow.RemoteEP + "'.",
                                                 localEP,
                                                 flow.RemoteEP,
                                                 responseData);
                    }

                    return;
                }
                catch
                {
                    // Do nothing, processing will continue.
                }
            }

            #endregion

            #region Reliable TCP,TLS, ...

            if (SIP_Utils.IsReliableTransport(via.ProtocolTransport))
            {
                // Get original request remote end point.
                IPEndPoint remoteEP = null;
                if (transaction != null && transaction.Request.RemoteEndPoint != null)
                {
                    remoteEP = transaction.Request.RemoteEndPoint;
                }
                else if (via.Received != null)
                {
                    remoteEP = new IPEndPoint(via.Received, via.SentBy.Port == -1 ? 5060 : via.SentBy.Port);
                }

                #region If original request connection alive, use it

                try
                {
                    SIP_Flow flow = null;

                    // Statefull
                    if (transaction != null)
                    {
                        if (transaction.Request.Flow != null && !transaction.Request.Flow.IsDisposed)
                        {
                            flow = transaction.Request.Flow;
                        }
                    }
                        // Stateless
                    else
                    {
                        string flowID = via.Parameters["connectionID"].Value;
                        if (flowID != null)
                        {
                            flow = m_pFlowManager[flowID];
                        }
                    }

                    if (flow != null)
                    {
                        flow.Send(response);

                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddWrite(logID,
                                                     null,
                                                     0,
                                                     "Response [flowReuse=true; transactionID='" +
                                                     transactionID + "'; method='" +
                                                     response.CSeq.RequestMethod + "'; cseq='" +
                                                     response.CSeq.SequenceNumber + "'; " + "transport='" +
                                                     flow.Transport + "'; size='" + responseData.Length +
                                                     "'; statusCode='" + response.StatusCode + "'; " +
                                                     "reason='" + response.ReasonPhrase + "'; sent '" +
                                                     flow.RemoteEP + "' -> '" + flow.LocalEP + "'.",
                                                     localEP,
                                                     remoteEP,
                                                     responseData);
                        }

                        return;
                    }
                }
                catch
                {
                    // Do nothing, processing will continue.
                    // Override RFC, if there is any existing connection and it gives error, try always RFC 3261 18.2.2(recieved) and 3265 5.
                }

                #endregion

                #region Send RFC 3261 18.2.2(recieved)

                if (remoteEP != null)
                {
                    try
                    {
                        SendResponseToHost(logID,
                                           transactionID,
                                           null,
                                           remoteEP.Address.ToString(),
                                           remoteEP.Port,
                                           via.ProtocolTransport,
                                           response);
                    }
                    catch
                    {
                        // Do nothing, processing will continue -> "RFC 3265 5.".
                    }
                }

                #endregion

                #region Send RFC 3265 5.

                SendResponse_RFC_3263_5(logID, transactionID, localEP, response);

                #endregion
            }

                #endregion

                #region UDP Via: maddr parameter

            else if (via.Maddr != null)
            {
                throw new SIP_TransportException(
                    "Sending responses to multicast address(Via: 'maddr') is not supported.");
            }

                #endregion

                #region RFC 3581 4. UDP Via: received and rport parameters

            else if (via.Maddr == null && via.Received != null && via.RPort > 0)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.Received.ToString(),
                                   via.RPort,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region UDP Via: received parameter

            else if (via.Received != null)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.Received.ToString(),
                                   via.SentByPortWithDefault,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region UDP

            else
            {
                SendResponse_RFC_3263_5(logID, transactionID, localEP, response);
            }

            #endregion
        }

        /// <summary>
        /// Sends specified response back to request maker using RFC 3263 5. rules.
        /// </summary>
        /// <param name="logID">Log ID.</param>
        /// <param name="transactionID">Transaction ID. If null, then stateless response sending.</param>
        /// <param name="localEP">UDP local end point to use for sending. If null, system will use default.</param>
        /// <param name="response">SIP response.</param>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        private void SendResponse_RFC_3263_5(string logID,
                                             string transactionID,
                                             IPEndPoint localEP,
                                             SIP_Response response)
        {
            /* RFC 3263 5.
                    RFC 3261 [1] defines procedures for sending responses from a server
                    back to the client.  Typically, for unicast UDP requests, the
                    response is sent back to the source IP address where the request came
                    from, using the port contained in the Via header.  For reliable
                    transport protocols, the response is sent over the connection the
                    request arrived on.  However, it is important to provide failover
                    support when the client element fails between sending the request and
                    receiving the response.

                    A server, according to RFC 3261 [1], will send a response on the
                    connection it arrived on (in the case of reliable transport
                    protocols), and for unreliable transport protocols, to the source
                    address of the request, and the port in the Via header field.  The
                    procedures here are invoked when a server attempts to send to that
                    location and that response fails (the specific conditions are
                    detailed in RFC 3261). "Fails" is defined as any closure of the
                    transport connection the request came in on before the response can
                    be sent, or communication of a fatal error from the transport layer.

                    In these cases, the server examines the value of the sent-by
                    construction in the topmost Via header.  If it contains a numeric IP
                    address, the server attempts to send the response to that address,
                    using the transport protocol from the Via header, and the port from
                    sent-by, if present, else the default for that transport protocol.
                    The transport protocol in the Via header can indicate "TLS", which
                    refers to TLS over TCP.  When this value is present, the server MUST
                    use TLS over TCP to send the response.
                 
                    If, however, the sent-by field contained a domain name and a port
                    number, the server queries for A or AAAA records with that name.  It
                    tries to send the response to each element on the resulting list of
                    IP addresses, using the port from the Via, and the transport protocol
                    from the Via (again, a value of TLS refers to TLS over TCP).  As in
                    the client processing, the next entry in the list is tried if the one
                    before it results in a failure.

                    If, however, the sent-by field contained a domain name and no port,
                    the server queries for SRV records at that domain name using the
                    service identifier "_sips" if the Via transport is "TLS", "_sip"
                    otherwise, and the transport from the topmost Via header ("TLS"
                    implies that the transport protocol in the SRV query is TCP).  The
                    resulting list is sorted as described in [2], and the response is
                    sent to the topmost element on the new list described there.  If that
                    results in a failure, the next entry on the list is tried.
                */

            SIP_t_ViaParm via = response.Via.GetTopMostValue();

            #region Sent-By is IP address

            if (via.SentBy.IsIPAddress)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.SentBy.Host,
                                   via.SentByPortWithDefault,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region Sent-By is host name with port number

            else if (via.SentBy.Port != -1)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.SentBy.Host,
                                   via.SentByPortWithDefault,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region Sent-By is just host name

            else
            {
                try
                {
                    // Query SRV records.
                    string srvQuery = "";
                    if (via.ProtocolTransport == SIP_Transport.UDP)
                    {
                        srvQuery = "_sip._udp." + via.SentBy.Host;
                    }
                    else if (via.ProtocolTransport == SIP_Transport.TCP)
                    {
                        srvQuery = "_sip._tcp." + via.SentBy.Host;
                    }
                    else if (via.ProtocolTransport == SIP_Transport.UDP)
                    {
                        srvQuery = "_sips._tcp." + via.SentBy.Host;
                    }
                    DnsServerResponse dnsResponse = m_pStack.Dns.Query(srvQuery, QTYPE.SRV);
                    if (dnsResponse.ResponseCode != RCODE.NO_ERROR)
                    {
                        throw new SIP_TransportException("Dns error: " + dnsResponse.ResponseCode);
                    }
                    DNS_rr_SRV[] srvRecords = dnsResponse.GetSRVRecords();

                    // Use SRV records.
                    if (srvRecords.Length > 0)
                    {
                        for (int i = 0; i < srvRecords.Length; i++)
                        {
                            DNS_rr_SRV srv = srvRecords[i];
                            try
                            {
                                if (m_pStack.Logger != null)
                                {
                                    m_pStack.Logger.AddText(logID,
                                                            "Starts sending response to DNS SRV record '" +
                                                            srv.Target + "'.");
                                }

                                SendResponseToHost(logID,
                                                   transactionID,
                                                   localEP,
                                                   srv.Target,
                                                   srv.Port,
                                                   via.ProtocolTransport,
                                                   response);
                            }
                            catch
                            {
                                // Generate error, all SRV records has failed.
                                if (i == (srvRecords.Length - 1))
                                {
                                    if (m_pStack.Logger != null)
                                    {
                                        m_pStack.Logger.AddText(logID,
                                                                "Failed to send response to DNS SRV record '" +
                                                                srv.Target + "'.");
                                    }

                                    throw new SIP_TransportException("Host '" + via.SentBy.Host +
                                                                     "' is not accessible.");
                                }
                                    // For loop will try next SRV record.
                                else
                                {
                                    if (m_pStack.Logger != null)
                                    {
                                        m_pStack.Logger.AddText(logID,
                                                                "Failed to send response to DNS SRV record '" +
                                                                srv.Target + "', will try next.");
                                    }
                                }
                            }
                        }
                    }
                        // If no SRV, use A and AAAA records. (Thats not in 3263 5., but we need to todo it so.)
                    else
                    {
                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddText(logID,
                                                    "No DNS SRV records found, starts sending to Via: sent-by host '" +
                                                    via.SentBy.Host + "'.");
                        }

                        SendResponseToHost(logID,
                                           transactionID,
                                           localEP,
                                           via.SentBy.Host,
                                           via.SentByPortWithDefault,
                                           via.ProtocolTransport,
                                           response);
                    }
                }
                catch (DNS_ClientException dnsX)
                {
                    throw new SIP_TransportException("Dns error: " + dnsX.ErrorCode);
                }
            }

            #endregion
        }

        /// <summary>
        /// Sends response to the specified host.
        /// </summary>
        /// <param name="logID">Log ID.</param>
        /// <param name="transactionID">Transaction ID. If null, then stateless response sending.</param>
        /// <param name="localEP">UDP local end point to use for sending. If null, system will use default.</param>
        /// <param name="host">Host name or IP address where to send response.</param>
        /// <param name="port">Target host port.</param>
        /// <param name="transport">SIP transport to use.</param>
        /// <param name="response">SIP response to send.</param>
        private void SendResponseToHost(string logID,
                                        string transactionID,
                                        IPEndPoint localEP,
                                        string host,
                                        int port,
                                        string transport,
                                        SIP_Response response)
        {
            try
            {
                IPAddress[] targets = null;
                if (Net_Utils.IsIPAddress(host))
                {
                    targets = new[] {IPAddress.Parse(host)};
                }
                else
                {
                    targets = m_pStack.Dns.GetHostAddresses(host);
                    if (targets.Length == 0)
                    {
                        throw new SIP_TransportException("Invalid Via: Sent-By host name '" + host +
                                                         "' could not be resolved.");
                    }
                }

                byte[] responseData = response.ToByteData();

                for (int i = 0; i < targets.Length; i++)
                {
                    IPEndPoint remoteEP = new IPEndPoint(targets[i], port);
                    try
                    {
                        SIP_Flow flow = GetOrCreateFlow(transport, localEP, remoteEP);
                        flow.Send(response);
                        // localEP = flow.LocalEP;

                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddWrite(logID,
                                                     null,
                                                     0,
                                                     "Response [transactionID='" + transactionID +
                                                     "'; method='" + response.CSeq.RequestMethod + "'; cseq='" +
                                                     response.CSeq.SequenceNumber + "'; " + "transport='" +
                                                     transport + "'; size='" + responseData.Length +
                                                     "'; statusCode='" + response.StatusCode + "'; " +
                                                     "reason='" + response.ReasonPhrase + "'; sent '" +
                                                     localEP + "' -> '" + remoteEP + "'.",
                                                     localEP,
                                                     remoteEP,
                                                     responseData);
                        }

                        // If we reach so far, send succeeded.
                        return;
                    }
                    catch
                    {
                        // Generate error, all IP addresses has failed.
                        if (i == (targets.Length - 1))
                        {
                            if (m_pStack.Logger != null)
                            {
                                m_pStack.Logger.AddText(logID,
                                                        "Failed to send response to host '" + host +
                                                        "' IP end point '" + remoteEP + "'.");
                            }

                            throw new SIP_TransportException("Host '" + host + ":" + port +
                                                             "' is not accessible.");
                        }
                            // For loop will try next IP address.
                        else
                        {
                            if (m_pStack.Logger != null)
                            {
                                m_pStack.Logger.AddText(logID,
                                                        "Failed to send response to host '" + host +
                                                        "' IP end point '" + remoteEP +
                                                        "', will try next A record.");
                            }
                        }
                    }
                }
            }
            catch (DNS_ClientException dnsX)
            {
                throw new SIP_TransportException("Dns error: " + dnsX.ErrorCode);
            }
        }

        #endregion

        #region Nested type: SIP_FlowManager

        /// <summary>
        /// Implements SIP flow manager.
        /// </summary>
        private class SIP_FlowManager : IDisposable
        {
            #region Members

            private readonly object m_pLock = new object();
            private int m_IdelTimeout = 60*5;
            private bool m_IsDisposed;
            private Dictionary<string, SIP_Flow> m_pFlows;
            private SIP_TransportLayer m_pOwner;
            private TimerEx m_pTimeoutTimer;

            #endregion

            #region Constructor

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="owner">Owner transport layer.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null reference.</exception>
            internal SIP_FlowManager(SIP_TransportLayer owner)
            {
                if (owner == null)
                {
                    throw new ArgumentNullException("owner");
                }

                m_pOwner = owner;

                m_pFlows = new Dictionary<string, SIP_Flow>();

                m_pTimeoutTimer = new TimerEx(15000);
                m_pTimeoutTimer.AutoReset = true;
                m_pTimeoutTimer.Elapsed += m_pTimeoutTimer_Elapsed;
                m_pTimeoutTimer.Enabled = true;
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets number of flows in the collection.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
            public int Count
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    return m_pFlows.Count;
                }
            }

            /// <summary>
            /// Gets active flows.
            /// </summary>
            public SIP_Flow[] Flows
            {
                get
                {
                    lock (m_pLock)
                    {
                        SIP_Flow[] retVal = new SIP_Flow[m_pFlows.Count];
                        m_pFlows.Values.CopyTo(retVal, 0);

                        return retVal;
                    }
                }
            }

            /// <summary>
            /// Gets if this object is disposed.
            /// </summary>
            public bool IsDisposed
            {
                get { return m_IsDisposed; }
            }

            /// <summary>
            /// Gets a flow with the specified flow ID.
            /// </summary>
            /// <param name="flowID">SIP flow ID.</param>
            /// <returns>Returns flow with the specified flow ID or null if not found.</returns>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
            /// <exception cref="ArgumentNullException">Is raised when <b>flowID</b> is null reference value.</exception>
            public SIP_Flow this[string flowID]
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }
                    if (flowID == null)
                    {
                        throw new ArgumentNullException("flowID");
                    }

                    if (m_pFlows.ContainsKey(flowID))
                    {
                        return m_pFlows[flowID];
                    }
                    else
                    {
                        return null;
                    }
                }
            }

            /// <summary>
            /// Gets owner transpoprt layer.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
            internal SIP_TransportLayer TransportLayer
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    return m_pOwner;
                }
            }

            #endregion

            #region Methods

            /// <summary>
            /// Cleans up any resources being used.
            /// </summary>
            public void Dispose()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    m_IsDisposed = true;

                    foreach (SIP_Flow flow in Flows)
                    {
                        flow.Dispose();
                    }

                    m_pOwner = null;
                    m_pFlows = null;
                    m_pTimeoutTimer.Dispose();
                    m_pTimeoutTimer = null;
                }
            }

            /// <summary>
            /// Returns specified flow or null if no such flow.
            /// </summary>
            /// <param name="flowID">Data flow ID.</param>
            /// <returns>Returns specified flow or null if no such flow.</returns>
            /// <exception cref="ArgumentNullException">Is raised when <b>flowID</b> is null reference.</exception>
            public SIP_Flow GetFlow(string flowID)
            {
                if (flowID == null)
                {
                    throw new ArgumentNullException("flowID");
                }

                lock (m_pFlows)
                {
                    SIP_Flow retVal = null;
                    m_pFlows.TryGetValue(flowID, out retVal);

                    return retVal;
                }
            }

            #endregion

            #region Internal methods

            /// <summary>
            /// Returns existing flow if exists, otherwise new created flow.
            /// </summary>
            /// <param name="isServer">Specifies if created flow is server or client flow. This has effect only if flow is created.</param>
            /// <param name="localEP">Local end point.</param>
            /// <param name="remoteEP">Remote end point.</param>
            /// <param name="transport">SIP transport.</param>
            /// <returns>Returns existing flow if exists, otherwise new created flow.</returns>
            /// <exception cref="ArgumentNullException">Is raised when <b>localEP</b>,<b>remoteEP</b> or <b>transport</b> is null reference.</exception>
            /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
            internal SIP_Flow GetOrCreateFlow(bool isServer,
                                              IPEndPoint localEP,
                                              IPEndPoint remoteEP,
                                              string transport)
            {
                if (localEP == null)
                {
                    throw new ArgumentNullException("localEP");
                }
                if (remoteEP == null)
                {
                    throw new ArgumentNullException("remoteEP");
                }
                if (transport == null)
                {
                    throw new ArgumentNullException("transport");
                }

                string flowID = localEP + "-" + remoteEP + "-" + transport;

                lock (m_pLock)
                {
                    SIP_Flow flow = null;
                    if (m_pFlows.TryGetValue(flowID, out flow))
                    {
                        return flow;
                    }
                    else
                    {
                        flow = new SIP_Flow(m_pOwner.Stack, isServer, localEP, remoteEP, transport);
                        m_pFlows.Add(flow.ID, flow);
                        flow.IsDisposing += delegate
                                                {
                                                    lock (m_pLock)
                                                    {
                                                        m_pFlows.Remove(flowID);
                                                    }
                                                };
                        flow.Start();

                        return flow;
                    }
                }
            }

            /// <summary>
            /// Creates new flow from TCP server session.
            /// </summary>
            /// <param name="session">TCP server session.</param>
            /// <returns>Returns created flow.</returns>
            /// <exception cref="ArgumentNullException">Is raised when <b>session</b> is null reference.</exception>
            internal SIP_Flow CreateFromSession(TCP_ServerSession session)
            {
                if (session == null)
                {
                    throw new ArgumentNullException("session");
                }

                string flowID = session.LocalEndPoint + "-" + session.RemoteEndPoint + "-" +
                                (session.IsSecureConnection ? SIP_Transport.TLS : SIP_Transport.TCP);

                lock (m_pLock)
                {
                    SIP_Flow flow = new SIP_Flow(m_pOwner.Stack, session);
                    m_pFlows.Add(flowID, flow);
                    flow.IsDisposing += delegate
                                            {
                                                lock (m_pLock)
                                                {
                                                    m_pFlows.Remove(flowID);
                                                }
                                            };
                    flow.Start();

                    return flow;
                }
            }

            #endregion

            #region Utility methods

            private void m_pTimeoutTimer_Elapsed(object sender, ElapsedEventArgs e)
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }

                    foreach (SIP_Flow flow in Flows)
                    {
                        try
                        {
                            if (flow.LastActivity.AddSeconds(m_IdelTimeout) < DateTime.Now)
                            {
                                flow.Dispose();
                            }
                        }
                        catch (ObjectDisposedException x)
                        {
                            string dummy = x.Message;
                        }
                    }
                }
            }

            #endregion
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/FTP/Client/FTP_ClientException.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.FTP.Client
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// FTP client exception.
    /// </summary>
    public class FTP_ClientException : Exception
    {
        #region Members

        private readonly string m_ResponseText = "";
        private readonly int m_StatusCode = 500;

        #endregion

        #region Properties

        /// <summary>
        /// Gets FTP status code.
        /// </summary>
        public int StatusCode
        {
            get { return m_StatusCode; }
        }

        /// <summary>
        /// Gets FTP server response text after status code.
        /// </summary>
        public string ResponseText
        {
            get { return m_ResponseText; }
        }

        /// <summary>
        /// Gets if it is permanent FTP(5xx) error.
        /// </summary>
        public bool IsPermanentError
        {
            get
            {
                if (m_StatusCode >= 500 && m_StatusCode <= 599)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="responseLine">FTP server response line.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>responseLine</b> is null.</exception>
        public FTP_ClientException(string responseLine) : base(responseLine)
        {
            if (responseLine == null)
            {
                throw new ArgumentNullException("responseLine");
            }

            string[] code_text = responseLine.Split(new[] {' '}, 2);
            try
            {
                m_StatusCode = Convert.ToInt32(code_text[0]);
            }
            catch {}
            if (code_text.Length == 2)
            {
                m_ResponseText = code_text[1];
            }
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Common/Caching/AscCache.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Runtime.Caching;
using System.Text.RegularExpressions;

using StackExchange.Redis.Extensions.Core.Extensions;

namespace ASC.Common.Caching
{
    public class AscCache : ICache, ICacheNotify
    {
        public static readonly ICache Default;

        public static readonly ICache Memory;

        public static readonly ICacheNotify Notify;


        private readonly ConcurrentDictionary<Type, ConcurrentBag<Action<object, CacheNotifyAction>>> actions =
            new ConcurrentDictionary<Type, ConcurrentBag<Action<object, CacheNotifyAction>>>();

        static AscCache()
        {
            Memory = new AscCache();
            Default = ConfigurationManagerExtension.GetSection("redisCacheClient") != null ? new RedisCache() : Memory;
            Notify = (ICacheNotify)Default;
            try
            {
                Notify.Subscribe<AscCacheItem>((item, action) => { OnClearCache(); });
            }
            catch (Exception)
            {

            }
        }

        private AscCache()
        {
        }

        public T Get<T>(string key) where T : class
        {
            var cache = GetCache();
            return cache.Get(key) as T;
        }

        public void Insert(string key, object value, TimeSpan sligingExpiration)
        {
            var cache = GetCache();
            cache.Set(key, value, new CacheItemPolicy { SlidingExpiration = sligingExpiration });
        }

        public void Insert(string key, object value, DateTime absolutExpiration)
        {
            var cache = GetCache();
            cache.Set(key, value,
                absolutExpiration == DateTime.MaxValue ? DateTimeOffset.MaxValue : new DateTimeOffset(absolutExpiration));
        }

        public void Remove(string key)
        {
            var cache = GetCache();
            cache.Remove(key);
        }

        public void Remove(Regex pattern)
        {
            var cache = GetCache();

            var copy = cache.ToDictionary(p => p.Key, p => p.Value);

            var keys = copy.Select(p => p.Key).Where(k => pattern.IsMatch(k)).ToArray();
            foreach (var key in keys)
            {
                cache.Remove(key);
            }
        }


        public IDictionary<string, T> HashGetAll<T>(string key)
        {
            var cache = GetCache();
            var dic = (IDictionary<string, T>)cache.Get(key);
            return dic != null ? new Dictionary<string, T>(dic) : new Dictionary<string, T>();
        }

        public T HashGet<T>(string key, string field)
        {
            var cache = GetCache();
            T value;
            var dic = (IDictionary<string, T>)cache.Get(key);
            if (dic != null && dic.TryGetValue(field, out value))
            {
                return value;
            }
            return default(T);
        }

        public void HashSet<T>(string key, string field, T value)
        {
            var cache = GetCache();
            var dic = (IDictionary<string, T>)cache.Get(key);
            if (value != null)
            {
                if (dic == null)
                {
                    dic = new Dictionary<string, T>();
                }
                dic[field] = value;
                cache.Set(key, dic, null);
            }
            else if (dic != null)
            {
                dic.Remove(field);
                if (dic.Count == 0)
                {
                    cache.Remove(key);
                }
                else
                {
                    cache.Set(key, dic, null);
                }
            }
        }


        public void Subscribe<T>(Action<T, CacheNotifyAction> onchange)
        {
            if (onchange != null)
            {
                Action<object, CacheNotifyAction> action = (o, a) => onchange((T)o, a);
                actions.AddOrUpdate(typeof(T),
                    new ConcurrentBag<Action<object, CacheNotifyAction>> { action },
                    (type, bag) =>
                    {
                        bag.Add(action);
                        return bag;
                    });
            }
            else
            {
                ConcurrentBag<Action<object, CacheNotifyAction>> removed;
                actions.TryRemove(typeof(T), out removed);
            }
        }

        public void Publish<T>(T obj, CacheNotifyAction action)
        {
            ConcurrentBag<Action<object, CacheNotifyAction>> onchange;
            actions.TryGetValue(typeof(T), out onchange);

            if (onchange != null)
            {
                onchange.ToArray().ForEach(r => r(obj, action));
            }
        }

        public static void ClearCache()
        {
            Notify.Publish(new AscCacheItem(), CacheNotifyAction.Any);
        }

        private MemoryCache GetCache()
        {
            return MemoryCache.Default;
        }

        public static void OnClearCache()
        {
            Default.Remove(new Regex(".*"));
            var keys = MemoryCache.Default.Select(r => r.Key).ToList();

            foreach (var k in keys)
            {
                MemoryCache.Default.Remove(k);
            }
        }
    }

    [Serializable]
    public class AscCacheItem
    {
        public Guid Id { get; set; }

        public AscCacheItem()
        {
            Id = Guid.NewGuid();
        }
    }
}

<|start_filename|>module/ASC.Socket.IO/app/log.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


const winston = require('winston');
const { format } = require('winston');
require('winston-daily-rotate-file')

const path = require('path');
const config = require('../config');
const fs = require('fs');
const fileName = config.get("logPath") || path.join(__dirname, "..", "..", "Logs", "web.socketio.%DATE%.log");
const dirName = path.dirname(fileName);

if (!fs.existsSync(dirName)) {
    fs.mkdirSync(dirName);
}

const fileTransport = new (winston.transports.DailyRotateFile)(
{
    filename: fileName,
    datePattern: 'MM-DD',
    handleExceptions: true,
    humanReadableUnhandledException: true,
    zippedArchive: true,
    maxSize: '50m',
    maxFiles: '30d'
});

const transports = [
    new (winston.transports.Console)(),
    fileTransport
];

winston.exceptions.handle(fileTransport);

module.exports = winston.createLogger({
    transports: transports,
    exitOnError: false,
    format: format.combine(
        format.timestamp({
          format: 'YYYY-MM-DD HH:mm:ss'
        }),
        format.printf(info => `${info.timestamp} - ${info.level}: ${info.message}`)
    )});


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/Mail/Mail_h_AddressList.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Mail
{
    #region usings

    using System;
    using System.Text;
    using MIME;

    #endregion

    /// <summary>
    /// This class represent generic <b>address-list</b> header fields. For example: To header.
    /// </summary>
    /// <example>
    /// <code>
    /// RFC 5322.
    ///     header       = "FiledName:" address-list CRLF
    ///     address-list = (address *("," address))
    ///     address      = mailbox / group
    /// </code>
    /// </example>
    public class Mail_h_AddressList : MIME_h
    {
        #region Members

        private readonly string m_Name;
        private readonly Mail_t_AddressList m_pAddresses;
        private string m_ParseValue;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this header field is modified since it has loaded.
        /// </summary>
        /// <remarks>All new added header fields has <b>IsModified = true</b>.</remarks>
        /// <exception cref="ObjectDisposedException">Is riased when this class is disposed and this property is accessed.</exception>
        public override bool IsModified
        {
            get { return m_pAddresses.IsModified; }
        }

        /// <summary>
        /// Gets header field name. For example "To".
        /// </summary>
        public override string Name
        {
            get { return m_Name; }
        }

        /// <summary>
        /// Gets addresses collection.
        /// </summary>
        public Mail_t_AddressList Addresses
        {
            get { return m_pAddresses; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="fieldName">Header field name. For example: "To".</param>
        /// <param name="values">Addresses collection.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>filedName</b> or <b>values</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public Mail_h_AddressList(string fieldName, Mail_t_AddressList values)
        {
            if (fieldName == null)
            {
                throw new ArgumentNullException("fieldName");
            }
            if (fieldName == string.Empty)
            {
                throw new ArgumentException("Argument 'fieldName' value must be specified.");
            }
            if (values == null)
            {
                throw new ArgumentNullException("values");
            }

            m_Name = fieldName;
            m_pAddresses = values;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        public static Mail_h_AddressList Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            string[] name_value = value.Split(new[] {':'}, 2);
            if (name_value.Length != 2)
            {
                throw new ParseException("Invalid header field value '" + value + "'.");
            }

            MIME_Reader r = new MIME_Reader(MIME_Utils.UnfoldHeader(name_value.Length == 2 ? name_value[1].TrimStart() : ""));
            
            Mail_h_AddressList retVal = new Mail_h_AddressList(name_value[0], new Mail_t_AddressList());


            while (true)
            {
                string word = r.QuotedReadToDelimiter(new[] { ',', '<', ':' });
                // We processed all data.
                if (word == null && r.Available == 0)
                {
                    break;
                }
                // name-addr
                else if (r.Peek(true) == '<')
                {
                    retVal.m_pAddresses.Add(
                        new Mail_t_Mailbox(
                            word != null
                                ? MIME_Encoding_EncodedWord.DecodeAll(TextUtils.UnQuoteString(word))
                                : null,
                            r.ReadParenthesized()));
                }
                // addr-spec
                else
                {
                    retVal.m_pAddresses.Add(new Mail_t_Mailbox(null, word));
                }

                // We have more addresses.
                if (r.Peek(true) == ',')
                {
                    r.Char(false);
                }
            }


            retVal.m_ParseValue = value;
            retVal.m_pAddresses.AcceptChanges();
            return retVal;
        }

        

        /// <summary>
        /// Returns header field as string.
        /// </summary>
        /// <param name="wordEncoder">8-bit words ecnoder. Value null means that words are not encoded.</param>
        /// <param name="parmetersCharset">Charset to use to encode 8-bit characters. Value null means parameters not encoded.</param>
        /// <returns>Returns header field as string.</returns>
        public override string ToString(MIME_Encoding_EncodedWord wordEncoder, Encoding parmetersCharset)
        {
            if (IsModified)
            {
                StringBuilder retVal = new StringBuilder();
                retVal.Append(Name + ": ");
                for (int i = 0; i < m_pAddresses.Count; i++)
                {
                    if (i > 0)
                    {
                        retVal.Append("\t");
                    }

                    // Don't add ',' for last item.
                    if (i == (m_pAddresses.Count - 1))
                    {
                        retVal.Append(m_pAddresses[i].ToString(wordEncoder) + "\r\n");
                    }
                    else
                    {
                        retVal.Append(m_pAddresses[i].ToString(wordEncoder) + ",\r\n");
                    }
                }

                return retVal.ToString();
            }
            else
            {
                return m_ParseValue;
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Common/BlogsModule.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Blogs.Core.Security;
using ASC.Core;
using ASC.Web.Community.Modules.Blogs.Core.Resources;
using ASC.Web.Community.Product;
using ASC.Web.Core;
using ASC.Web.Core.ModuleManagement;

namespace ASC.Web.Community.Blogs.Common
{
    public class BlogsModule : Module
    {
        public override Guid ID
        {
            get { return ASC.Blogs.Core.Constants.ModuleId; }
        }

        public override Guid ProjectId
        {
            get { return CommunityProduct.ID; }
        }

        public override string Name
        {
            get { return BlogsResource.AddonName; }
        }

        public override string Description
        {
            get { return BlogsResource.AddonDescriptionResourceKey; }
        }

        public override string StartURL
        {
            get { return ASC.Blogs.Core.Constants.BaseVirtualPath; }
        }

        public BlogsModule()
        {
            Context = new ModuleContext
            {
                DefaultSortOrder = 1,
                SmallIconFileName = "blog_add.png",
                IconFileName = "blogiconwg.png",
                SubscriptionManager = new BlogsSubscriptionManager(),
                GetCreateContentPageAbsoluteUrl = () => CanEdit() ? VirtualPathUtility.ToAbsolute(ASC.Blogs.Core.Constants.BaseVirtualPath + "AddBlog.aspx") : null,
                SearchHandler = new BlogsSearchHandler(),
            };
        }

        private static bool CanEdit()
        {
            return CommunitySecurity.CheckPermissions(new PersonalBlogSecObject(CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID)), ASC.Blogs.Core.Constants.Action_AddPost);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Dao/CommentDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;
using ASC.Core.Tenants;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;

using Microsoft.Security.Application;

namespace ASC.Projects.Data.DAO
{
    internal class CommentDao : BaseDao, ICommentDao
    {
        private static readonly string ColumnId = "id";
        private static readonly string ColumnTargetUniqId = "target_uniq_id";
        private static readonly string ColumnContent = "content";
        private static readonly string ColumnInactive = "inactive";
        private static readonly string ColumnCreateBy = "create_by";
        private static readonly string ColumnCreateOn = "create_on";
        private static readonly string ColumnParentId = "parent_id";
        private static readonly string ColumnCommentId = "comment_id";


        public CommentDao(int tenantID)
            : base(tenantID)
        {
        }


        public List<Comment> GetAll(DomainObject<int> target)
        {
            return Db
                .ExecuteList(
                    Query("projects_comments")
                        .Select(ColumnId,
                ColumnTargetUniqId,
                ColumnContent,
                ColumnInactive,
                ColumnCreateBy,
                ColumnCreateOn,
                ColumnParentId,
                ColumnCommentId)
                        .Where("target_uniq_id", target.UniqID))
                .ConvertAll(ToComment)
                .OrderBy(c => c.CreateOn)
                .ToList();
        }

        public Comment GetById(Guid id)
        {
            return Db.ExecuteList(Query(CommentsTable).Select(ColumnId,
                ColumnTargetUniqId,
                ColumnContent,
                ColumnInactive,
                ColumnCreateBy,
                ColumnCreateOn,
                ColumnParentId,
                ColumnCommentId).Where("id", id.ToString()))
                        .ConvertAll(ToComment)
                        .SingleOrDefault();
        }

        public List<int> Count(List<ProjectEntity> targets)
        {
            var pairs = Db.ExecuteList(
                Query(CommentsTable)
                    .Select("target_uniq_id", "count(*)")
                    .Where(Exp.In("target_uniq_id", targets.ConvertAll(target => target.UniqID)))
                    .Where("inactive", false)
                    .GroupBy(1)
                ).ConvertAll(r => new object[] { Convert.ToString(r[0]), Convert.ToInt32(r[1]) });

            return targets.ConvertAll(
                target =>
                {
                    var pair = pairs.Find(p => String.Equals(Convert.ToString(p[0]), target.UniqID));
                    return pair == null ? 0 : Convert.ToInt32(pair[1]);
                });
        }

        public List<Comment> GetComments(Exp where)
        {
            return Db.ExecuteList(
                Query(CommentsTable)
                    .Select(ColumnId,
                ColumnTargetUniqId,
                ColumnContent,
                ColumnInactive,
                ColumnCreateBy,
                ColumnCreateOn,
                ColumnParentId,
                ColumnCommentId)
                    .Where(where)
                    .Where("inactive", false)
                    .OrderBy("create_on", false))
                .ConvertAll(ToComment);
        }

        public int Count(DomainObject<Int32> target)
        {
            return Db.ExecuteScalar<int>(
                Query(CommentsTable)
                    .SelectCount()
                    .Where("target_uniq_id", target.UniqID)
                    .Where("inactive", false));
        }


        public Comment Save(Comment comment)
        {
            if (comment.OldGuidId == default(Guid)) comment.OldGuidId = Guid.NewGuid();

            if (!string.IsNullOrWhiteSpace(comment.Content) && comment.Content.Contains("<w:WordDocument>"))
            {
                try
                {
                    comment.Content = Sanitizer.GetSafeHtmlFragment(comment.Content);
                }
                catch (Exception err)
                {
                    LogManager.GetLogger("ASC").Error(err);
                }
            }

            var insert = Insert(CommentsTable)
                .InColumnValue(ColumnCommentId, comment.ID)
                .InColumnValue(ColumnId, comment.OldGuidId)
                .InColumnValue(ColumnTargetUniqId, comment.TargetUniqID)
                .InColumnValue(ColumnContent, comment.Content)
                .InColumnValue(ColumnInactive, comment.Inactive)
                .InColumnValue(ColumnCreateBy, comment.CreateBy.ToString())
                .InColumnValue(ColumnCreateOn, TenantUtil.DateTimeToUtc(comment.CreateOn))
                .InColumnValue(ColumnParentId, comment.Parent.ToString())
                .Identity(1, 0, true);

            comment.ID = Db.ExecuteScalar<int>(insert);
            return comment;
        }

        public void Delete(Guid id)
        {
            Db.ExecuteNonQuery(Delete(CommentsTable).Where("id", id.ToString()));
        }


        private static Comment ToComment(object[] r)
        {
            return new Comment
            {
                OldGuidId = ToGuid(r[0]),
                TargetUniqID = (string)r[1],
                Content = (string)r[2],
                Inactive = Convert.ToBoolean(r[3]),
                CreateBy = ToGuid(r[4]),
                CreateOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[5])),
                Parent = ToGuid(r[6]),
                ID = Convert.ToInt32(r[7])
            };
        }
    }
}

<|start_filename|>module/ASC.Files.Thirdparty/OneDrive/OneDriveProviderInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Web;

using ASC.Common.Caching;
using ASC.Common.Web;
using ASC.Core;
using ASC.FederatedLogin;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.Files.Core;

using Microsoft.OneDrive.Sdk;

namespace ASC.Files.Thirdparty.OneDrive
{
    [DebuggerDisplay("{CustomerTitle}")]
    public class OneDriveProviderInfo : IProviderInfo, IDisposable
    {
        private OAuth20Token _token;
        private readonly FolderType _rootFolderType;
        private readonly DateTime _createOn;

        internal OneDriveStorage Storage
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    var key = "__ONEDRIVE_STORAGE" + ID;
                    var wrapper = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                    if (wrapper == null || !wrapper.Storage.IsOpened)
                    {
                        wrapper = new StorageDisposableWrapper(CreateStorage());
                        DisposableHttpContext.Current[key] = wrapper;
                    }
                    return wrapper.Storage;
                }
                return CreateStorage();
            }
        }

        internal bool StorageOpened
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    var key = "__ONEDRIVE_STORAGE" + ID;
                    var wrapper = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                    return wrapper != null && wrapper.Storage.IsOpened;
                }
                return false;
            }
        }

        public int ID { get; set; }

        public Guid Owner { get; private set; }

        public string CustomerTitle { get; private set; }

        public DateTime CreateOn
        {
            get { return _createOn; }
        }

        public object RootFolderId
        {
            get { return "onedrive-" + ID; }
        }

        public string ProviderKey { get; private set; }

        public FolderType RootFolderType
        {
            get { return _rootFolderType; }
        }


        public OneDriveProviderInfo(int id, string providerKey, string customerTitle, string token, Guid owner, FolderType rootFolderType, DateTime createOn)
        {
            if (string.IsNullOrEmpty(providerKey)) throw new ArgumentNullException("providerKey");
            if (string.IsNullOrEmpty(token)) throw new ArgumentException("Token can't be null");

            ID = id;
            CustomerTitle = customerTitle;
            Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner;

            ProviderKey = providerKey;
            _token = OAuth20Token.FromJson(token);
            _rootFolderType = rootFolderType;
            _createOn = createOn;
        }

        public void Dispose()
        {
            if (StorageOpened)
                Storage.Close();
        }

        public bool CheckAccess()
        {
            try
            {
                return Storage.CheckAccess();
            }
            catch (AggregateException)
            {
                return false;
            }
        }

        public void InvalidateStorage()
        {
            if (HttpContext.Current != null)
            {
                var key = "__ONEDRIVE_STORAGE" + ID;
                var storage = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                if (storage != null)
                {
                    storage.Dispose();
                }
            }
            CacheReset();
        }

        internal void UpdateTitle(string newtitle)
        {
            CustomerTitle = newtitle;
        }

        private OneDriveStorage CreateStorage()
        {
            var onedriveStorage = new OneDriveStorage();

            CheckToken();

            onedriveStorage.Open(_token);
            return onedriveStorage;
        }

        private void CheckToken()
        {
            if (_token == null) throw new UnauthorizedAccessException("Cannot create GoogleDrive session with given token");
            if (_token.IsExpired)
            {
                _token = OAuth20TokenHelper.RefreshToken<OneDriveLoginProvider>(_token);

                using (var dbDao = new CachedProviderAccountDao(CoreContext.TenantManager.GetCurrentTenant().TenantId, FileConstant.DatabaseId))
                {
                    var authData = new AuthData(token: _token.ToJson());
                    dbDao.UpdateProviderInfo(ID, authData);
                }
            }
        }


        private class StorageDisposableWrapper : IDisposable
        {
            public OneDriveStorage Storage { get; private set; }


            public StorageDisposableWrapper(OneDriveStorage storage)
            {
                Storage = storage;
            }

            public void Dispose()
            {
                Storage.Close();
            }
        }


        private static readonly TimeSpan CacheExpiration = TimeSpan.FromMinutes(1);
        private static readonly ICache CacheItem = AscCache.Memory;
        private static readonly ICache CacheChildItems = AscCache.Memory;
        private static readonly ICacheNotify CacheNotify;

        static OneDriveProviderInfo()
        {
            CacheNotify = AscCache.Notify;
            CacheNotify.Subscribe<OneDriveCacheItem>((i, action) =>
                {
                    if (action != CacheNotifyAction.Remove) return;
                    if (i.ResetAll)
                    {
                        CacheChildItems.Remove(new Regex("^onedrivei-" + i.Key + ".*"));
                        CacheItem.Remove(new Regex("^onedrive-" + i.Key + ".*"));
                    }
                    else
                    {
                        CacheChildItems.Remove(new Regex("onedrivei-" + i.Key));
                        CacheItem.Remove("onedrive-" + i.Key);
                    }
                });
        }

        internal Item GetOneDriveItem(string itemId)
        {
            var file = CacheItem.Get<Item>("onedrive-" + ID + "-" + itemId);
            if (file == null)
            {
                file = Storage.GetItem(itemId);
                if (file != null)
                    CacheItem.Insert("onedrive-" + ID + "-" + itemId, file, DateTime.UtcNow.Add(CacheExpiration));
            }
            return file;
        }

        internal List<Item> GetOneDriveItems(string onedriveFolderId)
        {
            var items = CacheChildItems.Get<List<Item>>("onedrivei-" + ID + "-" + onedriveFolderId);

            if (items == null)
            {
                items = Storage.GetItems(onedriveFolderId);
                CacheChildItems.Insert("onedrivei-" + ID + "-" + onedriveFolderId, items, DateTime.UtcNow.Add(CacheExpiration));
            }
            return items;
        }

        internal void CacheReset(string onedriveId = null)
        {
            var key = ID + "-";
            if (string.IsNullOrEmpty(onedriveId))
            {
                CacheNotify.Publish(new OneDriveCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove);
            }
            else
            {
                key += onedriveId;

                CacheNotify.Publish(new OneDriveCacheItem { Key = key }, CacheNotifyAction.Remove);
            }
        }

        private class OneDriveCacheItem
        {
            public bool ResetAll { get; set; }
            public string Key { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Controls/Common/ProjectDocumentsPopup.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Files.Core;
using ASC.Web.Files;
using ASC.Web.Projects.Classes;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Common.LoaderPage;

namespace ASC.Web.Projects.Controls.Common
{
    public partial class ProjectDocumentsPopup : UserControl
    {
        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Common/ProjectDocumentsPopup.ascx"); }
        }

        protected string FrameUrl;

        protected void Page_Load(object sender, EventArgs e)
        {
            _documentUploader.Options.IsPopup = true;
            InitScripts();
        }

        private void InitScripts()
        {
            FrameUrl = FileChoice.GetUrl(filterType: FilterType.FilesOnly, root: FolderType.Projects, multiple: true, successButton: UserControlsCommonResource.AttachFiles);

            loaderHolder.Controls.Add(LoadControl(LoaderPage.Location));

            Page.RegisterStyle("~/Products/Projects/App_Themes/default/css/projectdocumentspopup.less")
                .RegisterBodyScripts("~/Products/Projects/js/projectdocumentspopup.js");
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/MailDomainSettings/MailDomainSettings.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.MessagingSystem;
using ASC.Web.Core.Utility.Settings;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    [ManagementControl(ManagementType.PortalSecurity, Location, SortOrder = 150)]
    [AjaxNamespace("MailDomainSettingsController")]
    public partial class MailDomainSettings : UserControl
    {
        public const string Location = "~/UserControls/Management/MailDomainSettings/MailDomainSettings.ascx";

        protected Tenant _currentTenant = null;
        protected StudioTrustedDomainSettings _studioTrustedDomainSettings;
        protected bool _enableInviteUsers;
        protected bool _tenantAccessAnyone;
        protected string HelpLink { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            AjaxPro.Utility.RegisterTypeForAjax(GetType());

            Page.RegisterBodyScripts("~/UserControls/Management/MailDomainSettings/js/maildomainsettings.js")
                .RegisterStyle("~/UserControls/Management/MailDomainSettings/css/maildomainsettings.less");

            _currentTenant = CoreContext.TenantManager.GetCurrentTenant();
            _studioTrustedDomainSettings = StudioTrustedDomainSettings.Load();
            _enableInviteUsers = TenantStatisticsProvider.GetUsersCount() < TenantExtra.GetTenantQuota().ActiveUsers;

            if (!_enableInviteUsers)
            {
                _studioTrustedDomainSettings.InviteUsersAsVisitors = true;
            }

            var managementPage = Page as Studio.Management;
            _tenantAccessAnyone = managementPage != null ?
                                     managementPage.TenantAccess.Anyone :
                                     TenantAccessSettings.Load().Anyone;

            HelpLink = CommonLinkUtility.GetHelpLink();
        }

        private bool CheckTrustedDomain(string domain)
        {
            return !string.IsNullOrEmpty(domain) && new Regex("^[(?\\*)a-z0-9]([a-z0-9-.]){1,98}[a-z0-9]$").IsMatch(domain);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object SaveMailDomainSettings(TenantTrustedDomainsType type, List<string> domains, bool inviteUsersAsVisitors)
        {
            try
            {
                SecurityContext.DemandPermissions(SecutiryConstants.EditPortalSettings);

                var tenant = CoreContext.TenantManager.GetCurrentTenant();

                if (type == TenantTrustedDomainsType.Custom)
                {
                    tenant.TrustedDomains.Clear();
                    foreach (var d in domains.Select(domain => (domain ?? "").Trim().ToLower()))
                    {
                        if (!CheckTrustedDomain(d))
                            return new { Status = 0, Message = Resource.ErrorNotCorrectTrustedDomain };

                        tenant.TrustedDomains.Add(d);
                    }

                    if (tenant.TrustedDomains.Count == 0)
                        type = TenantTrustedDomainsType.None;
                }

                tenant.TrustedDomainsType = type;

                new StudioTrustedDomainSettings { InviteUsersAsVisitors = inviteUsersAsVisitors }.Save();

                CoreContext.TenantManager.SaveTenant(tenant);

                MessageService.Send(HttpContext.Current.Request, MessageAction.TrustedMailDomainSettingsUpdated);

                return new { Status = 1, Message = Resource.SuccessfullySaveSettingsMessage };
            }
            catch (Exception e)
            {
                return new { Status = 0, Message = e.Message.HtmlEncode() };
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Masters/ClientScripts/ClientTemplateResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Web.Core.Client.HttpHandlers;

namespace ASC.Web.CRM.Masters.ClientScripts
{
    public class ClientTemplateResources : ClientScriptTemplate
    {
        protected override string[] Links
        {
            get
            {
                return new[] {
                "~/Products/CRM/Templates/CasesTemplates.html",
                "~/Products/CRM/Templates/CommonCustomFieldsTemplates.html",
                "~/Products/CRM/Templates/CommonTemplates.html",
                "~/Products/CRM/Templates/ContactsTemplates.html",
                "~/Products/CRM/Templates/DealsTemplates.html",
                "~/Products/CRM/Templates/DealsSelectorTemplates.html",
                "~/Products/CRM/Templates/SimpleContactListTemplate.html",
                "~/Products/CRM/Templates/TasksTemplates.html",
                "~/Products/CRM/Templates/ContactSelectorTemplates.html",
                "~/Products/CRM/Templates/ContactInfoCardTemplate.html",
                "~/Products/CRM/Templates/SettingsTemplates.html",
                "~/Products/CRM/Templates/InvoicesTemplates.html",
                "~/Products/CRM/Templates/VoipTemplates.html",
                "~/Products/Projects/ProjectsTemplates/ListProjectsTemplates.html"
                };
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/Base/MailComposeBase.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Files.Core.Security;
using ASC.Mail.Enums;
using ASC.Mail.Exceptions;
using ASC.Mail.Utils;

namespace ASC.Mail.Data.Contracts.Base
{
    public class MailComposeBase
    {
        private readonly string _calendarEventUid;
        private readonly string _calendarMethod;
        private readonly string _calendarIcs;

        public MailComposeBase(int id, MailBoxData mailBoxData, FolderType folder, string from, List<string> to, List<string> cc, List<string> bcc,
                         string subject, string mimeMessageId, string mimeReplyToId, bool important,
                         List<int> tags, string body, string streamId, List<MailAttachmentData> attachments, string calendarIcs = "")
        {
            Id = id;
            Mailbox = mailBoxData;
            Folder = folder;
            From = from;
            To = to ?? new List<string>();
            Cc = cc ?? new List<string>();
            Bcc = bcc ?? new List<string>();
            Subject = subject;
            MimeMessageId = mimeMessageId;
            MimeReplyToId = mimeReplyToId;
            Important = important;
            Labels = tags;
            HtmlBody = string.IsNullOrEmpty(body) ? "<p>&nbsp;</p>" : body;
            StreamId = streamId;

            var distinct = attachments == null ? new List<MailAttachmentData>() : attachments.Distinct().ToList();

            if (distinct.Sum(a => a.size) > Defines.ATTACHMENTS_TOTAL_SIZE_LIMIT)
                throw new DraftException(DraftException.ErrorTypes.TotalSizeExceeded,
                    "Total size of all files exceeds limit!");

            Attachments = distinct;
            AttachmentsEmbedded = new List<MailAttachmentData>();

            if (string.IsNullOrEmpty(calendarIcs))
                return;

            _calendarIcs = calendarIcs;

            var calendar = MailUtil.ParseValidCalendar(_calendarIcs);
            if (calendar != null)
            {
                _calendarMethod = calendar.Method;
                _calendarEventUid = calendar.Events[0].Uid;
            }
        }

        public int Id { get; set; }

        public MailBoxData Mailbox { get; set; }

        public FolderType Folder { get; set; }

        public List<string> To { get; set; }

        public List<string> Cc { get; set; }

        public List<string> Bcc { get; set; }

        public bool Important { get; set; }

        public string From { get; set; }

        public string Subject { get; set; }

        public string HtmlBody { get; set; }

        public List<MailAttachmentData> Attachments { get; set; }

        public List<MailAttachmentData> AttachmentsEmbedded { get; set; }

        public string StreamId { get; set; }

        public int ReplyToId { get; set; }

        public List<int> Labels { get; set; }

        public string MimeMessageId { get; set; }

        public string MimeReplyToId { get; set; }

        public FileShare FileLinksShareMode { get; set; }

        public bool AccountChanged
        {
            get { return Mailbox.MailBoxId != PreviousMailboxId; }
        }

        public int PreviousMailboxId { get; set; }

        public string CalendarIcs
        {
            get { return _calendarIcs; }
        }

        public string CalendarEventUid
        {
            get { return _calendarEventUid; }
        }

        public string CalendarMethod
        {
            get { return _calendarMethod; }
        }
    }
}

<|start_filename|>common/Tests/ASC.Data.Storage.Tests/Encryption/CryptTest.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using ASC.Core.Encryption;
using ASC.Data.Encryption;

namespace ASC.Data.Storage.Tests.Encryption
{
    [TestClass]
    public class CryptTest
    {
        private readonly CommonMethods CommonMethods;
        private readonly EncryptionSettings Settings;
        private readonly ICrypt Crypt;


        public CryptTest()
        {
            CommonMethods = new CommonMethods();

            Settings = new EncryptionSettings()
            {
                Password = EncryptionSettings.GeneratePassword(32, 16),
                Status = EncryprtionStatus.Encrypted,
                NotifyUsers = false
            };

            Crypt = new Crypt("test", Settings);
        }


        [TestMethod]
        public void EncryptDecryptReadonlyFiles()
        {
            var testFile = CommonMethods.CreateTestFile();

            var fileInfo = new FileInfo(testFile.Path);

            Assert.AreEqual(false, fileInfo.IsReadOnly);

            fileInfo.IsReadOnly = true;

            Assert.AreEqual(true, fileInfo.IsReadOnly);

            Encrypt(testFile);

            Decrypt(testFile);

            fileInfo = new FileInfo(testFile.Path);

            Assert.AreEqual(false, fileInfo.IsReadOnly);

            CommonMethods.DeleteTestFile(testFile.Path);
        }

        [TestMethod]
        public void EncryptDecryptFile()
        {
            var testFile = CommonMethods.CreateTestFile();

            Encrypt(testFile);

            Decrypt(testFile);

            CommonMethods.DeleteTestFile(testFile.Path);
        }

        [TestMethod]
        public void EncryptTwiceDecryptTwiceFile()
        {
            var testFile = CommonMethods.CreateTestFile();

            Encrypt(testFile);

            Encrypt(testFile);

            Decrypt(testFile);

            Decrypt(testFile);

            CommonMethods.DeleteTestFile(testFile.Path);
        }

        [TestMethod]
        public void GetReadStream()
        {
            var testFile = CommonMethods.CreateTestFile();

            Encrypt(testFile);

            GetReadStream(testFile);

            Decrypt(testFile);

            CommonMethods.DeleteTestFile(testFile.Path);
        }

        [TestMethod]
        public void GetFileSize()
        {
            var testFile = CommonMethods.CreateTestFile();

            Crypt.EncryptFile(testFile.Path);

            var size = Crypt.GetFileSize(testFile.Path);

            CommonMethods.DeleteTestFile(testFile.Path);

            Assert.AreEqual(testFile.Size, size);
        }


        private void Encrypt(CommonFileInfo fileInfo)
        {
            Crypt.EncryptFile(fileInfo.Path);

            Assert.AreNotEqual(fileInfo.Content, File.ReadAllText(fileInfo.Path));

            Assert.AreEqual(fileInfo.Size, Crypt.GetFileSize(fileInfo.Path));
        }

        private void Decrypt(CommonFileInfo fileInfo)
        {
            Crypt.DecryptFile(fileInfo.Path);

            Assert.AreEqual(fileInfo.Content, File.ReadAllText(fileInfo.Path));

            Assert.AreEqual(fileInfo.Size, new FileInfo(fileInfo.Path).Length);
        }

        private void GetReadStream(CommonFileInfo fileInfo)
        {
            using (var stream = Crypt.GetReadStream(fileInfo.Path))
            {
                stream.Position = 0;
                if (stream.CanSeek)
                {
                    stream.Seek(0, SeekOrigin.Begin);
                }
                Assert.AreEqual(fileInfo.Content, new StreamReader(stream).ReadToEnd());
                Assert.AreEqual(fileInfo.Size, stream.Length);
            }
        }
    }
}


<|start_filename|>module/ASC.Notify/ASC.Notify/NotifySender.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Threading;

using ASC.Common.Logging;
using ASC.Notify.Config;
using ASC.Notify.Messages;

namespace ASC.Notify
{
    class NotifySender
    {
        private static readonly ILog log = LogManager.GetLogger("ASC");

        private readonly DbWorker db = new DbWorker();

        private AutoResetEvent waiter;
        private Thread threadManager;
        private volatile bool work;
        private int threadsCount;


        public void StartSending()
        {
            db.ResetStates();

            work = true;
            threadsCount = 0;
            waiter = new AutoResetEvent(true);
            threadManager = new Thread(ThreadManagerWork)
            {
                Priority = ThreadPriority.BelowNormal,
                Name = "NotifyThreadManager",
            };
            threadManager.Start();
        }

        public void StopSending()
        {
            work = false;
            if (waiter != null)
            {
                waiter.Set();
            }
            if (threadManager != null)
            {
                threadManager.Join();
                threadManager = null;
            }
            if (waiter != null)
            {
                waiter.Close();
            }
            waiter = null;
        }


        private void ThreadManagerWork()
        {
            while (work)
            {
                try
                {
                    waiter.WaitOne(TimeSpan.FromSeconds(5));
                    if (!work)
                    {
                        return;
                    }

                    var count = Thread.VolatileRead(ref threadsCount);
                    if (count < NotifyServiceCfg.MaxThreads)
                    {
                        var messages = db.GetMessages(NotifyServiceCfg.BufferSize);
                        if (0 < messages.Count)
                        {
                            var t = new Thread(SendMessages)
                            {
                                Priority = ThreadPriority.BelowNormal,
                                Name = "NotifyThread " + DateTime.UtcNow.ToString("o"),
                                IsBackground = true,
                            };
                            t.Start(messages);
                            Interlocked.Increment(ref threadsCount);
                            waiter.Set();

                            log.DebugFormat("{0} started.", t.Name);
                        }
                    }
                }
                catch (ThreadAbortException)
                {
                    return;
                }
                catch (Exception e)
                {
                    log.Error(e);
                }
            }
        }

        private void SendMessages(object messages)
        {
            try
            {
                foreach (var m in (IDictionary<int, NotifyMessage>)messages)
                {
                    if (!work) return;

                    var result = MailSendingState.Sended;
                    try
                    {
                        NotifyServiceCfg.Senders[m.Value.Sender].Send(m.Value);
                        log.DebugFormat("Notify #{0} has been sent.", m.Key);
                    }
                    catch (Exception e)
                    {
                        result = MailSendingState.FatalError;
                        log.Error(e);
                    }
                    db.SetState(m.Key, result);
                }
            }
            catch (ThreadAbortException)
            {
                return;
            }
            catch (Exception e)
            {
                log.Error(e);
            }
            finally
            {
                Interlocked.Decrement(ref threadsCount);
                try
                {
                    waiter.Set();
                }
                catch (ObjectDisposedException) { }
                log.DebugFormat("{0} stopped.", Thread.CurrentThread.Name);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Core/Dao/ForumDataProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web;

using ASC.Common.Caching;
using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch;
using ASC.Web.Community.Forum;
using ASC.Web.Community.Product;
using ASC.Web.Community.Search;
using ASC.Web.Studio.Utility;

namespace ASC.Forum
{
    public enum DeletePostResult
    {
        Successfully,

        ReferencesBlock,

        Error
    }

    [Flags]
    public enum SearchTopicPlace
    {
        TopicName = 1,

        PostText = 2,

        TagName = 4,

        All = TopicName | PostText | TagName
    }

    internal class ThreadVisitInfo
    {
        public DateTime RecentVisitDate { get; set; }
        public int ThreadID { get; set; }
        public Dictionary<int, int> TopicViewRecentPostIDs { get; set; }

        public ThreadVisitInfo()
        {
            TopicViewRecentPostIDs = new Dictionary<int, int>();
            RecentVisitDate = DateTime.MinValue;
        }

        public static ThreadVisitInfo GetThreadVisitInfo(int threadID)
        {
            if (HttpContext.Current != null)
            {
                var key = UserKeys.StringSessionKey + SecurityContext.CurrentAccount.ID.ToString();
                var hash = HttpContext.Current.Session[key] as Hashtable;
                if (hash == null)
                {
                    hash = Hashtable.Synchronized(new Hashtable());
                    foreach (var f in ForumDataProvider.InitFirstVisit())
                    {
                        hash[UserKeys.StringThreadKey + f.ThreadID.ToString(CultureInfo.InvariantCulture)] = f;
                    }
                    HttpContext.Current.Session.Add(key, hash);
                }

                var threadKey = UserKeys.StringThreadKey + threadID.ToString(CultureInfo.InvariantCulture);
                var tvi = new ThreadVisitInfo { ThreadID = threadID };
                if (hash.Contains(threadKey))
                {
                    tvi = (ThreadVisitInfo)hash[threadKey];
                }
                else
                {
                    hash[threadKey] = tvi;
                    HttpContext.Current.Session[key] = hash;
                }

                return tvi;
            }

            return null;
        }

        public static DateTime GetMinVisitThreadDate()
        {
            HttpContext context = HttpContext.Current;
            if (context == null)
                return DateTime.MinValue;

            Guid userID = SecurityContext.CurrentAccount.ID;
            if (context.Session[UserKeys.StringSessionKey + userID.ToString()] == null)
                return DateTime.MinValue;

            DateTime result = DateTime.MinValue;
            var hash = (Hashtable)context.Session[UserKeys.StringSessionKey + userID.ToString()];

            foreach (var tvi in hash.Values)
            {
                if (tvi == null || !(tvi is ThreadVisitInfo)) continue;

                var t = (tvi as ThreadVisitInfo);
                if (result == DateTime.MinValue)
                    result = t.RecentVisitDate;

                if (t.RecentVisitDate < result)
                    result = t.RecentVisitDate;
            }

            return result;
        }
    }

    public class ForumDataProvider
    {
        internal static IDbManager DbManager
        {
            get
            {
                return Common.Data.DbManager.FromHttpContext(ASC.Web.Community.Forum.ForumManager.DbId);
            }
        }

        public static void SetThreadVisit(int tenantID, int threadID)
        {
            DbManager.ExecuteNonQuery(new SqlInsert("forum_lastvisit", true)
                .InColumns("tenantid", "user_id", "thread_id", "last_visit")
                .Values(tenantID, SecurityContext.CurrentAccount.ID.ToString(), threadID, DateTime.UtcNow));
        }

        public static void SetTopicVisit(Topic topic)
        {
            if (topic.RecentPostID > 0)
            {
                ThreadVisitInfo tvi = ThreadVisitInfo.GetThreadVisitInfo(topic.ThreadID);
                if (tvi != null)
                    tvi.TopicViewRecentPostIDs[topic.ID] = topic.RecentPostID;
            }

            SetThreadVisit(topic.TenantID, topic.ThreadID);

            DbManager.Connection.CreateCommand(@"update forum_topic set view_count = view_count+1 where id = @topicID and TenantID = @tid")
                .AddParameter("topicID", topic.ID)
                .AddParameter("tid", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .ExecuteNonQuery();
        }

        internal static IEnumerable<ThreadVisitInfo> InitFirstVisit()
        {
            return DbManager.ExecuteList(new SqlQuery("forum_lastvisit")
                .Select("thread_id", "last_visit")
                .Where("user_id", SecurityContext.CurrentAccount.ID.ToString())
                .Where("tenantid", CoreContext.TenantManager.GetCurrentTenant().TenantId))
                .ConvertAll(r => new ThreadVisitInfo { ThreadID = Convert.ToInt32(r[0]), RecentVisitDate = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[1])), });
        }

        #region Thread & Categories

        private static void ParseThreadCategories(IEnumerable<object[]> data, bool checkNew, out List<ThreadCategory> categories, out List<Thread> threads)
        {
            categories = new List<ThreadCategory>();
            threads = new List<Thread>();

            foreach (var row in data)
            {
                var cid = Convert.ToInt32(row[0]);
                if (categories.Find(c => c.ID == cid) == null)
                {
                    categories.Add(new ThreadCategory
                    {
                        ID = cid,
                        TenantID = Convert.ToInt32(row[1]),
                        Title = Convert.ToString(row[2]),
                        Description = (row[3] != null ? Convert.ToString(row[3]) : ""),
                        SortOrder = Convert.ToInt32(row[4]),
                        CreateDate = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[5])),
                        PosterID = new Guid(Convert.ToString(row[6]))
                    });
                }

                if (row[7] != null)
                {
                    threads.Add(new Thread
                    {
                        CategoryID = cid,
                        ID = Convert.ToInt32(row[7]),
                        TenantID = Convert.ToInt32(row[1]),
                        Title = Convert.ToString(row[8]),
                        Description = (row[9] != null ? Convert.ToString(row[9]) : ""),
                        SortOrder = Convert.ToInt32(row[10]),
                        TopicCount = Convert.ToInt32(row[11]),
                        PostCount = Convert.ToInt32(row[12]),
                        RecentPostID = Convert.ToInt32(row[13]),
                        RecentTopicID = Convert.ToInt32(row[14]),
                        IsApproved = Convert.ToBoolean(row[15]),
                        RecentTopicTitle = (row[16] != null ? Convert.ToString(row[16]) : ""),
                        RecentPostCreateDate = (row[17]) != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[17])) : DateTime.MinValue,
                        RecentPosterID = (row[18]) != null ? new Guid(Convert.ToString(row[18])) : Guid.Empty,
                        RecentTopicPostCount = (row[19]) != null ? Convert.ToInt32(row[19]) : 0
                    });
                }
            }

            if (checkNew)
            {
                if (threads.Count > 0)
                {
                    var minVisitDate = ThreadVisitInfo.GetMinVisitThreadDate();
                    List<object[]> threadTopics;

                    if (minVisitDate == DateTime.MinValue)
                        threadTopics = DbManager.ExecuteList(new SqlQuery("forum_topic t1").Select("t1.thread_id", "t1.id", "t1.recent_post_id", "t2.create_date")
                                                                .LeftOuterJoin("forum_post t2", Exp.EqColumns("t1.recent_post_id", "t2.id") & Exp.Eq("t2.TenantID", threads[0].TenantID))
                                                                .Where(Exp.Eq("t1.TenantID", threads[0].TenantID)
                                                                       & Exp.In("t1.thread_id", threads.ConvertAll(t => t.ID)))
                                                                 );
                    else
                        threadTopics = DbManager.ExecuteList(new SqlQuery("forum_topic t1").Select("t1.thread_id", "t1.id", "t1.recent_post_id", "t2.create_date")
                                                                .InnerJoin("forum_post t2", Exp.EqColumns("t1.recent_post_id", "t2.id") & Exp.Ge("t2.create_date", minVisitDate))
                                                                .Where(Exp.Eq("t1.TenantID", threads[0].TenantID)
                                                                       & Exp.Eq("t2.TenantID", threads[0].TenantID)
                                                                       & Exp.In("t1.thread_id", threads.ConvertAll(t => t.ID))
                                                                 ));


                    foreach (var row in threadTopics)
                    {
                        var tid = Convert.ToInt32(row[0]);

                        var thr = threads.Find(t => t.ID == tid);
                        if (thr != null)
                        {
                            thr.TopicLastUpdates.Add(new Thread.TopicLastUpdate
                            {
                                TopicID = Convert.ToInt32(row[1]),
                                RecentPostID = Convert.ToInt32(row[2]),
                                RecentPostCreateDate = (row[3]) != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[3])) : DateTime.MinValue
                            });
                        }
                    }
                }
            }
        }

        public static ThreadCategory GetCategoryByID(int tenantID, int categoryID, out List<Thread> threads)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_category t1")
                                                 .Select("t1.id", "t1.TenantID", "t1.title", "t1.description", "t1.sort_order", "t1.create_date", "t1.poster_id",
                                                         "t2.id", "t2.title, t2.description", "t2.sort_order", "t2.topic_count", "t2.post_count", "t2.recent_post_id", "t2.recent_topic_id", "t2.is_approved",
                                                         "t3.title", "t2.recent_post_date", "t2.recent_poster_id", "t3.post_count")
                                                 .LeftOuterJoin("forum_thread t2", Exp.EqColumns("t1.id", "t2.category_id") & Exp.Eq("t2.TenantID", tenantID))
                                                 .LeftOuterJoin("forum_topic t3", Exp.EqColumns("t2.recent_topic_id", "t3.id") & Exp.Eq("t3.TenantID", tenantID))
                                                 .Where(Exp.Eq("t1.TenantID", tenantID) & Exp.Eq("t1.id", categoryID))
                                                 .OrderBy("t1.sort_order", true).OrderBy("t2.sort_order", true));

            List<ThreadCategory> categories;
            ParseThreadCategories(data, false, out categories, out threads);

            return categories.Count > 0 ? categories[0] : null;
        }

        public static void GetThreadCategories(int tenantID, out List<ThreadCategory> categories, out List<Thread> threads)
        {
            GetThreadCategories(tenantID, false, out categories, out threads);
        }

        public static void GetThreadCategories(int tenantID, bool checkNew, out List<ThreadCategory> categories, out List<Thread> threads)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_category t1").Select("t1.id", "t1.TenantID", "t1.title", "t1.description", "t1.sort_order", "t1.create_date", "t1.poster_id",
                                                                                      "t2.id", "t2.title, t2.description", "t2.sort_order", "t2.topic_count", "t2.post_count", "t2.recent_post_id", "t2.recent_topic_id", "t2.is_approved",
                                                                                      "t3.title", "t2.recent_post_date", "t2.recent_poster_id", "t3.post_count")
                                                 .LeftOuterJoin("forum_thread t2", Exp.EqColumns("t1.id", "t2.category_id") & Exp.Eq("t2.TenantID", tenantID))
                                                 .LeftOuterJoin("forum_topic t3", Exp.EqColumns("t2.recent_topic_id", "t3.id") & Exp.Eq("t3.TenantID", tenantID))
                                                 .Where(Exp.Eq("t1.TenantID", tenantID))
                                                 .OrderBy("t1.sort_order", true).OrderBy("t2.sort_order", true));

            ParseThreadCategories(data, checkNew, out categories, out threads);
        }

        public static Thread GetThreadByID(int tenantID, int threadID)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_thread t2").Select(
                                        "t2.id", "t2.category_id", "t2.title, t2.description", "t2.sort_order", "t2.topic_count", "t2.post_count", "t2.recent_post_id", "t2.recent_topic_id", "t2.is_approved",
                                        "t3.title", "t2.recent_post_date", "t2.recent_poster_id", "t3.post_count")
                                        .LeftOuterJoin("forum_topic t3", Exp.EqColumns("t2.recent_topic_id", "t3.id") & Exp.Eq("t3.TenantID", tenantID))
                                        .Where(Exp.Eq("t2.TenantID", tenantID) & Exp.Eq("t2.id", threadID)));

            if (data.Count == 0)
                return null;

            var row = data[0];
            return new Thread
            {

                ID = threadID,
                CategoryID = Convert.ToInt32(row[1]),
                TenantID = tenantID,
                Title = Convert.ToString(row[2]),
                Description = (row[3] != null ? Convert.ToString(row[3]) : ""),
                SortOrder = Convert.ToInt32(row[4]),
                TopicCount = Convert.ToInt32(row[5]),
                PostCount = Convert.ToInt32(row[6]),
                RecentPostID = Convert.ToInt32(row[7]),
                RecentTopicID = Convert.ToInt32(row[8]),
                IsApproved = Convert.ToBoolean(row[9]),
                RecentTopicTitle = (row[10] != null ? Convert.ToString(row[10]) : ""),
                RecentPostCreateDate = (row[11]) != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[11])) : DateTime.MinValue,
                RecentPosterID = (row[12]) != null ? new Guid(Convert.ToString(row[12])) : Guid.Empty,
                RecentTopicPostCount = (row[13] != null ? Convert.ToInt32(row[13]) : 0)
            };
        }

        public static int CreateThreadCategory(int tenantID, string title, string description, int sortOrder)
        {
            return DbManager.ExecuteScalar<int>(new SqlInsert("forum_category")
                                                     .InColumnValue("id", 0)
                                                     .InColumnValue("TenantID", tenantID)
                                                     .InColumnValue("title", title)
                                                     .InColumnValue("description", description)
                                                     .InColumnValue("create_date", DateTime.UtcNow)
                                                     .InColumnValue("poster_id", SecurityContext.CurrentAccount.ID)
                                                     .InColumnValue("sort_order", sortOrder)
                                                     .Identity(0, 0, true));
        }

        public static void UpdateThreadCategory(int tenantID, int threadCategoryID, string title, string description, int sortOrder)
        {
            DbManager.ExecuteNonQuery(new SqlUpdate("forum_category").Set("title", title)
                                        .Set("description", description)
                                        .Set("sort_order", sortOrder)
                                        .Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("id", threadCategoryID)));
        }

        public static int CreateThread(int tenantID, int categoryID, string title, string description, int sortOrder)
        {
            return DbManager.ExecuteScalar<int>(new SqlInsert("forum_thread")
                                                     .InColumnValue("id", 0)
                                                     .InColumnValue("TenantID", tenantID)
                                                     .InColumnValue("category_id", categoryID)
                                                     .InColumnValue("title", title)
                                                     .InColumnValue("description", description)
                                                     .InColumnValue("is_approved", 1)
                                                     .InColumnValue("sort_order", sortOrder)
                                                     .Identity(0, 0, true));
        }

        public static void UpdateThread(int tenantID, int threadID, int categoryID, string title, string description, int sortOrder)
        {
            DbManager.ExecuteNonQuery(new SqlUpdate("forum_thread").Set("title", title)
                                        .Set("category_id", categoryID)
                                        .Set("description", description)
                                        .Set("sort_order", sortOrder)
                                        .Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("id", threadID)));
        }

        public static void RemoveThreadCategory(int tenantID, int threadCategoryID, out List<int> removedPostIDs)
        {
            removedPostIDs = new List<int>();
            List<int> threadIDs;
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                threadIDs = DbManager.Connection.CreateCommand("select id from forum_thread where TenantID = @tid and category_id = @cid")
                    .AddParameter("tid", tenantID).AddParameter("cid", threadCategoryID)
                    .ExecuteList().ConvertAll(row => Convert.ToInt32(row[0]));

                foreach (var threadID in threadIDs)
                {
                    List<int> topicIDs;
                    List<int> postIds;
                    ExeRemoveThreadCommand(tenantID, threadID, out topicIDs, out postIds);
                    removedPostIDs.AddRange(postIds);
                }

                DbManager.Connection.CreateCommand("delete from forum_category where id = @cid and TenantID = @tid")
                    .AddParameter("tid", tenantID).AddParameter("cid", threadCategoryID).ExecuteNonQuery();

                tr.Commit();
            }
            threadIDs.ForEach(SubscriberPresenter.UnsubscribeAllOnThread);

            AscCache.Default.Remove("communityScreen" + TenantProvider.CurrentTenantID);
        }

        public static void RemoveThread(int tenantID, int threadID, out List<int> removedPostIDs)
        {
            List<int> topicIDs;
            var thread = GetThreadByID(tenantID, threadID);

            using (var tr = DbManager.Connection.BeginTransaction())
            {
                ExeRemoveThreadCommand(tenantID, threadID, out topicIDs, out removedPostIDs);
                tr.Commit();
            }
            SubscriberPresenter.UnsubscribeAllOnThread(threadID);
            topicIDs.ForEach(SubscriberPresenter.UnsubscribeAllOnTopic);

            if (GetThreadCountInCategory(tenantID, thread.CategoryID) == 0)
                RemoveThreadCategory(tenantID, thread.CategoryID, out removedPostIDs);

        }

        private static void ExeRemoveThreadCommand(int tenantID, int threadID, out List<int> removedTopicIDs, out List<int> removedPostIDs)
        {
            removedPostIDs = new List<int>();
            DbManager.Connection.CreateCommand(@"delete from forum_attachment
                                                where TenantID = @tid and 
                                                      post_id in (select id from forum_post
                                                                  where TenantID = @tid and topic_id in (select id from forum_topic where TenantID = @tid and thread_id = @threadID))")
                                                 .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteNonQuery();


            removedPostIDs = DbManager.Connection.CreateCommand(@"select id from forum_post
                                    where TenantID = @tid and topic_id in (select id from forum_topic where TenantID = @tid and thread_id = @threadID)")
                                     .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteList()
                                     .ConvertAll(obj => Convert.ToInt32(obj[0]));


            DbManager.Connection.CreateCommand(@"delete from forum_post
                                    where TenantID = @tid and topic_id in (select id from forum_topic where TenantID = @tid and thread_id = @threadID)")
                                     .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteNonQuery();

            DbManager.Connection.CreateCommand(@"delete from forum_topic_tag
                                         where topic_id in (select id from forum_topic where TenantID = @tid and thread_id = @threadID)")
                                                 .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteNonQuery();

            DbManager.Connection.CreateCommand(@"delete from forum_tag
                                         where TenantID = @tid and id not in (select tag_id from forum_topic_tag)")
                                                 .AddParameter("tid", tenantID).ExecuteNonQuery();

            var q = new SqlQuery("forum_question")
                .Select("id")
                .Where("tenantid", tenantID)
                .Where(Exp.In("topic_id", new SqlQuery("forum_topic").Select("id").Where("TenantID", tenantID).Where("thread_id", threadID)));
            var questionIds = DbManager.ExecuteList(q).ConvertAll(r => Convert.ToInt32(r[0]));

            DbManager.ExecuteNonQuery(new SqlDelete("forum_question").Where(Exp.In("id", questionIds)));
            DbManager.ExecuteNonQuery(new SqlDelete("forum_variant").Where(Exp.In("question_id", questionIds)));
            DbManager.ExecuteNonQuery(new SqlDelete("forum_answer_variant").Where(Exp.In("answer_id", new SqlQuery("forum_answer").Select("id").Where(Exp.In("question_id", questionIds)))));
            DbManager.ExecuteNonQuery(new SqlDelete("forum_answer").Where(Exp.In("question_id", questionIds)));

            removedTopicIDs = DbManager.Connection.CreateCommand(@"select id from forum_topic where TenantID = @tid and thread_id = @threadID")
                                    .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteList()
                                     .ConvertAll(obj => Convert.ToInt32(obj[0]));

            DbManager.Connection.CreateCommand(@"delete from forum_topic where TenantID = @tid and thread_id = @threadID")
                                    .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteNonQuery();

            DbManager.Connection.CreateCommand(@"delete from forum_lastvisit where tenantid = @tid and thread_id = @threadID")
                                    .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteNonQuery();

            DbManager.Connection.CreateCommand(@"delete from forum_thread where id=@threadID and TenantID = @tid")
                    .AddParameter("tid", tenantID).AddParameter("threadID", threadID).ExecuteNonQuery();
        }

        public static int GetThreadCategoriesCount(int tenantID)
        {
            return DbManager.ExecuteScalar<int>(new SqlQuery("forum_category").SelectCount().Where("TenantID", tenantID));
        }

        public static int GetThreadCountInCategory(int tenantID, int categoryID)
        {
            return DbManager.ExecuteScalar<int>(new SqlQuery("forum_thread").SelectCount().Where("TenantID", tenantID).Where("category_id", categoryID));
        }

        #endregion

        #region Poll

        public static bool IsUserVote(int tenantID, int pollID, Guid userID)
        {
            if (CommunitySecurity.IsOutsider()) return true;

            var id = DbManager.ExecuteScalar<int>(new SqlQuery("forum_answer").Select("id")
                                            .Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("user_id", userID) & Exp.Eq("question_id", pollID)));

            return id > 0;
        }

        public static int CreatePoll(int tenantID, int topicID, QuestionType type, string name, List<string> answerVariants)
        {
            int pollID;
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                pollID = DbManager.ExecuteScalar<int>(new SqlInsert("forum_question")
                                                  .InColumnValue("id", 0)
                                                  .InColumnValue("TenantID", tenantID)
                                                  .InColumnValue("topic_id", topicID)
                                                  .InColumnValue("create_date", DateTime.UtcNow)
                                                  .InColumnValue("name", name)
                                                  .InColumnValue("type", (int)type)
                                                  .Identity(0, 0, true));


                int i = 0;
                foreach (var variant in answerVariants)
                {
                    DbManager.ExecuteNonQuery(new SqlInsert("forum_variant")
                                                .InColumnValue("name", variant)
                                                .InColumnValue("question_id", pollID)
                                                .InColumnValue("sort_order", i));
                    i++;
                }

                DbManager.ExecuteNonQuery(new SqlUpdate("forum_topic").Set("question_id", pollID)
                                            .Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("id", topicID)));

                tr.Commit();
            }

            return pollID;
        }

        public static void PollVote(int tenantID, int pollID, List<int> variantIDs)
        {
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                var answerID = DbManager.ExecuteScalar<int>(new SqlInsert("forum_answer")
                                                  .InColumnValue("id", 0)
                                                  .InColumnValue("TenantID", tenantID)
                                                  .InColumnValue("user_id", SecurityContext.CurrentAccount.ID)
                                                  .InColumnValue("create_date", DateTime.UtcNow)
                                                  .InColumnValue("question_id", pollID)
                                                  .Identity(0, 0, true));

                foreach (var vid in variantIDs)
                {
                    DbManager.ExecuteNonQuery(new SqlInsert("forum_answer_variant").InColumns("answer_id", "variant_id")
                                                            .Values(answerID, vid));
                }

                tr.Commit();
            }
        }

        public static Question GetPollByID(int tenantID, int pollID)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_question t1").Select("t1.id", "t1.topic_id", "t1.type", "t1.name", "t1.create_date",
                                                                                      "t2.id", "t2.name", "t2.sort_order", "sum(case when t4.variant_id is null then 0 else 1 end)")
                                                 .LeftOuterJoin("forum_variant t2", Exp.EqColumns("t1.id", "t2.question_id"))
                                                 .LeftOuterJoin("forum_answer t3", Exp.EqColumns("t3.question_id", "t1.id") & Exp.Eq("t3.TenantID", tenantID))
                                                 .LeftOuterJoin("forum_answer_variant t4", Exp.EqColumns("t4.answer_id", "t3.id") & Exp.EqColumns("t4.variant_id", "t2.id"))
                                                 .Where(Exp.Eq("t1.id", pollID) & Exp.Eq("t1.TenantID", tenantID))
                                                 .GroupBy("t1.id", "t1.topic_id", "t1.type", "t1.name", "t1.create_date", "t2.id", "t2.name", "t2.sort_order", "(case when t4.variant_id is null then t2.id else t4.variant_id end)")
                                                 .OrderBy("t2.sort_order", true)
                );

            Question q = null;
            foreach (var row in data)
            {
                if (q == null)
                {
                    q = new Question
                    {
                        ID = Convert.ToInt32(row[0]),
                        TopicID = Convert.ToInt32(row[1]),
                        Type = (QuestionType)Convert.ToInt32(row[2]),
                        Name = Convert.ToString(row[3]),
                        CreateDate = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[4])),
                        TenantID = tenantID

                    };
                }

                if (row[5] != null)
                {
                    q.AnswerVariants.Add(new AnswerVariant
                    {
                        ID = Convert.ToInt32(row[5]),
                        Name = Convert.ToString(row[6]),
                        SortOrder = Convert.ToInt32(row[7]),
                        QuestionID = q.ID,
                        AnswerCount = Convert.ToInt32(row[8])
                    });
                }
            }

            return q;
        }

        public static void UpdatePoll(int tenantID, int pollID, QuestionType type, string name, List<AnswerVariant> answerVariants)
        {
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                DbManager.ExecuteNonQuery(new SqlUpdate("forum_question")
                    .Set("type", (int)type).Set("name", name).Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("id", pollID)));

                var vids = DbManager.ExecuteList(new SqlQuery("forum_question t1").Select("t2.id")
                                        .InnerJoin("forum_variant t2", Exp.EqColumns("t1.id", "t2.question_id"))
                                        .Where(Exp.Eq("t1.id", pollID) & Exp.Eq("t1.TenantID", tenantID)))
                                        .ConvertAll(row => Convert.ToInt32(row[0]));

                vids.RemoveAll(vid => answerVariants.Find(av => av.ID == vid) != null);

                DbManager.ExecuteNonQuery(new SqlDelete("forum_variant").Where(Exp.Eq("question_id", pollID) & Exp.In("id", vids)));

                foreach (var av in answerVariants)
                {
                    if (av.ID == 0)
                        DbManager.ExecuteNonQuery(new SqlInsert("forum_variant")
                                                .InColumnValue("name", av.Name)
                                                .InColumnValue("question_id", pollID)
                                                .InColumnValue("sort_order", av.SortOrder));

                    else
                        DbManager.ExecuteNonQuery(new SqlUpdate("forum_variant")
                                                        .Set("name", av.Name).Set("sort_order", av.SortOrder)
                                                        .Where("id", av.ID));
                }

                tr.Commit();
            }
        }

        #endregion

        #region Topics

        public static List<Topic> SearchTopicsByText(int tenantID, string text, int curPageNumber, int topicOnPageCount, out int topicCount)
        {
            List<int> topicIDs, tIDs, pIDs = null;
            if (FactoryIndexer<TopicWrapper>.TrySelectIds(r => r.MatchAll(text), out tIDs) || FactoryIndexer<PostWrapper>.TrySelectIds(r => r.MatchAll(text), out pIDs))
            {
                topicIDs = tIDs;
                if (pIDs != null)
                {
                    topicIDs.AddRange(pIDs);
                }
            }
            else
            {
                var searchStringList = ConvertStringToArray(text);
                if (searchStringList == null || searchStringList.Count == 0)
                {
                    topicCount = 0;
                    return new List<Topic>();
                }

                var wordsCount = searchStringList.Count;
                var query = new StringBuilder();

                query.Append(@"
select id from
(
	select id, GROUP_CONCAT(word) as words, TenantID from (
");

                int j = 0;
                for (; j < wordsCount; j++)
                {
                    query.AppendFormat(@"
		select id, @searchWord{0} as word, TenantID
		from forum_topic as ft
		where tenantid = @tenant and (lower(ft.title) like @searchWord{0} or lower(ft.title) like @searchWordWithSpace{0} or lower(ft.title) like @searchWordWithNbsp{0})
		
		union all

		select topic_id as id, @searchWord{0} as word, TenantID
		from forum_post as fp
		where tenantid = @tenant and (lower(fp.text) like @searchWord{0} or lower(fp.text) like @searchWordWithSpace{0} or lower(fp.text) like @searchWordWithNbsp{0})

		union all

		select ftt.topic_id as id, @searchWord{0} as word, ftag.TenantID as TenantID
		from forum_tag as ftag

		inner join forum_topic_tag as ftt
		on ftag.id = ftt.tag_id

		where tenantid = @tenant and (lower(ftag.name) like @searchWord{0} or lower(ftag.name) like @searchWordWithSpace{0} or lower(ftag.name) like @searchWordWithNbsp{0})", j);


                    if (j < wordsCount - 1)
                    {
                        query.Append(@"
		union all
");
                    }
                }

                query.Append(@"
	) as topics
	group by id, TenantID

) as topicSearch
where ");


                j = 0;
                for (; j < wordsCount; j++)
                {
                    query.AppendFormat(" words like @searchWordWithPercent{0} ", j);
                    if (j < wordsCount - 1)
                    {
                        query.Append(" and ");
                    }
                }

                var topicIdsQuery = DbManager.Connection.CreateCommand(query.ToString()).AddParameter("Tenant", tenantID);

                j = 0;
                foreach (var t in searchStringList)
                {
                    topicIdsQuery.AddParameter(string.Format("searchWord{0}", j), string.Format("{0}%", t.ToLower()));
                    topicIdsQuery.AddParameter(string.Format("searchWordWithPercent{0}", j), string.Format("%{0}%", t.ToLower()));
                    topicIdsQuery.AddParameter(string.Format("searchWordWithSpace{0}", j), string.Format("% {0}%", t.ToLower()));
                    topicIdsQuery.AddParameter(string.Format("searchWordWithNbsp{0}", j), string.Format("%nbsp;{0}%", t.ToLower()));

                    j++;
                }
                topicIDs = topicIdsQuery.ExecuteList().ConvertAll(o => Convert.ToInt32(o[0]));
            }

            topicCount = topicIDs.Count;

            var necessaryTopicIDs = new List<int>();
            if (topicOnPageCount == -1)
                necessaryTopicIDs = topicIDs;
            else
            {
                for (int i = (curPageNumber - 1) * topicOnPageCount; i < curPageNumber * topicOnPageCount && i < topicIDs.Count; i++)
                    necessaryTopicIDs.Add(topicIDs[i]);
            }

            return GetTopicsByIDs(tenantID, necessaryTopicIDs, true);
        }

        private static IList<string> ConvertStringToArray(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                return new List<string>();
            }

            var searchString = System.Text.RegularExpressions.Regex.Replace(text, @"\s+", " ");
            const char separator = ' ';
            var searchStringList = new List<string>(searchString.Split(separator));

            for (int k = 0; k < searchStringList.Count; k++)
            {
                if (searchStringList[k].Length < 3)
                {
                    searchStringList.RemoveAt(k);
                    k--;
                }
            }

            return searchStringList;
        }

        public static List<Topic> SearchTopicsByTag(int tenantID, int tagID, int curPageNumber, int topicOnPageCount, out int topicCount)
        {
            var topicIDs = DbManager.Connection.CreateCommand(@"select id from forum_topic t1
                                                            join forum_topic_tag t2
                                                            on t1.id = t2.topic_id and t2.tag_id = @tagID and t1.TenantID = @tid   
                                                            order by t1.sticky desc, t1.recent_post_id desc")
                              .AddParameter("tid", tenantID)
                              .AddParameter("tagID", tagID)
                              .ExecuteList().ConvertAll(o => Convert.ToInt32(o[0]));

            topicCount = topicIDs.Count;

            var necessaryTopicIDs = new List<int>();
            for (int i = (curPageNumber - 1) * topicOnPageCount; i < curPageNumber * topicOnPageCount && i < topicIDs.Count; i++)
                necessaryTopicIDs.Add(topicIDs[i]);

            return GetTopicsByIDs(tenantID, necessaryTopicIDs, true);
        }

        public static List<Topic> SearchTopicsByUser(int tenantID, Guid userID, int curPageNumber, int topicOnPageCount, out int topicCount)
        {
            var topicIDs = DbManager.Connection.CreateCommand(@"select distinct(topic_id) id from forum_post t2
                                                                    join forum_topic t1
                                                                    on t1.id = t2.topic_id and  t2.poster_id=@userID
                                                                    where t1.TenantID = @tid and t2.TenantID = @tid
                                                                    order by t1.recent_post_id desc, t1.sticky desc")
                             .AddParameter("tid", tenantID)
                             .AddParameter("userID", userID)
                             .ExecuteList().ConvertAll(o => Convert.ToInt32(o[0]));

            topicCount = topicIDs.Count;

            var necessaryTopicIDs = new List<int>();
            for (var i = (curPageNumber - 1) * topicOnPageCount; i < curPageNumber * topicOnPageCount && i < topicIDs.Count; i++)
                necessaryTopicIDs.Add(topicIDs[i]);

            return GetTopicsByIDs(tenantID, necessaryTopicIDs, true);
        }

        public static List<Topic> GetLastUpdateTopics(int tenantID, int maxTopicCount)
        {
            return GetLastUpdateTopics(tenantID, 0, maxTopicCount);
        }

        public static List<Topic> GetLastUpdateTopics(int tenantID, int from, int maxTopicCount)
        {

            var ids = DbManager.ExecuteList(new SqlQuery("forum_topic").Select("id")
                                                    .Where("TenantID", tenantID)
                                                    .OrderBy("recent_post_id", false).SetFirstResult(from).SetMaxResults(maxTopicCount))
                                                    .ConvertAll(row => Convert.ToInt32(row[0]));

            var topics = GetTopicsByIDs(tenantID, ids, false);
            topics.Sort((t1, t2) => Comparer<int>.Default.Compare(t2.RecentPostID, t1.RecentPostID));
            return topics;

        }

        public static List<int> GetTopicIDs(int tenantID, int threadID)
        {
            return DbManager.Connection.CreateCommand(@"select id from forum_topic
                                                 where thread_id = @threadID and TenantID = @tid
                                                 order by sticky desc, recent_post_id desc")
                                .AddParameter("tid", tenantID)
                                .AddParameter("threadID", threadID)
                                .ExecuteList().ConvertAll(o => Convert.ToInt32(o[0]));
        }

        public static List<Topic> GetTopics(int tenantID, Guid userID, int threadID, int curPageNumber, int topicOnPageCount, out int topicCountInThread)
        {
            var topicIDs = GetTopicIDs(tenantID, threadID);
            topicCountInThread = topicIDs.Count;

            var necessaryTopicIDs = new List<int>();
            for (int i = (curPageNumber - 1) * topicOnPageCount; i < curPageNumber * topicOnPageCount && i < topicIDs.Count; i++)
                necessaryTopicIDs.Add(topicIDs[i]);

            return GetTopicsByIDs(tenantID, necessaryTopicIDs, true);

        }

        public static Topic GetTopicByID(int tenantID, int topicID)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_topic t1").Select("t1.id", "t1.thread_id", "t1.title", "t1.create_date", "t1.view_count",
                                                "t1.post_count", "t1.recent_post_id", "t1.is_approved", "t1.poster_id", "t1.sticky",
                                                "t1.closed", "t1.type", "t1.question_id", "t2.text", "t2.poster_id", "t2.create_date", "t2.formatter", "t3.title")
                                                .LeftOuterJoin("forum_post t2", Exp.EqColumns("t2.id", "t1.recent_post_id") & Exp.Eq("t2.TenantID", tenantID))
                                                .LeftOuterJoin("forum_thread t3", Exp.EqColumns("t1.thread_id", "t3.id") & Exp.Eq("t3.TenantID", tenantID))
                                                .Where(Exp.Eq("t1.id", topicID) & Exp.Eq("t1.TenantID", tenantID)));

            if (data.Count == 0)
                return null;

            return GetTagsForTopics(tenantID, ParseTopic(data[0], tenantID));
        }

        public static List<Topic> GetTopicsByIDs(int tenantID, List<int> necessaryTopicIDs, bool withTags)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_topic t1").Select("t1.id", "t1.thread_id", "t1.title", "t1.create_date", "t1.view_count",
                                                                                   "t1.post_count", "t1.recent_post_id", "t1.is_approved", "t1.poster_id", "t1.sticky",
                                                                                   "t1.closed", "t1.type", "t1.question_id", "t2.text", "t2.poster_id", "t2.create_date", "t2.formatter", "t3.title")
                                                 .LeftOuterJoin("forum_post t2", Exp.EqColumns("t2.id", "t1.recent_post_id") & Exp.Eq("t2.TenantID", tenantID))
                                                 .LeftOuterJoin("forum_thread t3", Exp.EqColumns("t1.thread_id", "t3.id") & Exp.Eq("t3.TenantID", tenantID))
                                                 .Where("t1.tenantid", tenantID)
                                                 .Where(Exp.In("t1.id", necessaryTopicIDs))
                                                 .OrderBy("t1.sticky", false).OrderBy("t1.recent_post_id", false));

            var topics = data.Select(row => ParseTopic(row, tenantID)).ToList();

            return withTags ? GetTagsForTopics(tenantID, topics) : topics;
        }

        public static List<Tag> GetAllTags(int tenantID)
        {
            var data = DbManager.Connection.CreateCommand(@"select t1.id, t1.name, t1.is_approved
                                                from forum_tag t1 
                                                where t1.TenantID= @tid
                                                order by name")
                                                .AddParameter("tid", tenantID).ExecuteList();

            return data.Select(row => new Tag
            {
                TenantID = tenantID,
                ID = Convert.ToInt32(row[0]),
                Name = Convert.ToString(row[1]),
                IsApproved = Convert.ToBoolean(row[2]),
            }).ToList();
        }

        public static List<RankTag> GetTagCloud(int tenantID, int limitTagCount)
        {
            var data = DbManager.Connection.CreateCommand(@"select t1.id, t1.name, t1.is_approved, sum(t3.post_count) rank from forum_tag t1                                                
                                                inner join forum_topic_tag t2 on t1.id = t2.tag_id
                                                inner join forum_topic t3 on t3.id = t2.topic_id
                                                where t1.TenantID = @tid and t3.TenantID = @tid 
                                                group by t1.id, t1.name, t1.is_approved
                                                order by rank desc limit " + limitTagCount.ToString())
                                                .AddParameter("tid", tenantID).ExecuteList();

            var tags = new List<RankTag>();
            foreach (var row in data)
            {
                tags.Add(new RankTag
                {
                    TenantID = tenantID,
                    ID = Convert.ToInt32(row[0]),
                    Name = Convert.ToString(row[1]),
                    IsApproved = Convert.ToBoolean(row[2]),
                    Rank = Convert.ToInt32(row[3])
                });
            }

            tags.Sort((t1, t2) => String.Compare(t1.Name, t2.Name));
            return tags;
        }

        private static Topic GetTagsForTopics(int tenantID, Topic topic)
        {
            var topics = new List<Topic> { topic };
            return GetTagsForTopics(tenantID, topics)[0];
        }



        private static List<Topic> GetTagsForTopics(int tenantID, List<Topic> topics)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_tag t1").Select("t2.topic_id", "t1.id", "t1.name", "t1.is_approved")
                                               .InnerJoin("forum_topic_tag t2", Exp.EqColumns("t1.id", "t2.tag_id"))
                                               .Where(Exp.In("t2.topic_id", topics.ConvertAll(t => t.ID)) & Exp.Eq("t1.TenantID", tenantID)));

            new List<Tag>();
            foreach (var row in data)
            {
                var topicID = Convert.ToInt32(row[0]);
                var topic = topics.Find(t => t.ID == topicID);
                topic.Tags.Add(new Tag
                {
                    TenantID = tenantID,
                    ID = Convert.ToInt32(row[1]),
                    Name = Convert.ToString(row[2]),
                    IsApproved = Convert.ToBoolean(row[3])
                });
            }

            return topics;
        }

        private static Topic ParseTopic(object[] row, int tenantID)
        {
            return new Topic
            {
                ID = Convert.ToInt32(row[0]),
                TenantID = tenantID,
                ThreadID = Convert.ToInt32(row[1]),
                Title = Convert.ToString(row[2]),
                CreateDate = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[3])),
                ViewCount = Convert.ToInt32(row[4]),
                PostCount = Convert.ToInt32(row[5]),
                RecentPostID = (row[6] != null ? Convert.ToInt32(row[6]) : 0),
                IsApproved = Convert.ToBoolean(row[7]),
                PosterID = new Guid(Convert.ToString(row[8])),
                Sticky = Convert.ToBoolean(row[9]),
                Closed = Convert.ToBoolean(row[10]),
                Type = (TopicType)Convert.ToInt32(row[11]),
                QuestionID = Convert.ToInt32(row[12]),
                RecentPostText = (row[13] != null ? Convert.ToString(row[13]) : ""),
                RecentPostAuthorID = (row[14] != null ? new Guid(Convert.ToString(row[14])) : Guid.Empty),
                RecentPostCreateDate = (row[15] != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[15])) : DateTime.MinValue),
                RecentPostFormatter = (row[16] != null ? (PostTextFormatter)Convert.ToInt32(row[16]) : PostTextFormatter.FCKEditor),
                ThreadTitle = Convert.ToString(row[17])
            };
        }

        public static void ApproveTopic(int tenantID, int topicID)
        {
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                DbManager.Connection.CreateCommand("update forum_post set is_approved = 1 where topic_id = @topicID and TenantID = @tid")
                    .AddParameter("topicID", topicID).AddParameter("tid", tenantID).ExecuteNonQuery();

                DbManager.Connection.CreateCommand("update forum_topic set is_approved = 1 where id = @topicID and TenantID = @tid")
                    .AddParameter("topicID", topicID).AddParameter("tid", tenantID).ExecuteNonQuery();

                var threadID = DbManager.Connection.CreateCommand("select thread_id from forum_topic where id = @topicID and TenantID = @tid")
                   .AddParameter("topicID", topicID).AddParameter("tid", tenantID).ExecuteScalar<int>();

                DbManager.Connection.CreateCommand(@"update forum_thread
                                                      set is_approved = (select coalesce(min(is_approved),1) from forum_topic where thread_id = @threadID and forum_topic.TenantID = @tid)
                                                    where id = @threadID and TenantID = @tid")
                                                .AddParameter("threadID", threadID).AddParameter("tid", tenantID).ExecuteNonQuery();

                tr.Commit();
            }
        }

        public static void UpdateTopic(int tenantID, int topicID, string title, bool sticky, bool closed)
        {
            DbManager.Connection.CreateCommand(@"update forum_topic 
                                                      set title = @title,
                                                          sticky = @sticky,
                                                          closed = @closed
                                                where id = @topicID and TenantID = @tid")
                                .AddParameter("title", title)
                                .AddParameter("sticky", sticky ? 1 : 0)
                                .AddParameter("closed", closed ? 1 : 0)
                                .AddParameter("topicID", topicID)
                                .AddParameter("tid", tenantID).ExecuteNonQuery();
        }

        public static int CreateTopic(int tenantID, int threadID, string title, TopicType type)
        {
            int topicID;
            using (var tr = DbManager.Connection.BeginTransaction(IsolationLevel.ReadUncommitted))
            {
                topicID = DbManager.ExecuteScalar<int>(new SqlInsert("forum_topic")
                                                    .InColumnValue("id", 0)
                                                    .InColumnValue("TenantID", tenantID)
                                                    .InColumnValue("thread_id", threadID)
                                                    .InColumnValue("title", title)
                                                    .InColumnValue("type", (int)type)
                                                    .InColumnValue("create_date", DateTime.UtcNow)
                                                    .InColumnValue("is_approved", 1)
                                                    .InColumnValue("poster_id", SecurityContext.CurrentAccount.ID)
                                                    .InColumnValue("sticky", 0)
                                                    .InColumnValue("closed", 0)
                                                    .Identity(0, 0, true));

                DbManager.Connection.CreateCommand(@"update forum_thread 
                                                        set topic_count = (select count(id) from forum_topic where TenantID= @tid and thread_id = @threadID),
                                                        recent_topic_id = @topicID
                                                      where id = @threadID and TenantID = @tid")
                                     .AddParameter("tid", tenantID)
                                     .AddParameter("topicID", topicID)
                                     .AddParameter("threadID", threadID)
                                     .ExecuteNonQuery();

                tr.Commit();
            }

            return topicID;
        }

        public static List<string> RemoveTopic(int tenantID, int topicID, out List<int> removedPostIDs)
        {
            removedPostIDs = new List<int>();

            List<string> attachmantOffsetPhysicalPaths;
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                attachmantOffsetPhysicalPaths = DbManager.ExecuteList(new SqlQuery("forum_attachment t1").Select("t1.path")
                                        .InnerJoin("forum_post t2", Exp.EqColumns("t1.post_id", "t2.id") & Exp.Eq("t2.topic_id", topicID)
                                                                   & Exp.Eq("t1.TenantID", tenantID) & Exp.Eq("t2.TenantID", tenantID))
                                        ).ConvertAll(row => Convert.ToString(row[0]));


                DbManager.Connection.CreateCommand(@"delete from forum_attachment
                                                where TenantID = @tid and 
                                                      post_id in (select id from forum_post
                                                                  where TenantID = @tid and topic_id = @topicID)")
                                                     .AddParameter("tid", tenantID).AddParameter("topicID", topicID).ExecuteNonQuery();

                removedPostIDs = DbManager.Connection.CreateCommand(@"select id from forum_post
                                    where TenantID = @tid and topic_id = @topicID")
                                         .AddParameter("tid", tenantID).AddParameter("topicID", topicID).ExecuteList()
                                         .ConvertAll(obj => Convert.ToInt32(obj[0]));


                DbManager.Connection.CreateCommand(@"delete from forum_post
                                    where TenantID = @tid and topic_id = @topicID")
                                         .AddParameter("tid", tenantID).AddParameter("topicID", topicID).ExecuteNonQuery();

                DbManager.Connection.CreateCommand(@"delete from forum_topic_tag
                                         where topic_id = @topicID")
                                                     .AddParameter("tid", tenantID).AddParameter("topicID", topicID).ExecuteNonQuery();

                DbManager.Connection.CreateCommand(@"delete from forum_tag
                                         where TenantID = @tid and id not in (select tag_id from forum_topic_tag)")
                                                     .AddParameter("tid", tenantID).ExecuteNonQuery();

                var q = new SqlQuery("forum_question").Select("id").Where("tenantid", tenantID).Where("topic_id", topicID);
                var questionIds = DbManager.ExecuteList(q).ConvertAll(r => Convert.ToInt32(r[0]));

                DbManager.ExecuteNonQuery(new SqlDelete("forum_question").Where(Exp.In("id", questionIds)));
                DbManager.ExecuteNonQuery(new SqlDelete("forum_variant").Where(Exp.In("question_id", questionIds)));
                DbManager.ExecuteNonQuery(new SqlDelete("forum_answer_variant").Where(Exp.In("answer_id", new SqlQuery("forum_answer a").Select("a.id").Where(Exp.Eq("a.tenantid", tenantID) & Exp.In("a.question_id", questionIds)))));
                DbManager.ExecuteNonQuery(new SqlDelete("forum_answer").Where(Exp.In("question_id", questionIds)));

                var threadID = DbManager.ExecuteScalar<int>(new SqlQuery("forum_topic").Select("thread_id")
                                            .Where(Exp.Eq("id", topicID) & Exp.Eq("TenantID", tenantID)));


                DbManager.Connection.CreateCommand(@"delete from forum_topic where TenantID = @tid and id = @topicID")
                                        .AddParameter("tid", tenantID).AddParameter("topicID", topicID).ExecuteNonQuery();


                var threadData = DbManager.Connection.CreateCommand(@"select sum(post_count), coalesce(min(is_approved),1), coalesce(max(recent_post_id),0), count(id)
                                                    from  forum_topic
                                                    where thread_id = @threadID and TenantID = @tid")
                                                  .AddParameter("threadID", threadID).AddParameter("tid", tenantID).ExecuteList();

                var postCount = Convert.ToInt32(threadData[0][0]);
                var recentPostID = (threadData[0][2] != null ? Convert.ToInt32(threadData[0][2]) : 0);
                var topicCount = Convert.ToInt32(threadData[0][3]);
                var isApproved = (topicCount == 0 || Convert.ToBoolean(threadData[0][1]));

                int recentTopicID = 0;
                DateTime recentPostDate = DateTime.MinValue;
                Guid recentPosterID = Guid.Empty;

                if (recentPostID != 0)
                {
                    var threadPostData = DbManager.Connection.CreateCommand(@"select topic_id, create_date, poster_id
                                                    from  forum_post
                                                    where id = @pid and TenantID = @tid")
                                                     .AddParameter("pid", recentPostID).AddParameter("tid", tenantID).ExecuteList();


                    recentTopicID = Convert.ToInt32(threadPostData[0][0]);
                    recentPostDate = Convert.ToDateTime(threadPostData[0][1]);
                    recentPosterID = threadPostData[0][2] != null ? new Guid(Convert.ToString(threadPostData[0][2])) : Guid.Empty;

                }

                DbManager.Connection.CreateCommand(@"update forum_thread
                                                        set post_count = @postCount,
                                                            topic_count = @topicCount,
                                                            is_approved = @isApproved,
                                                            recent_post_id = @recentPostID,
                                                            recent_topic_id = @recentTopicID,
                                                            recent_post_date =  @recentPostDate,
                                                            recent_topic_id = @recentTopicID,
                                                            recent_poster_id = @recentPosterID
                                                     where id = @threadID and TenantID = @tid")

                                     .AddParameter("threadID", threadID)
                                     .AddParameter("postCount", postCount)
                                     .AddParameter("topicCount", topicCount)
                                     .AddParameter("isApproved", isApproved)
                                     .AddParameter("recentPostID", recentPostID)
                                     .AddParameter("recentPostDate", recentPostDate)
                                     .AddParameter("recentTopicID", recentTopicID)
                                     .AddParameter("recentPosterID", recentPosterID)
                                     .AddParameter("tid", tenantID).ExecuteNonQuery();


                tr.Commit();
            }

            SubscriberPresenter.UnsubscribeAllOnTopic(topicID);

            return attachmantOffsetPhysicalPaths;
        }

        #endregion

        #region Posts

        public static int GetUserPostCount(int tenantID, Guid userID)
        {
            return DbManager.ExecuteScalar<int>(new SqlQuery("forum_post")
                                                    .SelectCount("id")
                                                    .Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("poster_id", userID)));
        }

        public static List<Post> GetRecentTopicPosts(int tenantID, int topicID, int postCount, int replyPostID)
        {
            List<int> necessaryPostIDs;

            if (replyPostID != -1 && replyPostID != 0)
            {
                necessaryPostIDs = DbManager.ExecuteList(new SqlQuery("forum_post").Select("id")
                                                        .Where(Exp.Eq("topic_id", topicID) & Exp.Eq("TenantID", tenantID) & Exp.Le("id", replyPostID))
                                                        .OrderBy("id", false)
                                                        .SetMaxResults(postCount))
                                                        .ConvertAll(o => Convert.ToInt32(o[0]));
            }
            else
            {
                necessaryPostIDs = DbManager.ExecuteList(new SqlQuery("forum_post").Select("id")
                                                        .Where(Exp.Eq("topic_id", topicID) & Exp.Eq("TenantID", tenantID))
                                                        .OrderBy("id", false)
                                                        .SetMaxResults(postCount))
                                                        .ConvertAll(o => Convert.ToInt32(o[0]));
            }

            var data = DbManager.ExecuteList(new SqlQuery("forum_post t1").Select("t1.id", "t1.topic_id", "t1.create_date", "t1.poster_id",
                                               "t1.subject", "t1.text", "t1.edit_date", "t1.edit_count", "t1.is_approved", "t1.parent_post_id", "t1.formatter", "t1.editor_id",
                                               "t2.id", "t2.name", "t2.size", "t2.download_count", "t2.content_type", "t2.mime_content_type", "t2.create_date", "t2.path")
                                               .LeftOuterJoin("forum_attachment t2", Exp.EqColumns("t1.id", "t2.post_id") & Exp.Eq("t2.tenantid", tenantID))
                                               .Where(Exp.In("t1.id", necessaryPostIDs))
                                               .Where("t1.tenantid", tenantID)
                                               .OrderBy("t1.create_date", true));

            return ParsePost(data, tenantID);
        }



        public static List<int> GetPostIDs(int tenantID, int topicID)
        {
            return DbManager.Connection.CreateCommand(@"select id from forum_post
                                                 where topic_id = @topicID and TenantID = @tid
                                                 order by create_date asc")
                                .AddParameter("tid", tenantID)
                                .AddParameter("topicID", topicID)
                                .ExecuteList().ConvertAll(o => Convert.ToInt32(o[0]));
        }

        public static List<Post> GetPosts(int tenantID, int topicID, int curPageNumber, int postOnPageCount, out int postCountInTopic)
        {
            var postIDs = GetPostIDs(tenantID, topicID);
            postCountInTopic = postIDs.Count;

            var necessaryPostIDs = new List<int>();
            for (int i = (curPageNumber - 1) * postOnPageCount; i < curPageNumber * postOnPageCount && i < postIDs.Count; i++)
                necessaryPostIDs.Add(postIDs[i]);

            return GetPostsByIDs(tenantID, necessaryPostIDs);
        }

        public static List<Post> GetPostsByIDs(int tenantID, List<int> necessaryPostIDs)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_post t1").Select("t1.id", "t1.topic_id", "t1.create_date", "t1.poster_id",
                                                                                  "t1.subject", "t1.text", "t1.edit_date", "t1.edit_count", "t1.is_approved", "t1.parent_post_id", "t1.formatter", "t1.editor_id",
                                                                                  "t2.id", "t2.name", "t2.size", "t2.download_count", "t2.content_type", "t2.mime_content_type", "t2.create_date", "t2.path")
                                                 .LeftOuterJoin("forum_attachment t2", Exp.EqColumns("t1.id", "t2.post_id") & Exp.Eq("t2.tenantid", tenantID))
                                                 .Where(Exp.In("t1.id", necessaryPostIDs))
                                                 .Where("t1.tenantid", tenantID)
                                                 .OrderBy("t1.create_date", true));

            return ParsePost(data, tenantID);
        }

        public static Post GetPostByID(int tenantID, int postID)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_post t1").Select("t1.id", "t1.topic_id", "t1.create_date", "t1.poster_id",
                                                "t1.subject", "t1.text", "t1.edit_date", "t1.edit_count", "t1.is_approved", "t1.parent_post_id", "t1.formatter", "t1.editor_id",
                                                "t2.id", "t2.name", "t2.size", "t2.download_count", "t2.content_type", "t2.mime_content_type", "t2.create_date", "t2.path")
                                                .LeftOuterJoin("forum_attachment t2", Exp.EqColumns("t1.id", "t2.post_id") & Exp.Eq("t2.tenantid", tenantID))
                                                .Where(Exp.Eq("t1.id", postID) & Exp.Eq("t1.TenantID", tenantID)));

            var posts = ParsePost(data, tenantID);
            if (posts.Count == 0)
                return null;

            return posts[0];
        }

        private static List<Post> ParsePost(IEnumerable<object[]> data, int tenantID)
        {

            var posts = new List<Post>();
            foreach (var row in data)
            {
                var post = posts.Find(p => p.ID.Equals(Convert.ToInt32(row[0])));
                if (post == null)
                {
                    post = new Post
                    {
                        TenantID = tenantID,
                        ID = Convert.ToInt32(row[0]),
                        TopicID = Convert.ToInt32(row[1]),
                        CreateDate = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[2])),
                        PosterID = new Guid(Convert.ToString(row[3])),
                        Subject = Convert.ToString(row[4]),
                        Text = Convert.ToString(row[5]),
                        EditDate = (row[6] != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[6])) : DateTime.MinValue),
                        EditCount = Convert.ToInt32(row[7]),
                        IsApproved = Convert.ToBoolean(row[8]),
                        ParentPostID = (row[9] != null ? Convert.ToInt32(row[9]) : 0),
                        Formatter = (PostTextFormatter)Convert.ToInt32(row[10]),
                        EditorID = (row[11] != null ? new Guid(Convert.ToString(row[11])) : Guid.Empty)
                    };
                    posts.Add(post);
                }

                if (row[12] != null)
                {
                    post.Attachments.Add(new Attachment
                    {
                        TenantID = tenantID,
                        ID = Convert.ToInt32(row[12]),
                        Name = Convert.ToString(row[13]),
                        Size = Convert.ToInt32(row[14]),
                        DownloadCount = Convert.ToInt32(row[15]),
                        ContentType = (AttachmentContentType)Convert.ToInt32(row[16]),
                        MIMEContentType = Convert.ToString(row[17]),
                        CreateDate = (row[18] != null ? TenantUtil.DateTimeFromUtc(Convert.ToDateTime(row[18])) : DateTime.MinValue),
                        PostID = post.ID,
                        OffsetPhysicalPath = Convert.ToString(row[19])
                    });
                }

            }
            return posts;
        }

        public static int CreateAttachment(int tenantID, int postID, string name, string path, int size, AttachmentContentType contentType, string mimeContentType)
        {

            return DbManager.ExecuteScalar<int>(new SqlInsert("forum_attachment")
                                                    .InColumnValue("id", 0)
                                                    .InColumnValue("TenantID", tenantID)
                                                    .InColumnValue("post_id", postID)
                                                    .InColumnValue("name", name)
                                                    .InColumnValue("size", size)
                                                    .InColumnValue("download_count", 0)
                                                    .InColumnValue("content_type", (int)contentType)
                                                    .InColumnValue("mime_content_type", mimeContentType)
                                                    .InColumnValue("create_date", DateTime.UtcNow)
                                                    .InColumnValue("path", path)
                                                    .Identity(0, 0, true));
        }

        public static void RemoveAttachment(int tenantID, int attachmentID)
        {
            DbManager.Connection.CreateCommand("delete from forum_attachment where id = @id and TenantID = @tid")
                .AddParameter("id", attachmentID).AddParameter("tid", tenantID).ExecuteNonQuery();
        }

        public static void ApprovePost(int tenantID, int postID)
        {
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                DbManager.Connection.CreateCommand("update forum_post set is_approved = 1 where id = @postID and TenantID = @tid")
                    .AddParameter("postID", postID).AddParameter("tid", tenantID).ExecuteNonQuery();


                var data = DbManager.Connection.CreateCommand(@"select id, thread_id from forum_topic                                                     
                                                    where TenantID = @tid 
                                                    and id = (select topic_id from forum_post where forum_post.id = @postID and TenantID = @tid)")
                                    .AddParameter("postID", postID).AddParameter("tid", tenantID).ExecuteList();

                if (data.Count == 1)
                {
                    var topicID = Convert.ToInt32(data[0][0]);
                    var threadID = Convert.ToInt32(data[0][1]);

                    DbManager.Connection.CreateCommand(@"update forum_topic
                                                      set is_approved = (select coalesce(min(is_approved),1) from forum_post where topic_id = @topicID and forum_post.TenantID = @tid)
                                                    where id = @topicID and TenantID = @tid")
                                                    .AddParameter("topicID", topicID).AddParameter("tid", tenantID).ExecuteNonQuery();

                    DbManager.Connection.CreateCommand(@"update forum_thread
                                                      set is_approved = (select coalesce(min(is_approved),1) from forum_topic where thread_id = @threadID and forum_topic.TenantID = @tid)
                                                    where id = @threadID and TenantID = @tid")
                                                    .AddParameter("threadID", threadID).AddParameter("tid", tenantID).ExecuteNonQuery();
                }

                tr.Commit();
            }
        }

        public static DeletePostResult RemovePost(int tenantID, int postID)
        {
            var result = DeletePostResult.Error;

            using (var tr = DbManager.BeginTransaction())
            {
                var parents = DbManager.Connection.CreateCommand("select id from forum_post where parent_post_id = @pid and TenantID = @tid")
                    .AddParameter("pid", postID).AddParameter("tid", tenantID).ExecuteList();

                if (parents.Count > 0)
                    return DeletePostResult.ReferencesBlock;

                var data = DbManager.Connection.CreateCommand(@"select ft.id, ft.thread_id, ft.post_count
from forum_topic ft

inner join forum_post fp
on ft.id = fp.topic_id and ft.TenantID = fp.TenantID

where ft.TenantID = @tid and fp.id = @postID")
                                  .AddParameter("postID", postID).AddParameter("tid", tenantID).ExecuteList();

                var topicID = Convert.ToInt32(data[0][0]);
                var threadID = Convert.ToInt32(data[0][1]);
                var postsCount = Convert.ToInt32(data[0][2]);

                //deny of deleting the last post in a topic
                if (postsCount == 1)
                {
                    tr.Rollback();
                    return result;
                }

                DbManager.Connection.CreateCommand("delete from forum_post where id = @pid and TenantID = @tid")
                    .AddParameter("pid", postID).AddParameter("tid", tenantID).ExecuteNonQuery();

                DbManager.Connection.CreateCommand("delete from forum_attachment where post_id = @pid and TenantID = @tid")
                    .AddParameter("pid", postID).AddParameter("tid", tenantID).ExecuteNonQuery();

                UpdateTopicThread(tenantID, topicID, threadID);

                tr.Commit();
                result = DeletePostResult.Successfully;

            }

            return result;
        }

        private static void UpdateTopicThread(int tenantID, int topicID, int threadID)
        {
            DbManager.Connection.CreateCommand(@"update forum_topic 
                                                        set post_count = (select count(id) from forum_post where topic_id = @topicID and TenantID = @tid),
                                                            is_approved = (select coalesce(min(is_approved),1) from forum_post where topic_id = @topicID and TenantID = @tid),
                                                            recent_post_id = (select coalesce(max(id),0) from forum_post where topic_id = @topicID and TenantID = @tid)
                                                     where id = @topicID and TenantID = @tid")
                                 .AddParameter("topicID", topicID).AddParameter("tid", tenantID).ExecuteNonQuery();


            var threadData = DbManager.Connection.CreateCommand(@"select sum(post_count), coalesce(min(is_approved),1), coalesce(max(recent_post_id),0)
                                                    from  forum_topic
                                                    where thread_id = @threadID and TenantID = @tid")
                                              .AddParameter("threadID", threadID).AddParameter("tid", tenantID).ExecuteList();

            var postCount = Convert.ToInt32(threadData[0][0]);
            var isApproved = Convert.ToBoolean(threadData[0][1]);
            var recentPostID = (threadData[0][2] != null ? Convert.ToInt32(threadData[0][2]) : 0);


            int recentTopicID = 0;
            DateTime recentPostDate = DateTime.MinValue;
            Guid recentPosterID = Guid.Empty;

            if (recentPostID != 0)
            {
                var threadPostData = DbManager.Connection.CreateCommand(@"select topic_id, create_date, poster_id
                                                    from  forum_post
                                                    where id = @pid and TenantID = @tid")
                                                 .AddParameter("pid", recentPostID).AddParameter("tid", tenantID).ExecuteList();


                recentTopicID = Convert.ToInt32(threadPostData[0][0]);
                recentPostDate = Convert.ToDateTime(threadPostData[0][1]);
                recentPosterID = threadPostData[0][2] != null ? new Guid(Convert.ToString(threadPostData[0][2])) : Guid.Empty;

            }


            DbManager.Connection.CreateCommand(@"update forum_thread
                                                        set post_count = @postCount,
                                                            is_approved = @isApproved,
                                                            recent_post_id = @recentPostID,
                                                            recent_topic_id = @recentTopicID,
                                                            recent_post_date =  @recentPostDate,
                                                            recent_topic_id = @recentTopicID,
                                                            recent_poster_id = @recentPosterID
                                                     where id = @threadID and TenantID = @tid")

                                 .AddParameter("threadID", threadID)
                                 .AddParameter("postCount", postCount)
                                 .AddParameter("isApproved", isApproved)
                                 .AddParameter("recentPostID", recentPostID)
                                 .AddParameter("recentPostDate", recentPostDate)
                                 .AddParameter("recentTopicID", recentTopicID)
                                 .AddParameter("recentPosterID", recentPosterID)
                                 .AddParameter("tid", tenantID).ExecuteNonQuery();
        }

        public static void UpdatePost(int tenantID, int postID, string subject, string text, PostTextFormatter formatter)
        {
            DbManager.Connection.CreateCommand(@"update forum_post 
                                                      set text = @text,
                                                          subject = @subject,
                                                          formatter = @formatter,
                                                          edit_count = edit_count+1,
                                                          edit_date = @date,
                                                          editor_id = @euid
                                                where id = @postID and TenantID = @tid")
                                .AddParameter("text", text)
                                .AddParameter("subject", subject)
                                .AddParameter("formatter", (int)formatter)
                                .AddParameter("date", DateTime.UtcNow)
                                .AddParameter("euid", SecurityContext.CurrentAccount.ID)
                                .AddParameter("postID", postID)
                                .AddParameter("tid", tenantID).ExecuteNonQuery();
        }

        public static int CreatePost(int tenantID, int topicID, int parentPostID, string subject, string text, bool isApprove, PostTextFormatter formatter)
        {
            int postID;
            using (var tr = DbManager.Connection.BeginTransaction(IsolationLevel.ReadUncommitted))
            {

                postID = DbManager.ExecuteScalar<int>(new SqlInsert("forum_post")
                                                    .InColumnValue("id", 0)
                                                    .InColumnValue("TenantID", tenantID)
                                                    .InColumnValue("topic_id", topicID)
                                                    .InColumnValue("create_date", DateTime.UtcNow)
                                                    .InColumnValue("subject", subject)
                                                    .InColumnValue("text", text)
                                                    .InColumnValue("poster_id", SecurityContext.CurrentAccount.ID)
                                                    .InColumnValue("is_approved", isApprove ? 1 : 0)
                                                    .InColumnValue("parent_post_id", parentPostID)
                                                    .InColumnValue("formatter", (int)formatter)

                                                    .Identity(0, 0, true));

                var threadID = DbManager.Connection.CreateCommand("select thread_id from forum_topic where id=@topicID and TenantID = @tid")
                    .AddParameter("topicID", topicID).AddParameter("tid", tenantID).ExecuteScalar<int>();



                UpdateTopicThread(tenantID, topicID, threadID);

                tr.Commit();
            }

            return postID;
        }

        #endregion

        #region Tags

        public static List<Tag> SearchTags(int tenantID, string text)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_tag").Select("id", "name", "is_approved")
                                  .Where(Exp.Eq("TenantID", tenantID) & Exp.Like("name", text, SqlLike.StartWith)));

            return data.Select(row => new Tag
            {
                TenantID = tenantID,
                ID = Convert.ToInt32(row[0]),
                Name = Convert.ToString(row[1]),
                IsApproved = Convert.ToBoolean(row[2])
            }).ToList();

        }

        public static List<Tag> GetTagByIDs(int tenantID, List<int> ids)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_tag").Select("id", "name", "is_approved")
                                  .Where(Exp.Eq("TenantID", tenantID) & Exp.In("id", ids)));

            return data.Select(row => new Tag
            {
                TenantID = tenantID,
                ID = Convert.ToInt32(row[0]),
                Name = Convert.ToString(row[1]),
                IsApproved = Convert.ToBoolean(row[2])
            }).ToList();
        }

        public static Tag GetTagByID(int tenantID, int tagID)
        {
            var data = DbManager.ExecuteList(new SqlQuery("forum_tag").Select("id", "name", "is_approved")
                                  .Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("id", tagID)));

            if (data.Count > 0)
            {
                var row = data[0];
                return new Tag
                {
                    TenantID = tenantID,
                    ID = Convert.ToInt32(row[0]),
                    Name = Convert.ToString(row[1]),
                    IsApproved = Convert.ToBoolean(row[2])
                };
            }

            return null;

        }

        public static int CreateTag(int tenantID, int topicID, string name, bool isApproved)
        {
            if (string.IsNullOrEmpty(name)) return 0;

            int tagID;
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                tagID = DbManager.ExecuteScalar<int>(new SqlQuery("forum_tag")
                    .Select("id")
                    .Where("TenantID", tenantID)
                    .Where("lower(name)", name.ToLower())
                    .SetMaxResults(1));
                if (tagID == 0)
                {
                    tagID = DbManager.ExecuteScalar<int>(new SqlInsert("forum_tag")
                                                        .InColumnValue("id", 0)
                                                        .InColumnValue("name", name)
                                                        .InColumnValue("TenantID", tenantID)
                                                        .InColumnValue("is_approved", isApproved ? 1 : 0)
                                                        .Identity(0, 0, true));
                }
                AttachTagToTopic(tenantID, tagID, topicID);

                tr.Commit();
            }
            return tagID;
        }

        public static void AttachTagToTopic(int tenantID, int tagID, int topicID)
        {
            DbManager.ExecuteNonQuery(new SqlInsert("forum_topic_tag", true).InColumnValue("topic_id", topicID)
                                                                    .InColumnValue("tag_id", tagID));
        }

        public static void RemoveTagFromTopic(int tenantID, int tagID, int topicID)
        {
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                DbManager.ExecuteNonQuery(new SqlDelete("forum_topic_tag").Where(
                                                Exp.Eq("topic_id", topicID) & Exp.Eq("tag_id", tagID)));


                DbManager.Connection.CreateCommand(@"delete from forum_tag
                                         where TenantID = @tid and id not in (select tag_id from forum_topic_tag)")
                                                     .AddParameter("tid", tenantID).ExecuteNonQuery();

                tr.Commit();
            }
        }

        public static void RemoveTag(int tenantID, int tagID)
        {
            using (var tr = DbManager.Connection.BeginTransaction())
            {
                DbManager.ExecuteNonQuery(new SqlDelete("forum_tag").Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("id", tagID)));
                DbManager.ExecuteNonQuery(new SqlDelete("forum_topic_tag").Where("tag_id", tagID));

                tr.Commit();
            }
        }

        public static void UpdateTag(int tenantID, int tagID, string name, bool isApproved)
        {
            DbManager.ExecuteNonQuery(new SqlUpdate("forum_tag").Set("name", name)
                                                              .Set("is_approved", isApproved ? 1 : 0)
                                                              .Where(Exp.Eq("TenantID", tenantID) & Exp.Eq("id", tagID)));
        }

        public static List<Topic> GetTopicsByAllTags(int tenantID)
        {
            var topicIDs = DbManager.ExecuteList(new SqlQuery("forum_tag t1").Select("distinct(t2.topic_id)")
                                  .InnerJoin("forum_topic_tag t2", Exp.EqColumns("t1.id", "t2.topic_id") & Exp.Eq("t1.TenantID", tenantID)))
                                  .ConvertAll(r => Convert.ToInt32(r[0]));

            return GetTopicsByIDs(tenantID, topicIDs, true);
        }

        #endregion

        #region News

        public static IEnumerable<Post> GetPosts(DateTime from, DateTime to, int tenantId)
        {
            var query = new SqlQuery("forum_post p")
                .Select("p.id", "p.create_date", "p.subject", "p.text", "p.LastModified", "p.poster_id")
                .LeftOuterJoin("forum_topic t", Exp.EqColumns("p.topic_id", "t.id"))
                .Where(Exp.Between("p.create_date", from, to) & !Exp.EqColumns("p.poster_id", "t.poster_id") & Exp.Eq("p.TenantID", tenantId))
                .OrderBy("p.create_date", false);
            return DbManager.ExecuteList(query).Select(x => new Post
            {
                ID = Convert.ToInt32(x[0]),
                CreateDate = Convert.ToDateTime(x[1]),
                Subject = Convert.ToString(x[2]),
                Text = Convert.ToString(x[3]),
                EditDate = Convert.ToDateTime(x[4]),
                PosterID = new Guid(Convert.ToString(x[5]))
            });
        }

        public static IEnumerable<Topic> GetTopics(DateTime from, DateTime to, int tenantId)
        {
            var query = new SqlQuery("forum_topic t")
                .Select("t.Id", "t.title", "t.create_date", "t.poster_id", "t.LastModified", "th.title", "t.type")
                .LeftOuterJoin("forum_thread th", Exp.EqColumns("t.thread_id", "th.id"))
                .Where(Exp.Between("t.create_date", from, to) & Exp.Eq("t.TenantId", tenantId))
                .OrderBy("t.create_date", false);
            return DbManager.ExecuteList(query).Select(x => new Topic
            {
                ID = Convert.ToInt32(x[0]),
                Title = Convert.ToString(x[1]),
                CreateDate = Convert.ToDateTime(x[2]),
                PosterID = new Guid(Convert.ToString(x[3])),
                RecentPostCreateDate = Convert.ToDateTime(x[4]),
                ThreadTitle = Convert.ToString(x[5]),
                Type =
                                                                        Convert.ToInt32(x[6]) == 0
                                                                            ? TopicType.Informational
                                                                            : TopicType.Poll
            });
        }

        #endregion
    }

    public class RemoveDataHelper
    {
        public static void RemoveThreadCategory(ThreadCategory category)
        {
            List<int> removedPostIDs;

            ForumDataProvider.RemoveThreadCategory(TenantProvider.CurrentTenantID, category.ID, out removedPostIDs);

            ForumManager.Instance.RemoveAttachments(category);

            removedPostIDs.ForEach(
                idPost =>
                CommonControlsConfigurer.FCKUploadsRemoveForItem(ForumManager.Settings.FileStoreModuleID,
                                                                 idPost.ToString(CultureInfo.InvariantCulture)));
        }

        public static void RemoveThread(Thread thread)
        {
            List<int> removedPostIDs;

            ForumDataProvider.RemoveThread(TenantProvider.CurrentTenantID, thread.ID, out removedPostIDs);

            ForumManager.Instance.RemoveAttachments(thread);

            removedPostIDs.ForEach(
                idPost =>
                CommonControlsConfigurer.FCKUploadsRemoveForItem(ForumManager.Settings.FileStoreModuleID,
                                                                 idPost.ToString(CultureInfo.InvariantCulture)));
        }

        public static void RemoveTopic(Topic topic)
        {
            List<int> removedPostIDs;

            var attachmantOffsetPhysicalPaths = ForumDataProvider.RemoveTopic(TenantProvider.CurrentTenantID, topic.ID,
                                                                              out removedPostIDs);

            foreach (var ace in Module.Constants.Aces)
            {
                CoreContext.AuthorizationManager.RemoveAce(new AzRecord(SecurityContext.CurrentAccount.ID, ace,
                                                                        Common.Security.Authorizing.AceType.Allow, topic));
            }

            FactoryIndexer<TopicWrapper>.DeleteAsync(topic);

            ForumManager.Settings.ForumManager.RemoveAttachments(attachmantOffsetPhysicalPaths.ToArray());

            removedPostIDs.ForEach(
                idPost =>
                CommonControlsConfigurer.FCKUploadsRemoveForItem(ForumManager.Settings.ForumManager.Settings.FileStoreModuleID,
                                                                 idPost.ToString(CultureInfo.InvariantCulture)));
        }

        public static DeletePostResult RemovePost(Post post)
        {
            var result = ForumDataProvider.RemovePost(TenantProvider.CurrentTenantID, post.ID);

            if (result == DeletePostResult.Successfully)
            {
                ForumManager.Settings.ForumManager.RemoveAttachments(post);

                FactoryIndexer<PostWrapper>.DeleteAsync(post);

                CommonControlsConfigurer.FCKUploadsRemoveForItem(ForumManager.Settings.ForumManager.Settings.FileStoreModuleID,
                                                                 post.ID.ToString(CultureInfo.InvariantCulture));
            }

            return result;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Configuration/SubscriptionManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Core;
using ASC.Notify.Model;
using ASC.Web.Core.Subscriptions;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Services.NotifyService;

namespace ASC.Web.Files.Classes
{
    public class SubscriptionManager : IProductSubscriptionManager
    {
        private readonly Guid _subscrTypeDocuSignComplete = new Guid("{0182E476-D63D-46ED-B928-104861507811}");
        private readonly Guid _subscrTypeDocuSignStatus = new Guid("{ED7F93CD-7575-40EB-86EB-82FBA23171D2}");
        private readonly Guid _subscrTypeShareDoc = new Guid("{552846EC-AC94-4408-AAC6-17C8989B8B38}");
        private readonly Guid _subscrTypeShareFolder = new Guid("{0292A4F4-0687-42a6-9CE4-E21215045ABE}");
        private readonly Guid _subscrTypeMailMerge = new Guid("{FB5858EC-046C-41E2-84C9-B44BF7884514}");
        private readonly Guid _subscrTypeEditorMentions = new Guid("{9D3CAB90-5718-4E82-959F-27EC83BFBC5F}");

        public GroupByType GroupByType
        {
            get { return GroupByType.Simple; }
        }

        public List<SubscriptionObject> GetSubscriptionObjects(Guid subItem)
        {
            return new List<SubscriptionObject>();
        }

        public List<SubscriptionType> GetSubscriptionTypes()
        {
            var subscriptionTypes = new List<SubscriptionType>
                                    {
                                        new SubscriptionType
                                            {
                                                ID = _subscrTypeShareDoc,
                                                Name = FilesCommonResource.SubscriptForAccess,
                                                NotifyAction = NotifyConstants.Event_ShareDocument,
                                                Single = true,
                                                CanSubscribe = true
                                            },
                                        new SubscriptionType
                                            {
                                                ID = _subscrTypeShareFolder,
                                                Name = FilesCommonResource.ShareFolder,
                                                NotifyAction = NotifyConstants.Event_ShareFolder,
                                                Single = true,
                                                CanSubscribe = true
                                            },
                                        new SubscriptionType
                                            {
                                                ID = _subscrTypeMailMerge,
                                                Name = FilesCommonResource.SubscriptForMailMerge,
                                                NotifyAction = NotifyConstants.Event_MailMergeEnd,
                                                Single = true,
                                                CanSubscribe = true
                                            },
                                        new SubscriptionType
                                            {
                                                ID = _subscrTypeEditorMentions,
                                                Name = FilesCommonResource.EditorMentions,
                                                NotifyAction = NotifyConstants.Event_EditorMentions,
                                                Single = true,
                                                CanSubscribe = true
                                            },
                                    };

            if (CoreContext.Configuration.CustomMode) return subscriptionTypes;

            subscriptionTypes.AddRange(new List<SubscriptionType>
                                    {
                                        new SubscriptionType
                                            {
                                                ID = _subscrTypeDocuSignComplete,
                                                Name = FilesCommonResource.SubscriptDocuSignComplete,
                                                NotifyAction = NotifyConstants.Event_DocuSignComplete,
                                                Single = true,
                                                CanSubscribe = true
                                            },
                                        new SubscriptionType
                                            {
                                                ID = _subscrTypeDocuSignStatus,
                                                Name = FilesCommonResource.SubscriptDocuSignStatus,
                                                NotifyAction = NotifyConstants.Event_DocuSignStatus,
                                                Single = true,
                                                CanSubscribe = true
                                            }
                                    });

            return subscriptionTypes;
        }

        public ISubscriptionProvider SubscriptionProvider
        {
            get { return NotifySource.Instance.GetSubscriptionProvider(); }
        }

        public List<SubscriptionGroup> GetSubscriptionGroups()
        {
            return new List<SubscriptionGroup>();
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Dao/TemplateDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core.Tenants;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;

namespace ASC.Projects.Data.DAO
{
    class TemplateDao : BaseDao, ITemplateDao
    {
        private readonly string[] templateColumns = new[] { "id", "title", "description", "create_by", "create_on" };
        private readonly Converter<object[], Template> converter;

        public TemplateDao(int tenant) : base(tenant)
        {
            converter = ToTemplate;
        }

        public List<Template> GetAll()
        {
            var q = Query(TemplatesTable + " p").Select(templateColumns).OrderBy("create_on", false);

            return Db.ExecuteList(q).ConvertAll(converter);
        }

        public int GetCount()
        {
            var q = Query(TemplatesTable + " p").SelectCount();

            return Db.ExecuteScalar<int>(q);
        }

        public Template GetByID(int id)
        {
            var query = Query(TemplatesTable + " p").Select(templateColumns).Where("p.id", id);
            return Db.ExecuteList(query).ConvertAll(converter).SingleOrDefault();
        }

        public Template Save(Template template)
        {
            var insert = Insert(TemplatesTable)
                .InColumnValue("id", template.Id)
                .InColumnValue("title", template.Title)
                .InColumnValue("description", template.Description)
                .InColumnValue("create_by", template.CreateBy.ToString())
                .InColumnValue("create_on", TenantUtil.DateTimeToUtc(template.CreateOn))
                .InColumnValue("last_modified_by", template.LastModifiedBy.ToString())
                .InColumnValue("last_modified_on", TenantUtil.DateTimeToUtc(template.LastModifiedOn))
                .Identity(1, 0, true);

            template.Id = Db.ExecuteScalar<int>(insert);

            return template;
        }

        public void Delete(int id)
        {
            Db.ExecuteNonQuery(Delete(TemplatesTable).Where("id", id));
        }

        private static Template ToTemplate(IList<object> r)
        {
            return new Template
            {
                Id = Convert.ToInt32(r[0]),
                Title = (string)r[1],
                Description = (string)r[2],
                CreateBy = new Guid((string)r[3]),
                CreateOn = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[4]))
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Controls/ChunkUploadDialog/chunkuploaddialog.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#chunkUploadDialog .progress-dialog-header.menu-upload-icon {
    background-image: url("../../../../skins/default/images/svg/crm/uploadblack.svg");
    background-position: 24px center;
    background-repeat: no-repeat;
    padding-left: 48px;
}
#chunkUploadDialog .settings-container {
    line-height: 32px;
}
#chunkUploadDialog .files-container {
    max-height: 240px;
    margin-bottom: 8px;
    overflow-y: auto;
}
.upload-info-container {
    margin-top: 8px;
}
#chunkUploadDialog .info-content {
    margin-bottom: 8px;
}
.fu-width-icon {
    width: 30px;
}
.fu-width-progress {
    width: 110px;
}
.fu-width-action {
    width: 90px;
}
body.wild-pink .upload-svg {
    fill: #ffffff;
}
body.bright-blue .upload-svg {
    fill: #ffffff;
}
.upload-svg {
    fill: #50565c;
    width: 16px;
    height: 16px;
    padding-top: 3px;
}
.fu-row .fu-action-cell {
    text-align: center;
    width: 80px;
}
.fu-row .fu-progress-cell {
    text-align: center;
    width: 100px;
}
.fu-row .fu-title-cell {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 190px;
}
.fu-row .fu-title-cell span {
    cursor: default;
}
.fu-row.done .ftFile_21,
.fu-row.done .fu-title-cell span {
    cursor: pointer;
}

.fu-row progress,
.fu-row .asc-progress-wrapper,
.fu-row .progress-color-anim {
    float: left;
    width: 100px;
}
.fu-row .progress-color-anim {
    height: 14px;
    background: url("images/uploader_progress.gif") no-repeat scroll 0 0 #D1D1D1;
}
.fu-row .progress-label {
    color: #FFFFFF;
    float: left;
    font-size: 10px;
    margin-left: -100px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 100px;
}
.fu-row.upload .share,
.fu-row.upload .upload-complete,
.fu-row.upload .upload-error,
.fu-row.upload .upload-canceled {
    display: none;
}
.fu-row.done .abort-file-uploadig,
.fu-row.done progress,
.fu-row.done .asc-progress-wrapper,
.fu-row.done .progress-label,
.fu-row.done .progress-color-anim,
.fu-row.done .upload-error,
.fu-row.done .upload-canceled {
    display: none;
}
.fu-row.error progress,
.fu-row.error .asc-progress-wrapper,
.fu-row.error .progress-label,
.fu-row.error .progress-color-anim,
.fu-row.error .upload-complete,
.fu-row.error .fu-action-cell,
.fu-row.error .upload-canceled {
    display: none;
}
.fu-row.canceled progress,
.fu-row.canceled .asc-progress-wrapper,
.fu-row.canceled .progress-label,
.fu-row.canceled .progress-color-anim,
.fu-row.canceled .upload-complete,
.fu-row.canceled .fu-action-cell,
.fu-row.canceled .upload-error {
    display: none;
}
.fu-row.convert .fu-action-cell,
.fu-row.convert .upload-complete,
.fu-row.convert .upload-error,
.fu-row.convert .upload-canceled {
    display: none;
}

.fu-row:hover .linkMedium {
    text-decoration: underline;
}

#abortUploadigBtn {
    float: right;
    margin-left: 5px;
}

#uploadSettingsPanel ul.dropdown-content label {
    white-space: nowrap;
}

#uploadSettingsSwitcher {
    cursor: pointer;
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Exceptions/ApiHelperException.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Net;

namespace ASC.Mail.Exceptions
{
    public class ApiHelperException : Exception
    {
        private readonly HttpStatusCode _statusCode;
        private readonly string _response;

        public HttpStatusCode StatusCode
        {
            get { return _statusCode; }
        }

        public string Response
        {
            get { return _response; }
        }

        public ApiHelperException(string message, HttpStatusCode statusCode, string response)
            : base(message)
        {
            _statusCode = statusCode;
            _response = response;
        }

        public override string ToString()
        {
            return string.Format("Api error has been occurred: Message = '{0}' StatusCode = '{1}' Response = '{2}'",
                Message, StatusCode, Response);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/ListItemHistoryDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.Globalization;

using ASC.Collections;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.CRM.Core.Entities;


#endregion

namespace ASC.CRM.Core.Dao
{

    public class CachedListItemHistory : ListItemHistoryDao
    {

        #region Members

        private readonly HttpRequestDictionary<ListItemHistory> _listItemHistoryCache = new HttpRequestDictionary<ListItemHistory>("crm_list_item_history");

        #endregion

        #region Constructor

        public CachedListItemHistory(int tenantId, DaoFactory factory)
            : base(tenantId, factory)
        {

        }

        #endregion

        #region Members

        public override ListItemHistory GetByID(int id)
        {
            return _listItemHistoryCache.Get(id.ToString(CultureInfo.InvariantCulture), () => GetByIDBase(id));
        }

        private ListItemHistory GetByIDBase(int id)
        {
            return base.GetByID(id);
        }

        private void ResetCache(int id)
        {
            _listItemHistoryCache.Reset(id.ToString(CultureInfo.InvariantCulture));
        }

        #endregion


    }

    public class ListItemHistoryDao : AbstractDao
    {
        #region Constructor

        private DaoFactory DaoFactory { get; set; }

        public ListItemHistoryDao(int tenantId, DaoFactory daoFactory)
            : base(tenantId)
        {
            DaoFactory = daoFactory;
        }

        #endregion

        public List<ListItemHistory> GetItems(EntityType entityType, int statusID, DateTime? startDate, DateTime? endDate)
        {
            var sqlQuery = GetListItemSqlQuery(Exp.Eq("entity_type", (int)entityType) & Exp.Eq("status", statusID));

            if (startDate.HasValue)
                sqlQuery.Where(Exp.Gt("modifed_on", startDate));

            if (endDate.HasValue)
                sqlQuery.Where(Exp.Lt("modifed_on", endDate));

            return Db.ExecuteList(sqlQuery.OrderBy("entity_id", true))
                .ConvertAll(ToListItemHistory);
        }

        public int GetItemsCount(EntityType entityType, int statusID, DateTime? startDate, DateTime? endDate)
        {
            var sqlQuery = Query("crm_item_history")
                .SelectCount()
                .Where(Exp.Eq("entity_type", (int)entityType) & Exp.Eq("status", statusID));

            if (startDate.HasValue)
                sqlQuery.Where(Exp.Gt("modifed_on", startDate));

            if (endDate.HasValue)
                sqlQuery.Where(Exp.Lt("modifed_on", endDate));

            return Db.ExecuteScalar<int>(sqlQuery);
        }

        public virtual ListItemHistory GetByID(int id)
        {
            var sqlQuery = GetListItemSqlQuery(Exp.Eq("id", id));

            var result = Db.ExecuteList(sqlQuery).ConvertAll(ToListItemHistory);

            return result.Count > 0 ? result[0] : null;
        }

        public virtual List<ListItemHistory> GetAll(EntityType entityType)
        {
            var sqlQuery = GetListItemSqlQuery(Exp.Eq("entity_type", (int)entityType))
                .OrderBy("entity_id", true);

            return Db.ExecuteList(sqlQuery).ConvertAll(ToListItemHistory);
        }

        public virtual int CreateItem(ListItemHistory item)
        {
            if (item.EntityType != EntityType.Opportunity || item.EntityType != EntityType.Contact)
                throw new ArgumentException();

            if (item.EntityType == EntityType.Opportunity &&
                (DaoFactory.DealDao.GetByID(item.EntityID) == null ||
                 DaoFactory.DealMilestoneDao.GetByID(item.StatusID) == null))
                throw new ArgumentException();

            if (item.EntityType == EntityType.Contact &&
                (DaoFactory.ContactDao.GetByID(item.EntityID) == null ||
                 DaoFactory.ListItemDao.GetByID(item.StatusID) == null))
                throw new ArgumentException();

            var sqlQuery = Insert("crm_item_history")
                .InColumnValue("id", 0)
                .InColumnValue("entity_id", item.EntityID)
                .InColumnValue("entity_type", (int)item.EntityType)
                .InColumnValue("status", item.StatusID)
                .InColumnValue("modifed_on", TenantUtil.DateTimeToUtc(TenantUtil.DateTimeNow()))
                .InColumnValue("modifed_by", SecurityContext.CurrentAccount.ID)
                .Identity(1, 0, true);

            return Db.ExecuteScalar<int>(sqlQuery);
        }

        public virtual void DeleteItem(EntityType entityType, int statusID)
        {
            if (HaveRelativeItems(entityType, statusID))
                throw new ArgumentException();

            var sqlQuery = Delete("crm_item_history")
                .Where(Exp.Eq("entity_type", (int)entityType) & Exp.Eq("status", statusID));

            Db.ExecuteNonQuery(sqlQuery);
        }

        private bool HaveRelativeItems(EntityType entityType, int statusID)
        {
            SqlQuery sqlQuery;

            switch (entityType)
            {
                case EntityType.Contact:
                    sqlQuery = Query("crm_contact")
                               .Where(Exp.Eq("status_id", statusID));
                    break;
                case EntityType.Opportunity:
                    sqlQuery = Query("crm_deal")
                             .Where(Exp.Eq("deal_milestone_id", statusID));
                    break;
                default:
                    throw new ArgumentException();
            }

            return Db.ExecuteScalar<int>(sqlQuery.SelectCount()) > 0;
        }

        private SqlQuery GetListItemSqlQuery(Exp where)
        {
            var result = Query("crm_list_item_history")
               .Select(
                   "id",
                   "entity_id",
                   "entity_type",
                   "status",
                   "modifed_on",
                   "modifed_by"
               );

            if (where != null)
                result.Where(where);

            return result;

        }

        public static ListItemHistory ToListItemHistory(object[] row)
        {
            return new ListItemHistory
            {
                ID = Convert.ToInt32(row[0]),
                EntityID = Convert.ToInt32(row[1]),
                EntityType = (EntityType)Convert.ToInt32(row[2]),
                StatusID = Convert.ToInt32(row[3]),
                ModifedOn = TenantUtil.DateTimeFromUtc(DateTime.Parse(row[4].ToString())),
                ModifedBy = ToGuid(row[5]),
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/HttpHandlers/docusignhandler.ashx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Net;
using System.Web;
using System.Xml;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Helpers;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Services.NotifyService;
using ASC.Web.Studio.UserControls.Statistics;

namespace ASC.Web.Files.HttpHandlers
{
    public class DocuSignHandler : IHttpHandler
    {
        public static string Path
        {
            get { return FilesLinkUtility.FilesBaseAbsolutePath + "httphandlers/docusignhandler.ashx"; }
        }

        private static ILog Log
        {
            get { return Global.Logger; }
        }

        public void ProcessRequest(HttpContext context)
        {
            if (TenantStatisticsProvider.IsNotPaid())
            {
                context.Response.StatusCode = (int)HttpStatusCode.PaymentRequired;
                context.Response.StatusDescription = "Payment Required.";
                return;
            }

            try
            {
                switch ((context.Request[FilesLinkUtility.Action] ?? "").ToLower())
                {
                    case "redirect":
                        Redirect(context);
                        break;
                    case "webhook":
                        Webhook(context);
                        break;
                    default:
                        throw new HttpException((int)HttpStatusCode.BadRequest, FilesCommonResource.ErrorMassage_BadRequest);
                }
            }
            catch (InvalidOperationException e)
            {
                throw new HttpException((int)HttpStatusCode.InternalServerError, FilesCommonResource.ErrorMassage_BadRequest, e);
            }
        }

        private static void Redirect(HttpContext context)
        {
            Log.Info("DocuSign redirect query: " + context.Request.QueryString);

            var eventRedirect = context.Request["event"];
            switch (eventRedirect.ToLower())
            {
                case "send":
                    context.Response.Redirect(PathProvider.StartURL + "#message/" + HttpUtility.UrlEncode(FilesCommonResource.DocuSignStatusSended), true);
                    break;
                case "save":
                case "cancel":
                    context.Response.Redirect(PathProvider.StartURL + "#error/" + HttpUtility.UrlEncode(FilesCommonResource.DocuSignStatusNotSended), true);
                    break;
                case "error":
                case "sessionend":
                    context.Response.Redirect(PathProvider.StartURL + "#error/" + HttpUtility.UrlEncode(FilesCommonResource.DocuSignStatusError), true);
                    break;
            }
            context.Response.Redirect(PathProvider.StartURL, true);
        }

        private const string XmlPrefix = "docusign";

        private static void Webhook(HttpContext context)
        {
            Global.Logger.Info("DocuSign webhook: " + context.Request.QueryString);
            try
            {
                var xmldoc = new XmlDocument();
                xmldoc.Load(context.Request.InputStream);
                Global.Logger.Info("DocuSign webhook outerXml: " + xmldoc.OuterXml);

                var mgr = new XmlNamespaceManager(xmldoc.NameTable);
                mgr.AddNamespace(XmlPrefix, "http://www.docusign.net/API/3.0");

                var envelopeStatusNode = GetSingleNode(xmldoc, "DocuSignEnvelopeInformation/" + XmlPrefix + ":EnvelopeStatus", mgr);
                var envelopeId = GetSingleNode(envelopeStatusNode, "EnvelopeID", mgr).InnerText;
                var subject = GetSingleNode(envelopeStatusNode, "Subject", mgr).InnerText;

                var statusString = GetSingleNode(envelopeStatusNode, "Status", mgr).InnerText;
                DocuSignStatus status;
                if (!Enum.TryParse(statusString, true, out status))
                {
                    throw new Exception("DocuSign webhook unknown status: " + statusString);
                }

                Global.Logger.Info("DocuSign webhook: " + envelopeId + " " + subject + " " + status);

                var customFieldUserIdNode = GetSingleNode(envelopeStatusNode, "CustomFields/" + XmlPrefix + ":CustomField[" + XmlPrefix + ":Name='" + DocuSignHelper.UserField + "']", mgr);
                var userIdString = GetSingleNode(customFieldUserIdNode, "Value", mgr).InnerText;
                Auth(userIdString);

                switch (status)
                {
                    case DocuSignStatus.Completed:

                        var documentStatuses = GetSingleNode(envelopeStatusNode, "DocumentStatuses", mgr);
                        foreach (XmlNode documentStatus in documentStatuses.ChildNodes)
                        {
                            try
                            {
                                var documentId = GetSingleNode(documentStatus, "ID", mgr).InnerText;
                                var documentName = GetSingleNode(documentStatus, "Name", mgr).InnerText;

                                string folderId = null;
                                string sourceTitle = null;

                                var documentFiels = GetSingleNode(documentStatus, "DocumentFields", mgr, true);
                                if (documentFiels != null)
                                {
                                    var documentFieldFolderNode = GetSingleNode(documentFiels, "DocumentField[" + XmlPrefix + ":Name='" + FilesLinkUtility.FolderId + "']", mgr, true);
                                    if (documentFieldFolderNode != null)
                                    {
                                        folderId = GetSingleNode(documentFieldFolderNode, "Value", mgr).InnerText;
                                    }
                                    var documentFieldTitleNode = GetSingleNode(documentFiels, "DocumentField[" + XmlPrefix + ":Name='" + FilesLinkUtility.FileTitle + "']", mgr, true);
                                    if (documentFieldTitleNode != null)
                                    {
                                        sourceTitle = GetSingleNode(documentFieldTitleNode, "Value", mgr).InnerText;
                                    }
                                }

                                var file = DocuSignHelper.SaveDocument(envelopeId, documentId, documentName, folderId);

                                NotifyClient.SendDocuSignComplete(file, sourceTitle ?? documentName);
                            }
                            catch (Exception ex)
                            {
                                Global.Logger.Error("DocuSign webhook save document: " + documentStatus.InnerText, ex);
                            }
                        }
                        break;
                    case DocuSignStatus.Declined:
                    case DocuSignStatus.Voided:
                        var statusFromResource = status == DocuSignStatus.Declined
                                                     ? FilesCommonResource.DocuSignStatusDeclined
                                                     : FilesCommonResource.DocuSignStatusVoided;
                        NotifyClient.SendDocuSignStatus(subject, statusFromResource);
                        break;
                }
            }
            catch (Exception e)
            {
                Global.Logger.Error("DocuSign webhook", e);

                throw new HttpException((int)HttpStatusCode.BadRequest, e.Message);
            }
        }

        private static void Auth(string userIdString)
        {
            Guid userId;
            if (!Guid.TryParse(userIdString ?? "", out userId))
            {
                throw new Exception("DocuSign incorrect User ID: " + userIdString);
            }

            SecurityContext.AuthenticateMe(userId);
        }

        private static XmlNode GetSingleNode(XmlNode node, string xpath, XmlNamespaceManager mgr, bool canMiss = false)
        {
            var result = node.SelectSingleNode(XmlPrefix + ":" + xpath, mgr);
            if (!canMiss && result == null) throw new Exception(xpath + " is null");
            return result;
        }

        public bool IsReusable
        {
            get { return false; }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiHttpHandlerBase.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Threading;
using System.Web;
using System.Web.Routing;

using ASC.Api.Enums;
using ASC.Api.Interfaces;
using ASC.Api.Utils;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Web.Core.Client;

using Autofac;

namespace ASC.Api.Impl
{
    public abstract class ApiHttpHandlerBase : IApiHttpHandler
    {
        public ILog Log { get; set; }

        public IApiManager ApiManager { get; set; }

        public ILifetimeScope Container { get; set; }

        public RouteData RouteData { get; private set; }

        protected IApiMethodCall Method { get; private set; }


        public IApiStandartResponce ApiResponce { get; private set; }

        public ApiContext ApiContext { get; private set; }




        protected ApiHttpHandlerBase(RouteData routeData)
        {
            RouteData = routeData;
        }

        protected void RespondTo(IApiMethodCall method, HttpContextBase context)
        {
            try
            {
                context.Response.Cache.SetETag(Guid.NewGuid().ToString("N"));
                context.Response.Cache.SetMaxAge(TimeSpan.FromSeconds(0));
            }
            catch (Exception)
            {
                //Nothing happens if we didn't set cache tags   
            }

            IApiResponder responder = null;

            if (method != null && method.Responders != null && method.Responders.Any())
            {
                try
                {
                    //Try custom responders
                    var methodCustomResponders = new List<IApiResponder>(method.Responders);
                    responder = methodCustomResponders.FirstOrDefault(x => x != null && x.CanRespondTo(ApiResponce, context));
                }
                catch (Exception)
                {
                    Log.WarnFormat("Custom reponder for {0} failed", method.ToString());
                }
            }
            if (responder == null)
            {
                responder = Container.Resolve<IEnumerable<IApiResponder>>().FirstOrDefault(x => x.CanRespondTo(ApiResponce, context));
            }

            if (responder != null)
            {
                try
                {
                    responder.RespondTo(ApiResponce, context);
                }
                catch (Exception e)
                {
                    Log.Error("Error while responding!", e);
                    throw;
                }
            }
            else
            {
                Log.Error("no formatter error");
                throw new HttpException((int)HttpStatusCode.BadRequest, "No formatter");
            }
        }

        public void Process(HttpContextBase context)
        {
            using (Container)
            {
                ApiManager = Container.Resolve<IApiManager>();
                RouteContext = new RequestContext(context, RouteData);
                var config = Container.Resolve<IApiConfiguration>();
                ApiContext = Container.Resolve<ApiContext>(new NamedParameter("requestContext", RouteContext), new NamedParameter("apiConfiguration", config));
                ApiResponce = Container.Resolve<IApiStandartResponce>();

                //NOTE: Don't register anything it will be resolved when needed
                //Container.RegisterInstance(ApiContext, new HttpContextLifetimeManager2(context));//Regiter only api context

                Method = ApiManager.GetMethod(((Route)RouteData.Route).Url, context.Request.RequestType); //Set method

                DoProcess(context);
            }
        }

        protected RequestContext RouteContext { get; private set; }

        protected abstract void DoProcess(HttpContextBase context);

        public void ProcessRequest(HttpContext context)
        {
            var contextWrapper = new HttpContextWrapper(context);
            ProcessInternal(contextWrapper);
        }

        private void ProcessInternal(HttpContextWrapper contextWrapper)
        {
            try
            {
                Process(contextWrapper);
            }
            catch (ThreadAbortException e)
            {
                Log.Error("thread aborted", e);
            }
            catch (Exception e)
            {
                var method = contextWrapper.Request != null ? contextWrapper.Request.HttpMethod : null;
                var url = contextWrapper.Request != null ? contextWrapper.Request.Url : null;
                var user = contextWrapper.User != null ? contextWrapper.User.Identity.Name : null;
                Log.Error(string.Format("error during processing http request {0}: {1}, user: {2}", method, url, user), e);
                throw;
            }
        }

        public bool IsReusable
        {
            get { return false; }
        }


        protected void PostProcessResponse(HttpContextBase context, object responce)
        {
            ApiResponce.Status = ApiStatus.Ok;
            //Set 'created' when posted
            if (context.Request.RequestType.Equals("POST", StringComparison.OrdinalIgnoreCase))
            {
                context.Response.StatusCode = (int)HttpStatusCode.Created;
                context.Response.StatusDescription = HttpStatusCode.Created.ToString();
            }
            if (responce != null)
            {
                //Correct item count
                var beforeFilterCount = Binder.GetCollectionCount(responce);

                var filters = Container.Resolve<IEnumerable<IApiResponceFilter>>();
                //Do filtering
                if (filters != null)
                    responce = filters.Aggregate(responce, (current, apiResponceFilter) => apiResponceFilter.FilterResponce(current, ApiContext));

                ApiResponce.Count = Binder.GetCollectionCount(responce);
                if (ApiResponce.Count == ApiContext.SpecifiedCount && (beforeFilterCount - ApiContext.StartIndex) > ApiContext.SpecifiedCount)
                {
                    //This means we have more
                    ApiResponce.NextPage = ApiContext.SpecifiedStartIndex + ApiContext.SpecifiedCount + 1;
                    //Cut collection by 1
                }
                ApiResponce.TotalCount = ApiContext.TotalCount;
                ApiResponce.Response = responce;
            }
            else
            {
                ApiResponce.Count = 0;
                ApiResponce.Response = new object();
            }
            ApiResponce.Code = context.Response.StatusCode;
            if (context.Handler.GetType() == GetType())
            {
                var acceptEncoding = context.Request.Headers["Accept-Encoding"];

                if (!string.IsNullOrEmpty(acceptEncoding))
                {
                    var encodings = acceptEncoding.Split(',');
                    if (encodings.Contains("gzip") && ClientSettings.GZipEnabled)
                    {
                        context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress);
                        context.Response.AppendHeader("Content-Encoding", "gzip");
                    }
                }

                SecurityContext.Logout();
            }
        }

        protected void SetError(HttpContextBase context, Exception e, HttpStatusCode code)
        {
            SetError(context, e, code, "Server error");
        }

        protected void SetError(HttpContextBase context, Exception e, HttpStatusCode code, string description)
        {
            Log.Error(string.Format("method error: {0} - {1}", context.Request.Url, description), e);
            if (context.Response.StatusCode / 100 == 2)
            {
                context.Response.StatusCode = (int)code;
            }
            context.Response.StatusDescription = description;
            ApiResponce.Response = null;
            ApiResponce.Status = ApiStatus.Error;
            ApiResponce.Code = context.Response.StatusCode;
            ApiResponce.Count = 0;
            ApiResponce.Error = new ErrorWrapper(e);
            context.Response.TrySkipIisCustomErrors = true;//try always
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/Core/Patterns/BookmarkingPatternResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Community.Modules.Bookmarking.Core.Patterns {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class BookmarkingPatternResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal BookmarkingPatternResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Community.Modules.Bookmarking.Core.Patterns.BookmarkingPatternResource", typeof(BookmarkingPatternResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.New Comment to Bookmark: &quot;$BookmarkTitle&quot;:&quot;$BookmarkUrl&quot;
        ///
        ///$Date &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a comment to the bookmark:&quot;$BookmarkTitle&quot;:&quot;$BookmarkUrl&quot;
        ///
        ///$CommentBody
        ///
        ///&quot;Read More&quot;:&quot;$BookmarkUrl&quot;
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you do not want to receive the notifications about new comments added to this bookmark, please manage your &quot;subscription settings&quot;:&quot;$RecipientSubscriptionConfigURL&quot;.^.
        /// </summary>
        public static string pattern_BookmarkCommentCreatedID {
            get {
                return ResourceManager.GetString("pattern_BookmarkCommentCreatedID", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.New Bookmark Added: &quot;$BookmarkTitle&quot;:&quot;$BookmarkUrl&quot;
        ///
        ///$Date &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new bookmark:&quot;$BookmarkTitle&quot;:&quot;$BookmarkUrl&quot;
        ///
        ///$BookmarkDescription
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you do not want to receive the notifications about new bookmarks added, please manage your &quot;subscription settings&quot;:&quot;$RecipientSubscriptionConfigURL&quot;.^.
        /// </summary>
        public static string pattern_BookmarkCreatedID {
            get {
                return ResourceManager.GetString("pattern_BookmarkCreatedID", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. New comment to bookmark: $BookmarkTitle.
        /// </summary>
        public static string subject_BookmarkCommentCreatedID {
            get {
                return ResourceManager.GetString("subject_BookmarkCommentCreatedID", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. New comment to bookmark: [$BookmarkTitle]($BookmarkUrl).
        /// </summary>
        public static string subject_BookmarkCommentCreatedID_tg {
            get {
                return ResourceManager.GetString("subject_BookmarkCommentCreatedID_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. New bookmark added: $BookmarkTitle.
        /// </summary>
        public static string subject_BookmarkCreatedID {
            get {
                return ResourceManager.GetString("subject_BookmarkCreatedID", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. New bookmark added: [$BookmarkTitle]($BookmarkUrl).
        /// </summary>
        public static string subject_BookmarkCreatedID_tg {
            get {
                return ResourceManager.GetString("subject_BookmarkCreatedID_tg", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/filters/manager.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.filtersManager = (function($) {
    var isInit = false,
        filters = [],
        eventsHandler = $({}),
        supportedCustomEvents = {
            OnCreate: "mf.create",
            OnUpdate: "mf.update",
            OnDelete: "mf.delete",
            OnError: "mf.error"
        },
        onLoading = false,
        progressBarIntervalId,
        getStatusTimeout = 1000;

    function init() {
        if (isInit === true) return;

        if (ASC.Mail.Presets.Filters) {
            onLoading = true;
            loadFilters(ASC.Mail.Presets.Filters);
            onLoading = false;
        }

        filterModal.init();
        filtersPage.init();
        editFilterPage.init();
    }

    function loadFilters(filterList) {
        filters = [];
        filterList.forEach(function (filter) {
            filter.actions.forEach(function(actionItem) {
                if (actionItem.action === ASC.Mail.Filter.Constants.ActionType.MoveTo) {
                    actionItem.data = actionItem.data.replace(/&quot;/g, '"');
                }
            });

            filter.conditions = $.map(filter.conditions, function (conditionItem) {
                return new ASC.Mail.Filter.Condition(conditionItem.key,
                    conditionItem.operation,
                    conditionItem.value);
            });

            filters.push(filter);
        });
    }

    function compare(f1, f2) {
        if (f1.position < f2.position)
            return -1;
        if (f1.position > f2.position)
            return 1;
        return 0;
    }

    function refresh() {
        var d = jq.Deferred();

        if (onLoading) {
            return d.resolve({}, getList());
        }

        onLoading = true;

        window.Teamlab.getMailFilters({},
        {
            success: function (params, filterList) {
                onLoading = false;

                loadFilters(filterList);

                return d.resolve(params, getList());
            },
            error: function (params, errors) {
                onLoading = false;

                window.toastr.error(errors[0]);

                eventsHandler.trigger(supportedCustomEvents.OnError, errors[0]);

                return d.reject(params, errors);
            }
        });

        return d.promise();
    }

    function getList() {
        return filters.sort(compare);
    }

    function get(id) {
        id = parseInt(id);

        var index = getFilterIndex(id);

        return index > -1 ? filters[index] : null;
    }

    function enable(id, enabled) {
        var filter = get(id);

        if (!filter) return;

        if (filter.enabled === enabled)
            return;

        filter.enabled = enabled;

        update(filter);
    }

    function create(filter) {
        window.Teamlab.createMailFilter({}, filter,
        {
            success: function (params, newFilter) {
                filters.push(newFilter);
                eventsHandler.trigger(supportedCustomEvents.OnCreate, newFilter);
            },
            error: function (params, errors) {
                window.toastr.error(errors[0]);
                eventsHandler.trigger(supportedCustomEvents.OnError, errors[0]);
            }
        });
    }

    function update(filter) {
        window.Teamlab.updateMailFilter({}, filter,
        {
            success: function (params, newFilter) {
                var index = getFilterIndex(newFilter.id);

                if (index > -1)
                    filters[index] = newFilter;

                eventsHandler.trigger(supportedCustomEvents.OnUpdate, newFilter);
            },
            error: function (params, errors) {
                window.toastr.error(errors[0]);
                eventsHandler.trigger(supportedCustomEvents.OnError, errors[0]);
            }
        });
    }

    function remove(id) {
        filterModal.showDelete(get(id),
        {
            onSuccess: function (filter) {
                window.Teamlab.deleteMailFilter({},
                    filter.id,
                    {
                        success: function () {
                            var index = getFilterIndex(filter.id);

                            if (index === -1)
                                return;

                            filters.splice(index, 1);
                            eventsHandler.trigger(supportedCustomEvents.OnDelete, filter.id);
                        },
                        error: function(params, errors) {
                            window.toastr.error(errors[0]);
                            eventsHandler.trigger(supportedCustomEvents.OnError, errors[0]);
                        }
                    });
            }
        });
    }

    function applyFilter(id) {
        filterModal.showApply(get(id),
        {
            onSuccess: function(filter) {

                LoadingBanner.displayMailLoading();

                window.Teamlab.applyMailFilter({},
                    filter.id,
                    {
                        success: function(p, operation) {
                            //console.log("Applying filter started", p, operation);

                            progressBarIntervalId = setInterval(function() {
                                    Teamlab.getMailOperationStatus({},
                                        operation.id,
                                        {
                                            success: function(params, data) {
                                                if (data.completed) {
                                                    clearInterval(progressBarIntervalId);
                                                    progressBarIntervalId = null;

                                                    if (data.error !== "") {
                                                        toastr.error(ASC.Resources.Master.ResourceJS.OperationFailedMsg);
                                                        console.log(data.error);
                                                    } else {
                                                        toastr
                                                            .success(ASC.Resources.Master.ResourceJS
                                                                .OperationSuccededMsg);
                                                    }

                                                    window.serviceManager.updateFolders();
                                                    window.LoadingBanner.hideLoading();
                                                }
                                            },
                                            error: function(params, errors) {
                                                console.error("checkMailOperationStatus failed", e, errors);
                                                clearInterval(progressBarIntervalId);
                                                progressBarIntervalId = null;

                                                window.LoadingBanner.hideLoading();
                                            }
                                        });
                                },
                                getStatusTimeout);

                        },
                        error: function(params, errors) {
                            window.toastr.error(errors[0]);
                            eventsHandler.trigger(supportedCustomEvents.OnError, errors[0]);
                            LoadingBanner.hideLoading();
                        }
                    });
            }
        });
    }

    function getFilterIndex(id) {
        var i, n = filters.length;
        for (i = 0; i < n; i++) {
            var filter = filters[i];

            if (filter.id === id) {
                return i;
            }
        }

        return -1;
    }

    function bind(eventName, fn) {
        eventsHandler.bind(eventName, fn);
    }

    function unbind(eventName) {
        eventsHandler.unbind(eventName);
    }

    function isLoading() {
        return onLoading;
    }

    return {
        init: init,
        bind: bind,
        unbind: unbind,
        events: supportedCustomEvents,

        getList: getList,
        get: get,
        refresh: refresh,

        create: create,
        update: update,
        remove: remove,
        enable: enable,
        applyFilter: applyFilter,

        isLoading: isLoading
    };
})(jQuery);

<|start_filename|>module/ASC.TelegramService/Core/Core.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

using ASC.Common.Logging;

using Telegram.Bot;
using Telegram.Bot.Types;

namespace ASC.TelegramService.Core
{
    public class TelegramCommand
    {
        public string CommandName { get; private set; }
        public string[] Args { get; private set; }

        public Message Message { get; private set; }
        public User User { get { return Message.From; } }
        public Chat Chat { get { return Message.Chat; } }

        public TelegramCommand(Message msg, string cmdName, string[] args = null)
        {
            Message = msg;
            CommandName = cmdName;
            Args = args;
        }
    }

    public class CommandModule
    {
        private readonly ILog log;

        private static readonly Regex cmdReg = new Regex(@"^\/([^\s]+)\s?(.*)");
        private static readonly Regex argsReg = new Regex(@"[^""\s]\S*|"".+?""");

        private readonly Dictionary<string, MethodInfo> commands = new Dictionary<string, MethodInfo>();
        private readonly Dictionary<string, Type> contexts = new Dictionary<string, Type>();
        private readonly Dictionary<Type, ParamParser> parsers = new Dictionary<Type, ParamParser>();

        public CommandModule(ILog log)
        {
            this.log = log;

            var assembly = Assembly.GetExecutingAssembly();

            foreach (var t in assembly.GetExportedTypes())
            {
                if (t.IsAbstract) continue;

                if (t.IsSubclassOf(typeof(CommandContext)))
                {
                    foreach (var method in t.GetRuntimeMethods())
                    {
                        if (method.IsPublic && Attribute.IsDefined(method, typeof(CommandAttribute)))
                        {
                            var attr = method.GetCustomAttribute<CommandAttribute>();
                            commands.Add(attr.Name, method);
                            contexts.Add(attr.Name, t);
                        }
                    }
                }

                if (t.IsSubclassOf(typeof(ParamParser)) && Attribute.IsDefined(t, typeof(ParamParserAttribute)))
                {
                    parsers.Add(t.GetCustomAttribute<ParamParserAttribute>().Type, (ParamParser)Activator.CreateInstance(t));
                }
            }
        }

        private TelegramCommand ParseCommand(Message msg)
        {
            var reg = cmdReg.Match(msg.Text);
            var args = argsReg.Matches(reg.Groups[2].Value);

            return new TelegramCommand(msg, reg.Groups[1].Value.ToLowerInvariant(), args.Count > 0 ? args.Cast<Match>().Select(a => a.Value).ToArray() : null);
        }

        private object[] ParseParams(MethodInfo cmd, string[] args)
        {
            List<object> parsedParams = new List<object>();

            var cmdArgs = cmd.GetParameters();

            if (cmdArgs.Any() && args == null || cmdArgs.Count() != args.Count()) throw new Exception("Wrong parameters count");

            for (var i = 0; i < cmdArgs.Count(); i++)
            {
                var type = cmdArgs[i].ParameterType;

                if (type == typeof(string))
                {
                    parsedParams.Add(args[i]);
                    continue;
                }

                if (!parsers.ContainsKey(type)) throw new Exception(string.Format("No parser found for type '{0}'", type));

                parsedParams.Add(parsers[cmdArgs[i].ParameterType].FromString(args[i]));
            }

            return parsedParams.ToArray();
        }

        public async Task HandleCommand(Message msg, TelegramBotClient client, int tenantId)
        {
            try
            {
                var cmd = ParseCommand(msg);

                if (!commands.ContainsKey(cmd.CommandName)) throw new Exception(string.Format("No handler found for command '{0}'", cmd.CommandName));

                var command = commands[cmd.CommandName];
                var context = (CommandContext)Activator.CreateInstance(contexts[cmd.CommandName]);

                var param = ParseParams(command, cmd.Args);

                context.Context = cmd;
                context.Client = client;
                context.TenantId = tenantId;
                await Task.FromResult(command.Invoke(context, param));
            }
            catch (Exception ex)
            {
                log.DebugFormat("Couldn't handle ({0}) message ({1})", msg.Text, ex.Message);
            }
        }
    }

    public abstract class CommandContext
    {
        public ITelegramBotClient Client { get; set; }
        public TelegramCommand Context { get; set; }
        public int TenantId { get; set; }

        protected async Task ReplyAsync(string message)
        {
            await Client.SendTextMessageAsync(Context.Chat, message);
        }
    }

    public abstract class ParamParser
    {
        protected Type type;

        protected ParamParser(Type type)
        {
            this.type = type;
        }

        public abstract object FromString(string arg);
        public abstract string ToString(object arg);
    }

    public abstract class ParamParser<T> : ParamParser
    {
        public ParamParser() : base(typeof(T)) { }

        public override abstract object FromString(string arg);
        public override abstract string ToString(object arg);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Sender/SmtpSender.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;

using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Controls.Common;

namespace ASC.Web.CRM.Controls.Sender
{
    public partial class SmtpSender : BaseUserControl
    {
        public static String Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Sender/SmtpSender.ascx"); }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            phFileUploader.Controls.Add(LoadControl(FileUploader.Location));

            RegisterScript();
        }

        protected string RenderTagSelector(bool isCompany)
        {
            var sb = new StringBuilder();
            var manager = new MailTemplateManager(DaoFactory);
            var tags = manager.GetTags(isCompany);

            var current = tags[0].Category;
            sb.AppendFormat("<optgroup label='{0}'>", current);

            foreach (var tag in tags)
            {
                if (tag.Category != current)
                {
                    current = tag.Category;
                    sb.Append("</optgroup>");
                    sb.AppendFormat("<optgroup label='{0}'>", current);
                }

                sb.AppendFormat("<option value='{0}'>{1}</option>",
                                tag.Name,
                                tag.DisplayName);
            }

            sb.Append("</optgroup>");

            return sb.ToString();
        }

        private void RegisterScript()
        {
            Page.RegisterBodyScripts("~/UserControls/Common/ckeditor/ckeditor-connector.js");

            var sb = new StringBuilder();

            sb.AppendFormat(@"ASC.CRM.SmtpSender.init({0});", MailSender.GetQuotas());

            Page.RegisterInlineScript(sb.ToString());
        }

    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/MailboxEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;

using ASC.Common.Data;
using ASC.Common.Logging;
using ASC.Mail.Authorization;
using ASC.Mail.Core.Dao.Expressions.Attachment;
using ASC.Mail.Core.Dao.Expressions.Conversation;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Core.Dao.Expressions.Message;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Enums;
using ASC.Mail.Utils;

namespace ASC.Mail.Core.Engine
{
    public class MailboxEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ILog Log { get; private set; }

        public EngineFactory Factory { get; private set; }

        public MailboxEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.MailboxEngine");

            Factory = new EngineFactory(Tenant, User, Log);
        }

        public MailBoxData GetMailboxData(IMailboxExp exp)
        {
            var tuple = GetMailboxFullInfo(exp);
            return tuple == null ? null : tuple.Item1;
        }

        public List<MailBoxData> GetMailboxDataList(IMailboxesExp exp)
        {
            var tuples = GetMailboxFullInfoList(exp);
            return tuples.Select(t => t.Item1).ToList();
        }

        public List<Tuple<MailBoxData, Mailbox>> GetMailboxFullInfoList(IMailboxesExp exp)
        {
            var list = new List<Tuple<MailBoxData, Mailbox>>();

            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                var mailboxes = daoMailbox.GetMailBoxes(exp);

                list.AddRange(mailboxes.Select(mailbox => GetMailbox(daoFactory, mailbox)).Where(tuple => tuple != null));
            }

            return list;
        }

        public Tuple<MailBoxData, Mailbox> GetMailboxFullInfo(IMailboxExp exp)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                var mailbox = daoMailbox.GetMailBox(exp);

                if (mailbox == null)
                    return null;

                var tuple = GetMailbox(daoFactory, mailbox);

                return tuple;
            }
        }

        public Tuple<int, int> GetRangeMailboxes(IMailboxExp exp)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                return daoMailbox.GetRangeMailboxes(exp);
            }
        }

        public bool TryGetNextMailboxData(IMailboxExp exp, out MailBoxData mailBoxData, out int failedId)
        {
            failedId = -1;

            try
            {
                using (var daoFactory = new DaoFactory())
                {
                    var daoMailbox = daoFactory.CreateMailboxDao();

                    var mailbox = daoMailbox.GetNextMailBox(exp);

                    if (mailbox == null)
                    {
                        mailBoxData = null;
                        return false;
                    }

                    var tuple = GetMailbox(daoFactory, mailbox);

                    if (tuple == null)
                    {
                        Log.WarnFormat("Mailbox id = {0} is not well-formated.", mailbox.Id);

                        mailBoxData = null;
                        failedId = mailbox.Id;
                        return false;
                    }

                    mailBoxData = tuple.Item1;
                    return true;
                }
            }
            catch (Exception ex)
            {
                Log.Error("TryGetNextMailboxData failed", ex);
            }

            mailBoxData = null;
            return false;
        }

        public MailBoxData GetDefaultMailboxData(string email, string password,
            AuthorizationServiceType type, bool? imap, bool isNullNeeded)
        {
            var address = new MailAddress(email);

            var host = address.Host.ToLowerInvariant();

            if (type == AuthorizationServiceType.Google) host = Defines.GOOGLE_HOST;

            MailBoxData initialMailbox = null;

            if (imap.HasValue)
            {
                try
                {
                    var settings = Factory.MailBoxSettingEngine.GetMailBoxSettings(host);

                    if (settings != null)
                    {
                        var outgoingServerLogin = "";

                        var incommingType = imap.Value ? "imap" : "pop3";

                        var incomingServer =
                            settings.EmailProvider.IncomingServer
                            .FirstOrDefault(serv =>
                                serv.Type
                                .ToLowerInvariant()
                                .Equals(incommingType));

                        var outgoingServer = settings.EmailProvider.OutgoingServer.FirstOrDefault() ?? new ClientConfigEmailProviderOutgoingServer();

                        if (incomingServer != null && !string.IsNullOrEmpty(incomingServer.Username))
                        {
                            var incomingServerLogin = address.ToLogin(incomingServer.Username);

                            if (!string.IsNullOrEmpty(outgoingServer.Username))
                            {
                                outgoingServerLogin = address.ToLogin(outgoingServer.Username);
                            }

                            initialMailbox = new MailBoxData
                            {
                                EMail = address,
                                Name = "",

                                Account = incomingServerLogin,
                                Password = password,
                                Server = host.ToHost(incomingServer.Hostname),
                                Port = incomingServer.Port,
                                Encryption = incomingServer.SocketType.ToEncryptionType(),
                                SmtpEncryption = outgoingServer.SocketType.ToEncryptionType(),
                                Authentication = incomingServer.Authentication.ToSaslMechanism(),
                                SmtpAuthentication = outgoingServer.Authentication.ToSaslMechanism(),
                                Imap = imap.Value,

                                SmtpAccount = outgoingServerLogin,
                                SmtpPassword = password,
                                SmtpServer = host.ToHost(outgoingServer.Hostname),
                                SmtpPort = outgoingServer.Port,
                                Enabled = true,
                                TenantId = Tenant,
                                UserId = User,
                                BeginDate = DateTime.UtcNow.Subtract(new TimeSpan(MailBoxData.DefaultMailLimitedTimeDelta)),
                                OAuthType = (byte)type
                            };
                        }
                    }
                }
                catch (Exception)
                {
                    initialMailbox = null;
                }
            }

            if (initialMailbox != null || isNullNeeded)
            {
                return initialMailbox;
            }

            var isImap = imap.GetValueOrDefault(true);
            return new MailBoxData
            {
                EMail = address,
                Name = "",
                Account = email,
                Password = password,
                Server = string.Format((isImap ? "imap.{0}" : "pop.{0}"), host),
                Port = (isImap ? 993 : 110),
                Encryption = isImap ? EncryptionType.SSL : EncryptionType.None,
                SmtpEncryption = EncryptionType.None,
                Imap = isImap,
                SmtpAccount = email,
                SmtpPassword = password,
                SmtpServer = string.Format("smtp.{0}", host),
                SmtpPort = 25,
                Enabled = true,
                TenantId = Tenant,
                UserId = User,
                BeginDate = DateTime.UtcNow.Subtract(new TimeSpan(MailBoxData.DefaultMailLimitedTimeDelta)),
                Authentication = SaslMechanism.Login,
                SmtpAuthentication = SaslMechanism.Login
            };
        }

        public MailboxStatus GetMailboxStatus(IMailboxExp exp)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                var status = daoMailbox.GetMailBoxStatus(exp);

                return status;
            }
        }

        public bool SaveMailBox(MailBoxData mailbox, AuthorizationServiceType authType = AuthorizationServiceType.None)
        {
            if (mailbox == null)
                throw new ArgumentNullException("mailbox");

            if (mailbox.IsTeamlab)
                throw new ArgumentException("Mailbox with specified email can't be updated");

            using (var daoFactory = new DaoFactory())
            {
                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    var daoMailbox = daoFactory.CreateMailboxDao();
                    var daoMailboxServer = daoFactory.CreateMailboxServerDao();
                    var daoMailboxDomain = daoFactory.CreateMailboxDomainDao();
                    var daoMailboxProvider = daoFactory.CreateMailboxProviderDao();

                    var existingMailbox = daoMailbox.GetMailBox(
                        new СoncreteUserMailboxExp(
                            mailbox.EMail,
                            mailbox.TenantId, mailbox.UserId));

                    int newInServerId, newOutServerId;

                    var mailboxId = 0;
                    var dateCreated = DateTime.UtcNow;
                    var enabled = true;
                    var host = authType == AuthorizationServiceType.Google ? Defines.GOOGLE_HOST : mailbox.EMail.Host;

                    // Get new imap/pop3 server from MailBoxData
                    var newInServer = new MailboxServer
                    {
                        Hostname = mailbox.Server,
                        Port = mailbox.Port,
                        Type = mailbox.Imap ? Defines.IMAP : Defines.POP3,
                        Username = mailbox.EMail.ToLoginFormat(mailbox.Account) ?? mailbox.Account,
                        SocketType = mailbox.Encryption.ToNameString(),
                        Authentication = mailbox.Authentication.ToNameString()
                    };

                    // Get new smtp server from MailBoxData
                    var newOutServer = new MailboxServer
                    {
                        Hostname = mailbox.SmtpServer,
                        Port = mailbox.SmtpPort,
                        Type = Defines.SMTP,
                        Username =
                            mailbox.SmtpAuthentication != SaslMechanism.None
                                ? mailbox.EMail.ToLoginFormat(mailbox.SmtpAccount) ?? mailbox.SmtpAccount
                                : "",
                        SocketType = mailbox.SmtpEncryption.ToNameString(),
                        Authentication = mailbox.SmtpAuthentication.ToNameString()
                    };

                    if (existingMailbox != null)
                    {
                        mailboxId = existingMailbox.Id;
                        enabled = existingMailbox.Enabled;
                        dateCreated = existingMailbox.DateCreated;

                        // Get existing settings by existing ids
                        var dbInServer = daoMailboxServer.GetServer(existingMailbox.ServerId);
                        var dbOutServer = daoMailboxServer.GetServer(existingMailbox.SmtpServerId);

                        // Compare existing settings with new
                        if (!dbInServer.Equals(newInServer) || !dbOutServer.Equals(newOutServer))
                        {
                            var domain = daoMailboxDomain.GetDomain(host);

                            List<MailboxServer> trustedServers = null;
                            if (domain != null)
                                trustedServers = daoMailboxServer.GetServers(domain.ProviderId);

                            newInServerId = GetMailboxServerId(daoMailboxServer, dbInServer, newInServer, trustedServers);
                            newOutServerId = GetMailboxServerId(daoMailboxServer, dbOutServer, newOutServer,
                                trustedServers);
                        }
                        else
                        {
                            newInServerId = existingMailbox.ServerId;
                            newOutServerId = existingMailbox.SmtpServerId;
                        }
                    }
                    else
                    {
                        //Find settings by host

                        var domain = daoMailboxDomain.GetDomain(host);

                        if (domain != null)
                        {
                            //Get existing servers with isUserData = 0
                            var trustedServers = daoMailboxServer.GetServers(domain.ProviderId);

                            //Compare existing settings with new

                            var foundInServer = trustedServers.FirstOrDefault(ts => ts.Equals(newInServer));
                            var foundOutServer = trustedServers.FirstOrDefault(ts => ts.Equals(newOutServer));

                            //Use existing or save new servers
                            newInServerId = foundInServer != null
                                ? foundInServer.Id
                                : SaveMailboxServer(daoMailboxServer, newInServer, domain.ProviderId);

                            newOutServerId = foundOutServer != null
                                ? foundOutServer.Id
                                : SaveMailboxServer(daoMailboxServer, newOutServer, domain.ProviderId);
                        }
                        else
                        {
                            //Save new servers
                            var newProvider = new MailboxProvider
                            {
                                Id = 0,
                                Name = host,
                                DisplayShortName = "",
                                DisplayName = "",
                                Url = ""
                            };

                            newProvider.Id = daoMailboxProvider.SaveProvider(newProvider);

                            var newDomain = new MailboxDomain
                            {
                                Id = 0,
                                Name = host,
                                ProviderId = newProvider.Id
                            };

                            daoMailboxDomain.SaveDomain(newDomain);

                            newInServerId = SaveMailboxServer(daoMailboxServer, newInServer, newProvider.Id);
                            newOutServerId = SaveMailboxServer(daoMailboxServer, newOutServer, newProvider.Id);
                        }
                    }

                    var loginDelayTime = GetLoginDelayTime(mailbox);

                    //Save Mailbox to DB
                    var mb = new Mailbox
                    {
                        Id = mailboxId,
                        Tenant = mailbox.TenantId,
                        User = mailbox.UserId,
                        Address = mailbox.EMail.Address.ToLowerInvariant(),
                        Name = mailbox.Name,
                        Password = mailbox.Password,
                        MsgCountLast = mailbox.MessagesCount,
                        SmtpPassword = mailbox.SmtpPassword,
                        SizeLast = mailbox.Size,
                        LoginDelay = loginDelayTime,
                        Enabled = enabled,
                        Imap = mailbox.Imap,
                        BeginDate = mailbox.BeginDate,
                        OAuthType = mailbox.OAuthType,
                        OAuthToken = mailbox.OAuthToken,
                        ServerId = newInServerId,
                        SmtpServerId = newOutServerId,
                        DateCreated = dateCreated
                    };

                    var mailBoxId = daoMailbox.SaveMailBox(mb);

                    mailbox.MailBoxId = mailBoxId;

                    if (mailBoxId < 1)
                    {
                        tx.Rollback();
                        return false;
                    }

                    tx.Commit();
                }
            }

            return true;
        }

        public List<MailBoxData> GetMailboxesForProcessing(TasksConfig tasksConfig, int needTasks)
        {
            var mailboxes = new List<MailBoxData>();

            var boundaryRatio = !(tasksConfig.InactiveMailboxesRatio > 0 && tasksConfig.InactiveMailboxesRatio < 100);

            if (needTasks > 1 || boundaryRatio)
            {
                var inactiveCount = (int)Math.Round(needTasks * tasksConfig.InactiveMailboxesRatio / 100, MidpointRounding.AwayFromZero);

                var activeCount = needTasks - inactiveCount;

                if (activeCount == needTasks)
                {
                    mailboxes.AddRange(GetActiveMailboxesForProcessing(tasksConfig, activeCount));
                }
                else if (inactiveCount == needTasks)
                {
                    mailboxes.AddRange(GetInactiveMailboxesForProcessing(tasksConfig, inactiveCount));
                }
                else
                {
                    mailboxes.AddRange(GetActiveMailboxesForProcessing(tasksConfig, activeCount));

                    var difference = inactiveCount + activeCount - mailboxes.Count;

                    if (difference > 0)
                        mailboxes.AddRange(GetInactiveMailboxesForProcessing(tasksConfig, difference));
                }
            }
            else
            {
                mailboxes.AddRange(GetActiveMailboxesForProcessing(tasksConfig, 1));

                var difference = needTasks - mailboxes.Count;

                if (difference > 0)
                    mailboxes.AddRange(GetInactiveMailboxesForProcessing(tasksConfig, difference));
            }

            return mailboxes;
        }

        public bool LockMaibox(int id)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                var status = daoMailbox.SetMailboxInProcess(id);

                return status;
            }
        }

        public bool ReleaseMaibox(MailBoxData account, TasksConfig tasksConfig)
        {
            var disableMailbox = false;

            var engineFactory = new EngineFactory(account.TenantId, account.UserId);

            if (account.AuthErrorDate.HasValue)
            {
                var difference = DateTime.UtcNow - account.AuthErrorDate.Value;

                if (difference > tasksConfig.AuthErrorDisableMailboxTimeout)
                {
                    disableMailbox = true;

                    engineFactory.AlertEngine.CreateAuthErrorDisableAlert(account.TenantId, account.UserId,
                        account.MailBoxId);
                }
                else if (difference > tasksConfig.AuthErrorWarningTimeout)
                {
                    engineFactory.AlertEngine.CreateAuthErrorWarningAlert(account.TenantId, account.UserId,
                        account.MailBoxId);
                }
            }

            if (account.QuotaErrorChanged)
            {
                if (account.QuotaError)
                {
                    engineFactory.AlertEngine.CreateQuotaErrorWarningAlert(account.TenantId, account.UserId);
                }
                else
                {
                    engineFactory.AlertEngine.DeleteAlert(MailAlertTypes.QuotaError);
                }
            }

            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                var mailbox =
                    daoMailbox.GetMailBox(new СoncreteUserMailboxExp(account.MailBoxId, account.TenantId,
                        account.UserId));

                if (mailbox == null) // Mailbox has been removed
                    return true;

                bool? enabled = null;
                int? messageCount = null;
                long? size = null;
                bool? quotaError = null;
                string oAuthToken = null;
                string imapIntervalsJson = null;
                bool? resetImapIntervals = null;

                if (account.AuthErrorDate.HasValue)
                {
                    if (disableMailbox)
                    {
                        enabled = false;
                    }
                }

                if (mailbox.MsgCountLast != account.MessagesCount)
                {
                    messageCount = account.MessagesCount;
                }

                if (mailbox.SizeLast != account.Size)
                {
                    size = account.Size;
                }

                if (account.QuotaErrorChanged)
                {
                    quotaError = account.QuotaError;
                }

                if (account.AccessTokenRefreshed)
                {
                    oAuthToken = account.OAuthToken;
                }

                if (account.Imap && account.ImapFolderChanged)
                {
                    if (account.BeginDateChanged)
                    {
                        resetImapIntervals = true;
                    }
                    else
                    {
                        imapIntervalsJson = account.ImapIntervalsJson;
                    }
                }

                return daoMailbox.SetMailboxProcessed(mailbox, account.ServerLoginDelay, enabled, messageCount, size,
                    quotaError, oAuthToken, imapIntervalsJson, resetImapIntervals);
            }
        }

        public bool SetMaiboxAuthError(int id, DateTime? authErroDate)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                return daoMailbox.SetMailboxAuthError(id, authErroDate);
            }
        }

        public List<int> ReleaseMailboxes(int timeoutInMinutes)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                return daoMailbox.SetMailboxesProcessed(timeoutInMinutes);
            }
        }

        public List<Tuple<int, string>> GetMailUsers(IMailboxExp exp)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                return daoMailbox.GetMailUsers(exp);
            }
        }

        public bool DisableMailboxes(IMailboxExp exp)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                return daoMailbox.Enable(exp, false);
            }
        }

        public bool SetNextLoginDelay(IMailboxExp exp, TimeSpan delay)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMailbox = daoFactory.CreateMailboxDao();

                return daoMailbox.SetNextLoginDelay(exp, delay);
            }
        }

        public void RemoveMailBox(MailBoxData mailbox, bool needRecalculateFolders = true)
        {
            if (mailbox.MailBoxId <= 0)
                throw new Exception("MailBox id is 0");

            long freedQuotaSize;

            using (var db = new DbManager(Defines.CONNECTION_STRING_NAME, Defines.RemoveMailboxTimeout))
            {
                var daoFactory = new DaoFactory(db);
                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    freedQuotaSize = RemoveMailBoxInfo(daoFactory, mailbox);

                    tx.Commit();
                }
            }

            var engine = new EngineFactory(mailbox.TenantId, mailbox.UserId, Log);
            engine.QuotaEngine.QuotaUsedDelete(freedQuotaSize);

            CacheEngine.Clear(mailbox.UserId);

            engine.IndexEngine.Remove(mailbox);

            if (!needRecalculateFolders)
                return;

            engine.OperationEngine.RecalculateFolders();
        }

        public void RemoveMailBox(IDaoFactory daoFactory, MailBoxData mailbox, bool needRecalculateFolders = true)
        {
            if (mailbox.MailBoxId <= 0)
                throw new Exception("MailBox id is 0");

            var freedQuotaSize = RemoveMailBoxInfo(daoFactory, mailbox);

            var engine = new EngineFactory(mailbox.TenantId, mailbox.UserId);

            engine.QuotaEngine.QuotaUsedDelete(freedQuotaSize);

            if (!needRecalculateFolders)
                return;

            engine.OperationEngine.RecalculateFolders();
        }

        /// <summary>
        /// Set mailbox removed
        /// </summary>
        /// <param name="mailBoxData"></param>
        /// <returns>Return freed quota value</returns>
        public long RemoveMailBoxInfo(MailBoxData mailBoxData)
        {
            long freedQuotaSize;

            using (var db = new DbManager(Defines.CONNECTION_STRING_NAME, Defines.RemoveMailboxTimeout))
            {
                var daoFactory = new DaoFactory(db);
                using (var tx = daoFactory.DbManager.BeginTransaction())
                {
                    freedQuotaSize = RemoveMailBoxInfo(daoFactory, mailBoxData);

                    tx.Commit();
                }
            }

            return freedQuotaSize;
        }

        /// <summary>
        /// Set mailbox removed
        /// </summary>
        /// <param name="daoFactory"></param>
        /// <param name="mailBoxData"></param>
        /// <returns>Return freed quota value</returns>
        private static long RemoveMailBoxInfo(IDaoFactory daoFactory, MailBoxData mailBoxData)
        {
            if (mailBoxData.MailBoxId <= 0)
                throw new Exception("MailBox id is 0");

            var daoMailbox = daoFactory.CreateMailboxDao();

            var mailbox = daoMailbox.GetMailBox(
                new СoncreteUserMailboxExp(mailBoxData.MailBoxId, mailBoxData.TenantId, mailBoxData.UserId, null));

            if (mailbox == null)
            {
                throw new Exception(string.Format("MailBox with id = {0} (Tenant={1}, User='{2}') not found",
                    mailBoxData.MailBoxId, mailBoxData.TenantId, mailBoxData.UserId));
            }

            daoMailbox.SetMailboxRemoved(mailbox);

            var daoChain = daoFactory.CreateChainDao(mailBoxData.TenantId, mailBoxData.UserId);

            var folderTypes = Enum.GetValues(typeof(FolderType)).Cast<int>().ToList();

            daoChain.Delete(
                SimpleConversationsExp.CreateBuilder(mailBoxData.TenantId, mailBoxData.UserId)
                    .SetFoldersIds(folderTypes)
                    .SetMailboxId(mailBoxData.MailBoxId)
                    .Build());

            var daoCrmLink = daoFactory.CreateCrmLinkDao(mailBoxData.TenantId, mailBoxData.UserId);

            daoCrmLink.RemoveCrmLinks(mailBoxData.MailBoxId);

            var daoMailInfo = daoFactory.CreateMailInfoDao(mailBoxData.TenantId, mailBoxData.UserId);

            daoMailInfo.SetFieldValue(
                SimpleMessagesExp.CreateBuilder(mailBoxData.TenantId, mailBoxData.UserId)
                    .SetMailboxId(mailBoxData.MailBoxId)
                    .Build(),
                MailTable.Columns.IsRemoved,
                true);

            var exp = new ConcreteMailboxAttachmentsExp(mailBoxData.MailBoxId, mailBoxData.TenantId, mailBoxData.UserId,
                onlyEmbedded: null);

            var daoAttachment = daoFactory.CreateAttachmentDao(mailBoxData.TenantId, mailBoxData.UserId);

            var totalAttachmentsSize = daoAttachment.GetAttachmentsSize(exp);

            daoAttachment.SetAttachmnetsRemoved(exp);

            var tagDao = daoFactory.CreateTagDao(mailBoxData.TenantId, mailBoxData.UserId);

            var tagMailDao = daoFactory.CreateTagMailDao(mailBoxData.TenantId, mailBoxData.UserId);

            var tagIds = tagMailDao.GetTagIds(mailBoxData.MailBoxId);

            tagMailDao.DeleteByMailboxId(mailBoxData.MailBoxId);

            foreach (var tagId in tagIds)
            {
                var tag = tagDao.GetTag(tagId);

                if (tag == null)
                    continue;

                var count = tagMailDao.CalculateTagCount(tag.Id);

                tag.Count = count;

                tagDao.SaveTag(tag);
            }

            daoFactory.CreateMailboxSignatureDao(mailBoxData.TenantId, mailBoxData.UserId).DeleteSignature(mailBoxData.MailBoxId);

            daoFactory.CreateMailboxAutoreplyDao(mailBoxData.TenantId, mailBoxData.UserId)
                .DeleteAutoreply(mailBoxData.MailBoxId);

            daoFactory.CreateMailboxAutoreplyHistoryDao(mailBoxData.TenantId, mailBoxData.UserId).DeleteAutoreplyHistory(mailBoxData.MailBoxId);

            daoFactory.CreateAlertDao(mailBoxData.TenantId, mailBoxData.UserId).DeleteAlerts(mailBoxData.MailBoxId);

            daoFactory.CreateUserFolderXMailDao(mailBoxData.TenantId, mailBoxData.UserId)
                .RemoveByMailbox(mailBoxData.MailBoxId);

            return totalAttachmentsSize;
        }

        private IEnumerable<MailBoxData> GetActiveMailboxesForProcessing(TasksConfig tasksConfig, int tasksLimit)
        {
            if (tasksLimit <= 0)
                return new List<MailBoxData>();

            Log.Debug("GetActiveMailboxForProcessing()");

            var mailboxes = GetMailboxDataList(new MailboxesForProcessingExp(tasksConfig, tasksLimit, true));

            Log.DebugFormat("Found {0} active tasks", mailboxes.Count);

            return mailboxes;
        }

        private IEnumerable<MailBoxData> GetInactiveMailboxesForProcessing(TasksConfig tasksConfig, int tasksLimit)
        {
            if (tasksLimit <= 0)
                return new List<MailBoxData>();

            Log.Debug("GetInactiveMailboxForProcessing()");

            var mailboxes = GetMailboxDataList(new MailboxesForProcessingExp(tasksConfig, tasksLimit, false));

            Log.DebugFormat("Found {0} inactive tasks", mailboxes.Count);

            return mailboxes;
        }

        private static int GetMailboxServerId(IMailboxServerDao daoMailboxServer, MailboxServer dbServer,
            MailboxServer newServer, List<MailboxServer> trustedServers)
        {
            int serverId;

            if (!dbServer.Equals(newServer))
            {
                // Server settings have been changed
                if (dbServer.IsUserData)
                {
                    if (trustedServers != null)
                    {
                        var foundInServer = trustedServers.FirstOrDefault(ts => ts.Equals(newServer));
                        if (foundInServer != null)
                        {
                            daoMailboxServer.DelteServer(dbServer.Id);
                            newServer.Id = foundInServer.Id;
                            newServer.IsUserData = false;
                        }
                        else
                        {
                            newServer.Id = dbServer.Id;
                            newServer.Id = SaveMailboxServer(daoMailboxServer, newServer, dbServer.ProviderId);
                        }
                    }
                    else
                    {
                        newServer.Id = dbServer.Id;
                        newServer.Id = SaveMailboxServer(daoMailboxServer, newServer, dbServer.ProviderId);
                    }
                }
                else
                {
                    if (trustedServers != null)
                    {
                        var foundInServer = trustedServers.FirstOrDefault(ts => ts.Equals(newServer));
                        if (foundInServer != null)
                        {
                            newServer.Id = foundInServer.Id;
                            newServer.IsUserData = false;
                        }
                        else
                        {
                            newServer.Id = SaveMailboxServer(daoMailboxServer, newServer, dbServer.ProviderId);
                        }
                    }
                    else
                    {
                        newServer.Id = SaveMailboxServer(daoMailboxServer, newServer, dbServer.ProviderId);

                    }
                }

                serverId = newServer.Id;
            }
            else
            {
                serverId = dbServer.Id;
            }

            return serverId;
        }

        private static int SaveMailboxServer(IMailboxServerDao daoMailboxServer, MailboxServer server,
            int providerId)
        {
            server.IsUserData = true;
            server.ProviderId = providerId;
            return daoMailboxServer.SaveServer(server);
        }

        private static int GetLoginDelayTime(MailBoxData mailbox)
        {
            //Todo: This hardcode inserted because pop3.live.com doesn't support CAPA command.
            //Right solution for that collision type:
            //1) Create table in DB: mail_login_delays. With REgexs and delays
            //1.1) Example of mail_login_delays data:
            //    <EMAIL>    900
            //    <EMAIL>    900
            //    .*                30
            //1.2) Load this table to aggregator cache. Update it on changing.
            //1.3) Match email addreess of account with regexs from mail_login_delays
            //1.4) If email matched then set delay from that record.
            if (mailbox.Server == "pop3.live.com")
                return Defines.HARDCODED_LOGIN_TIME_FOR_MS_MAIL;

            return mailbox.ServerLoginDelay < MailBoxData.DefaultServerLoginDelay
                       ? MailBoxData.DefaultServerLoginDelay
                       : mailbox.ServerLoginDelay;
        }

        private static Tuple<MailBoxData, Mailbox> GetMailbox(IDaoFactory daoFactory, Mailbox mailbox)
        {
            var daoMailboxServer = daoFactory.CreateMailboxServerDao();

            var inServer = daoMailboxServer.GetServer(mailbox.ServerId);

            if (inServer == null)
                return null;

            var outServer = daoMailboxServer.GetServer(mailbox.SmtpServerId);

            if (outServer == null)
                return null;

            var daoMailboxAutoreply = daoFactory.CreateMailboxAutoreplyDao(mailbox.Tenant, mailbox.User);

            var autoreply = daoMailboxAutoreply.GetAutoreply(mailbox.Id);

            return new Tuple<MailBoxData, Mailbox>(ToMailBoxData(mailbox, inServer, outServer, autoreply), mailbox);
        }

        public static MailBoxData ToMailBoxData(Mailbox mailbox, MailboxServer inServer, MailboxServer outServer,
            MailboxAutoreply autoreply)
        {
            var address = new MailAddress(mailbox.Address);

            var mailAutoReply = autoreply != null
                ? new MailAutoreplyData(autoreply.MailboxId, autoreply.Tenant, autoreply.TurnOn, autoreply.OnlyContacts,
                    autoreply.TurnOnToDate, autoreply.FromDate, autoreply.ToDate, autoreply.Subject, autoreply.Html)
                : null;

            var inServerOldFormat = string.Format("{0}:{1}", inServer.Hostname, inServer.Port);
            var outServerOldFormat = string.Format("{0}:{1}", outServer.Hostname, outServer.Port);

            var mailboxData = new MailBoxData(mailbox.Tenant, mailbox.User, mailbox.Id, mailbox.Name, address,
                address.ToLogin(inServer.Username), mailbox.Password, inServerOldFormat,
                inServer.SocketType.ToEncryptionType(), inServer.Authentication.ToSaslMechanism(), mailbox.Imap,
                address.ToLogin(outServer.Username), mailbox.SmtpPassword, outServerOldFormat,
                outServer.SocketType.ToEncryptionType(), outServer.Authentication.ToSaslMechanism(),
                Convert.ToByte(mailbox.OAuthType), mailbox.OAuthToken)
            {
                Size = mailbox.SizeLast,
                MessagesCount = mailbox.MsgCountLast,
                ServerLoginDelay = mailbox.LoginDelay,
                BeginDate = mailbox.BeginDate,
                QuotaError = mailbox.QuotaError,
                AuthErrorDate = mailbox.DateAuthError,
                ImapIntervalsJson = mailbox.ImapIntervals,
                SmtpServerId = mailbox.SmtpServerId,
                InServerId = mailbox.ServerId,
                EMailInFolder = mailbox.EmailInFolder,
                MailAutoreply = mailAutoReply,
                AccessTokenRefreshed = false, //TODO: ???

                Enabled = mailbox.Enabled,
                IsRemoved = mailbox.IsRemoved,
                IsTeamlab = mailbox.IsTeamlabMailbox
            };

            return mailboxData;
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_NameAddress.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements SIP "name-addr" value. Defined in RFC 3261.
    /// </summary>
    /// <remarks>
    /// <code>
    /// RFC 3261 Syntax:
    ///     name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
    ///     addr-spec = SIP-URI / SIPS-URI / absoluteURI
    /// </code>
    /// </remarks>
    public class SIP_t_NameAddress
    {
        #region Members

        private string m_DisplayName = "";
        private AbsoluteUri m_pUri;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets display name.
        /// </summary>
        public string DisplayName
        {
            get { return m_DisplayName; }

            set
            {
                if (value == null)
                {
                    value = "";
                }

                m_DisplayName = value;
            }
        }

        /// <summary>
        /// Gets or sets URI. This can be SIP-URI / SIPS-URI / absoluteURI.
        /// Examples: sip:<EMAIL>,sips:<EMAIL>,mailto:<EMAIL>, .... .
        /// </summary>
        /// <exception cref="ArgumentNullException">Is raised when null reference passed.</exception>
        public AbsoluteUri Uri
        {
            get { return m_pUri; }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }

                m_pUri = value;
            }
        }

        /// <summary>
        /// Gets if current URI is sip or sips URI.
        /// </summary>
        public bool IsSipOrSipsUri
        {
            get { return IsSipUri || IsSecureSipUri; }
        }

        /// <summary>
        /// Gets if current URI is SIP uri.
        /// </summary>
        public bool IsSipUri
        {
            get
            {
                if (m_pUri.Scheme == UriSchemes.sip)
                {
                    return true;
                }
                return false;
            }
        }

        /// <summary>
        /// Gets if current URI is SIPS uri.
        /// </summary>
        public bool IsSecureSipUri
        {
            get
            {
                if (m_pUri.Scheme == UriSchemes.sips)
                {
                    return true;
                }
                return false;
            }
        }

        /// <summary>
        /// Gets if current URI is MAILTO uri.
        /// </summary>
        public bool IsMailToUri
        {
            get
            {
                if (m_pUri.Scheme == UriSchemes.mailto)
                {
                    return true;
                }
                return false;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SIP_t_NameAddress() {}

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="value">SIP <b>name-addr</b> value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public SIP_t_NameAddress(string value)
        {
            Parse(value);
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="displayName">Display name.</param>
        /// <param name="uri">Uri.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>uri</b> is null reference.</exception>
        public SIP_t_NameAddress(string displayName, AbsoluteUri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            DisplayName = displayName;
            Uri = uri;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "name-addr" or "addr-spec" from specified value.
        /// </summary>
        /// <param name="value">SIP "name-addr" or "addr-spec" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("reader");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "name-addr" or "addr-spec" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(StringReader reader)
        {
            /* RFC 3261.
                name-addr =  [ display-name ] LAQUOT addr-spec RAQUOT
                addr-spec =  SIP-URI / SIPS-URI / absoluteURI
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            reader.ReadToFirstChar();

            // LAQUOT addr-spec RAQUOT
            if (reader.StartsWith("<"))
            {
                m_pUri = AbsoluteUri.Parse(reader.ReadParenthesized());
            }
            else
            {
                string word = reader.ReadWord();
                if (word == null)
                {
                    throw new SIP_ParseException("Invalid 'name-addr' or 'addr-spec' value !");
                }

                reader.ReadToFirstChar();

                // name-addr
                if (reader.StartsWith("<"))
                {
                    m_DisplayName = word;
                    m_pUri = AbsoluteUri.Parse(reader.ReadParenthesized());
                }
                    // addr-spec
                else
                {
                    m_pUri = AbsoluteUri.Parse(word);
                }
            }
        }

        /// <summary>
        /// Converts this to valid name-addr or addr-spec string as needed.
        /// </summary>
        /// <returns>Returns name-addr or addr-spec string.</returns>
        public string ToStringValue()
        {
            /* RFC 3261.
                name-addr =  [ display-name ] LAQUOT addr-spec RAQUOT
                addr-spec =  SIP-URI / SIPS-URI / absoluteURI
            */

            // addr-spec
            if (string.IsNullOrEmpty(m_DisplayName))
            {
                return "<" + m_pUri + ">";
            }
                // name-addr
            else
            {
                return TextUtils.QuoteString(m_DisplayName) + " <" + m_pUri + ">";
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Core/Sms/SmsManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Web.Core;
using ASC.Web.Core.Sms;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Common;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Core.SMS
{
    public static class SmsManager
    {
        public static string SaveMobilePhone(UserInfo user, string mobilePhone)
        {
            mobilePhone = SmsSender.GetPhoneValueDigits(mobilePhone);

            if (user == null || Equals(user, Constants.LostUser)) throw new Exception(Resource.ErrorUserNotFound);
            if (string.IsNullOrEmpty(mobilePhone)) throw new Exception(Resource.ActivateMobilePhoneEmptyPhoneNumber);
            if (!string.IsNullOrEmpty(user.MobilePhone) && user.MobilePhoneActivationStatus == MobilePhoneActivationStatus.Activated) throw new Exception(Resource.MobilePhoneMustErase);

            user.MobilePhone = mobilePhone;
            user.MobilePhoneActivationStatus = MobilePhoneActivationStatus.NotActivated;
            if (SecurityContext.IsAuthenticated)
            {
                CoreContext.UserManager.SaveUserInfo(user);
            }
            else
            {
                try
                {
                    SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);
                    CoreContext.UserManager.SaveUserInfo(user);
                }
                finally
                {
                    SecurityContext.Logout();
                }
            }

            if (StudioSmsNotificationSettings.Enable)
            {
                PutAuthCode(user, false);
            }

            return mobilePhone;
        }

        public static void PutAuthCode(UserInfo user, bool again)
        {
            if (user == null || Equals(user, Constants.LostUser)) throw new Exception(Resource.ErrorUserNotFound);

            if (!StudioSmsNotificationSettings.IsVisibleSettings || !StudioSmsNotificationSettings.Enable) throw new MethodAccessException();

            var mobilePhone = SmsSender.GetPhoneValueDigits(user.MobilePhone);

            if (SmsKeyStorage.ExistsKey(mobilePhone) && !again) return;

            string key;
            if (!SmsKeyStorage.GenerateKey(mobilePhone, out key)) throw new Exception(Resource.SmsTooMuchError);
            if (SmsSender.SendSMS(mobilePhone, string.Format(Resource.SmsAuthenticationMessageToUser, key)))
            {
                CoreContext.TenantManager.SetTenantQuotaRow(new TenantQuotaRow { Tenant = TenantProvider.CurrentTenantID, Path = "/sms", Counter = 1 }, true);
            }
        }

        public static void ValidateSmsCode(UserInfo user, string code)
        {
            if (!StudioSmsNotificationSettings.IsVisibleSettings
                || !StudioSmsNotificationSettings.Enable)
            {
                return;
            }

            if (user == null || Equals(user, Constants.LostUser)) throw new Exception(Resource.ErrorUserNotFound);

            var valid = SmsKeyStorage.ValidateKey(user.MobilePhone, code);
            switch (valid)
            {
                case SmsKeyStorage.Result.Empty:
                    throw new Exception(Resource.ActivateMobilePhoneEmptyCode);
                case SmsKeyStorage.Result.TooMuch:
                    throw new Authorize.BruteForceCredentialException(Resource.SmsTooMuchError);
                case SmsKeyStorage.Result.Timeout:
                    throw new TimeoutException(Resource.SmsAuthenticationTimeout);
                case SmsKeyStorage.Result.Invalide:
                    throw new ArgumentException(Resource.SmsAuthenticationMessageError);
            }
            if (valid != SmsKeyStorage.Result.Ok) throw new Exception("Error: " + valid);

            if (!SecurityContext.IsAuthenticated)
            {
                var cookiesKey = SecurityContext.AuthenticateMe(user.ID);
                CookiesManager.SetCookies(CookiesType.AuthKey, cookiesKey);
            }

            if (user.MobilePhoneActivationStatus == MobilePhoneActivationStatus.NotActivated)
            {
                user.MobilePhoneActivationStatus = MobilePhoneActivationStatus.Activated;
                CoreContext.UserManager.SaveUserInfo(user);
            }
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Data/DbQuotaService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Tenants;

namespace ASC.Core.Data
{
    public class DbQuotaService : DbBaseService, IQuotaService
    {
        private const string tenants_quota = "tenants_quota";
        public const string tenants_quotarow = "tenants_quotarow";


        public DbQuotaService(ConnectionStringSettings connectionString)
            : base(connectionString, "tenant")
        {
        }


        public IEnumerable<TenantQuota> GetTenantQuotas()
        {
            return GetTenantQuotas(Exp.Empty);
        }

        public TenantQuota GetTenantQuota(int id)
        {
            return GetTenantQuotas(Exp.Eq("tenant", id))
                .SingleOrDefault();
        }

        private IEnumerable<TenantQuota> GetTenantQuotas(Exp where)
        {
            var q = new SqlQuery(tenants_quota)
                .Select("tenant", "name", "max_file_size", "max_total_size", "active_users", "features", "price", "price2", "avangate_id", "visible")
                .Where(where);

            return ExecList(q)
                .ConvertAll(r => new TenantQuota(Convert.ToInt32(r[0]))
                {
                    Name = (string)r[1],
                    MaxFileSize = GetInBytes(Convert.ToInt64(r[2])),
                    MaxTotalSize = GetInBytes(Convert.ToInt64(r[3])),
                    ActiveUsers = Convert.ToInt32(r[4]) != 0 ? Convert.ToInt32(r[4]) : int.MaxValue,
                    Features = (string)r[5],
                    Price = Convert.ToDecimal(r[6]),
                    Price2 = Convert.ToDecimal(r[7]),
                    AvangateId = (string)r[8],
                    Visible = Convert.ToBoolean(r[9]),
                });
        }


        public TenantQuota SaveTenantQuota(TenantQuota quota)
        {
            if (quota == null) throw new ArgumentNullException("quota");

            var i = Insert(tenants_quota, quota.Id)
                .InColumnValue("name", quota.Name)
                .InColumnValue("max_file_size", GetInMBytes(quota.MaxFileSize))
                .InColumnValue("max_total_size", GetInMBytes(quota.MaxTotalSize))
                .InColumnValue("active_users", quota.ActiveUsers)
                .InColumnValue("features", quota.Features)
                .InColumnValue("price", quota.Price)
                .InColumnValue("price2", quota.Price2)
                .InColumnValue("avangate_id", quota.AvangateId)
                .InColumnValue("visible", quota.Visible);

            ExecNonQuery(i);
            return quota;
        }

        public void RemoveTenantQuota(int id)
        {
            var d = Delete(tenants_quota, id);
            ExecNonQuery(d);
        }


        public void SetTenantQuotaRow(TenantQuotaRow row, bool exchange)
        {
            if (row == null) throw new ArgumentNullException("row");

            using (var db = GetDb())
            using (var tx = db.BeginTransaction())
            {
                var counter = db.ExecuteScalar<long>(Query(tenants_quotarow, row.Tenant)
                    .Select("counter")
                    .Where("path", row.Path));

                db.ExecuteNonQuery(Insert(tenants_quotarow, row.Tenant)
                    .InColumnValue("path", row.Path)
                    .InColumnValue("counter", exchange ? counter + row.Counter : row.Counter)
                    .InColumnValue("tag", row.Tag)
                    .InColumnValue("last_modified", DateTime.UtcNow));

                tx.Commit();
            }
        }

        public IEnumerable<TenantQuotaRow> FindTenantQuotaRows(int tenantId)
        {
            var q = new SqlQuery(tenants_quotarow).Select("tenant", "path", "counter", "tag");
            var where = Exp.Empty;

            if (tenantId != Tenant.DEFAULT_TENANT)
            {
                where &= Exp.Eq("tenant", tenantId);
            }

            if (where != Exp.Empty)
            {
                q.Where(where);
            }

            return ExecList(q)
                .ConvertAll(r => new TenantQuotaRow
                {
                    Tenant = Convert.ToInt32(r[0]),
                    Path = (string)r[1],
                    Counter = Convert.ToInt64(r[2]),
                    Tag = (string)r[3],
                });
        }


        private static long GetInBytes(long bytes)
        {
            const long MB = 1024 * 1024;
            return bytes < MB ? bytes * MB : bytes;
        }

        private static long GetInMBytes(long bytes)
        {
            const long MB = 1024 * 1024;
            return bytes < MB * MB ? bytes / MB : bytes;
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Storage/StorageManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Web;

using ASC.Common.Logging;
using ASC.Data.Storage;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Extensions;
using ASC.Mail.Utils;
using ASC.Web.Core.Files;

using HtmlAgilityPack;

namespace ASC.Mail.Data.Storage
{
    public class StorageManager
    {
        public const string CKEDITOR_IMAGES_DOMAIN = "mail";

        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ILog Log { get; private set; }

        public StorageManager(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.StorageManager");
        }

        public static IDataStore GetDataStoreForCkImages(int tenant)
        {
            return StorageFactory.GetStorage(null, tenant.ToString(CultureInfo.InvariantCulture), "fckuploaders", null);
        }

        public static IDataStore GetDataStoreForAttachments(int tenant)
        {
            return StorageFactory.GetStorage(null, tenant.ToString(CultureInfo.InvariantCulture), "mailaggregator", null);
        }

        public static byte[] LoadLinkData(string link, ILog log = null)
        {
            if (log == null)
                log = new NullLog();

            var data = new byte[] { };

            try
            {
                using (var webClient = new WebClient())
                {
                    data = webClient.DownloadData(link);
                }
            }
            catch (Exception)
            {
                log.ErrorFormat("LoadLinkData(url='{0}')", link);
            }

            return data;
        }

        public static byte[] LoadDataStoreItemData(string domain, string fileLink, IDataStore storage)
        {
            using (var stream = storage.GetReadStream(domain, fileLink))
            {
                return stream.ReadToEnd();
            }
        }

        public string ChangeEditorImagesLinks(string html, int mailboxId)
        {
            if (string.IsNullOrEmpty(html) || mailboxId < 1)
                return html;

            var newHtml = html;

            var ckStorage = GetDataStoreForCkImages(Tenant);
            var signatureStorage = GetDataStoreForAttachments(Tenant);
            //todo: replace selector
            var currentMailCkeditorUrl = ckStorage.GetUri(CKEDITOR_IMAGES_DOMAIN, "").ToString();

            var xpathQuery = GetXpathQueryForCkImagesToResaving(currentMailCkeditorUrl);

            var doc = new HtmlDocument();
            doc.LoadHtml(html);

            var linkNodes = doc.DocumentNode.SelectNodes(xpathQuery);

            if (linkNodes != null)
            {
                foreach (var linkNode in linkNodes)
                {
                    try
                    {
                        var link = linkNode.Attributes["src"].Value;

                        Log.InfoFormat("ChangeSignatureEditorImagesLinks() Original image link: {0}", link);

                        var fileLink = HttpUtility.UrlDecode(link.Substring(currentMailCkeditorUrl.Length));

                        var fileName = Path.GetFileName(fileLink);

                        var bytes = LoadDataStoreItemData(CKEDITOR_IMAGES_DOMAIN, fileLink, ckStorage);

                        var stableImageLink = StoreCKeditorImageWithoutQuota(mailboxId, fileName, bytes,
                                                               signatureStorage);

                        linkNode.SetAttributeValue("src", stableImageLink);
                    }
                    catch (Exception ex)
                    {
                        Log.ErrorFormat("ChangeSignatureEditorImagesLinks() failed with exception: {0}", ex.ToString());
                    }
                }

                newHtml = doc.DocumentNode.OuterHtml;
            }

            return newHtml;
        }

        public string StoreCKeditorImageWithoutQuota(int mailboxId, string fileName, byte[] imageData, IDataStore storage)
        {
            try
            {
                if (imageData == null || imageData.Length == 0)
                    throw new ArgumentNullException("imageData");

                var ext = string.IsNullOrEmpty(fileName) ? ".jpg" : Path.GetExtension(fileName);

                if (string.IsNullOrEmpty(ext))
                    ext = ".jpg";

                var storeName = imageData.GetMd5();
                storeName = Path.ChangeExtension(storeName, ext);

                var contentDisposition = ContentDispositionUtil.GetHeaderValue(storeName);
                var contentType = MimeMapping.GetMimeMapping(ext);

                var signatureImagePath = MailStoragePathCombiner.GerStoredSignatureImagePath(User, mailboxId, storeName);

                using (var reader = new MemoryStream(imageData))
                {
                    var uploadUrl = storage.Save(string.Empty, signatureImagePath, reader, contentType, contentDisposition);
                    return MailStoragePathCombiner.GetStoredUrl(uploadUrl);
                }
            }
            catch (Exception e)
            {
                Log.ErrorFormat("StoreCKeditorImageWithoutQuota(). filename: {0} Exception:\r\n{1}\r\n", fileName,
                           e.ToString());

                throw;
            }
        }

        public void StoreAttachmentWithoutQuota(MailAttachmentData mailAttachmentData)
        {
            try
            {
                if ((mailAttachmentData.dataStream == null || mailAttachmentData.dataStream.Length == 0) && (mailAttachmentData.data == null || mailAttachmentData.data.Length == 0))
                    return;

                if (string.IsNullOrEmpty(mailAttachmentData.fileName))
                    mailAttachmentData.fileName = "attachment.ext";

                var storage = MailDataStore.GetDataStore(Tenant);

                storage.QuotaController = null;

                if (string.IsNullOrEmpty(mailAttachmentData.storedName))
                {
                    mailAttachmentData.storedName = MailUtil.CreateStreamId();

                    var ext = Path.GetExtension(mailAttachmentData.fileName);

                    if (!string.IsNullOrEmpty(ext))
                        mailAttachmentData.storedName = Path.ChangeExtension(mailAttachmentData.storedName, ext);
                }

                mailAttachmentData.fileNumber =
                    !string.IsNullOrEmpty(mailAttachmentData.contentId) //Upload hack: embedded attachment have to be saved in 0 folder
                        ? 0
                        : mailAttachmentData.fileNumber;

                var attachmentPath = MailStoragePathCombiner.GerStoredFilePath(mailAttachmentData);

                if (mailAttachmentData.data != null)
                {
                    using (var reader = new MemoryStream(mailAttachmentData.data))
                    {
                        var uploadUrl = (mailAttachmentData.needSaveToTemp)
                            ? storage.Save("attachments_temp", attachmentPath, reader, mailAttachmentData.fileName)
                            : storage.Save(attachmentPath, reader, mailAttachmentData.fileName);

                        mailAttachmentData.storedFileUrl = MailStoragePathCombiner.GetStoredUrl(uploadUrl);
                    }
                }
                else
                {
                    var uploadUrl = (mailAttachmentData.needSaveToTemp)
                        ? storage.Save("attachments_temp", attachmentPath, mailAttachmentData.dataStream, mailAttachmentData.fileName)
                        : storage.Save(attachmentPath, mailAttachmentData.dataStream, mailAttachmentData.fileName);

                    mailAttachmentData.storedFileUrl = MailStoragePathCombiner.GetStoredUrl(uploadUrl);
                }

                if (mailAttachmentData.needSaveToTemp)
                {
                    mailAttachmentData.tempStoredUrl = mailAttachmentData.storedFileUrl;
                }
            }
            catch (Exception e)
            {
                Log.ErrorFormat("StoreAttachmentWithoutQuota(). filename: {0}, ctype: {1} Exception:\r\n{2}\r\n",
                    mailAttachmentData.fileName,
                    mailAttachmentData.contentType,
                    e.ToString());

                throw;
            }
        }

        public static string GetXpathQueryForAttachmentsToResaving(string thisMailFckeditorUrl,
                                                                    string thisMailAttachmentFolderUrl,
                                                                    string thisUserStorageUrl)
        {
            const string src_condition_format = "contains(@src,'{0}')";
            var addedByUserToFck = string.Format(src_condition_format, thisMailFckeditorUrl);
            var addedToThisMail = string.Format(src_condition_format, thisMailAttachmentFolderUrl);
            var addedToThisUserMails = string.Format(src_condition_format, thisUserStorageUrl);
            var xpathQuery = string.Format("//img[@src and ({0} or {1}) and not({2})]", addedByUserToFck,
                                            addedToThisUserMails, addedToThisMail);
            return xpathQuery;
        }

        public static string GetXpathQueryForCkImagesToResaving(string thisMailCkeditorUrl)
        {
            const string src_condition_format = "contains(@src,'{0}')";
            var addedByUserToFck = string.Format(src_condition_format, thisMailCkeditorUrl);
            var xpathQuery = string.Format("//img[@src and {0}]", addedByUserToFck);
            return xpathQuery;
        }
    }
}


<|start_filename|>common/ASC.ActiveDirectory/BuiltIn/SystemLdapHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.ActiveDirectory.DirectoryServices;
using ASC.ActiveDirectory.Expressions;
using ASC.Security.Cryptography;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
using System.Linq;
using System.Net;
using System.Text;
using System.Web.Hosting;

namespace ASC.ActiveDirectory.BuiltIn
{
    public class SystemLdapHelper : LdapHelper
    {
        private readonly SystemLdapSearcher _systemLdapSearcher = new SystemLdapSearcher();

        #region common methods

        public override LDAPObject GetDomain(LDAPSupportSettings settings)
        {
            try
            {
                string password;
                var type = AuthenticationTypes.ReadonlyServer | AuthenticationTypes.Secure;
                try
                {
                    password = new UnicodeEncoding().GetString(InstanceCrypto.Decrypt(settings.PasswordBytes));
                }
                catch (Exception)
                {
                    password = string.Empty;
                }

                if (settings.PortNumber == Constants.SSL_LDAP_PORT)
                    type |= AuthenticationTypes.SecureSocketsLayer;

                var entry = settings.Authentication
                                ? new DirectoryEntry(settings.Server + ":" + settings.PortNumber, settings.Login, password,
                                                     type)
                                : new DirectoryEntry(settings.Server + ":" + settings.PortNumber);

                return LDAPObjectFactory.CreateObject(entry);
            }
            catch (Exception e)
            {
                Log.WarnFormat("Can't get current domain. May be current user has not needed permissions. {0}", e);
                return null;
            }
        }

        public override string GetDefaultDistinguishedName(string server, int portNumber)
        {
            try
            {
                if (string.IsNullOrEmpty(server) || portNumber < 0)
                    return null;

                using (HostingEnvironment.Impersonate())
                {
                    return
                        new DirectoryEntry(server + ":" + portNumber).InvokeGet(
                            Constants.ADSchemaAttributes.DISTINGUISHED_NAME).ToString();
                }
            }
            catch
            {
                return null;
            }
        }

        public override void CheckCredentials(string login, string password, string server, int portNumber,
                                              bool startTls)
        {
            var domain = server.Split('/').Last();
            var serverConnection = domain + ":" + portNumber;

            // if login with domain
            string loginDomain = null;
            var loginLocalPart = login;

            if (login.Contains("\\"))
            {
                var splited = login.Split('\\');
                loginLocalPart = splited[1];
                loginDomain = splited[0];
            }
            else if (login.Contains("@"))
            {
                var splited = login.Split('@');
                loginLocalPart = splited[0];
                loginDomain = splited[1];
            }

            if (!string.IsNullOrEmpty(loginDomain))
            {
                if (!domain.StartsWith(loginDomain, StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new LdapException(string.Format("Domain '{0}' from login '{1}' not found", loginDomain, login));
                }
            }

            using (var ldap = new LdapConnection(serverConnection))
            {
                var networkCredential = new NetworkCredential(loginLocalPart, password, domain);
                ldap.SessionOptions.VerifyServerCertificate = (con, cer) => true;
                ldap.SessionOptions.SecureSocketLayer = (portNumber == Constants.SSL_LDAP_PORT);
                ldap.SessionOptions.ProtocolVersion = Constants.LDAP_V3;
                ldap.AuthType = AuthType.Negotiate;
                ldap.Bind(networkCredential);
            }
        }

        #endregion

        #region users

        public override List<LDAPObject> GetUsersByAttributes(LDAPSupportSettings settings)
        {
            var distinguishedName = settings.Server + ":" + settings.PortNumber + "/" + settings.UserDN;
            
            try
            {
                return _systemLdapSearcher.Search(distinguishedName,
                                                  Criteria.All(Expression.Exists(settings.LoginAttribute)),
                                                  settings.UserFilter, settings);
            }
            catch (ArgumentException)
            {
                throw new ArgumentException();
            }
            catch (Exception e)
            {
                Log.ErrorFormat("Can not access to directory: {0}. {1}", distinguishedName, e);
            }
            
            return null;
        }

        public override List<LDAPObject> GetUsersByAttributesAndFilter(LDAPSupportSettings settings, string filter)
        {
            var distinguishedName = settings.Server + ":" + settings.PortNumber + "/" + settings.UserDN;
            
            if (!string.IsNullOrEmpty(settings.UserFilter) && !settings.UserFilter.StartsWith("(") &&
                !settings.UserFilter.EndsWith(")"))
            {
                settings.UserFilter = "(" + settings.UserFilter + ")";
            }
            
            filter = "(&" + settings.UserFilter + filter + ")";
            
            try
            {
                return _systemLdapSearcher.Search(distinguishedName, null, filter, settings);
            }
            catch (Exception e)
            {
                Log.ErrorFormat("Can not access to directory: {0}. {1}", distinguishedName, e);
            }
            
            return null;
        }

        public override List<LDAPObject> GetUsersFromPrimaryGroup(LDAPSupportSettings settings, string primaryGroupId)
        {
            var distinguishedName = settings.Server + ":" + settings.PortNumber + "/" + settings.UserDN;
            
            try
            {
               return _systemLdapSearcher.Search(distinguishedName, Criteria.All(Expression.Equal(
                    Constants.ADSchemaAttributes.PRIMARY_GROUP_ID, primaryGroupId)), settings.UserFilter, settings);
            }
            catch (Exception e)
            {
                Log.ErrorFormat("Can not access to directory: {0}. {1}", distinguishedName, e);
            }
            
            return null;
        }

        public override LDAPObject GetUserBySid(LDAPSupportSettings settings, string sid)
        {
            var distinguishedName = settings.Server + ":" + settings.PortNumber + "/" + settings.UserDN;
            
            try
            {
                var list = _systemLdapSearcher.Search(distinguishedName, Criteria.All(
                    Expression.Equal(Constants.ADSchemaAttributes.OBJECT_SID, sid)), settings.UserFilter, settings);

                if (list.Count != 0)
                    return list[0];
            }
            catch (Exception e)
            {
                Log.ErrorFormat("Can not access to directory: {0}. {1}", distinguishedName, e);
            }

            return null;
        }

        public override bool CheckUserDN(string userDN, string server,
            int portNumber, bool authentication, string login, string password, bool startTls)
        {
            var type = AuthenticationTypes.ReadonlyServer | AuthenticationTypes.Secure;

            if (portNumber == Constants.SSL_LDAP_PORT)
                type |= AuthenticationTypes.SecureSocketsLayer;

            var userEntry = authentication ?
                new DirectoryEntry(server + ":" + portNumber + "/" + userDN, login, password, type) :
                new DirectoryEntry(server + ":" + portNumber + "/" + userDN);
            
            if (userEntry.SchemaClassName == string.Empty)
            {
                Log.ErrorFormat("Wrong User DN parameter: {0}", userDN);
                return false;
            }
            
            return true;
        }

        #endregion

        #region groups

        public override bool CheckGroupDN(string groupDN, string server,
            int portNumber, bool authentication, string login, string password, bool startTls)
        {
            var type = AuthenticationTypes.ReadonlyServer | AuthenticationTypes.Secure;
            
            if (portNumber == Constants.SSL_LDAP_PORT)
                type |= AuthenticationTypes.SecureSocketsLayer;
 
            var userEntry = authentication ?
                new DirectoryEntry(server + ":" + portNumber + "/" + groupDN, login, password, type) :
                new DirectoryEntry(server + ":" + portNumber + "/" + groupDN);

            if (userEntry.SchemaClassName == string.Empty)
            {
                Log.ErrorFormat("Wrong GroupDN DN parameter: {0}", groupDN);
                return false;
            }

            return true;
        }

        public override List<LDAPObject> GetGroupsByAttributes(LDAPSupportSettings settings)
        {
            try
            {
                var groups = _systemLdapSearcher.Search(
                    settings.Server + ":" + settings.PortNumber + "/" + settings.GroupDN, null, settings.GroupFilter, settings);
                return groups;
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("Wrong Group DN or Group Filter parameter: GroupDN = {0}, GroupFilter = {1}, {2}",
                    settings.GroupDN, settings.GroupFilter, ex);
            }

            return null;
        }
        
        #endregion
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Controls/ConvertFile/convertfile.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/*******************************************************************************
    Convert&Dowload
*******************************************************************************/
.cnvrt-list-file-block {
    padding: 10px 0;
}
.cnvrt-list-file-block .tl-combobox {
    max-width: 100%;
    display: none;
}
.cnvrt-list-file-block .tl-combobox .combobox-container .container-top {
    right: 8px;
}
.cnvrt-list-file-block .tl-combobox .combobox-container .combobox-options {
    max-height: none;
}
.cnvrt-file-block {
    border-left: medium none;
    border-right: medium none;
    margin-bottom: -1px;
    min-height: 30px;
}
.cnvrt-file-block:hover {
    background-color: #f2f2f2;
}
.cnvrt-file-block-active {
    background-color: #fafafa;
}
.cnvrt-file-block-open .cnvrt-file-block-head {
    border-bottom: 1px dotted #d1d1d1;
}
.cnvrt-file-block-body {
    padding-left: 20px;
}
.cnvrt-file-block-open .cnvrt-file-block-body {
    display: block;
}
.cnvrt-file-block-closed .cnvrt-file-block-body {
    display: none;
}
.cnvrt-status-content {
    background-color: transparent;
    background-image: url("images/tree_action.png");
    background-repeat: no-repeat;
    cursor: pointer;
    float: left;
    height: 30px;
    width: 20px;
}
.cnvrt-file-block-open .cnvrt-status-content {
    background-position: -12px 5px;
}
.cnvrt-file-block-closed .cnvrt-status-content {
    background-position: 5px 5px;
}
.cnvrt-cbx-content {
    float: left;
    margin-top: 6px;
}
.cnvrt-format-icon-content {
    float: left;
    margin: 4px 5px 5px;
}
.cnvrt-title-content {
    float: left;
    line-height: 30px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 205px;
}
.cnvrt-title-content .file-extension {
    font-weight: bold;
}
.cnvrt-file-block-head .cnvrt-title-content {
    cursor: pointer;
    font-size: 14px;
    margin-left: 5px;
    width: 231px;
}
.cnvrt-tooltip-content {
    color: #808080;
    display: none;
    float: left;
    line-height: 30px;
    overflow: hidden;
    padding: 0 10px;
    text-align: right;
    text-overflow: ellipsis;
    width: 115px;
    white-space: nowrap;
}
.cnvrt-format-title-content {
    float: right;
    margin-top: 8px;
    width: 130px;
}
.cnvrt-format-title-content select {
    width: 122px;
}
.mobile .cnvrt-format-title-content {
    margin-top: 3px;
}
.cnvrt-format-title-content .tl-combobox {
    height: 15px;
}
.cnvrt-format-title {
    display: none;
}

.cnvrt-file-block-active .tl-combobox {
    display: inline-block;
}
.cnvrt-file-block-active .tl-combobox .combobox-title .inner-text {
    border-bottom-width: 0;
}
.cnvrt-file-block-active:hover .tl-combobox .combobox-title .inner-text {
    border-bottom-width: 1px;
}

.cnvrt-file-block-active .cnvrt-file-block-head .cnvrt-tooltip-content,
.cnvrt-file-block-active .cnvrt-file-row-active .cnvrt-tooltip-content {
    display: block;
}
.cnvrt-file-row,
.cnvrt-file-block-head {
    height: 30px;
}
/***********************************\
    Convert and Open
\***********************************/
#confirmCopyConvert .files-progress-box {
    border: none;
    display: block;
    margin-left: auto;
    padding: 0;
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/TestEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using ASC.Common.Logging;
using ASC.Common.Web;
using ASC.Mail.Clients;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Enums;
using ASC.Mail.Exceptions;
using ASC.Mail.Extensions;
using ASC.Mail.Utils;

using MailMessage = ASC.Mail.Data.Contracts.MailMessageData;

namespace ASC.Mail.Core.Engine
{
    public class TestEngine
    {
        public int TenantId { get; private set; }
        public string Username { get; private set; }

        public ILog Log { get; private set; }

        private readonly EngineFactory _engineFactory;

        private const string SAMPLE_UIDL = "api sample";
        private const string SAMPLE_REPLY_UIDL = "api sample reply";
        private const string LOREM_IPSUM_SUBJECT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
        private const string LOREM_IPSUM_INTRO = "Lorem ipsum introduction";

        private const string LOREM_IPSUM_BODY =
            "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vestibulum luctus mauris, " +
            "eget blandit libero auctor quis. Vestibulum quam ex, euismod sit amet luctus eget, condimentum " +
            "vel nulla. Etiam pretium justo tortor, gravida scelerisque augue porttitor sed. Sed in purus neque. " +
            "Sed eget efficitur erat. Ut lobortis eros vitae urna lacinia, mattis efficitur felis accumsan. " +
            "Nullam at dapibus tortor, ut vulputate libero. Fusce ac auctor eros. Aenean justo quam, sodales nec " +
            "risus eget, cursus semper lacus. Nullam mattis neque ac felis euismod aliquet. Donec id eros " +
            "condimentum, egestas sapien vitae, tempor tortor. Nam vehicula ligula eget congue egestas. " +
            "Nulla facilisi. Aenean sodales gravida arcu, a volutpat nulla accumsan ac. Duis leo enim, condimentum " +
            "in malesuada at, rhoncus sed ex. Quisque fringilla scelerisque lacus.</p>";

        public TestEngine(int tenant, string user, ILog log = null)
        {
            TenantId = tenant;
            Username = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.TestEngine");

            _engineFactory = new EngineFactory(TenantId, Username, Log);
        }

        public int CreateSampleMessage(
            int? folderId,
            int? mailboxId,
            List<string> to,
            List<string> cc,
            List<string> bcc,
            bool importance,
            bool unread,
            string subject,
            string body,
            string calendarUid = null,
            DateTime? date = null,
            List<int> tagIds = null,
            string fromAddress = null,
            bool add2Index = false,
            string mimeMessageId = null,
            uint? userFolderId = null)
        {
            var folder = folderId.HasValue ? (FolderType)folderId.Value : FolderType.Inbox;

            if (!MailFolder.IsIdOk(folder))
                throw new ArgumentException(@"Invalid folder id", "folderId");

            if (!mailboxId.HasValue)
                throw new ArgumentException(@"Invalid mailbox id", "mailboxId");

            var accounts = _engineFactory.AccountEngine.GetAccountInfoList().ToAccountData().ToList();

            var account = mailboxId.HasValue
                ? accounts.FirstOrDefault(a => a.MailboxId == mailboxId)
                : accounts.FirstOrDefault(a => a.IsDefault) ?? accounts.FirstOrDefault();

            if (account == null)
                throw new ArgumentException("Mailbox not found");

            var mbox = _engineFactory.MailboxEngine.GetMailboxData(
                new СoncreteUserMailboxExp(account.MailboxId, TenantId, Username));

            if (mbox == null)
                throw new ArgumentException("no such mailbox");

            var internalId = string.IsNullOrEmpty(mimeMessageId) ? MailUtil.CreateMessageId() : mimeMessageId;

            var restoreFolder = folder == FolderType.Spam || folder == FolderType.Trash
                ? FolderType.Inbox
                : folder;

            string sampleBody;
            string sampleIntro;

            if (!to.Any())
            {
                to = new List<string> { mbox.EMail.Address };
            }

            if (!string.IsNullOrEmpty(body))
            {
                sampleBody = body;
                sampleIntro = MailUtil.GetIntroduction(body);
            }
            else
            {
                sampleBody = LOREM_IPSUM_BODY;
                sampleIntro = LOREM_IPSUM_INTRO;
            }

            var sampleMessage = new MailMessage
            {
                Date = date ?? DateTime.UtcNow,
                MimeMessageId = internalId,
                MimeReplyToId = null,
                ChainId = internalId,
                ReplyTo = "",
                To = string.Join(", ", to.ToArray()),
                Cc = cc.Any() ? string.Join(", ", cc.ToArray()) : "",
                Bcc = bcc.Any() ? string.Join(", ", bcc.ToArray()) : "",
                Subject = string.IsNullOrEmpty(subject) ? LOREM_IPSUM_SUBJECT : subject,
                Important = importance,
                TextBodyOnly = false,
                Attachments = new List<MailAttachmentData>(),
                Size = sampleBody.Length,
                MailboxId = mbox.MailBoxId,
                HtmlBody = sampleBody,
                Introduction = sampleIntro,
                Folder = folder,
                RestoreFolderId = restoreFolder,
                IsNew = unread,
                StreamId = MailUtil.CreateStreamId(),
                CalendarUid = calendarUid
            };

            if (!string.IsNullOrEmpty(fromAddress))
            {
                var from = Parser.ParseAddress(fromAddress);

                sampleMessage.From = from.ToString();
                sampleMessage.FromEmail = from.Email;
            }
            else
            {
                sampleMessage.From = MailUtil.CreateFullEmail(mbox.Name, mbox.EMail.Address);
                sampleMessage.FromEmail = mbox.EMail.Address;
            }

            if (tagIds != null && tagIds.Any())
            {
                sampleMessage.TagIds = tagIds;
            }

            MessageEngine.StoreMailBody(mbox, sampleMessage, Log);

            var id = _engineFactory.MessageEngine.MailSave(mbox, sampleMessage, 0, folder, restoreFolder, userFolderId,
                SAMPLE_UIDL, "", false);

            if (!add2Index)
                return id;

            var message = _engineFactory.MessageEngine.GetMessage(id, new MailMessageData.Options());

            message.IsNew = unread;

            var wrapper = message.ToMailWrapper(mbox.TenantId, new Guid(mbox.UserId));

            _engineFactory.IndexEngine.Add(wrapper);

            return id;
        }

        public int CreateReplyToSampleMessage(int id, string body, bool add2Index = false)
        {
            var message = _engineFactory.MessageEngine.GetMessage(id, new MailMessage.Options());

            if (message == null)
                throw new ArgumentException("Message with id not found");

            var mbox = _engineFactory.MailboxEngine.GetMailboxData(
                new СoncreteUserMailboxExp(message.MailboxId, TenantId, Username));

            if (mbox == null)
                throw new ArgumentException("Mailbox not found");

            var mimeMessageId = MailUtil.CreateMessageId();

            var sampleMessage = new MailMessage
            {
                Date = DateTime.UtcNow,
                MimeMessageId = mimeMessageId,
                MimeReplyToId = message.MimeMessageId,
                ChainId = message.MimeMessageId,
                ReplyTo = message.FromEmail,
                To = message.FromEmail,
                Cc = "",
                Bcc = "",
                Subject = "Re: " + message.Subject,
                Important = message.Important,
                TextBodyOnly = false,
                Attachments = new List<MailAttachmentData>(),
                Size = body.Length,
                MailboxId = mbox.MailBoxId,
                HtmlBody = body,
                Introduction = body,
                Folder = FolderType.Sent,
                RestoreFolderId = FolderType.Sent,
                IsNew = false,
                StreamId = MailUtil.CreateStreamId(),
                From = MailUtil.CreateFullEmail(mbox.Name, mbox.EMail.Address),
                FromEmail = mbox.EMail.Address
            };

            MessageEngine.StoreMailBody(mbox, sampleMessage, Log);

            var replyId = _engineFactory.MessageEngine.MailSave(mbox, sampleMessage, 0, FolderType.Sent, FolderType.Sent, null,
                SAMPLE_REPLY_UIDL, "", false);

            if (!add2Index)
                return replyId;

            var replyMessage = _engineFactory.MessageEngine.GetMessage(replyId, new MailMessageData.Options());

            var wrapper = replyMessage.ToMailWrapper(mbox.TenantId, new Guid(mbox.UserId));

            _engineFactory.IndexEngine.Add(wrapper);

            return replyId;
        }

        public MailAttachmentData AppendAttachmentsToSampleMessage(
            int? messageId, string filename, Stream stream, string contentType)
        {
            if (!messageId.HasValue || messageId.Value <= 0)
                throw new ArgumentException(@"Invalid message id", "messageId");

            var message = _engineFactory.MessageEngine.GetMessage(messageId.Value, new MailMessage.Options());

            if (message == null)
                throw new AttachmentsException(AttachmentsException.Types.MessageNotFound, "Message not found.");

            if (!message.Uidl.Equals(SAMPLE_UIDL))
                throw new Exception("Message is not api sample.");

            if (string.IsNullOrEmpty(filename))
                throw new Exception("File name is empty.");

            if (stream == null)
                throw new Exception("File stream is empty.");

            contentType = string.IsNullOrEmpty(contentType) ? MimeMapping.GetMimeMapping(filename) : contentType;

            return _engineFactory.AttachmentEngine.AttachFile(TenantId, Username, message, filename, stream, stream.Length, contentType);
        }

        public int LoadSampleMessage(
            int? folderId,
            uint? userFolderId,
            int? mailboxId,
            bool unread,
            Stream emlStream,
            bool add2Index = false)
        {
            var folder = folderId.HasValue ? (FolderType)folderId.Value : FolderType.Inbox;

            if (!MailFolder.IsIdOk(folder))
                throw new ArgumentException(@"Invalid folder id", "folderId");

            if (!mailboxId.HasValue)
                throw new ArgumentException(@"Invalid mailbox id", "mailboxId");

            var accounts = _engineFactory.AccountEngine.GetAccountInfoList().ToAccountData().ToList();

            var account = mailboxId.HasValue
                ? accounts.FirstOrDefault(a => a.MailboxId == mailboxId)
                : accounts.FirstOrDefault(a => a.IsDefault) ?? accounts.FirstOrDefault();

            if (account == null)
                throw new ArgumentException("Mailbox not found");

            var mbox = _engineFactory.MailboxEngine.GetMailboxData(
                new СoncreteUserMailboxExp(account.MailboxId, TenantId, Username));

            if (mbox == null)
                throw new ArgumentException("no such mailbox");

            var mimeMessage = MailClient.ParseMimeMessage(emlStream);

            var message = MessageEngine.Save(mbox, mimeMessage, SAMPLE_UIDL, new MailFolder(folder, ""), userFolderId,
                unread, Log);

            if (message == null)
                return -1;

            if (!add2Index)
                return message.Id;

            _engineFactory.IndexEngine.Add(message.ToMailWrapper(mbox.TenantId, new Guid(mbox.UserId)));

            return message.Id;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/talk.notification.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var port;

self.addEventListener('install', function (event) {
    event.waitUntil(self.skipWaiting()); 
});

self.addEventListener('activate', function (event) {
    event.waitUntil(self.clients.claim());
});

self.addEventListener('push', function (event) {

    var obj = JSON.parse(event.data.text());
    fireNotification(obj.data, event);
	
});
self.onmessage = function (e) {
    port = e.ports[0];
};

self.addEventListener('notificationclick', function (event) {
 
    event.notification.close();
    
    event.waitUntil(
      self.clients.matchAll({
          type: 'window',
          includeUncontrolled: true
      })
      .then(function (clientList) {
          var url = "JabberClient.aspx";
           for (var i = 0; i < clientList.length; i++) {
               var client = clientList[i];
               var clientUrl = client.url.split("/");
               if (clientUrl[clientUrl.length-1] == url && 'focus' in client)
                   return client.focus();
             }
           if (clients.openWindow) {
               return clients.openWindow(url);
           }
      })
    );
});

function fireNotification(obj, event) {
    var title = unescape(obj.fromFullName);
    var body = obj.msg;
    var tag = 'simple-push-notification-tag';
    var photo;
    if ((obj.photoPath.indexOf('http://') != -1 || obj.photoPath.indexOf('https://') != -1) && obj.photoPath != '') {
        photo = obj.photoPath;
    } else if (obj.photoPath != '') {
        photo = event.target.origin != '' ? event.target.origin + obj.photoPath : "http://download.onlyoffice.com/assets/logo/emptyuser-48.png";
    } else {
        photo = "http://download.onlyoffice.com/assets/logo/emptyuser-48.png";
    }
    event.waitUntil(self.registration.showNotification(title, {
        icon: photo,
		title:title,
		body: body,
        tag: tag
	}));
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Utils/ExportToCSV.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;

using ASC.Common;
using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Security.Authentication;
using ASC.Common.Threading.Progress;
using ASC.Core;
using ASC.Core.Users;
using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.CRM.Core.Entities;
using ASC.Data.Storage;
using ASC.Web.Core.Files;
using ASC.Web.CRM.Core;
using ASC.Web.CRM.Resources;
using ASC.Web.CRM.Services.NotifyService;
using ASC.Web.Files.Utils;
using ASC.Web.Studio.Utility;

using Autofac;

using Ionic.Zip;

using Newtonsoft.Json.Linq;

namespace ASC.Web.CRM.Classes
{
    class ExportDataCache
    {
        public static readonly ICache Cache = AscCache.Default;

        public static String GetStateCacheKey(string key)
        {
            return String.Format("{0}:crm:queue:exporttocsv", key);
        }

        public static String GetCancelCacheKey(string key)
        {
            return String.Format("{0}:crm:queue:exporttocsv:cancel", key);
        }

        public static ExportDataOperation Get(string key)
        {
            return Cache.Get<ExportDataOperation>(GetStateCacheKey(key));
        }

        public static void Insert(string key, ExportDataOperation data)
        {
            Cache.Insert(GetStateCacheKey(key), data, TimeSpan.FromMinutes(1));
        }

        public static bool CheckCancelFlag(string key)
        {
            var fromCache = Cache.Get<String>(GetCancelCacheKey(key));

            return !String.IsNullOrEmpty(fromCache);
        }

        public static void SetCancelFlag(string key)
        {
            Cache.Insert(GetCancelCacheKey(key), "true", TimeSpan.FromMinutes(1));
        }

        public static void ResetAll(string key)
        {
            Cache.Remove(GetStateCacheKey(key));
            Cache.Remove(GetCancelCacheKey(key));
        }
    }

    class ExportDataOperation : IProgressItem
    {
        #region Constructor

        public ExportDataOperation(FilterObject filterObject, string fileName)
        {
            _tenantId = TenantProvider.CurrentTenantID;
            _author = SecurityContext.CurrentAccount;
            _dataStore = Global.GetStore();
            _notifyClient = NotifyClient.Instance;
            _filterObject = filterObject;
            _log = LogManager.GetLogger("ASC.CRM");

            Id = ExportToCsv.GetKey(filterObject != null);
            Status = ProgressStatus.Queued;
            Error = null;
            Percentage = 0;
            IsCompleted = false;
            FileName = fileName ?? string.Format("{0}_{1}.{2}", CRMSettingResource.Export, DateTime.UtcNow.Ticks, filterObject == null ? "zip" : "csv");
            FileUrl = null;
        }

        public ExportDataOperation()
            : this(null, null)
        {
        }

        #endregion

        #region Members

        private readonly int _tenantId;

        private readonly IAccount _author;

        private readonly IDataStore _dataStore;

        private readonly NotifyClient _notifyClient;

        private readonly FilterObject _filterObject;

        private readonly ILog _log;

        private int _totalCount;

        #endregion

        public override bool Equals(object obj)
        {
            if (obj == null) return false;

            var exportDataOperation = obj as ExportDataOperation;

            if (exportDataOperation == null) return false;

            return Id == exportDataOperation.Id;
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }

        public object Clone()
        {
            var cloneObj = new ExportDataOperation
            {
                Id = Id,
                Status = Status,
                Error = Error,
                Percentage = Percentage,
                IsCompleted = IsCompleted,
                FileName = FileName,
                FileUrl = FileUrl
            };

            return cloneObj;
        }

        #region Property

        public object Id { get; set; }

        public object Status { get; set; }

        public object Error { get; set; }

        public double Percentage { get; set; }

        public bool IsCompleted { get; set; }

        public string FileName { get; set; }

        public string FileUrl { get; set; }

        #endregion

        #region Private Methods

        private static String WrapDoubleQuote(String value)
        {
            return "\"" + value.Trim().Replace("\"", "\"\"") + "\"";
        }

        private static String DataTableToCsv(DataTable dataTable)
        {
            var result = new StringBuilder();

            var columnsCount = dataTable.Columns.Count;

            for (var index = 0; index < columnsCount; index++)
            {
                if (index != columnsCount - 1)
                    result.Append(dataTable.Columns[index].Caption + ",");
                else
                    result.Append(dataTable.Columns[index].Caption);
            }

            result.Append(Environment.NewLine);

            foreach (DataRow row in dataTable.Rows)
            {
                for (var i = 0; i < columnsCount; i++)
                {
                    var itemValue = WrapDoubleQuote(row[i].ToString());

                    if (i != columnsCount - 1)
                        result.Append(itemValue + ",");
                    else
                        result.Append(itemValue);
                }

                result.Append(Environment.NewLine);
            }

            return result.ToString();
        }

        #endregion

        public void RunJob()
        {
            try
            {
                Status = ProgressStatus.Started;

                CoreContext.TenantManager.SetCurrentTenant(_tenantId);
                SecurityContext.AuthenticateMe(_author);

                using (var scope = DIHelper.Resolve())
                {
                    var daoFactory = scope.Resolve<DaoFactory>();
                    var userCulture = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).GetCulture();

                    System.Threading.Thread.CurrentThread.CurrentCulture = userCulture;
                    System.Threading.Thread.CurrentThread.CurrentUICulture = userCulture;

                    _log.Debug("Start Export Data");

                    ExportDataCache.Insert((string)Id, (ExportDataOperation)Clone());

                    if (_filterObject == null)
                        ExportAllData(daoFactory);
                    else
                        ExportPartData(daoFactory);
                }

                Complete(100, ProgressStatus.Done, null);

                _log.Debug("Export is completed");
            }
            catch (OperationCanceledException ocex)
            {
                Complete(0, ProgressStatus.Failed, ocex.Message);

                _log.Debug("Export is cancel");
            }
            catch (Exception ex)
            {
                Complete(0, ProgressStatus.Failed, ex.Message);

                _log.Error(ex);
            }
            finally
            {
                ExportDataCache.ResetAll((string)Id);
            }
        }

        private void Complete(double percentage, ProgressStatus status, object error)
        {
            IsCompleted = true;
            Percentage = percentage;
            Status = status;
            Error = error;

            ExportDataCache.Insert((string)Id, (ExportDataOperation)Clone());
        }

        private void ExportAllData(DaoFactory daoFactory)
        {
            using (var stream = TempStream.Create())
            {
                var contactDao = daoFactory.ContactDao;
                var contactInfoDao = daoFactory.ContactInfoDao;
                var dealDao = daoFactory.DealDao;
                var casesDao = daoFactory.CasesDao;
                var taskDao = daoFactory.TaskDao;
                var historyDao = daoFactory.RelationshipEventDao;
                var invoiceItemDao = daoFactory.InvoiceItemDao;

                _totalCount += contactDao.GetAllContactsCount();
                _totalCount += dealDao.GetDealsCount();
                _totalCount += casesDao.GetCasesCount();
                _totalCount += taskDao.GetAllTasksCount();
                _totalCount += historyDao.GetAllItemsCount();
                _totalCount += invoiceItemDao.GetInvoiceItemsCount();

                using (var zipStream = new ZipOutputStream(stream, true))
                {
                    zipStream.AlternateEncoding = Encoding.UTF8;
                    zipStream.AlternateEncodingUsage = ZipOption.Always;

                    zipStream.PutNextEntry(CRMContactResource.Contacts + ".csv");
                    var contactData = contactDao.GetAllContacts();
                    var contactInfos = new StringDictionary();
                    contactInfoDao.GetAll()
                                  .ForEach(item =>
                                               {
                                                   var contactInfoKey = String.Format("{0}_{1}_{2}", item.ContactID, (int)item.InfoType, item.Category);
                                                   if (contactInfos.ContainsKey(contactInfoKey))
                                                   {
                                                       contactInfos[contactInfoKey] += "," + item.Data;
                                                   }
                                                   else
                                                   {
                                                       contactInfos.Add(contactInfoKey, item.Data);
                                                   }
                                               });

                    using (var zipEntryData = new MemoryStream(Encoding.UTF8.GetBytes(ExportContactsToCsv(contactData, contactInfos, daoFactory))))
                    {
                        zipEntryData.CopyTo(zipStream);
                    }

                    zipStream.PutNextEntry(CRMCommonResource.DealModuleName + ".csv");
                    var dealData = dealDao.GetAllDeals();
                    using (var zipEntryData = new MemoryStream(Encoding.UTF8.GetBytes(ExportDealsToCsv(dealData, daoFactory))))
                    {
                        zipEntryData.CopyTo(zipStream);
                    }

                    zipStream.PutNextEntry(CRMCommonResource.CasesModuleName + ".csv");
                    var casesData = casesDao.GetAllCases();
                    using (var zipEntryData = new MemoryStream(Encoding.UTF8.GetBytes(ExportCasesToCsv(casesData, daoFactory))))
                    {
                        zipEntryData.CopyTo(zipStream);
                    }

                    zipStream.PutNextEntry(CRMCommonResource.TaskModuleName + ".csv");
                    var taskData = taskDao.GetAllTasks();
                    using (var zipEntryData = new MemoryStream(Encoding.UTF8.GetBytes(ExportTasksToCsv(taskData, daoFactory))))
                    {
                        zipEntryData.CopyTo(zipStream);
                    }

                    zipStream.PutNextEntry(CRMCommonResource.History + ".csv");
                    var historyData = historyDao.GetAllItems();
                    using (var zipEntryData = new MemoryStream(Encoding.UTF8.GetBytes(ExportHistoryToCsv(historyData, daoFactory))))
                    {
                        zipEntryData.CopyTo(zipStream);
                    }

                    zipStream.PutNextEntry(CRMCommonResource.ProductsAndServices + ".csv");
                    var invoiceItemData = invoiceItemDao.GetAll();
                    using (var zipEntryData = new MemoryStream(Encoding.UTF8.GetBytes(ExportInvoiceItemsToCsv(invoiceItemData, daoFactory))))
                    {
                        zipEntryData.CopyTo(zipStream);
                    }

                    zipStream.Flush();
                    zipStream.Close();

                    stream.Position = 0;
                }

                if (_dataStore.IsDirectory("export", string.Empty))
                {
                    _dataStore.DeleteFiles("export", string.Empty, "*.*", true);
                }

                FileUrl = CommonLinkUtility.GetFullAbsolutePath(_dataStore.Save("export", FileName, stream).ToString());

                _notifyClient.SendAboutExportCompleted(_author.ID, FileName, FileUrl);
            }
        }

        private void ExportPartData(DaoFactory daoFactory)
        {
            var items = _filterObject.GetItemsByFilter(daoFactory);

            string fileContent;

            _totalCount = items.Count;

            if (_totalCount == 0)
                throw new ArgumentException(CRMErrorsResource.ExportToCSVDataEmpty);

            if (items is List<Contact>)
            {
                var contactInfoDao = daoFactory.ContactInfoDao;

                var contacts = (List<Contact>)items;

                var contactInfos = new StringDictionary();

                contactInfoDao.GetAll(contacts.Select(item => item.ID).ToArray())
                              .ForEach(item =>
                                  {
                                      var contactInfoKey = String.Format("{0}_{1}_{2}", item.ContactID,
                                                                         (int)item.InfoType,
                                                                         item.Category);

                                      if (contactInfos.ContainsKey(contactInfoKey))
                                          contactInfos[contactInfoKey] += "," + item.Data;
                                      else
                                          contactInfos.Add(contactInfoKey, item.Data);
                                  });

                fileContent = ExportContactsToCsv(contacts, contactInfos, daoFactory);
            }
            else if (items is List<Deal>)
            {
                fileContent = ExportDealsToCsv((List<Deal>)items, daoFactory);
            }
            else if (items is List<ASC.CRM.Core.Entities.Cases>)
            {
                fileContent = ExportCasesToCsv((List<ASC.CRM.Core.Entities.Cases>)items, daoFactory);
            }
            else if (items is List<RelationshipEvent>)
            {
                fileContent = ExportHistoryToCsv((List<RelationshipEvent>)items, daoFactory);
            }
            else if (items is List<Task>)
            {
                fileContent = ExportTasksToCsv((List<Task>)items, daoFactory);
            }
            else if (items is List<InvoiceItem>)
            {
                fileContent = ExportInvoiceItemsToCsv((List<InvoiceItem>)items, daoFactory);
            }
            else
                throw new ArgumentException();

            FileUrl = SaveCsvFileInMyDocument(FileName, fileContent);
        }

        private String ExportContactsToCsv(IReadOnlyCollection<Contact> contacts, StringDictionary contactInfos, DaoFactory daoFactory)
        {
            var key = (string)Id;
            var listItemDao = daoFactory.ListItemDao;
            var tagDao = daoFactory.TagDao;
            var customFieldDao = daoFactory.CustomFieldDao;
            var contactDao = daoFactory.ContactDao;

            var dataTable = new DataTable();

            dataTable.Columns.AddRange(new[]
                {
                    new DataColumn
                        {
                            Caption = CRMCommonResource.TypeCompanyOrPerson,
                            ColumnName = "company/person"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.FirstName,
                            ColumnName = "firstname"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.LastName,
                            ColumnName = "lastname"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.CompanyName,
                            ColumnName = "companyname"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.JobTitle,
                            ColumnName = "jobtitle"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.About,
                            ColumnName = "about"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.ContactStage,
                            ColumnName = "contact_stage"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.ContactType,
                            ColumnName = "contact_type"
                        },
                    new DataColumn
                        {
                            Caption = CRMContactResource.ContactTagList,
                            ColumnName = "contact_tag_list"
                        }
                });

            foreach (ContactInfoType infoTypeEnum in Enum.GetValues(typeof(ContactInfoType)))
                foreach (Enum categoryEnum in Enum.GetValues(ContactInfo.GetCategory(infoTypeEnum)))
                {
                    var localTitle = String.Format("{1} ({0})", categoryEnum.ToLocalizedString().ToLower(), infoTypeEnum.ToLocalizedString());

                    if (infoTypeEnum == ContactInfoType.Address)
                        dataTable.Columns.AddRange((from AddressPart addressPartEnum in Enum.GetValues(typeof(AddressPart))
                                                    select new DataColumn
                                                    {
                                                        Caption = String.Format(localTitle + " {0}", addressPartEnum.ToLocalizedString().ToLower()),
                                                        ColumnName = String.Format("contactInfo_{0}_{1}_{2}", (int)infoTypeEnum, categoryEnum, (int)addressPartEnum)
                                                    }).ToArray());

                    else
                        dataTable.Columns.Add(new DataColumn
                        {
                            Caption = localTitle,
                            ColumnName = String.Format("contactInfo_{0}_{1}", (int)infoTypeEnum, categoryEnum)
                        });
                }

            var fieldsDescription = customFieldDao.GetFieldsDescription(EntityType.Company);

            customFieldDao.GetFieldsDescription(EntityType.Person).ForEach(item =>
                                                                               {
                                                                                   var alreadyContains = fieldsDescription.Any(field => field.ID == item.ID);

                                                                                   if (!alreadyContains)
                                                                                       fieldsDescription.Add(item);
                                                                               });

            fieldsDescription.ForEach(
                item =>
                {
                    if (item.FieldType == CustomFieldType.Heading) return;

                    dataTable.Columns.Add(
                        new DataColumn
                        {
                            Caption = item.Label,
                            ColumnName = "customField_" + item.ID
                        }
                        );
                });

            var companyCustomFields = contacts.Where(x => x is Company).Any() ? customFieldDao.GetEntityFields(EntityType.Company, contacts.Where(x => x is Company).Select(x => x.ID).ToArray()) : new List<CustomField>();
            var personCustomFields = contacts.Where(x => x is Person).Any() ? customFieldDao.GetEntityFields(EntityType.Person, contacts.Where(x => x is Person).Select(x => x.ID).ToArray()) : new List<CustomField>();
            var customFields = companyCustomFields.Union(personCustomFields);

            var customFieldEntity = customFields
                           .GroupBy(x => x.EntityID)
                           .ToDictionary(x => x.Key, x => x.ToList());

            var tags = tagDao.GetEntitiesTags(EntityType.Contact);

            foreach (var contact in contacts)
            {
                if (ExportDataCache.CheckCancelFlag(key))
                {
                    ExportDataCache.ResetAll(key);

                    throw new OperationCanceledException();
                }

                ExportDataCache.Insert(key, (ExportDataOperation)Clone());

                Percentage += 1.0 * 100 / _totalCount;

                var isCompany = contact is Company;

                var compPersType = (isCompany) ? CRMContactResource.Company : CRMContactResource.Person;

                var contactTags = String.Empty;

                if (tags.ContainsKey(contact.ID))
                    contactTags = String.Join(",", tags[contact.ID].OrderBy(x => x));

                String firstName;
                String lastName;

                String companyName;
                String title;

                if (contact is Company)
                {
                    firstName = String.Empty;
                    lastName = String.Empty;
                    title = String.Empty;
                    companyName = ((Company)contact).CompanyName;
                }
                else
                {
                    var people = (Person)contact;

                    firstName = people.FirstName;
                    lastName = people.LastName;
                    title = people.JobTitle;

                    companyName = String.Empty;

                    if (people.CompanyID > 0)
                    {
                        var personCompany = contacts.SingleOrDefault(item => item.ID == people.CompanyID) ??
                                            contactDao.GetByID(people.CompanyID);

                        if (personCompany != null)
                            companyName = personCompany.GetTitle();
                    }
                }

                var contactStatus = String.Empty;

                if (contact.StatusID > 0)
                {

                    var listItem = listItemDao.GetByID(contact.StatusID);

                    if (listItem != null)
                        contactStatus = listItem.Title;
                }

                var contactType = String.Empty;

                if (contact.ContactTypeID > 0)
                {

                    var listItem = listItemDao.GetByID(contact.ContactTypeID);

                    if (listItem != null)
                        contactType = listItem.Title;
                }

                var dataRowItems = new List<String>
                    {
                        compPersType,
                        firstName,
                        lastName,
                        companyName,
                        title,
                        contact.About,
                        contactStatus,
                        contactType,
                        contactTags
                    };

                foreach (ContactInfoType infoTypeEnum in Enum.GetValues(typeof(ContactInfoType)))
                    foreach (Enum categoryEnum in Enum.GetValues(ContactInfo.GetCategory(infoTypeEnum)))
                    {
                        var contactInfoKey = String.Format("{0}_{1}_{2}", contact.ID,
                                                           (int)infoTypeEnum,
                                                           Convert.ToInt32(categoryEnum));

                        var columnValue = "";

                        if (contactInfos.ContainsKey(contactInfoKey))
                            columnValue = contactInfos[contactInfoKey];

                        if (infoTypeEnum == ContactInfoType.Address)
                        {
                            if (!String.IsNullOrEmpty(columnValue))
                            {
                                var addresses = JArray.Parse(String.Concat("[", columnValue, "]"));

                                dataRowItems.AddRange((from AddressPart addressPartEnum in Enum.GetValues(typeof(AddressPart))
                                                       select String.Join(",", addresses.Select(item => (String)item.SelectToken(addressPartEnum.ToString().ToLower())).ToArray())).ToArray());
                            }
                            else
                            {
                                dataRowItems.AddRange(new[] { "", "", "", "", "" });
                            }
                        }
                        else
                        {
                            dataRowItems.Add(columnValue);
                        }
                    }

                var dataRow = dataTable.Rows.Add(dataRowItems.ToArray());

                if (customFieldEntity.ContainsKey(contact.ID))
                    customFieldEntity[contact.ID].ForEach(item => dataRow["customField_" + item.ID] = item.Value);
            }

            return DataTableToCsv(dataTable);
        }

        private String ExportDealsToCsv(IEnumerable<Deal> deals, DaoFactory daoFactory)
        {
            var key = (string)Id;
            var tagDao = daoFactory.TagDao;
            var customFieldDao = daoFactory.CustomFieldDao;
            var dealMilestoneDao = daoFactory.DealMilestoneDao;
            var contactDao = daoFactory.ContactDao;

            var dataTable = new DataTable();

            dataTable.Columns.AddRange(new[]
                {
                    new DataColumn
                        {
                            Caption = CRMDealResource.NameDeal,
                            ColumnName = "title"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.ClientDeal,
                            ColumnName = "client_deal"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.OtherMembersDeal,
                            ColumnName = "member"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.DescriptionDeal,
                            ColumnName = "description"
                        },
                    new DataColumn
                        {
                            Caption = CRMCommonResource.Currency,
                            ColumnName = "currency"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.DealAmount,
                            ColumnName = "amount"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.BidType,
                            ColumnName = "bid_type"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.BidTypePeriod,
                            ColumnName = "bid_type_period"
                        },
                    new DataColumn
                        {
                            Caption = CRMJSResource.ExpectedCloseDate,
                            ColumnName = "expected_close_date"
                        },
                    new DataColumn
                        {
                            Caption = CRMJSResource.ActualCloseDate,
                            ColumnName = "actual_close_date"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.ResponsibleDeal,
                            ColumnName = "responsible_deal"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.CurrentDealMilestone,
                            ColumnName = "current_deal_milestone"
                        },
                    new DataColumn
                        {
                            Caption = CRMDealResource.DealMilestoneType,
                            ColumnName = "deal_milestone_type"
                        },
                    new DataColumn
                        {
                            Caption = (CRMDealResource.ProbabilityOfWinning + " %"),
                            ColumnName = "probability_of_winning"
                        },
                    new DataColumn
                        {
                            Caption = (CRMDealResource.DealTagList),
                            ColumnName = "tag_list"
                        }
                });

            customFieldDao.GetFieldsDescription(EntityType.Opportunity).ForEach(
                item =>
                {
                    if (item.FieldType == CustomFieldType.Heading) return;

                    dataTable.Columns.Add(new DataColumn
                    {
                        Caption = item.Label,
                        ColumnName = "customField_" + item.ID
                    });
                });
            
            var customFieldEntity = customFieldDao.GetEntityFields(EntityType.Opportunity, deals.Select(x => x.ID).ToArray())
               .GroupBy(x => x.EntityID)
               .ToDictionary(x => x.Key, x => x.ToList());

            var tags = tagDao.GetEntitiesTags(EntityType.Opportunity);

            foreach (var deal in deals)
            {
                if (ExportDataCache.CheckCancelFlag(key))
                {
                    ExportDataCache.ResetAll(key);

                    throw new OperationCanceledException();
                }

                ExportDataCache.Insert(key, (ExportDataOperation)Clone());

                Percentage += 1.0 * 100 / _totalCount;

                var contactTags = String.Empty;

                if (tags.ContainsKey(deal.ID))
                    contactTags = String.Join(",", tags[deal.ID].OrderBy(x => x));

                String bidType;

                switch (deal.BidType)
                {
                    case BidType.FixedBid:
                        bidType = CRMDealResource.BidType_FixedBid;
                        break;
                    case BidType.PerDay:
                        bidType = CRMDealResource.BidType_PerDay;
                        break;
                    case BidType.PerHour:
                        bidType = CRMDealResource.BidType_PerHour;
                        break;
                    case BidType.PerMonth:
                        bidType = CRMDealResource.BidType_PerMonth;
                        break;
                    case BidType.PerWeek:
                        bidType = CRMDealResource.BidType_PerWeek;
                        break;
                    case BidType.PerYear:
                        bidType = CRMDealResource.BidType_PerYear;
                        break;
                    default:
                        throw new ArgumentException();
                }

                var currentDealMilestone = dealMilestoneDao.GetByID(deal.DealMilestoneID);
                var currentDealMilestoneStatus = currentDealMilestone.Status.ToLocalizedString();
                var contactTitle = String.Empty;

                if (deal.ContactID != 0)
                    contactTitle = contactDao.GetByID(deal.ContactID).GetTitle();

                var members = string.Empty;
                var dealMembersIDs = daoFactory.DealDao.GetMembers(deal.ID).Where(id => id != deal.ContactID);
                if (dealMembersIDs.Any())
                {
                    var dealMembers = daoFactory.ContactDao.GetContacts(dealMembersIDs.ToArray());
                    members = string.Join(",", dealMembers.Select(member => member.GetTitle()));
                }

                var dataRow = dataTable.Rows.Add(new object[]
                    {
                        deal.Title,
                        contactTitle,
                        members,
                        deal.Description,
                        deal.BidCurrency,
                        deal.BidValue.ToString(CultureInfo.InvariantCulture),
                        bidType,
                        deal.PerPeriodValue == 0 ? "" : deal.PerPeriodValue.ToString(CultureInfo.InvariantCulture),
                        deal.ExpectedCloseDate.Date == DateTime.MinValue.Date ? "" : deal.ExpectedCloseDate.ToString(DateTimeExtension.DateFormatPattern),
                        deal.ActualCloseDate.Date == DateTime.MinValue.Date ? "" : deal.ActualCloseDate.ToString(DateTimeExtension.DateFormatPattern),
                        CoreContext.UserManager.GetUsers(deal.ResponsibleID).DisplayUserName(false),
                        currentDealMilestone.Title,
                        currentDealMilestoneStatus,
                        deal.DealMilestoneProbability.ToString(CultureInfo.InvariantCulture),
                        contactTags
                    });

                if (customFieldEntity.ContainsKey(deal.ID))
                    customFieldEntity[deal.ID].ForEach(item => dataRow["customField_" + item.ID] = item.Value);
            }

            return DataTableToCsv(dataTable);
        }

        private String ExportCasesToCsv(IEnumerable<ASC.CRM.Core.Entities.Cases> cases, DaoFactory daoFactory)
        {
            var key = (string)Id;
            var tagDao = daoFactory.TagDao;
            var customFieldDao = daoFactory.CustomFieldDao;

            var dataTable = new DataTable();

            dataTable.Columns.AddRange(new[]
                {
                    new DataColumn
                        {
                            Caption = CRMCasesResource.CaseTitle,
                            ColumnName = "title"
                        },
                    new DataColumn(CRMCasesResource.CasesTagList)
                        {
                            Caption = CRMCasesResource.CasesTagList,
                            ColumnName = "tag_list"
                        }
                });

            customFieldDao.GetFieldsDescription(EntityType.Case).ForEach(
                item =>
                {
                    if (item.FieldType == CustomFieldType.Heading) return;

                    dataTable.Columns.Add(new DataColumn
                    {
                        Caption = item.Label,
                        ColumnName = "customField_" + item.ID
                    });
                });

            var customFieldEntity = customFieldDao.GetEntityFields(EntityType.Case, cases.Select(x => x.ID).ToArray())
                                   .GroupBy(x => x.EntityID)
                                   .ToDictionary(x => x.Key, x => x.ToList());


            var tags = tagDao.GetEntitiesTags(EntityType.Case);

            foreach (var item in cases)
            {
                if (ExportDataCache.CheckCancelFlag(key))
                {
                    ExportDataCache.ResetAll(key);

                    throw new OperationCanceledException();
                }

                ExportDataCache.Insert(key, (ExportDataOperation)Clone());

                Percentage += 1.0 * 100 / _totalCount;

                var contactTags = String.Empty;

                if (tags.ContainsKey(item.ID))
                    contactTags = String.Join(",", tags[item.ID].OrderBy(x => x));

                var dataRow = dataTable.Rows.Add(new object[]
                    {
                        item.Title,
                        contactTags
                    });

                if (customFieldEntity.ContainsKey(item.ID))
                    customFieldEntity[item.ID].ForEach(row => dataRow["customField_" + row.ID] = row.Value);
            }

            return DataTableToCsv(dataTable);
        }

        private String ExportHistoryToCsv(IEnumerable<RelationshipEvent> events, DaoFactory daoFactory)
        {
            var key = (string)Id;
            var listItemDao = daoFactory.ListItemDao;
            var dealDao = daoFactory.DealDao;
            var casesDao = daoFactory.CasesDao;
            var contactDao = daoFactory.ContactDao;

            var dataTable = new DataTable();

            dataTable.Columns.AddRange(new[]
                {
                    new DataColumn
                        {
                            Caption = (CRMContactResource.Content),
                            ColumnName = "content"
                        },
                    new DataColumn
                        {
                            Caption = (CRMCommonResource.Category),
                            ColumnName = "category"
                        },
                    new DataColumn
                        {
                            Caption = (CRMContactResource.ContactTitle),
                            ColumnName = "contact_title"
                        },
                    new DataColumn
                        {
                            Caption = (CRMContactResource.RelativeEntity),
                            ColumnName = "relative_entity"
                        },
                    new DataColumn
                        {
                            Caption = (CRMCommonResource.Author),
                            ColumnName = "author"
                        },
                    new DataColumn
                        {
                            Caption = (CRMCommonResource.CreateDate),
                            ColumnName = "create_date"
                        }
                });

            foreach (var item in events)
            {
                if (ExportDataCache.CheckCancelFlag(key))
                {
                    ExportDataCache.ResetAll(key);

                    throw new OperationCanceledException();
                }

                ExportDataCache.Insert(key, (ExportDataOperation)Clone());

                Percentage += 1.0 * 100 / _totalCount;

                var entityTitle = String.Empty;

                if (item.EntityID > 0)
                    switch (item.EntityType)
                    {
                        case EntityType.Case:
                            var casesObj = casesDao.GetByID(item.EntityID);

                            if (casesObj != null)
                                entityTitle = String.Format("{0}: {1}", CRMCasesResource.Case,
                                                            casesObj.Title);
                            break;
                        case EntityType.Opportunity:
                            var dealObj = dealDao.GetByID(item.EntityID);

                            if (dealObj != null)
                                entityTitle = String.Format("{0}: {1}", CRMDealResource.Deal,
                                                            dealObj.Title);
                            break;
                    }

                var contactTitle = String.Empty;

                if (item.ContactID > 0)
                {
                    var contactObj = contactDao.GetByID(item.ContactID);

                    if (contactObj != null)
                        contactTitle = contactObj.GetTitle();
                }

                var categoryTitle = String.Empty;

                if (item.CategoryID > 0)
                {
                    var categoryObj = listItemDao.GetByID(item.CategoryID);

                    if (categoryObj != null)
                        categoryTitle = categoryObj.Title;

                }
                else if (item.CategoryID == (int)HistoryCategorySystem.TaskClosed)
                    categoryTitle = HistoryCategorySystem.TaskClosed.ToLocalizedString();
                else if (item.CategoryID == (int)HistoryCategorySystem.FilesUpload)
                    categoryTitle = HistoryCategorySystem.FilesUpload.ToLocalizedString();
                else if (item.CategoryID == (int)HistoryCategorySystem.MailMessage)
                    categoryTitle = HistoryCategorySystem.MailMessage.ToLocalizedString();

                dataTable.Rows.Add(new object[]
                    {
                        item.Content,
                        categoryTitle,
                        contactTitle,
                        entityTitle,
                        CoreContext.UserManager.GetUsers(item.CreateBy).DisplayUserName(false),
                        item.CreateOn.ToShortString()
                    });
            }

            return DataTableToCsv(dataTable);
        }

        private String ExportTasksToCsv(IEnumerable<Task> tasks, DaoFactory daoFactory)
        {
            var key = (string)Id;
            var listItemDao = daoFactory.ListItemDao;
            var dealDao = daoFactory.DealDao;
            var casesDao = daoFactory.CasesDao;
            var contactDao = daoFactory.ContactDao;

            var dataTable = new DataTable();

            dataTable.Columns.AddRange(new[]
                {
                    new DataColumn
                        {
                            Caption = (CRMTaskResource.TaskTitle),
                            ColumnName = "title"
                        },
                    new DataColumn
                        {
                            Caption = (CRMTaskResource.Description),
                            ColumnName = "description"
                        },
                    new DataColumn
                        {
                            Caption = (CRMTaskResource.DueDate),
                            ColumnName = "due_date"
                        },
                    new DataColumn
                        {
                            Caption = (CRMTaskResource.Responsible),
                            ColumnName = "responsible"
                        },
                    new DataColumn
                        {
                            Caption = (CRMContactResource.ContactTitle),
                            ColumnName = "contact_title"
                        },
                    new DataColumn
                        {
                            Caption = (CRMTaskResource.TaskStatus),
                            ColumnName = "task_status"
                        },
                    new DataColumn
                        {
                            Caption = (CRMTaskResource.TaskCategory),
                            ColumnName = "task_category"
                        },
                    new DataColumn
                        {
                            Caption = (CRMContactResource.RelativeEntity),
                            ColumnName = "relative_entity"
                        },
                    new DataColumn
                        {
                            Caption = (CRMCommonResource.Alert),
                            ColumnName = "alert_value"
                        }
                });

            foreach (var item in tasks)
            {
                if (ExportDataCache.CheckCancelFlag(key))
                {
                    ExportDataCache.ResetAll(key);

                    throw new OperationCanceledException();
                }

                ExportDataCache.Insert(key, (ExportDataOperation)Clone());

                Percentage += 1.0 * 100 / _totalCount;

                var entityTitle = String.Empty;

                if (item.EntityID > 0)
                    switch (item.EntityType)
                    {
                        case EntityType.Case:
                            var caseObj = casesDao.GetByID(item.EntityID);

                            if (caseObj != null)
                                entityTitle = String.Format("{0}: {1}", CRMCasesResource.Case, caseObj.Title);
                            break;
                        case EntityType.Opportunity:
                            var dealObj = dealDao.GetByID(item.EntityID);

                            if (dealObj != null)
                                entityTitle = String.Format("{0}: {1}", CRMDealResource.Deal, dealObj.Title);
                            break;
                    }

                var contactTitle = String.Empty;

                if (item.ContactID > 0)
                {
                    var contact = contactDao.GetByID(item.ContactID);

                    if (contact != null)
                        contactTitle = contact.GetTitle();
                }

                dataTable.Rows.Add(new object[]
                    {
                        item.Title,
                        item.Description,
                        item.DeadLine == DateTime.MinValue
                            ? ""
                            : item.DeadLine.ToShortString(),
                        CoreContext.UserManager.GetUsers(item.ResponsibleID).DisplayUserName(false),
                        contactTitle,
                        item.IsClosed
                            ? CRMTaskResource.TaskStatus_Closed
                            : CRMTaskResource.TaskStatus_Open,
                        listItemDao.GetByID(item.CategoryID).Title,
                        entityTitle,
                        item.AlertValue.ToString(CultureInfo.InvariantCulture)
                    });
            }

            return DataTableToCsv(dataTable);
        }

        private String ExportInvoiceItemsToCsv(IEnumerable<InvoiceItem> invoiceItems, DaoFactory daoFactory)
        {
            var key = (string)Id;
            var taxes = daoFactory.InvoiceTaxDao.GetAll();
            var dataTable = new DataTable();

            dataTable.Columns.AddRange(new[]
                {
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.InvoiceItemName),
                            ColumnName = "title"
                        },
                    new DataColumn
                        {
                            Caption = (CRMSettingResource.Description),
                            ColumnName = "description"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.StockKeepingUnit),
                            ColumnName = "sku"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.InvoiceItemPrice),
                            ColumnName = "price"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.FormInvoiceItemStockQuantity),
                            ColumnName = "stock_quantity"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.TrackInventory),
                            ColumnName = "track_inventory"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.Currency),
                            ColumnName = "currency"
                        },

                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.InvoiceTax1Name),
                            ColumnName = "tax1_name"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.InvoiceTax1Rate),
                            ColumnName = "tax1_rate"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.InvoiceTax2Name),
                            ColumnName = "tax2_name"
                        },
                    new DataColumn
                        {
                            Caption = (CRMInvoiceResource.InvoiceTax2Rate),
                            ColumnName = "tax2_rate"
                        }

                });


            foreach (var item in invoiceItems)
            {
                if (ExportDataCache.CheckCancelFlag(key))
                {
                    ExportDataCache.ResetAll(key);

                    throw new OperationCanceledException();
                }

                ExportDataCache.Insert(key, (ExportDataOperation)Clone());

                Percentage += 1.0 * 100 / _totalCount;

                var tax1 = item.InvoiceTax1ID != 0 ? taxes.Find(t => t.ID == item.InvoiceTax1ID) : null;
                var tax2 = item.InvoiceTax2ID != 0 ? taxes.Find(t => t.ID == item.InvoiceTax2ID) : null;

                dataTable.Rows.Add(new object[]
                    {
                        item.Title,
                        item.Description,
                        item.StockKeepingUnit,
                        item.Price.ToString(CultureInfo.InvariantCulture),
                        item.StockQuantity.ToString(CultureInfo.InvariantCulture),
                        item.TrackInventory.ToString(),
                        item.Currency,
                        tax1 != null ? tax1.Name : "",
                        tax1 != null ? tax1.Rate.ToString(CultureInfo.InvariantCulture) : "",
                        tax2 != null ? tax2.Name : "",
                        tax2 != null ? tax2.Rate.ToString(CultureInfo.InvariantCulture) : ""
                    });
            }

            return DataTableToCsv(dataTable);
        }

        private static String SaveCsvFileInMyDocument(String title, String data)
        {
            string fileUrl;

            using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
            {
                var file = FileUploader.Exec(Files.Classes.Global.FolderMy.ToString(), title, memStream.Length, memStream, true);

                if (FileUtility.CanWebView(title) || FileUtility.CanWebEdit(title))
                {
                    fileUrl = FilesLinkUtility.GetFileWebEditorUrl((int)file.ID);
                    fileUrl += string.Format("&options={{\"delimiter\":{0},\"codePage\":{1}}}",
                                     (int)FileUtility.CsvDelimiter.Comma,
                                     Encoding.UTF8.CodePage);
                }
                else
                {
                    fileUrl = FilesLinkUtility.GetFileDownloadUrl((int)file.ID);
                }
            }

            return fileUrl;
        }
    }

    public class ExportToCsv
    {
        #region Members

        private static readonly object Locker = new object();

        private static readonly ProgressQueue Queue = new ProgressQueue(Global.GetQueueWorkerCount("export"), Global.GetQueueWaitInterval("export"), true);

        #endregion

        #region Public Methods

        public static IProgressItem GetStatus(bool partialDataExport)
        {
            var key = GetKey(partialDataExport);

            return Queue.GetStatus(key) ?? ExportDataCache.Get(key);
        }

        public static IProgressItem Start(FilterObject filterObject, string fileName)
        {
            lock (Locker)
            {
                var key = GetKey(filterObject != null);

                var operation = Queue.GetStatus(key);

                if (operation == null)
                {
                    var fromCache = ExportDataCache.Get(key);

                    if (fromCache != null)
                        return fromCache;
                }

                if (operation == null)
                {
                    ExportDataCache.ResetAll(key);

                    operation = new ExportDataOperation(filterObject, fileName);

                    Queue.Add(operation);
                }

                if (!Queue.IsStarted)
                    Queue.Start(x => x.RunJob());

                return operation;
            }
        }

        public static void Cancel(bool partialDataExport)
        {
            lock (Locker)
            {
                var key = GetKey(partialDataExport);

                var findedItem = Queue.GetItems().FirstOrDefault(elem => (string)elem.Id == key);

                if (findedItem != null)
                {
                    Queue.Remove(findedItem);
                }

                ExportDataCache.SetCancelFlag(key);
            }
        }

        public static string GetKey(bool partialDataExport)
        {
            return string.Format("{0}_{1}", TenantProvider.CurrentTenantID,
                                 partialDataExport ? SecurityContext.CurrentAccount.ID : Guid.Empty);
        }

        public static String ExportItems(FilterObject filterObject, string fileName)
        {
            var operation = new ExportDataOperation(filterObject, fileName);

            operation.RunJob();

            return operation.FileUrl;
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Common/Logging/SelfCleaningAppender.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Linq;

using log4net.Appender;
using log4net.Core;
using log4net.Util;

namespace ASC.Common.Logging
{
    public class SelfCleaningAppender : RollingFileAppender
    {
        private static DateTime _lastCleanDate;

        private static int? _cleanPeriod;

        private static int GetCleanPeriod()
        {
            if (_cleanPeriod != null)
                return _cleanPeriod.Value;

            const string key = "CleanPeriod";

            var value = 30;

            var repo = log4net.LogManager.GetRepository();

            if (repo != null && repo.Properties.GetKeys().Contains(key))
            {
                int.TryParse(repo.Properties[key].ToString(), out value);
            }

            _cleanPeriod = value;

            return value;
        }

        private void Clean()
        {
            try
            {
                if (string.IsNullOrEmpty(File))
                    return;

                var fileInfo = new FileInfo(File);

                if (!fileInfo.Exists)
                    return;

                var directory = fileInfo.Directory;

                if (directory == null || !directory.Exists)
                    return;

                var files = directory.GetFiles();

                var cleanPeriod = GetCleanPeriod();

                foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
                {
                    file.Delete();
                }
            }
            catch (Exception err)
            {
                LogLog.Error(GetType(), err.Message, err);
            }
        }

        protected override void Append(LoggingEvent loggingEvent)
        {
            if (DateTime.UtcNow.Date > _lastCleanDate.Date)
            {
                _lastCleanDate = DateTime.UtcNow.Date;
                Clean();
            }

            base.Append(loggingEvent);
        }

        protected override void Append(LoggingEvent[] loggingEvents)
        {
            if (DateTime.UtcNow.Date > _lastCleanDate.Date)
            {
                _lastCleanDate = DateTime.UtcNow.Date;
                Clean();
            }

            base.Append(loggingEvents);
        }
    }
}


<|start_filename|>common/ASC.Common/DependencyInjection/ListElementCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;

namespace ASC.Common.DependencyInjection
{
    [TypeConverter(typeof(ListElementTypeConverter))]
    public class ListElementCollection : ConfigurationElementCollection<ListItemElement>
    {
        public ListElementCollection()
          : base("item")
        {
        }

        private class ListElementTypeConverter : TypeConverter
        {
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                var instantiableType = GetInstantiableType(destinationType);
                var elementCollection = (ListElementCollection)value;
                if (elementCollection == null || !(instantiableType != null))
                    return base.ConvertTo(context, culture, value, destinationType);
                var genericArguments = instantiableType.GetGenericArguments();
                var list = (IList)Activator.CreateInstance(instantiableType);
                foreach (var listItemElement in elementCollection)
                    list.Add(TypeManipulation.ChangeToCompatibleType(listItemElement.Value, genericArguments[0], null));
                return list;
            }

            public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
            {
                return GetInstantiableType(destinationType) != null || base.CanConvertTo(context, destinationType);
            }

            private static Type GetInstantiableType(Type destinationType)
            {
                if (!typeof(IEnumerable).IsAssignableFrom(destinationType)) return null;
                var typeArray1 = !destinationType.IsGenericType ? new[] { typeof(object) } : destinationType.GetGenericArguments();
                var typeArray2 = typeArray1;
                if (typeArray2.Length != 1)
                    return null;
                var c = typeof(List<>).MakeGenericType(typeArray2);
                return destinationType.IsAssignableFrom(c) ? c : null;
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/js/asc/plugins/jquery-projectadvansedselector.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function ($) {
    var ResourceJS = ASC.Resources.Master.ResourceJS, teamlab = Teamlab;

    var projectadvancedSelector = function (element, options) {
        this.$element = $(element);
        this.options = $.extend({}, $.fn.projectadvancedSelector.defaults, options);

        this.init();
    };

    projectadvancedSelector.prototype = $.extend({}, $.fn.advancedSelector.Constructor.prototype, {
        constructor: projectadvancedSelector,
        initCreationBlock: function (data) {
            var that = this,
                opts = {},
                itemsSimpleSelect = [];

            opts.newoptions = [
                      { title: ResourceJS.SelectorTitle, type: "input", tag: "title" },
                      { title: ResourceJS.SelectorManager, type: "select", tag: "manager" }
            ];
            opts.newbtn = ResourceJS.CreateButton;

            that.displayAddItemBlock.call(that, opts);

            var filter = {
                employeeStatus: 1,
                employeeType: 1
            };

            teamlab.getSimpleProfilesByFilter({}, {
                before: function () {
                    that.showLoaderSimpleSelector.call(that, "manager");
                },
                filter: filter,
                success: function (params, data) {
                    for (var i = 0, length = data.length; i < length; i++) {
                        if (data[i].id == teamlab.profile.id) {
                            itemsSimpleSelect.unshift(
                                {
                                    title: ResourceJS.MeLabel,
                                    id: data[i].id
                                }
                            );
                        }
                        else {
                            itemsSimpleSelect.push(
                                {
                                    title: data[i].displayName,
                                    id: data[i].id
                                }
                            );
                        }
                    }
                    that.initDataSimpleSelector.call(that, { tag: "manager", items: itemsSimpleSelect });
                    that.hideLoaderSimpleSelector.call(that, "manager");
                },

                error: function (params, errors) {
                    toastr.error(errors);
                }
            });
        },

        initAdvSelectorData: function () {

        },
        
        rewriteObjectItem: function (data) {
            var that = this;
            
            that.items = data.map(function(item) {
                return { id: item.id, title: item.title, description: item.description, isPrivate: item.isPrivate, responsible: item.responsible, deadline: item.deadline };
            });
            that.items = that.items.sort(that.options.sortMethod || SortData);
            that.showItemsListAdvSelector.call(that);
        },

        createNewItemFn: function () {
            var that = this,
                $addPanel = that.$advancedSelector.find(".advanced-selector-add-new-block"),
                $btn = $addPanel.find(".advanced-selector-btn-add"),
                isError;

            var newProject = {
                title: $addPanel.find(".title input").val().trim(),
                responsibleid: $addPanel.find(".manager input").attr("data-id"),
                notify: false,
                description: "",
                tags: "",
                'private': false
            };

            if (!newProject.title) {
                that.showErrorField.call(that, { field: $addPanel.find(".title"), error: ResourceJS.ProjectSelectorEmptyTitleError });
                isError = true;
            }
            if (!newProject.responsibleid) {
                that.showErrorField.call(that, { field: $addPanel.find(".manager"), error: ResourceJS.ProjectSelectorEmptyManagerError });
                isError = true;
            }
            if (!newProject.responsibleid && $addPanel.find(".manager input").val()) {
                that.showErrorField.call(that, { field: $addPanel.find(".manager"), error: ResourceJS.ProjectSelectorNotPersonError });
                isError = true;
            }
            if (isError) {
                $addPanel.find(".error input").first().focus();
                return;
            }
            teamlab.addPrjProject({}, newProject, {
                before: function() {
                    that.displayLoadingBtn.call(that, { btn: $btn, text: ResourceJS.LoadingProcessing });
                },
                error: function(params, errors) {
                    that.showServerError.call(that, { field: $btn, error: errors });
                },
                success: function(params, project) {
                    project = this.__responses[0];
                    var newproject = {
                        id: project.id,
                        title: project.title
                    }
                    that.actionsAfterCreateItem.call(that, { newitem: newproject, response: project });
                },
                after: function() {
                    that.hideLoadingBtn.call(that, $btn);
                }
            });
        }

    });


    $.fn.projectadvancedSelector = function (option) {
        var selfargs = Array.prototype.slice.call(arguments, 1);
        return this.each(function() {
            var $this = $(this),
                data = $this.data('projectadvancedSelector'),
                options = $.extend({},
                    $.fn.projectadvancedSelector.defaults,
                    $this.data(),
                    typeof option == 'object' && option);
            if (!data) $this.data('projectadvancedSelector', (data = new projectadvancedSelector(this, options)));
            if (typeof option == 'string') data[option].apply(data, selfargs);
        });
    };
    
    $.fn.projectadvancedSelector.defaults = $.extend({}, $.fn.advancedSelector.defaults, {
        showme: true,
        addtext: ResourceJS.ProjectSelectorAddText,
        noresults: ResourceJS.ProjectSelectorNoResult,
        noitems: ResourceJS.ProjectSelectorNoItems,
        emptylist: ResourceJS.ProjectSelectorEmptyList
    });

})(jQuery);

<|start_filename|>common/ASC.Common/Data/Sql/ISqlDialect.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Data;

namespace ASC.Common.Data.Sql
{
    public interface ISqlDialect
    {
        string IdentityQuery { get; }

        string Autoincrement { get; }

        string InsertIgnore { get; }


        bool SupportMultiTableUpdate { get; }

        bool SeparateCreateIndex { get; }


        string DbTypeToString(DbType type, int size, int precision);

        IsolationLevel GetSupportedIsolationLevel(IsolationLevel il);

        string UseIndex(string index);
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/PrivacyRoom/js/privacyroom.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var Encryption = function () {
    function init () {
        jq("#saveEncryption").click(setStatus);
    }

    function showStatusValue (data) {
        var on = !!data;

        jq("#encryption_off").prop("checked", !on);
        jq("#encryption_on").prop("checked", on);
    }

    function setStatus () {
        showLoader();

        Teamlab.setPrivacyRoom(
            null,
            jq("#encryption_on").prop("checked"),
            {
                success: function (params, data) {
                    hideLoader();
                    showStatusValue(data);

                    LoadingBanner.showMesInfoBtn("#studio_encryptionSettings", ASC.Resources.Master.ResourceJS.SuccessfullySaveSettingsMessage, "success");
                },
                error: function (e, err) {
                    LoadingBanner.showMesInfoBtn("#studio_encryptionSettings", err[0], "error");
                    hideLoader();
                }
            });
    }

    function showLoader () {
        LoadingBanner.showLoaderBtn("#studio_encryptionSettings");
    }

    function hideLoader () {
        LoadingBanner.hideLoaderBtn("#studio_encryptionSettings");
    }

    return {
        init: init
    };
}();

jQuery(function() {
    Encryption.init();
});

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/DbSchema/Tables/AttachmentTable.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


// ReSharper disable InconsistentNaming

using System.Collections.Generic;

using ASC.Mail.Core.DbSchema.Interfaces;

namespace ASC.Mail.Core.DbSchema.Tables
{
    public class AttachmentTable : ITable
    {
        public const string TABLE_NAME = "mail_attachment";

        public static class Columns
        {
            public const string Id = "id";
            public const string MailId = "id_mail";
            public const string Name = "name";
            public const string StoredName = "stored_name";
            public const string Type = "type";
            public const string Size = "size";
            public const string IsRemoved = "need_remove";
            public const string FileNumber = "file_number";
            public const string ContentId = "content_id";
            public const string Tenant = "tenant";
            public const string MailboxId = "id_mailbox";
        }

        public string Name
        {
            get { return TABLE_NAME; }
        }

        public IEnumerable<string> OrderedColumnCollection { get; private set; }

        public AttachmentTable()
        {
            OrderedColumnCollection = new List<string>
            {
                Columns.Id,
                Columns.MailId,
                Columns.Name,
                Columns.StoredName,
                Columns.Type,
                Columns.Size,
                Columns.IsRemoved,
                Columns.FileNumber,
                Columns.ContentId,
                Columns.Tenant,
                Columns.MailboxId
            };
        }
    }
}

<|start_filename|>common/ASC.Data.Storage/GoogleCloud/GoogleCloudStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;

using ASC.Common;
using ASC.Data.Storage.Configuration;

using Google.Apis.Auth.OAuth2;
using Google.Cloud.Storage.V1;

using MimeMapping = ASC.Common.Web.MimeMapping;


#endregion

namespace ASC.Data.Storage.GoogleCloud
{
    public class GoogleCloudStorage : BaseStorage
    {
        private String _subDir = String.Empty;
        private readonly Dictionary<string, PredefinedObjectAcl> _domainsAcl;
        private readonly PredefinedObjectAcl _moduleAcl;

        private string _bucket = "";
        private string _json = "";

        private Uri _bucketRoot;
        private Uri _bucketSSlRoot;

        private bool _lowerCasing = true;

        public GoogleCloudStorage(string tenant)
        {
            _tenant = tenant;

            _modulename = string.Empty;
            _dataList = null;

            _domainsExpires = new Dictionary<string, TimeSpan> { { string.Empty, TimeSpan.Zero } };
            _domainsAcl = new Dictionary<string, PredefinedObjectAcl>();
            _moduleAcl = PredefinedObjectAcl.PublicRead;

        }

        public GoogleCloudStorage(string tenant, HandlerConfigurationElement handlerConfig, ModuleConfigurationElement moduleConfig)
        {
            _tenant = tenant;

            _modulename = moduleConfig.Name;
            _dataList = new DataList(moduleConfig);

            _domainsExpires =
                moduleConfig.Domains.Cast<DomainConfigurationElement>().Where(x => x.Expires != TimeSpan.Zero).
                    ToDictionary(x => x.Name,
                                 y => y.Expires);

            _domainsExpires.Add(string.Empty, moduleConfig.Expires);

            _domainsAcl = moduleConfig.Domains.Cast<DomainConfigurationElement>().ToDictionary(x => x.Name,
                                                                                   y => GetGoogleCloudAcl(y.Acl));
            _moduleAcl = GetGoogleCloudAcl(moduleConfig.Acl);

        }

        public override IDataStore Configure(IDictionary<string, string> props)
        {

            _bucket = props["bucket"];

            _bucketRoot = props.ContainsKey("cname") && Uri.IsWellFormedUriString(props["cname"], UriKind.Absolute)
                              ? new Uri(props["cname"], UriKind.Absolute)
                              : new Uri(string.Format("https://storage.googleapis.com/{0}/", _bucket), UriKind.Absolute);

            _bucketSSlRoot = props.ContainsKey("cnamessl") &&
                             Uri.IsWellFormedUriString(props["cnamessl"], UriKind.Absolute)
                                 ? new Uri(props["cnamessl"], UriKind.Absolute)
                                 : new Uri(string.Format("https://storage.googleapis.com/{0}/", _bucket), UriKind.Absolute);

            if (props.ContainsKey("lower"))
            {
                bool.TryParse(props["lower"], out _lowerCasing);
            }

            _json = props["json"];

            if (props.ContainsKey("subdir"))
            {
                _subDir = props["subdir"];
            }

            return this;
        }

        private StorageClient GetStorage()
        {
            var credential = GoogleCredential.FromJson(_json);

            return StorageClient.Create(credential);
        }

        private string MakePath(string domain, string path)
        {
            string result;

            path = path.TrimStart('\\', '/').TrimEnd('/').Replace('\\', '/');

            if (!String.IsNullOrEmpty(_subDir))
            {
                if (_subDir.Length == 1 && (_subDir[0] == '/' || _subDir[0] == '\\'))
                    result = path;
                else
                    result = String.Format("{0}/{1}", _subDir, path); // Ignory all, if _subDir is not null
            }
            else//Key combined from module+domain+filename
                result = string.Format("{0}/{1}/{2}/{3}",
                                                         _tenant,
                                                         _modulename,
                                                         domain,
                                                         path);

            result = result.Replace("//", "/").TrimStart('/');
            if (_lowerCasing)
            {
                result = result.ToLowerInvariant();
            }

            return result;
        }


        public static long DateToUnixTimestamp(DateTime date)
        {
            var ts = date - new DateTime(1970, 1, 1, 0, 0, 0);
            return (long)ts.TotalSeconds;
        }

        public override Uri GetInternalUri(string domain, string path, TimeSpan expire, IEnumerable<string> headers)
        {
            if (expire == TimeSpan.Zero || expire == TimeSpan.MinValue || expire == TimeSpan.MaxValue)
            {
                expire = GetExpire(domain);
            }
            if (expire == TimeSpan.Zero || expire == TimeSpan.MinValue || expire == TimeSpan.MaxValue)
            {
                return GetUriShared(domain, path);
            }

            var storage = GetStorage();

            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(_json ?? "")))
            {
                var preSignedURL = UrlSigner.FromServiceAccountData(stream)
                                            .Sign(_bucket, MakePath(domain, path), expire, HttpMethod.Get);

                return MakeUri(preSignedURL);
            }
        }

        public Uri GetUriShared(string domain, string path)
        {
            return new Uri(SecureHelper.IsSecure() ? _bucketSSlRoot : _bucketRoot, MakePath(domain, path));
        }

        private Uri MakeUri(string preSignedURL)
        {
            var uri = new Uri(preSignedURL);
            var signedPart = uri.PathAndQuery.TrimStart('/');

            return new Uri(uri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? _bucketSSlRoot : _bucketRoot, signedPart);

        }

        public override System.IO.Stream GetReadStream(string domain, string path)
        {
            return GetReadStream(domain, path, 0);
        }

        public override System.IO.Stream GetReadStream(string domain, string path, int offset)
        {
            var tempStream = TempStream.Create();

            var storage = GetStorage();

            storage.DownloadObject(_bucket, MakePath(domain, path), tempStream, null, null);

            if (offset > 0)
                tempStream.Seek(offset, SeekOrigin.Begin);

            tempStream.Position = 0;

            return tempStream;
        }

        public override async Task<Stream> GetReadStreamAsync(string domain, string path, int offset)
        {
            var tempStream = TempStream.Create();

            var storage = GetStorage();

            await storage.DownloadObjectAsync(_bucket, MakePath(domain, path), tempStream);

            if (offset > 0)
                tempStream.Seek(offset, SeekOrigin.Begin);

            tempStream.Position = 0;

            return tempStream;
        }

        public override Uri Save(string domain, string path, System.IO.Stream stream)
        {
            return Save(domain, path, stream, string.Empty, string.Empty);
        }

        public override Uri Save(string domain, string path, System.IO.Stream stream, Configuration.ACL acl)
        {
            return Save(domain, path, stream, null, null, acl);
        }

        protected override Uri SaveWithAutoAttachment(string domain, string path, System.IO.Stream stream, string attachmentFileName)
        {
            var contentDisposition = string.Format("attachment; filename={0};",
                                                 HttpUtility.UrlPathEncode(attachmentFileName));
            if (attachmentFileName.Any(c => c >= 0 && c <= 127))
            {
                contentDisposition = string.Format("attachment; filename*=utf-8''{0};",
                                                   HttpUtility.UrlPathEncode(attachmentFileName));
            }
            return Save(domain, path, stream, null, contentDisposition);
        }

        public override Uri Save(string domain, string path, System.IO.Stream stream, string contentType, string contentDisposition)
        {
            return Save(domain, path, stream, contentType, contentDisposition, ACL.Auto);
        }

        public override Uri Save(string domain, string path, System.IO.Stream stream, string contentEncoding, int cacheDays)
        {
            return Save(domain, path, stream, string.Empty, string.Empty, ACL.Auto, contentEncoding, cacheDays);
        }

        public Uri Save(string domain, string path, Stream stream, string contentType,
                          string contentDisposition, ACL acl, string contentEncoding = null, int cacheDays = 5)
        {

            var buffered = stream.GetBuffered();

            if (QuotaController != null)
            {
                QuotaController.QuotaUsedCheck(buffered.Length);
            }

            var mime = string.IsNullOrEmpty(contentType)
                        ? MimeMapping.GetMimeMapping(Path.GetFileName(path))
                        : contentType;

            var storage = GetStorage();

            UploadObjectOptions uploadObjectOptions = new UploadObjectOptions
            {
                PredefinedAcl = acl == ACL.Auto ? GetDomainACL(domain) : GetGoogleCloudAcl(acl)
            };

            buffered.Position = 0;

            var uploaded = storage.UploadObject(_bucket, MakePath(domain, path), mime, buffered, uploadObjectOptions, null);

            uploaded.ContentEncoding = contentEncoding;
            uploaded.CacheControl = String.Format("public, maxage={0}", (int)TimeSpan.FromDays(cacheDays).TotalSeconds);

            if (uploaded.Metadata == null)
                uploaded.Metadata = new Dictionary<String, String>();

            uploaded.Metadata["Expires"] = DateTime.UtcNow.Add(TimeSpan.FromDays(cacheDays)).ToString("R");

            if (!string.IsNullOrEmpty(contentDisposition))
            {
                uploaded.ContentDisposition = contentDisposition;
            }
            else if (mime == "application/octet-stream")
            {
                uploaded.ContentDisposition = "attachment";
            }

            storage.UpdateObject(uploaded);

            //           InvalidateCloudFront(MakePath(domain, path));

            QuotaUsedAdd(domain, buffered.Length);

            return GetUri(domain, path);
        }

        private void InvalidateCloudFront(params string[] paths)
        {
            throw new NotImplementedException();
        }

        private PredefinedObjectAcl GetGoogleCloudAcl(ACL acl)
        {
            switch (acl)
            {
                case ACL.Read:
                    return PredefinedObjectAcl.PublicRead;
                default:
                    return PredefinedObjectAcl.PublicRead;
            }
        }

        private PredefinedObjectAcl GetDomainACL(string domain)
        {
            if (GetExpire(domain) != TimeSpan.Zero)
            {
                return PredefinedObjectAcl.Private;
            }

            if (_domainsAcl.ContainsKey(domain))
            {
                return _domainsAcl[domain];
            }
            return _moduleAcl;
        }

        public override void Delete(string domain, string path)
        {
            var storage = GetStorage();

            var key = MakePath(domain, path);
            var size = GetFileSize(domain, path);

            storage.DeleteObject(_bucket, key);

            QuotaUsedDelete(domain, size);
        }


        public override void DeleteFiles(string domain, string folderPath, string pattern, bool recursive)
        {
            var storage = GetStorage();

            IEnumerable<Google.Apis.Storage.v1.Data.Object> objToDel;

            if (recursive)
                objToDel = storage
                           .ListObjects(_bucket, MakePath(domain, folderPath))
                           .Where(x => Wildcard.IsMatch(pattern, Path.GetFileName(x.Name)));
            else
                objToDel = new List<Google.Apis.Storage.v1.Data.Object>();

            foreach (var obj in objToDel)
            {
                storage.DeleteObject(_bucket, obj.Name);
                QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
            }
        }

        public override void DeleteFiles(string domain, List<string> paths)
        {
            if (!paths.Any()) return;

            var keysToDel = new List<string>();

            long quotaUsed = 0;

            foreach (var path in paths)
            {
                try
                {

                    var key = MakePath(domain, path);

                    if (QuotaController != null)
                    {
                        quotaUsed += GetFileSize(domain, path);
                    }

                    keysToDel.Add(key);
                }
                catch (FileNotFoundException)
                {

                }
            }

            if (!keysToDel.Any()) return;

            var storage = GetStorage();

            keysToDel.ForEach(x => storage.DeleteObject(_bucket, x));

            if (quotaUsed > 0)
            {
                QuotaUsedDelete(domain, quotaUsed);
            }
        }

        public override void DeleteFiles(string domain, string folderPath, DateTime fromDate, DateTime toDate)
        {
            var storage = GetStorage();

            var objToDel = GetObjects(domain, folderPath, true)
                              .Where(x => x.Updated >= fromDate && x.Updated <= toDate);

            foreach (var obj in objToDel)
            {
                storage.DeleteObject(_bucket, obj.Name);
                QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
            }
        }

        public override void MoveDirectory(string srcdomain, string srcdir, string newdomain, string newdir)
        {
            var storage = GetStorage();

            var srckey = MakePath(srcdomain, srcdir);
            var dstkey = MakePath(newdomain, newdir);

            var objects = storage.ListObjects(_bucket, srckey);

            foreach (var obj in objects)
            {
                storage.CopyObject(_bucket, srckey, _bucket, dstkey, new CopyObjectOptions
                {
                    DestinationPredefinedAcl = GetDomainACL(newdomain)
                });

                storage.DeleteObject(_bucket, srckey);

            }
        }

        public override Uri Move(string srcdomain, string srcpath, string newdomain, string newpath, bool quotaCheckFileSize = true)
        {
            var storage = GetStorage();

            var srcKey = MakePath(srcdomain, srcpath);
            var dstKey = MakePath(newdomain, newpath);
            var size = GetFileSize(srcdomain, srcpath);

            storage.CopyObject(_bucket, srcKey, _bucket, dstKey, new CopyObjectOptions
            {
                DestinationPredefinedAcl = GetDomainACL(newdomain)
            });

            Delete(srcdomain, srcpath);

            QuotaUsedDelete(srcdomain, size);
            QuotaUsedAdd(newdomain, size, quotaCheckFileSize);

            return GetUri(newdomain, newpath);

        }

        public override Uri SaveTemp(string domain, out string assignedPath, System.IO.Stream stream)
        {
            assignedPath = Guid.NewGuid().ToString();

            return Save(domain, assignedPath, stream);
        }

        public override string[] ListDirectoriesRelative(string domain, string path, bool recursive)
        {
            return GetObjects(domain, path, recursive)
                   .Select(x => x.Name.Substring(MakePath(domain, path + "/").Length))
                   .ToArray();
        }

        private IEnumerable<Google.Apis.Storage.v1.Data.Object> GetObjects(string domain, string path, bool recursive)
        {
            var storage = GetStorage();

            var items = storage.ListObjects(_bucket, MakePath(domain, path));

            if (recursive) return items;

            return items.Where(x => x.Name.IndexOf('/', MakePath(domain, path + "/").Length) == -1);
        }

        public override string[] ListFilesRelative(string domain, string path, string pattern, bool recursive)
        {
            return GetObjects(domain, path, recursive).Where(x => Wildcard.IsMatch(pattern, Path.GetFileName(x.Name)))
                   .Select(x => x.Name.Substring(MakePath(domain, path + "/").Length).TrimStart('/')).ToArray();
        }

        public override bool IsFile(string domain, string path)
        {
            var storage = GetStorage();

            var objects = storage.ListObjects(_bucket, MakePath(domain, path), null);

            return objects.Count() > 0;
        }

        public override async Task<bool> IsFileAsync(string domain, string path)
        {
            var storage = GetStorage();

            var objects = await storage.ListObjectsAsync(_bucket, MakePath(domain, path)).ReadPageAsync(1);

            return objects.Count() > 0;
        }

        public override bool IsDirectory(string domain, string path)
        {
            return IsFile(domain, path);
        }

        public override void DeleteDirectory(string domain, string path)
        {
            var storage = GetStorage();

            var objToDel = storage
                          .ListObjects(_bucket, MakePath(domain, path));

            foreach (var obj in objToDel)
            {
                storage.DeleteObject(_bucket, obj.Name);
                QuotaUsedDelete(domain, Convert.ToInt64(obj.Size));
            }
        }

        public override long GetFileSize(string domain, string path)
        {
            var storage = GetStorage();

            var obj = storage.GetObject(_bucket, MakePath(domain, path));

            if (obj.Size.HasValue)
                return Convert.ToInt64(obj.Size.Value);

            return 0;
        }

        public override long GetDirectorySize(string domain, string path)
        {
            var storage = GetStorage();

            var objToDel = storage
                          .ListObjects(_bucket, MakePath(domain, path));

            long result = 0;

            foreach (var obj in objToDel)
            {
                if (obj.Size.HasValue)
                    result += Convert.ToInt64(obj.Size.Value);
            }

            return result;
        }

        public override long ResetQuota(string domain)
        {
            var storage = GetStorage();

            var objects = storage
                          .ListObjects(_bucket, MakePath(domain, String.Empty));

            if (QuotaController != null)
            {
                long size = 0;

                foreach (var obj in objects)
                {
                    if (obj.Size.HasValue)
                        size += Convert.ToInt64(obj.Size.Value);
                }

                QuotaController.QuotaUsedSet(_modulename, domain, _dataList.GetData(domain), size);

                return size;
            }

            return 0;
        }

        public override long GetUsedQuota(string domain)
        {
            var storage = GetStorage();

            var objects = storage
                          .ListObjects(_bucket, MakePath(domain, String.Empty));

            long result = 0;

            foreach (var obj in objects)
            {
                if (obj.Size.HasValue)
                    result += Convert.ToInt64(obj.Size.Value);
            }

            return result;
        }

        public override Uri Copy(string srcdomain, string srcpath, string newdomain, string newpath)
        {
            var storage = GetStorage();

            var srcKey = MakePath(srcdomain, srcpath);
            var dstKey = MakePath(newdomain, newpath);

            var size = GetFileSize(srcdomain, srcpath);

            CopyObjectOptions options = new CopyObjectOptions();

            options.DestinationPredefinedAcl = GetDomainACL(newdomain);

            storage.CopyObject(_bucket, MakePath(srcdomain, srcpath), _bucket, MakePath(newdomain, newpath), options);

            QuotaUsedAdd(newdomain, size);

            return GetUri(newdomain, newpath);
        }

        public override void CopyDirectory(string srcdomain, string srcdir, string newdomain, string newdir)
        {
            var srckey = MakePath(srcdomain, srcdir);
            var dstkey = MakePath(newdomain, newdir);
            //List files from src

            var storage = GetStorage();


            var options = new ListObjectsOptions();

            var objects = storage.ListObjects(_bucket, srckey);

            foreach (var obj in objects)
            {
                storage.CopyObject(_bucket, srckey, _bucket, dstkey, new CopyObjectOptions
                {
                    DestinationPredefinedAcl = GetDomainACL(newdomain)
                });


                QuotaUsedAdd(newdomain, Convert.ToInt64(obj.Size));
            }
        }

        public override string SavePrivate(string domain, string path, System.IO.Stream stream, DateTime expires)
        {
            var storage = GetStorage();

            var objectKey = MakePath(domain, path);
            var buffered = stream.GetBuffered();

            UploadObjectOptions uploadObjectOptions = new UploadObjectOptions
            {
                PredefinedAcl = PredefinedObjectAcl.BucketOwnerFullControl
            };

            buffered.Position = 0;

            var uploaded = storage.UploadObject(_bucket, MakePath(domain, path), "application/octet-stream", buffered, uploadObjectOptions, null);

            uploaded.CacheControl = String.Format("public, maxage={0}", (int)TimeSpan.FromDays(5).TotalSeconds);
            uploaded.ContentDisposition = "attachment";

            if (uploaded.Metadata == null)
                uploaded.Metadata = new Dictionary<String, String>();

            uploaded.Metadata["Expires"] = DateTime.UtcNow.Add(TimeSpan.FromDays(5)).ToString("R");
            uploaded.Metadata.Add("private-expire", expires.ToFileTimeUtc().ToString(CultureInfo.InvariantCulture));

            storage.UpdateObject(uploaded);

            using (var mStream = new MemoryStream(Encoding.UTF8.GetBytes(_json ?? "")))
            {
                var preSignedURL = UrlSigner.FromServiceAccountData(mStream)
                                .Sign(_bucket, MakePath(domain, path), expires, null);

                //TODO: CNAME!
                return preSignedURL;
            }
        }

        public override void DeleteExpired(string domain, string path, TimeSpan oldThreshold)
        {
            var storage = GetStorage();

            var objects = storage.ListObjects(_bucket, MakePath(domain, path));

            foreach (var obj in objects)
            {
                var objInfo = storage.GetObject(_bucket, MakePath(domain, path), null);

                var privateExpireKey = objInfo.Metadata["private-expire"];

                if (string.IsNullOrEmpty(privateExpireKey)) continue;

                long fileTime;

                if (!long.TryParse(privateExpireKey, out fileTime)) continue;
                if (DateTime.UtcNow <= DateTime.FromFileTimeUtc(fileTime)) continue;

                storage.DeleteObject(_bucket, MakePath(domain, path));

            }
        }

        #region chunking

        public override String InitiateChunkedUpload(string domain, string path)
        {
            var storage = GetStorage();

            var tempUploader = storage.CreateObjectUploader(_bucket, MakePath(domain, path), null, new MemoryStream());

            var sessionUri = tempUploader.InitiateSessionAsync().Result;

            return sessionUri.ToString();
        }

        public override string UploadChunk(String domain,
                                           String path,
                                           String uploadUri,
                                           Stream stream,
                                           long defaultChunkSize,
                                           int chunkNumber,
                                           long chunkLength)
        {

            String bytesRangeStart = Convert.ToString((chunkNumber - 1) * defaultChunkSize);
            String bytesRangeEnd = Convert.ToString((chunkNumber - 1) * defaultChunkSize + chunkLength - 1);

            String totalBytes = "*";

            int BufferSize = 2 * 4096;

            if (chunkLength != defaultChunkSize)
                totalBytes = Convert.ToString((chunkNumber - 1) * defaultChunkSize + chunkLength);

            String contentRangeHeader = String.Format("bytes {0}-{1}/{2}", bytesRangeStart, bytesRangeEnd, totalBytes);

            var request = HttpWebRequest.CreateHttp(uploadUri);

            request.Method = HttpMethod.Put.ToString();
            request.ContentLength = chunkLength;
            request.Headers.Add("Content-Range", contentRangeHeader);

            using (Stream rs = request.GetRequestStream())
            {
                var buffer = new byte[BufferSize];

                int readed;

                while ((readed = stream.Read(buffer, 0, BufferSize)) != 0)
                {
                    rs.Write(buffer, 0, readed);
                }

                stream.Close();
            }

            long MAX_RETRIES = 100;
            int millisecondsTimeout;

            for (int i = 0; i < MAX_RETRIES; i++)
            {
                Random random = new Random();

                millisecondsTimeout = Math.Min(Convert.ToInt32(Math.Pow(2, i)) + random.Next(0, 1000), 32 * 1000);

                try
                {
                    var response = request.GetResponse();
                    var status = ((HttpWebResponse)response).StatusCode;

                    break;
                }
                catch (WebException ex)
                {
                    var response = (HttpWebResponse)ex.Response;

                    var status = (int)response.StatusCode;

                    if (status == 408 || status == 500 || status == 502 || status == 503 || status == 504)
                    {
                        Thread.Sleep(millisecondsTimeout);
                        continue;
                    }

                    if (status != 308)
                        throw (ex);

                    break;
                }
                catch (Exception ex)
                {
                    AbortChunkedUpload(domain, path, uploadUri);
                    throw (ex);
                }
            }

            return String.Empty;
        }

        public override Uri FinalizeChunkedUpload(string domain, string path, string uploadUri, Dictionary<int, string> eTags)
        {
            if (QuotaController != null)
            {
                var size = GetFileSize(domain, path);
                QuotaUsedAdd(domain, size);
            }

            return GetUri(domain, path);
        }

        public override void AbortChunkedUpload(string domain, string path, string uploadUri)
        {

        }

        public override bool IsSupportChunking { get { return true; } }

        #endregion

        public override string GetUploadForm(string domain, string directoryPath, string redirectTo, long maxUploadSize, string contentType, string contentDisposition, string submitLabel)
        {
            throw new NotImplementedException();
        }

        public override string GetUploadedUrl(string domain, string directoryPath)
        {
            throw new NotImplementedException();
        }

        public override string GetUploadUrl()
        {
            throw new NotImplementedException();
        }

        public override string GetPostParams(string domain, string directoryPath, long maxUploadSize, string contentType, string contentDisposition)
        {
            throw new NotImplementedException();
        }
    }
}



<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Common/WikiSearchHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Common.Utils;
using ASC.Web.Community.Modules.Wiki.Resources;
using ASC.Web.Community.Product;
using ASC.Web.Core.ModuleManagement.Common;
using ASC.Web.Core.Utility;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Controls.Common;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Wiki;
using ASC.Web.UserControls.Wiki.Handlers;
using ASC.Web.UserControls.Wiki.UC;

namespace ASC.Web.Community.Wiki.Common
{
    public class WikiSearchHandler : BaseSearchHandlerEx
    {
        public override SearchResultItem[] Search(string text)
        {
            var list = new List<SearchResultItem>();
            var defPageHref = VirtualPathUtility.ToAbsolute(WikiManager.ViewVirtualPath);

            foreach (var page in new WikiEngine().SearchPagesByContent(text))
            {
                var pageName = page.PageName;
                if (string.IsNullOrEmpty(pageName))
                {
                    pageName = WikiResource.MainWikiCaption;
                }

                list.Add(new SearchResultItem
                {
                    Name = pageName,
                    Description = HtmlUtil.GetText(
                            EditPage.ConvertWikiToHtml(page.PageName, page.Body, defPageHref,
                                                       WikiSection.Section.ImageHangler.UrlFormat, TenantProvider.CurrentTenantID), 120),
                    URL = ActionHelper.GetViewPagePath(defPageHref, page.PageName),
                    Date = page.Date
                });
            }
            return list.ToArray();
        }

        public override ImageOptions Logo
        {
            get { return new ImageOptions { ImageFileName = "wikilogo16.png", PartID = WikiManager.ModuleId }; }
        }

        public override string SearchName
        {
            get { return WikiManager.SearchDefaultString; }
        }

        public override Guid ModuleID
        {
            get { return WikiManager.ModuleId; }
        }

        public override Guid ProductID
        {
            get { return CommunityProduct.ID; }
        }

        public override IItemControl Control
        {
            get { return new ResultsView(); }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/AccountDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class AccountDao : IAccountDao
    {
        public IDbManager Db { get; private set; }

        public int Tenant { get; private set; }
        public string User { get; private set; }

        public AccountDao(IDbManager dbManager, int tenant, string user)
        {
            Db = dbManager;

            Tenant = tenant;
            User = user;
        }

        public List<Account> GetAccounts()
        {
            const string mailbox_alias = "ma";
            const string server_address = "sa";
            const string server_domain = "sd";
            const string group_x_address = "ga";
            const string server_group = "sg";

            var query = new SqlQuery(MailboxTable.TABLE_NAME.Alias(mailbox_alias))
                .LeftOuterJoin(ServerAddressTable.TABLE_NAME.Alias(server_address),
                    Exp.EqColumns(MailboxTable.Columns.Id.Prefix(mailbox_alias),
                        ServerAddressTable.Columns.MailboxId.Prefix(server_address)))
                .LeftOuterJoin(ServerDomainTable.TABLE_NAME.Alias(server_domain),
                    Exp.EqColumns(ServerAddressTable.Columns.DomainId.Prefix(server_address),
                        ServerDomainTable.Columns.Id.Prefix(server_domain)))
                .LeftOuterJoin(ServerMailGroupXAddressesTable.TABLE_NAME.Alias(group_x_address),
                    Exp.EqColumns(ServerAddressTable.Columns.Id.Prefix(server_address),
                        ServerMailGroupXAddressesTable.Columns.AddressId.Prefix(group_x_address)))
                .LeftOuterJoin(ServerMailGroupTable.TABLE_NAME.Alias(server_group),
                    Exp.EqColumns(ServerMailGroupXAddressesTable.Columns.MailGroupId.Prefix(group_x_address),
                        ServerMailGroupTable.Columns.Id.Prefix(server_group)))
                .Select(MailboxTable.Columns.Id.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.Address.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.Enabled.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.Name.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.QuotaError.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.DateAuthError.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.OAuthToken.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.IsServerMailbox.Prefix(mailbox_alias))
                .Select(MailboxTable.Columns.EmailInFolder.Prefix(mailbox_alias))
                .Select(ServerAddressTable.Columns.Id.Prefix(server_address))
                .Select(ServerAddressTable.Columns.AddressName.Prefix(server_address))
                .Select(ServerAddressTable.Columns.IsAlias.Prefix(server_address))
                .Select(ServerDomainTable.Columns.Id.Prefix(server_domain))
                .Select(ServerDomainTable.Columns.DomainName.Prefix(server_domain))
                .Select(ServerMailGroupTable.Columns.Id.Prefix(server_group))
                .Select(ServerMailGroupTable.Columns.Address.Prefix(server_group))
                .Select(ServerDomainTable.Columns.Tenant.Prefix(server_domain))
                .Where(MailboxTable.Columns.IsRemoved.Prefix(mailbox_alias), false)
                .Where(MailboxTable.Columns.Tenant.Prefix(mailbox_alias), Tenant)
                .Where(MailboxTable.Columns.User.Prefix(mailbox_alias), User)
                .OrderBy(ServerAddressTable.Columns.IsAlias.Prefix(server_address), true);

            return Db.ExecuteList(query)
                .ConvertAll(ToAccount);
        }

        private static Account ToAccount(object[] r)
        {
            var a = new Account
            {
                MailboxId = Convert.ToInt32(r[0]),
                MailboxAddress = Convert.ToString(r[1]),
                MailboxEnabled = Convert.ToBoolean(r[2]),
                MailboxAddressName = Convert.ToString(r[3]),
                MailboxQuotaError = Convert.ToBoolean(r[4]),
                MailboxDateAuthError = r[5] != null ? Convert.ToDateTime(r[5]) : (DateTime?)null,
                MailboxOAuthToken = Convert.ToString(r[6]),
                MailboxIsTeamlabMailbox = Convert.ToBoolean(r[7]),
                MailboxEmailInFolder = Convert.ToString(r[8]),
                ServerAddressId = Convert.ToInt32(r[9]),
                ServerAddressName = Convert.ToString(r[10]),
                ServerAddressIsAlias = Convert.ToBoolean(r[11]),
                ServerDomainId = Convert.ToInt32(r[12]),
                ServerDomainName = Convert.ToString(r[13]),
                ServerMailGroupId = Convert.ToInt32(r[14]),
                ServerMailGroupAddress = Convert.ToString(r[15]),
                ServerDomainTenant = Convert.ToInt32(r[16])
            };

            return a;
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Settings/Smtp/SmtpOperationStatus.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

namespace ASC.Api.Settings.Smtp
{
    [DataContract]
    public class SmtpOperationStatus
    {
        [DataMember]
        public bool Completed { get; set; }

        [DataMember]
        public string Id { get; set; }

        [DataMember]
        public string Status { get; set; }

        [DataMember]
        public string Error { get; set; }

        [DataMember]
        public int Percents { get; set; }

        [DataMember]
        public string Source { get; set; }

        public static SmtpOperationStatus GetSample()
        {
            return new SmtpOperationStatus
            {
                Id = "{some-random-guid}",
                Error = "",
                Percents = 0,
                Completed = true,
                Status = "",
                Source = ""
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Domain/TaskFilter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Collections.Generic;

using ASC.Projects.Core.Domain.Reports;

#endregion

namespace ASC.Projects.Core.Domain
{
    public class TaskFilter : ReportFilter, ICloneable
    {
        public int? Milestone { get; set; }

        public bool Follow { get; set; }

        public string SortBy { get; set; }

        public bool SortOrder { get; set; }

        public string SearchText { get; set; }

        public long Offset { get; set; }

        public long Max { get; set; }

        public int LastId { get; set; }

        public bool MyProjects { get; set; }

        public bool MyMilestones { get; set; }

        public Guid? ParticipantId { get; set; }

        public TaskFilter()
        {
            Max = 150001;
        }

        public Dictionary<string, Dictionary<string, bool>> SortColumns
        {
            get
            {
                return new Dictionary<string, Dictionary<string, bool>>
                           {
                               {
                                   "Task", new Dictionary<string, bool>{{"deadline", true}, {"priority", false}, {"create_on", false}, {"start_date", false}, {"title", true}, {"sort_order", true}}
                               },
                               {
                                   "Milestone", new Dictionary<string, bool> {{"deadline", true}, {"create_on", false}, {"title", true}}
                               },
                               {
                                   "Project", new Dictionary<string, bool> {{"create_on", false}, {"title", true}}
                               },
                               {
                                   "Message", new Dictionary<string, bool> {{"comments", false}, {"create_on", false}, {"title", true}}
                               },
                               {
                                   "TimeSpend", new Dictionary<string, bool> {{"date", false}, { "create_on", false }, {"hours", false}, {"note", true } }
                               }
                           };
            }
        }

        public string ToXml()
        {
            return ReportFilterSerializer.ToXml(this);
        }

        public static TaskFilter FromXml(string xml)
        {
            return ReportFilterSerializer.FromXml(xml);
        }

        public string ToUri()
        {
            return ReportFilterSerializer.ToUri(this);
        }

        public static TaskFilter FromUri(string uri)
        {
            return ReportFilterSerializer.FromUri(uri);
        }

        public static TaskFilter FromUri(Uri uri)
        {
            return FromUri(uri.Query);
        }

        public object Clone()
        {
            return FromXml(ToXml());
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/VideoGuides/VideoGuides.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web.UI;

using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Core.HelpCenter;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Common.VideoGuides
{
    public partial class VideoGuidesControl : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Common/VideoGuides/VideoGuides.ascx"; }
        }

        public bool IsSubItem;

        public bool DisableVideo { get; set; }
        protected List<VideoGuideItem> VideoGuideItems { get; set; }
        protected string AllVideoLink { get; set; }


        protected void Page_Load(object sender, EventArgs e)
        {
            // Mirgate to CommonBodyScripts.ascx.cs
            // Page.RegisterBodyScripts("~/UserControls/Common/VideoGuides/js/videoguides.js");
            RenderVideoHandlers();
        }

        protected void RenderVideoHandlers()
        {
            var settings = AdditionalWhiteLabelSettings.Instance;

            if (!settings.VideoGuidesEnabled || String.IsNullOrEmpty(settings.VideoGuidesUrl))
            {
                DisableVideo = true;
                return;
            }

            AllVideoLink = CommonLinkUtility.GetRegionalUrl(settings.VideoGuidesUrl, CultureInfo.CurrentCulture.TwoLetterISOLanguageName);

            VideoGuideItems = HelpCenterHelper.GetVideoGuides();

            if (VideoGuideItems.Count > 0)
            {
                AjaxPro.Utility.RegisterTypeForAjax(typeof(UserVideoSettings));
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Masters/MasterResources/MasterTemplateResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Web.Core.Client.HttpHandlers;

namespace ASC.Web.Studio.Masters.MasterResources
{
    public class MasterTemplateResources : ClientScriptTemplate
    {
        protected override string[] Links
        {
            get
            {
                return new[]
                {
                    "~/Templates/UserProfileCardTemplate.html",
                    "~/Templates/AdvansedUserProfileEditTemplate.html",
                    "~/Templates/AdvansedFilterTemplate.html",
                    "~/Templates/FeedListTemplate.html",
                    "~/Templates/DropFeedTemplate.html",
                    "~/Templates/DropMailTemplate.html",
                    "~/Templates/GroupSelectorTemplate.html",
                    "~/Templates/SharingSettingsTemplate.html",
                    "~/Templates/AdvansedSelectorTemplate.html",
                    "~/Templates/AdvansedEmailSelectorTemplate.html",
                    "~/Templates/CommonTemplates.html",
                    "~/Templates/ManagementTemplates.html",
                    "~/Templates/CommentsTemplates.html",
                    "~/Templates/ContainerTemplate.html",
                    "~/Templates/ProgressDialogTemplate.html"
                };
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/POP3/Server/POP3_MessageCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.POP3.Server
{
    #region usings

    using System.Collections;
    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// POP3 messages info collection.
    /// </summary>
    public class POP3_MessageCollection : IEnumerable
    {
        #region Members

        private readonly List<POP3_Message> m_pMessages;

        #endregion

        #region Properties

        /// <summary>
        /// Gets number of messages in the collection.
        /// </summary>
        public int Count
        {
            get { return m_pMessages.Count; }
        }

        /// <summary>
        /// Gets a POP3_Message object in the collection by index number.
        /// </summary>
        /// <param name="index">An Int32 value that specifies the position of the POP3_Message object in the POP3_MessageCollection collection.</param>
        public POP3_Message this[int index]
        {
            get { return m_pMessages[index]; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public POP3_MessageCollection()
        {
            m_pMessages = new List<POP3_Message>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Adds new message info to the collection.
        /// </summary>
        /// <param name="id">Message ID.</param>
        /// <param name="uid">Message UID.</param>
        /// <param name="size">Message size in bytes.</param>
        public POP3_Message Add(string id, string uid, long size)
        {
            return Add(id, uid, size, null);
        }

        /// <summary>
        /// Adds new message info to the collection.
        /// </summary>
        /// <param name="id">Message ID.</param>
        /// <param name="uid">Message UID.</param>
        /// <param name="size">Message size in bytes.</param>
        /// <param name="tag">Message user data.</param>
        public POP3_Message Add(string id, string uid, long size, object tag)
        {
            POP3_Message message = new POP3_Message(this, id, uid, size);
            m_pMessages.Add(message);
            message.Tag = tag;

            return message;
        }

        /// <summary>
        /// Removes specified message from the collection.
        /// </summary>
        /// <param name="message">Message to remove.</param>
        public void Remove(POP3_Message message)
        {
            m_pMessages.Remove(message);
        }

        /// <summary>
        /// Gets if collection contains message with the specified UID.
        /// </summary>
        /// <param name="uid">Message UID to check.</param>
        /// <returns></returns>
        public bool ContainsUID(string uid)
        {
            foreach (POP3_Message message in m_pMessages)
            {
                if (message.UID.ToLower() == uid.ToLower())
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Removes all messages from the collection.
        /// </summary>
        public void Clear()
        {
            m_pMessages.Clear();
        }

        /// <summary>
        /// Checks if message exists. NOTE marked for delete messages returns false.
        /// </summary>
        /// <param name="sequenceNo">Message 1 based sequence number.</param>
        /// <returns></returns>
        public bool MessageExists(int sequenceNo)
        {
            if (sequenceNo > 0 && sequenceNo <= m_pMessages.Count)
            {
                if (!m_pMessages[sequenceNo - 1].MarkedForDelete)
                {
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Gets messages total sizes. NOTE messages marked for deletion is excluded.
        /// </summary>
        /// <returns></returns>
        public long GetTotalMessagesSize()
        {
            long totalSize = 0;
            foreach (POP3_Message msg in m_pMessages)
            {
                if (!msg.MarkedForDelete)
                {
                    totalSize += msg.Size;
                }
            }

            return totalSize;
        }

        /// <summary>
        /// Resets deleted flags on all messages.
        /// </summary>
        public void ResetDeletedFlag()
        {
            foreach (POP3_Message msg in m_pMessages)
            {
                msg.MarkedForDelete = false;
            }
        }

        /// <summary>
        /// Gets enumerator.
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            return m_pMessages.GetEnumerator();
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTP_PayloadTypes.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    /// <summary>
    /// RTP payload specifies data type which is RTP packet.
    /// IANA registered RTP payload types. Defined in http://www.iana.org/assignments/rtp-parameters.
    /// </summary>
    public class RTP_PayloadTypes
    {
        #region Members

        /// <summary>
        /// CELB video codec. Defined in RFC 2029.
        /// </summary>
        public static readonly int CELB = 25;

        /// <summary>
        /// DVI4 11025hz audio codec.
        /// </summary>
        public static readonly int DVI4_11025 = 16;

        /// <summary>
        /// DVI4 16khz audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int DVI4_16000 = 6;

        /// <summary>
        /// DVI4 220505hz audio codec.
        /// </summary>
        public static readonly int DVI4_22050 = 17;

        /// <summary>
        /// DVI4 8khz audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int DVI4_8000 = 5;

        /// <summary>
        /// G722 audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int G722 = 9;

        /// <summary>
        /// G723 audio codec.
        /// </summary>
        public static readonly int G723 = 4;

        /// <summary>
        /// G728 audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int G728 = 15;

        /// <summary>
        /// G729 audio codec.
        /// </summary>
        public static readonly int G729 = 18;

        /// <summary>
        /// GSM audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int GSM = 3;

        /// <summary>
        /// H261 video codec. Defined in RFC 2032.
        /// </summary>
        public static readonly int H261 = 31;

        /// <summary>
        /// H263 video codec.
        /// </summary>
        public static readonly int H263 = 34;

        /// <summary>
        /// JPEG video codec. Defined in RFC 2435.
        /// </summary>
        public static readonly int JPEG = 26;

        /// <summary>
        /// L16 1 channel audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int L16_1CH = 10;

        /// <summary>
        /// L16 2 channel audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int L16_2CH = 11;

        /// <summary>
        /// LPC audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int LPC = 7;

        /// <summary>
        /// MP2T video codec. Defined in RFC 2250.
        /// </summary>
        public static readonly int MP2T = 33;

        /// <summary>
        /// MPA audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int MPA = 14;

        /// <summary>
        /// H261 video codec. Defined in RFC 2250.
        /// </summary>
        public static readonly int MPV = 32;

        /// <summary>
        /// NV video codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int NV = 28;

        /// <summary>
        /// PCMA(a-law) audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int PCMA = 8;

        /// <summary>
        /// PCMU8(u-law) audio codec. Defined in RFC 3551.
        /// </summary>
        public static readonly int PCMU;

        /// <summary>
        /// QCELP audio codec.
        /// </summary>
        public static readonly int QCELP = 12;

        #endregion
    }
}

<|start_filename|>common/ASC.Core.Common/Data/DbTenantService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Utils;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Security.Cryptography;

namespace ASC.Core.Data
{
    public class DbTenantService : DbBaseService, ITenantService
    {
        private static TimeZoneInfo defaultTimeZone;
        private List<string> forbiddenDomains;


        public DbTenantService(ConnectionStringSettings connectionString)
            : base(connectionString, null)
        {
        }


        public void ValidateDomain(string domain)
        {
            using (var db = GetDb())
            {
                ValidateDomain(db, domain, Tenant.DEFAULT_TENANT, true);
            }
        }

        public IEnumerable<Tenant> GetTenants(DateTime from, bool active = true)
        {
            return GetTenants(
                Exp.And(
                    active
                        ? Exp.Eq("t.status", (int)TenantStatus.Active)
                        : Exp.Empty,
                    from != default(DateTime)
                        ? Exp.Ge("last_modified", from)
                        : Exp.Empty
                    )
                );
        }

        public IEnumerable<Tenant> GetTenants(string login, string passwordHash)
        {
            if (string.IsNullOrEmpty(login)) throw new ArgumentNullException("login");

            if (passwordHash == null)
            {
                var q = TenantsQuery(Exp.Empty)
                    .InnerJoin("core_user u", Exp.EqColumns("t.id", "u.tenant"))
                    .Where("t.status", (int)TenantStatus.Active)
                    .Where(login.Contains('@') ? "u.email" : "u.id", login)
                    .Where("u.status", EmployeeStatus.Active)
                    .Where("u.removed", false);

                return ExecList(q).ConvertAll(ToTenant);
            }

            Guid userId;
            if (Guid.TryParse(login, out userId))
            {
                var q = TenantsQuery(Exp.Empty)
                    .InnerJoin("core_user u", Exp.EqColumns("t.id", "u.tenant"))
                    .InnerJoin("core_usersecurity s", Exp.EqColumns("u.id", "s.userid"))
                    .Where("t.status", (int)TenantStatus.Active)
                    .Where("u.id", userId)
                    .Where("u.status", EmployeeStatus.Active)
                    .Where("u.removed", false)
                    .Where(Exp.Or(
                            Exp.Eq("s.pwdhash", GetPasswordHash(userId, passwordHash)),
                            Exp.Eq("s.pwdhash", Hasher.Base64Hash(passwordHash, HashAlg.SHA256)) //todo: remove old scheme
                        ));

                return ExecList(q).ConvertAll(ToTenant);
            }
            else
            {
                var q = TenantsQuery(Exp.Empty)
                    .InnerJoin("core_user u", Exp.EqColumns("t.id", "u.tenant"))
                    .InnerJoin("core_usersecurity s", Exp.EqColumns("u.id", "s.userid"))
                    .Where("t.status", (int)TenantStatus.Active)
                    .Where(login.Contains('@') ? "u.email" : "u.id", login)
                    .Where("u.status", EmployeeStatus.Active)
                    .Where("u.removed", false)
                    .Where("s.pwdhash", Hasher.Base64Hash(passwordHash, HashAlg.SHA256));

                //old password
                var result = ExecList(q).ConvertAll(ToTenant);

                var usersQuery = new SqlQuery("core_user u")
                    .Select("u.id")
                    .Where("u.email", login)
                    .Where("u.status", EmployeeStatus.Active)
                    .Where("u.removed", false);

                var passwordHashs = ExecList(usersQuery).ConvertAll(r =>
                        GetPasswordHash(new Guid((string)r[0]), passwordHash)
                    );

                q = TenantsQuery(Exp.Empty)
                    .InnerJoin("core_usersecurity s", Exp.EqColumns("t.id", "s.tenant"))
                    .Where("t.status", (int)TenantStatus.Active)
                    .Where(Exp.In("s.pwdhash", passwordHashs));

                //new password
                result = result.Concat(ExecList(q).ConvertAll(ToTenant)).ToList();
                result.Distinct();

                return result;
            }
        }

        public Tenant GetTenant(int id)
        {
            return GetTenants(Exp.Eq("id", id))
                .SingleOrDefault();
        }

        public Tenant GetTenant(string domain)
        {
            if (string.IsNullOrEmpty(domain)) throw new ArgumentNullException("domain");

            return GetTenants(Exp.Eq("alias", domain.ToLowerInvariant()) | Exp.Eq("mappeddomain", domain.ToLowerInvariant()))
                .OrderBy(a => a.Status == TenantStatus.Restoring ? TenantStatus.Active : a.Status)
                .ThenByDescending(a => a.Status == TenantStatus.Restoring ? 0 : a.TenantId)
                .FirstOrDefault();
        }

        public Tenant GetTenantForStandaloneWithoutAlias(string ip)
        {
            return GetTenants(Exp.Empty)
                .OrderBy(a => a.Status)
                .ThenByDescending(a => a.TenantId)
                .FirstOrDefault();
        }

        public Tenant SaveTenant(Tenant t)
        {
            if (t == null) throw new ArgumentNullException("tenant");

            using (var db = GetDb())
            using (var tx = db.BeginTransaction())
            {
                if (!string.IsNullOrEmpty(t.MappedDomain))
                {
                    var baseUrl = TenantUtil.GetBaseDomain(t.HostedRegion);

                    if (baseUrl != null && t.MappedDomain.EndsWith("." + baseUrl, StringComparison.InvariantCultureIgnoreCase))
                    {
                        ValidateDomain(db, t.MappedDomain.Substring(0, t.MappedDomain.Length - baseUrl.Length - 1), t.TenantId, false);
                    }
                    else
                    {
                        ValidateDomain(db, t.MappedDomain, t.TenantId, false);
                    }
                }

                if (t.TenantId == Tenant.DEFAULT_TENANT)
                {
                    var q = new SqlQuery("tenants_version")
                        .Select("id")
                        .Where(Exp.Eq("default_version", 1) | Exp.Eq("id", 0))
                        .OrderBy(1, false)
                        .SetMaxResults(1);
                    t.Version = db.ExecuteScalar<int>(q);

                    var i = new SqlInsert("tenants_tenants")
                        .InColumnValue("id", t.TenantId)
                        .InColumnValue("alias", t.TenantAlias.ToLowerInvariant())
                        .InColumnValue("mappeddomain", !string.IsNullOrEmpty(t.MappedDomain) ? t.MappedDomain.ToLowerInvariant() : null)
                        .InColumnValue("version", t.Version)
                        .InColumnValue("version_changed", t.VersionChanged)
                        .InColumnValue("name", t.Name ?? t.TenantAlias)
                        .InColumnValue("language", t.Language)
                        .InColumnValue("timezone", t.TimeZone.Id)
                        .InColumnValue("owner_id", t.OwnerId.ToString())
                        .InColumnValue("trusteddomains", t.GetTrustedDomains())
                        .InColumnValue("trusteddomainsenabled", (int)t.TrustedDomainsType)
                        .InColumnValue("creationdatetime", t.CreatedDateTime)
                        .InColumnValue("status", (int)t.Status)
                        .InColumnValue("statuschanged", t.StatusChangeDate)
                        .InColumnValue("payment_id", t.PaymentId)
                        .InColumnValue("last_modified", t.LastModified = DateTime.UtcNow)
                        .InColumnValue("industry", (int)t.Industry)
                        .InColumnValue("spam", t.Spam)
                        .InColumnValue("calls", t.Calls)
                        .Identity<int>(0, t.TenantId, true);


                    t.TenantId = db.ExecuteScalar<int>(i);
                }
                else
                {
                    var u = new SqlUpdate("tenants_tenants")
                        .Set("alias", t.TenantAlias.ToLowerInvariant())
                        .Set("mappeddomain", !string.IsNullOrEmpty(t.MappedDomain) ? t.MappedDomain.ToLowerInvariant() : null)
                        .Set("version", t.Version)
                        .Set("version_changed", t.VersionChanged)
                        .Set("name", t.Name ?? t.TenantAlias)
                        .Set("language", t.Language)
                        .Set("timezone", t.TimeZone.Id)
                        .Set("owner_id", t.OwnerId.ToString())
                        .Set("trusteddomains", t.GetTrustedDomains())
                        .Set("trusteddomainsenabled", (int)t.TrustedDomainsType)
                        .Set("creationdatetime", t.CreatedDateTime)
                        .Set("status", (int)t.Status)
                        .Set("statuschanged", t.StatusChangeDate)
                        .Set("payment_id", t.PaymentId)
                        .Set("last_modified", t.LastModified = DateTime.UtcNow)
                        .Set("industry", (int)t.Industry)
                        .Set("spam", t.Spam)
                        .Set("calls", t.Calls)
                        .Where("id", t.TenantId);

                    db.ExecuteNonQuery(u);
                }

                if (string.IsNullOrEmpty(t.PartnerId) && string.IsNullOrEmpty(t.AffiliateId) && string.IsNullOrEmpty(t.Campaign))
                {
                    var d = new SqlDelete("tenants_partners").Where("tenant_id", t.TenantId);
                    db.ExecuteNonQuery(d);
                }
                else
                {
                    var i = new SqlInsert("tenants_partners", true)
                        .InColumnValue("tenant_id", t.TenantId)
                        .InColumnValue("partner_id", t.PartnerId)
                        .InColumnValue("affiliate_id", t.AffiliateId)
                        .InColumnValue("campaign", t.Campaign);
                    db.ExecuteNonQuery(i);
                }

                tx.Commit();
            }
            //CalculateTenantDomain(t);
            return t;
        }

        public void RemoveTenant(int id, bool auto = false)
        {
            var postfix = auto ? "_auto_deleted" : "_deleted";

            using (var db = GetDb())
            using (var tx = db.BeginTransaction())
            {
                var alias = db.ExecuteScalar<string>(new SqlQuery("tenants_tenants").Select("alias").Where("id", id));
                var count = db.ExecuteScalar<int>(new SqlQuery("tenants_tenants").SelectCount().Where(Exp.Like("alias", alias + postfix, SqlLike.StartWith)));
                db.ExecuteNonQuery(
                    new SqlUpdate("tenants_tenants")
                        .Set("alias", alias + postfix + (count > 0 ? count.ToString() : ""))
                        .Set("status", TenantStatus.RemovePending)
                        .Set("statuschanged", DateTime.UtcNow)
                        .Set("last_modified", DateTime.UtcNow)
                        .Where("id", id));

                tx.Commit();
            }
        }

        public IEnumerable<TenantVersion> GetTenantVersions()
        {
            var q = new SqlQuery("tenants_version")
                .Select("id", "version")
                .Where("visible", true);
            return ExecList(q)
                .ConvertAll(r => new TenantVersion(Convert.ToInt32(r[0]), (string)r[1]));
        }


        public byte[] GetTenantSettings(int tenant, string key)
        {
            return ExecScalar<byte[]>(new SqlQuery("core_settings").Select("value").Where("tenant", tenant).Where("id", key));
        }

        public void SetTenantSettings(int tenant, string key, byte[] data)
        {
            var i = data == null || data.Length == 0 ?
                (ISqlInstruction)new SqlDelete("core_settings").Where("tenant", tenant).Where("id", key) :
                (ISqlInstruction)new SqlInsert("core_settings", true).InColumns("tenant", "id", "value").Values(tenant, key, data);
            ExecNonQuery(i);
        }

        private IEnumerable<Tenant> GetTenants(Exp where)
        {
            var q = TenantsQuery(where);
            return ExecList(q).ConvertAll(ToTenant);
        }

        private static SqlQuery TenantsQuery(Exp where)
        {
            return new SqlQuery("tenants_tenants t")
                .Select("t.id", "t.alias", "t.mappeddomain", "t.version", "t.version_changed", "t.name", "t.language", "t.timezone", "t.owner_id")
                .Select("t.trusteddomains", "t.trusteddomainsenabled", "t.creationdatetime", "t.status", "t.statuschanged", "t.payment_id", "t.last_modified")
                .Select("p.partner_id", "p.affiliate_id", "p.campaign")
                .Select("t.industry", "t.spam", "t.calls")
                .LeftOuterJoin("tenants_partners p", Exp.EqColumns("t.id", "p.tenant_id"))
                .Where(where);
        }

        private Tenant ToTenant(object[] r)
        {
            var tenant = new Tenant(Convert.ToInt32(r[0]), (string)r[1])
            {
                MappedDomain = (string)r[2],
                Version = Convert.ToInt32(r[3]),
                VersionChanged = Convert.ToDateTime(r[4]),
                Name = (string)r[5],
                Language = (string)r[6],
                TimeZone = GetTimeZone((string)r[7]),
                OwnerId = r[8] != null ? new Guid((string)r[8]) : Guid.Empty,
                TrustedDomainsType = (TenantTrustedDomainsType)Convert.ToInt32(r[10]),
                CreatedDateTime = (DateTime)r[11],
                Status = (TenantStatus)Convert.ToInt32(r[12]),
                StatusChangeDate = r[13] != null ? (DateTime)r[13] : default(DateTime),
                PaymentId = (string)r[14],
                LastModified = (DateTime)r[15],
                PartnerId = (string)r[16],
                AffiliateId = (string)r[17],
                Campaign = (string)r[18],
                Industry = r[18] != null ? (TenantIndustry)Convert.ToInt32(r[19]) : TenantIndustry.Other,
                Spam = Convert.ToBoolean(r[20]),
                Calls = Convert.ToBoolean(r[21]),
            };
            tenant.SetTrustedDomains((string)r[9]);

            return tenant;
        }

        private TimeZoneInfo GetTimeZone(string zoneId)
        {
            if (defaultTimeZone == null)
            {
                try
                {
                    var tz = TimeZoneInfo.Local;
                    if (Path.DirectorySeparatorChar == '/')
                    {
                        if (tz.StandardName == "UTC" || tz.StandardName == "UCT")
                        {
                            tz = TimeZoneInfo.Utc;
                        }
                        else
                        {
                            var id = string.Empty;
                            if (File.Exists("/etc/timezone"))
                            {
                                id = File.ReadAllText("/etc/timezone").Trim();
                            }

                            if (string.IsNullOrEmpty(id))
                            {
                                var psi = new ProcessStartInfo
                                {
                                    FileName = "/bin/bash",
                                    Arguments = "date +%Z",
                                    RedirectStandardOutput = true,
                                    UseShellExecute = false,
                                };
                                using (var p = Process.Start(psi))
                                {
                                    if (p.WaitForExit(1000))
                                    {
                                        id = p.StandardOutput.ReadToEnd();
                                    }
                                    p.Close();
                                }
                            }
                            if (!string.IsNullOrEmpty(id))
                            {
                                tz = TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(z => z.Id == id) ?? tz;
                            }
                        }
                    }
                    defaultTimeZone = tz;
                }
                catch (Exception)
                {
                    // ignore
                    defaultTimeZone = TimeZoneInfo.Utc;
                }
            }

            return string.IsNullOrEmpty(zoneId) ? defaultTimeZone : TimeZoneConverter.GetTimeZone(zoneId);
        }

        private void ValidateDomain(IDbManager db, string domain, int tenantId, bool validateCharacters)
        {
            // size
            TenantDomainValidator.ValidateDomainLength(domain);

            // characters
            if (validateCharacters)
            {
                TenantDomainValidator.ValidateDomainCharacters(domain);
            }

            // forbidden or exists
            var exists = false;
            domain = domain.ToLowerInvariant();
            if (!exists)
            {
                if (forbiddenDomains == null)
                {
                    forbiddenDomains = ExecList(new SqlQuery("tenants_forbiden").Select("address")).Select(r => (string)r[0]).ToList();
                }
                exists = tenantId != 0 && forbiddenDomains.Contains(domain);
            }
            if (!exists)
            {
                exists = 0 < db.ExecuteScalar<int>(new SqlQuery("tenants_tenants").SelectCount().Where(Exp.Eq("alias", domain) & !Exp.Eq("id", tenantId)));
            }
            if (!exists)
            {
                exists = 0 < db.ExecuteScalar<int>(new SqlQuery("tenants_tenants").SelectCount()
                    .Where(Exp.Eq("mappeddomain", domain) & !Exp.Eq("id", tenantId) & !Exp.In("status", new[] { (int)TenantStatus.RemovePending, (int)TenantStatus.Restoring })));
            }
            if (exists)
            {
                // cut number suffix
                while (true)
                {
                    if (6 < domain.Length && char.IsNumber(domain, domain.Length - 1))
                    {
                        domain = domain.Substring(0, domain.Length - 1);
                    }
                    else
                    {
                        break;
                    }
                }

                var q = new SqlQuery("tenants_forbiden").Select("address").Where(Exp.Like("address", domain, SqlLike.StartWith))
                    .Union(new SqlQuery("tenants_tenants").Select("alias").Where(Exp.Like("alias", domain, SqlLike.StartWith) & !Exp.Eq("id", tenantId)))
                    .Union(new SqlQuery("tenants_tenants").Select("mappeddomain")
                        .Where(Exp.Like("mappeddomain", domain, SqlLike.StartWith) & !Exp.Eq("id", tenantId) & !Exp.Eq("status", (int)TenantStatus.RemovePending)));

                var existsTenants = db.ExecuteList(q).ConvertAll(r => (string)r[0]);
                throw new TenantAlreadyExistsException("Address busy.", existsTenants);
            }
        }
    }
}


<|start_filename|>common/ASC.ActiveDirectory/ComplexOperations/Data/LdapItemChange.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace ASC.ActiveDirectory.ComplexOperations.Data
{
    public class LdapItemChange
    {
        [JsonConverter(typeof(StringEnumConverter))]
        public LdapItemChangeKey Key { get; private set; }

        public string Before { get; private set; }
        public string After { get; private set; }

        public bool IsChanged { get; private set; }

        public LdapItemChange(LdapItemChangeKey key, string before, string after)
        {
            Key = key;
            Before = before;
            After = after;

            IsChanged = Before != null && !Before.Equals(After) || After != null && !After.Equals(Before);
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Client/Bundling/DiscTransform.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Web.Optimization;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Data.Storage;
using ASC.Data.Storage.Configuration;
using ASC.Data.Storage.DiscStorage;

namespace ASC.Web.Core.Client.Bundling
{
    class DiscTransform : IBundleTransform
    {
        private static readonly ILog log;

        public static readonly bool SuccessInitialized;

        const string BaseVirtualPath = "/discbundle/";
        static readonly string BaseStoragePath;

        static DiscTransform()
        {
            try
            {
                log = LogManager.GetLogger("ASC.Web.Bundle.DiscTransform");

                var section = (StorageConfigurationSection)ConfigurationManagerExtension.GetSection("storage");
                if (section == null)
                {
                    throw new Exception("Storage section not found.");
                }

                foreach (HandlerConfigurationElement h in section.Handlers)
                {
                    if (h.Name == "disc")
                    {
                        BaseStoragePath = Path.Combine(h.HandlerProperties["$STORAGE_ROOT"].Value, "bundle");
                        break;
                    }
                }

                if (!string.IsNullOrEmpty(BaseStoragePath))
                {
                    DiscDataHandler.RegisterVirtualPath(BaseVirtualPath, GetFullPhysicalPath("/"), true);
                    SuccessInitialized = CoreContext.Configuration.Standalone && !StaticUploader.CanUpload();
                }
            }
            catch (Exception fatal)
            {
                log.Fatal(fatal);
            }
        }

        public void Process(BundleContext context, BundleResponse response)
        {
            if (!SuccessInitialized || !BundleTable.Bundles.UseCdn) return;

            try
            {
                var bundle = context.BundleCollection.GetBundleFor(context.BundleVirtualPath);
                if (bundle != null)
                {
                    UploadToDisc(new CdnItem { Bundle = bundle, Response = response });
                }
            }
            catch (Exception fatal)
            {
                log.Fatal(fatal);
                throw;
            }
        }

        private static void UploadToDisc(CdnItem item)
        {
            var filePath = GetFullFileName(item.Bundle.Path, item.Response.ContentType).TrimStart('/');
            var fullFilePath = GetFullPhysicalPath(filePath);

            try
            {
                using (var mutex = new Mutex(true, filePath))
                {
                    var wait = mutex.WaitOne(60000);

                    try
                    {
                        CreateDir(fullFilePath);

                        if (!File.Exists(fullFilePath))
                        {
                            var gzip = ClientSettings.GZipEnabled;

                            using (var fs = File.OpenWrite(fullFilePath))
                            using (var tw = new StreamWriter(fs))
                            {
                                tw.WriteLine(item.Response.Content);
                            }

                            item.Bundle.CdnPath = GetUri(filePath);

                            if (gzip)
                            {
                                using (var fs = File.OpenWrite(fullFilePath + ".gz"))
                                using (var zip = new GZipStream(fs, CompressionMode.Compress, true))
                                using (var tw = new StreamWriter(zip))
                                {
                                    tw.WriteLine(item.Response.Content);
                                }
                            }

                        }
                        else
                        {
                            item.Bundle.CdnPath = GetUri(item.Bundle.Path, item.Response.ContentType);
                        }
                    }
                    finally
                    {
                        if (wait)
                        {
                            mutex.ReleaseMutex();
                        }
                    }
                }
            }
            catch (Exception err)
            {
                log.Error(err);
            }
        }

        internal static string GetUri(string path)
        {
            return BaseVirtualPath + path.TrimStart('/');
        }

        internal static string GetUri(string path, string contentType)
        {
            return GetUri(GetFullFileName(path, contentType));
        }

        internal static string GetFullFileName(string path, string contentType)
        {
            var href = Path.GetFileNameWithoutExtension(path);
            var category = GetCategoryFromPath(path);

            var hrefTokenSource = href;

            if (Uri.IsWellFormedUriString(href, UriKind.Relative))
                hrefTokenSource = (SecureHelper.IsSecure() ? "https" : "http") + href;

            var hrefToken = string.Concat(HttpServerUtility.UrlTokenEncode(MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(hrefTokenSource))));

            if (string.Compare(contentType, "text/css", StringComparison.OrdinalIgnoreCase) == 0)
                return string.Format("/{0}/css/{1}.css", category, hrefToken);

            return string.Format("/{0}/javascript/{1}.js", category, hrefToken);
        }

        internal static bool IsFile(string path)
        {
            var filePath = GetFullPhysicalPath(path);
            var staticPath = GetFullStaticPhysicalPath(path);
            if (!File.Exists(filePath) && File.Exists(staticPath))
            {
                using (var mutex = new Mutex(true, path))
                {
                    mutex.WaitOne();

                    try
                    {
                        CreateDir(filePath);

                        if (File.Exists(staticPath))
                        {
                            File.Copy(staticPath, filePath, true);
                        }

                        if (File.Exists(staticPath + ".gz"))
                        {
                            File.Copy(staticPath + ".gz", filePath + ".gz", true);
                        }
                    }
                    finally
                    {
                        mutex.ReleaseMutex();
                    }
                }
            }

            return File.Exists(filePath);
        }

        private static string GetCategoryFromPath(string controlPath)
        {
            var result = "common";

            controlPath = controlPath.ToLower();
            var matches = Regex.Match(controlPath, "~/(\\w+)/(\\w+)-(\\w+)/?", RegexOptions.Compiled);

            if (matches.Success && matches.Groups.Count > 3 && matches.Groups[2].Success)
                result = matches.Groups[2].Value;

            return result;
        }

        private static string GetFullPhysicalPath(string path)
        {
            return Path.GetFullPath(Path.Combine(HttpContext.Current.Server.MapPath("~/"), BaseStoragePath, path.TrimStart('/')));
        }

        private static string GetFullStaticPhysicalPath(string path)
        {
            return Path.GetFullPath(Path.Combine(HttpContext.Current.Server.MapPath("~/"), "App_Data/static/bundle/", path.TrimStart('/')));
        }

        private static void CreateDir(string path)
        {
            var dir = Path.GetDirectoryName(path);
            if (dir != null && !Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
        }
    }
}

<|start_filename|>common/ASC.Common/Data/Sql/SqlQuery.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

using ASC.Common.Data.Sql.Expressions;

namespace ASC.Common.Data.Sql
{
    [DebuggerTypeProxy(typeof(SqlDebugView))]
    public class SqlQuery : ISqlInstruction
    {
        private readonly List<ISqlInstruction> columns = new List<ISqlInstruction>();
        private readonly ArrayList groups = new ArrayList();
        private readonly List<JoinInfo> joins = new List<JoinInfo>();
        private readonly List<ISqlInstruction> tables = new List<ISqlInstruction>();
        private readonly List<UnionInfo> unions = new List<UnionInfo>();
        private bool distinct;
        private int firstResult;
        private Exp having;
        private int maxResults;
        protected IDictionary<object, bool> orders = new Dictionary<object, bool>();
        private bool selectAll;
        protected Exp where;
        private bool forupdate;
        private string index;


        public SqlQuery()
        {
        }

        public SqlQuery(string table)
        {
            From(table);
        }

        #region ISqlInstruction Members

        public string ToString(ISqlDialect dialect)
        {
            var sql = new StringBuilder();

            sql.Append("select ");
            if (distinct) sql.Append("distinct ");
            if (selectAll)
            {
                sql.Append("*");
            }
            else
            {
                columns.ForEach(column => sql.AppendFormat("{0}, ", column.ToString(dialect)));
                sql.Remove(sql.Length - 2, 2);
            }

            if (0 < tables.Count)
            {
                sql.Append(" from ");
                tables.ForEach(table => sql.AppendFormat("{0}, ", table.ToString(dialect)));
                sql.Remove(sql.Length - 2, 2);
            }

            if (!string.IsNullOrEmpty(index))
            {
                sql.AppendFormat(" {0}", dialect.UseIndex(index));
            }

            if (0 < joins.Count)
            {
                foreach (JoinInfo join in joins)
                {
                    if (join.JoinType == SqlJoin.Inner) sql.Append(" inner join ");
                    if (join.JoinType == SqlJoin.LeftOuter) sql.Append(" left outer join ");
                    if (join.JoinType == SqlJoin.RightOuter) sql.Append(" right outer join ");
                    sql.AppendFormat("{0} on {1}", join.With.ToString(dialect), join.On.ToString(dialect));
                }
            }

            if (where != Exp.Empty) sql.AppendFormat(" where {0}", where.ToString(dialect));

            if (0 < groups.Count)
            {
                sql.Append(" group by ");
                foreach (object group in groups)
                {
                    sql.AppendFormat("{0}, ", group.ToString());
                }
                sql.Remove(sql.Length - 2, 2);
            }

            if (having != Exp.Empty) sql.AppendFormat(" having {0}", having.ToString(dialect));

            if (0 < orders.Count)
            {
                sql.Append(" order by ");
                foreach (var order in orders)
                {
                    sql.Append(order.Key.ToString());
                    sql.AppendFormat(" {0}, ", order.Value ? "asc" : "desc");
                }
                sql.Remove(sql.Length - 2, 2);
            }

            if (0 < maxResults)
            {
                sql.AppendFormat(" limit {0}", maxResults);
                if (0 < firstResult) sql.AppendFormat(" offset {0}", firstResult);
            }

            if (forupdate)
            {
                sql.Append(" for update");
            }

            unions.ForEach(u => sql.AppendFormat(" union {0}{1}", u.UnionAll ? "all " : string.Empty, u.Query.ToString(dialect)));
            return sql.ToString();
        }

        public object[] GetParameters()
        {
            var parameters = new List<object>();
            columns.ForEach(column => parameters.AddRange(column.GetParameters()));
            tables.ForEach(table => parameters.AddRange(table.GetParameters()));
            foreach (JoinInfo join in joins)
            {
                parameters.AddRange(join.With.GetParameters());
                parameters.AddRange(join.On.GetParameters());
            }
            if (where != Exp.Empty) parameters.AddRange(where.GetParameters());
            if (having != Exp.Empty) parameters.AddRange(having.GetParameters());
            unions.ForEach(u => parameters.AddRange(u.Query.GetParameters()));
            return parameters.ToArray();
        }

        #endregion


        public SqlQuery From(params string[] tables)
        {
            Array.ForEach(tables, table => this.tables.Add((SqlIdentifier)table));
            return this;
        }

        public SqlQuery From(SqlQuery subQuery)
        {
            return From(subQuery, null);
        }

        public SqlQuery From(SqlQuery subQuery, string alias)
        {
            tables.Add(new AsExp(subQuery, alias));
            return this;
        }

        public SqlQuery UseIndex(string index)
        {
            this.index = index;
            return this;
        }

        private SqlQuery Join(SqlJoin join, ISqlInstruction instruction, Exp on)
        {
            joins.Add(new JoinInfo(join, instruction, on));
            return this;
        }

        public SqlQuery InnerJoin(string table, Exp on)
        {
            return Join(SqlJoin.Inner, new SqlIdentifier(table), on);
        }

        public SqlQuery LeftOuterJoin(string table, Exp on)
        {
            return Join(SqlJoin.LeftOuter, new SqlIdentifier(table), on);
        }

        public SqlQuery RightOuterJoin(string table, Exp on)
        {
            return Join(SqlJoin.RightOuter, new SqlIdentifier(table), on);
        }

        public SqlQuery InnerJoin(SqlQuery subQuery, Exp on)
        {
            return InnerJoin(subQuery, string.Empty, on);
        }

        public SqlQuery LeftOuterJoin(SqlQuery subQuery, Exp on)
        {
            return LeftOuterJoin(subQuery, string.Empty, on);
        }

        public SqlQuery RightOuterJoin(SqlQuery subQuery, Exp on)
        {
            return RightOuterJoin(subQuery, string.Empty, on);
        }

        public SqlQuery InnerJoin(SqlQuery subQuery, string alias, Exp on)
        {
            return Join(SqlJoin.Inner, new AsExp(subQuery, alias), on);
        }

        public SqlQuery LeftOuterJoin(SqlQuery subQuery, string alias, Exp on)
        {
            return Join(SqlJoin.LeftOuter, new AsExp(subQuery, alias), on);
        }

        public SqlQuery RightOuterJoin(SqlQuery subQuery, string alias, Exp on)
        {
            return Join(SqlJoin.RightOuter, new AsExp(subQuery, alias), on);
        }

        public SqlQuery Select(string column)
        {
            columns.Add((SqlIdentifier)column);
            return this;
        }

        public SqlQuery Select(params string[] columns)
        {
            this.columns.AddRange(columns.Select(r => (SqlIdentifier)r));
            return this;
        }

        public SqlQuery Select(SqlQuery subQuery, string alias = null)
        {
            columns.Add(new AsExp(subQuery, alias));
            return this;
        }

        public SqlQuery Select(ISqlInstruction instraction)
        {
            columns.Add(instraction);
            return this;
        }

        public SqlQuery SelectAll()
        {
            selectAll = true;
            return this;
        }

        public SqlQuery SelectCount()
        {
            selectAll = false;
            columns.Add(new SelectAgregate(AgregateType.count));
            return this;
        }

        public SqlQuery SelectCount(string column)
        {
            selectAll = false;
            columns.Add(new SelectAgregate(AgregateType.count, column));
            return this;
        }

        public SqlQuery SelectMin(string column)
        {
            selectAll = false;
            columns.Add(new SelectAgregate(AgregateType.min, column));
            return this;
        }

        public SqlQuery SelectMax(string column)
        {
            selectAll = false;
            columns.Add(new SelectAgregate(AgregateType.max, column));
            return this;
        }

        public SqlQuery SelectAvg(string column)
        {
            selectAll = false;
            columns.Add(new SelectAgregate(AgregateType.avg, column));
            return this;
        }

        public SqlQuery SelectSum(string column)
        {
            selectAll = false;
            columns.Add(new SelectAgregate(AgregateType.sum, column));
            return this;
        }

        public SqlQuery Distinct()
        {
            distinct = true;
            return this;
        }

        public SqlQuery Where(Exp exp)
        {
            where = where & exp;
            return this;
        }

        public SqlQuery Where(string sql)
        {
            return Where(new SqlExp(sql));
        }

        public SqlQuery Where(string column, object value)
        {
            return Where(new EqExp(column, value));
        }

        public SqlQuery OrderBy(string column, bool asc)
        {
            orders.Add(column, asc);
            return this;
        }

        public SqlQuery OrderBy(int positin, bool asc)
        {
            orders.Add(positin, asc);
            return this;
        }

        public SqlQuery GroupBy(params string[] columns)
        {
            groups.AddRange(columns);
            return this;
        }

        public SqlQuery GroupBy(params int[] positins)
        {
            groups.AddRange(positins);
            return this;
        }

        public SqlQuery Having(Exp having)
        {
            this.having = having;
            return this;
        }

        public SqlQuery SetFirstResult(int firstResult)
        {
            this.firstResult = firstResult;
            return this;
        }

        public SqlQuery SetMaxResults(int maxResults)
        {
            this.maxResults = maxResults;
            return this;
        }

        public SqlQuery Union(params SqlQuery[] queries)
        {
            foreach (var q in queries)
            {
                unions.Add(new UnionInfo(q, false));
            }
            return this;
        }

        public SqlQuery UnionAll(params SqlQuery[] queries)
        {
            foreach (var q in queries)
            {
                unions.Add(new UnionInfo(q, true));
            }
            return this;
        }

        public SqlQuery ForUpdate(bool forupdate)
        {
            this.forupdate = forupdate;
            return this;
        }

        public override string ToString()
        {
            return ToString(SqlDialect.Default);
        }


        private class JoinInfo
        {
            public readonly SqlJoin JoinType;
            public readonly Exp On;
            public readonly ISqlInstruction With;

            public JoinInfo(SqlJoin joinType, ISqlInstruction with, Exp on)
            {
                With = with;
                JoinType = joinType;
                On = on;
            }
        }

        private enum SqlJoin
        {
            LeftOuter,
            RightOuter,
            Inner
        }

        private class UnionInfo
        {
            public readonly SqlQuery Query;
            public readonly bool UnionAll;

            public UnionInfo(SqlQuery query, bool unionAll)
            {
                Query = query;
                UnionAll = unionAll;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/App_Themes/default/css/projectaction.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.mainContainerClass > .containerHeaderBlock table td > div:last-child {
    display: none;
}

#pageHeader #TemplatesComboboxContainer {
    float: right;
    padding-top: 4px;
    margin-right: 5px;
}

#pageHeader #TemplatesComboboxContainer .viewSwitcherItem {
    padding: 0px;
    margin-right: 4px;
}

.dottedHeader .headerPanel {
    display: inline-block;
    border-bottom: 1px dotted #3C4046;
    cursor: pointer;
}

#projectTitleContainer .inputTitleContainer,
#projectTagsContainer .dottedHeaderContent {
    width: 500px;
}

#projectDescriptionContainer textarea {
    resize: vertical;
}

#projectManagerContainer .headerPanelSmall,
#projectTeamContainer .headerPanelSmall,
#projectStatusContainer .headerPanelSmall {
    margin-bottom:15px;
}

#projectManagerContainer .notifyManagerContainer {
    padding-top: 10px;
}

#notifyManagerCheckbox {
    margin: 3px 0px 0px;
    padding: 0px;
    float: left;
}

#projectManagerContainer label {
    padding-left: 5px;
}

#projectStatusContainer {
    margin-top: 28px;
    margin-bottom: 24px;
}

#projectStatusContainer .headerPanel {
    margin-bottom: 7px;
}

#projectTeamContainer {
    margin-bottom: 19px;
}

#projectParticipantsContainer {
    display: none;
    overflow: auto;
    margin-top: 20px;
    margin-bottom: 20px;
}

#projectContactsContainer {
    margin-bottom: 20px;
}

    #projectContactsContainer.border-bottom {
        border-bottom: 1px solid #D1D1D1;
    }

    #projectContactsContainer .no-linked-contacts {
        display: none;
    }

    #projectContactsContainer .headerPanelSmall {
        margin-bottom: 10px;
    }

    #projectContactsContainer .crm-contact {
        border-top: 1px solid #D1D1D1;
        padding: 9px 20px;
    }

#projectTagsContainer .describe-text {
    margin-bottom: 12px;
}

.checkboxContainer,
#projectTagsContainer {
    margin-bottom: 22px;
}

#tagsContainer {
    margin-top: 12px;
    display: block;
}

.checkboxContainer input[type='checkbox'] {
    margin: 3px 0px 0px;
    padding: 0px;
    float: left;
}

.checkboxContainer label {
    padding-left: 5px;
}

#projectActionsContainer #projectDeleteButton {
    margin-right: 0px;
    float: right;
    line-height: 17px;
}

.HelpCenterSwitcher {
    margin-left: 5px;
}

#projectManager {
    display: none;
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/UserControls/TabsContainerPart.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Core;

namespace ASC.Web.Talk.UserControls
{
    public partial class TabsContainerPart : UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterBodyScripts("~/addons/talk/js/talk.tabscontainer.js");
            Page.RegisterInlineScript("ASC.TMTalk.tabsContainer.init();");
        }

        private string _topLogo = "";
        public string TopLogo
        {
            get
            {
                if (!String.IsNullOrEmpty(_topLogo)) return _topLogo;

                _topLogo = TenantLogoManager.GetTopLogo(!TenantLogoManager.IsRetina(Request));

                return _topLogo;
            }
            set { _topLogo = value; }
        }


        protected string GetAbsoluteCompanyTopLogoPath()
        {
            return string.IsNullOrEmpty(SetupInfo.MainLogoURL) ? TopLogo : SetupInfo.MainLogoURL;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/DocumentsEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Mail.Core.Dao.Expressions.Attachment;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Data.Storage;
using ASC.Mail.Utils;

namespace ASC.Mail.Core.Engine
{
    public class DocumentsEngine
    {
        public const string MY_DOCS_FOLDER_ID = "@my";
        private readonly int _tenantId;
        private readonly string _userId;

        private int Tenant
        {
            get { return _tenantId; }
        }

        private string User
        {
            get { return _userId; }
        }

        private string HttpContextScheme { get; set; }

        public DocumentsEngine(int tenant, string user, string httpContextScheme)
        {
            _tenantId = tenant;
            _userId = user;

            HttpContextScheme = httpContextScheme;

            if (SecurityContext.IsAuthenticated) return;

            CoreContext.TenantManager.SetCurrentTenant(Tenant);
            SecurityContext.AuthenticateMe(new Guid(_userId));
        }

        public List<object> StoreAttachmentsToMyDocuments(int messageId)
        {
            return StoreAttachmentsToDocuments(messageId, MY_DOCS_FOLDER_ID);
        }

        public object StoreAttachmentToMyDocuments(int attachmentId)
        {
            return StoreAttachmentToDocuments(attachmentId, MY_DOCS_FOLDER_ID);
        }

        public List<object> StoreAttachmentsToDocuments(int messageId, string folderId)
        {
            var engine = new EngineFactory(Tenant, User);
            var attachments =
                engine.AttachmentEngine.GetAttachments(new ConcreteMessageAttachmentsExp(messageId, Tenant, User));

            return
                attachments.Select(attachment => StoreAttachmentToDocuments(attachment, folderId))
                    .Where(uploadedFileId => uploadedFileId != null)
                    .ToList();
        }

        public object StoreAttachmentToDocuments(int attachmentId, string folderId)
        {
            var engine = new EngineFactory(Tenant, User);
            var attachment = engine.AttachmentEngine.GetAttachment(
                new ConcreteUserAttachmentExp(attachmentId, Tenant, User));

            if (attachment == null)
                return -1;

            return StoreAttachmentToDocuments(attachment, folderId);
        }

        public object StoreAttachmentToDocuments(MailAttachmentData mailAttachmentData, string folderId)
        {
            if (mailAttachmentData == null)
                return -1;

            var apiHelper = new ApiHelper(HttpContextScheme);

            using (var file = mailAttachmentData.ToAttachmentStream())
            {
                var uploadedFileId = apiHelper.UploadToDocuments(file.FileStream, file.FileName,
                    mailAttachmentData.contentType, folderId, true);

                return uploadedFileId;
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/HttpHandlers/WebToLeadFromHandler.ashx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;
using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.CRM.Core.Entities;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Configuration;
using ASC.Web.CRM.Core;
using ASC.Web.CRM.Core.Enums;
using ASC.Web.CRM.Resources;
using ASC.Web.CRM.Services.NotifyService;

using Autofac;

using Newtonsoft.Json.Linq;

namespace ASC.Web.CRM.HttpHandlers
{
    public class WebToLeadFromHandler : IHttpHandler
    {
        private HttpContext _context;

        private String GetValue(String propertyName)
        {
            return _context.Request.Form[propertyName];
        }

        private bool CheckPermission()
        {
            try
            {
                var webFromKey = GetValue("web_form_key");

                if (String.IsNullOrEmpty(webFromKey))
                    return false;

                var webFromKeyAsGuid = new Guid(webFromKey);

                return Global.TenantSettings.WebFormKey == webFromKeyAsGuid;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public void ProcessRequest(HttpContext context)
        {
            try
            {
                using (var scope = DIHelper.Resolve())
                {
                    var daoFactory = scope.Resolve<DaoFactory>();
                    _context = context;

                    SecurityContext.AuthenticateMe(ASC.Core.Configuration.Constants.CoreSystem);

                    if (!CheckPermission())
                    {
                        throw new Exception(CRMSettingResource.WebToLeadsForm_InvalidKeyException);
                    }

                    var productInfo = WebItemSecurity.GetSecurityInfo(ProductEntryPoint.ID.ToString());
                    if (!productInfo.Enabled)
                    {
                        throw new Exception(CRMCommonResource.CRMProductIsDisabled);
                    }

                    Contact contact;

                    var fieldCollector = new NameValueCollection();

                    var addressTemplate = new JObject();
                    foreach (String addressPartName in Enum.GetNames(typeof(AddressPart)))
                        addressTemplate.Add(addressPartName.ToLower(), "");
                    var addressTemplateStr = addressTemplate.ToString();

                    var isCompany = false;

                    var isCompanyString = GetValue("is_company");
                    var firstName = GetValue("firstName");
                    var lastName = GetValue("lastName");
                    var companyName = GetValue("companyName");

                    if (!String.IsNullOrEmpty(isCompanyString))
                    {
                        if (!Boolean.TryParse(isCompanyString, out isCompany))
                        {
                            throw new ArgumentException();
                        }
                    }
                    else //old scheme
                    {
                        if (!String.IsNullOrEmpty(firstName))
                        {
                            isCompany = false;
                        }
                        else if (!String.IsNullOrEmpty(companyName))
                        {
                            isCompany = true;
                        }
                        else
                        {
                            throw new ArgumentException();
                        }
                    }


                    if (isCompany)
                    {
                        contact = new Company();

                        ((Company)contact).CompanyName = companyName;

                        fieldCollector.Add(CRMContactResource.CompanyName, companyName);
                    }
                    else
                    {
                        contact = new Person();

                        ((Person)contact).FirstName = firstName;
                        ((Person)contact).LastName = lastName;
                        ((Person)contact).JobTitle = GetValue("jobTitle");

                        fieldCollector.Add(CRMContactResource.FirstName, firstName);
                        fieldCollector.Add(CRMContactResource.LastName, lastName);

                        if (!String.IsNullOrEmpty(GetValue("jobTitle")))
                            fieldCollector.Add(CRMContactResource.JobTitle, ((Person)contact).JobTitle);
                    }

                    contact.About = GetValue("about");

                    if (!String.IsNullOrEmpty(contact.About))
                        fieldCollector.Add(CRMContactResource.About, contact.About);

                    if (!String.IsNullOrEmpty(GetValue("is_shared")))
                    {
                        contact.ShareType = Convert.ToBoolean(GetValue("is_shared"))
                            ? ShareType.ReadWrite
                            : ShareType.None;
                    }
                    else
                    {
                        contact.ShareType = (ShareType)(Convert.ToInt32(GetValue("share_type")));
                    }

                    contact.ID = daoFactory.ContactDao.SaveContact(contact);

                    var messageAction = contact is Company
                        ? MessageAction.CompanyCreatedWithWebForm
                        : MessageAction.PersonCreatedWithWebForm;
                    MessageService.Send(HttpContext.Current.Request, MessageInitiator.System, messageAction,
                        MessageTarget.Create(contact.ID), contact.GetTitle());

                    var contactInfos = new List<ContactInfo>();

                    foreach (var key in _context.Request.Form.AllKeys)
                    {
                        if (key.StartsWith("customField_"))
                        {
                            var fieldID = Convert.ToInt32(key.Split(new[] { '_' })[1]);
                            String fieldValue = GetValue(key);

                            if (String.IsNullOrEmpty(fieldValue)) continue;

                            var customField = daoFactory.CustomFieldDao.GetFieldDescription(fieldID);

                            if (customField == null ||
                                !(customField.EntityType == EntityType.Contact ||
                                  customField.EntityType == EntityType.Company && isCompany ||
                                  customField.EntityType == EntityType.Person && !isCompany)) continue;

                            if (customField.FieldType == CustomFieldType.CheckBox)
                            {
                                fieldValue = fieldValue == "on" || fieldValue == "true" ? "true" : "false";
                            }
                            fieldCollector.Add(customField.Label, fieldValue);

                            daoFactory.CustomFieldDao.SetFieldValue(isCompany ? EntityType.Company : EntityType.Person, contact.ID, fieldID, fieldValue);
                        }
                        else if (key.StartsWith("contactInfo_"))
                        {
                            var nameParts = key.Split(new[] { '_' }).Skip(1).ToList();
                            var contactInfoType = (ContactInfoType)Enum.Parse(typeof(ContactInfoType), nameParts[0]);
                            var category = Convert.ToInt32(nameParts[1]);

                            bool categoryIsExists = Enum.GetValues(ContactInfo.GetCategory(contactInfoType))
                                .Cast<object>()
                                .Any(categoryEnum => (int)categoryEnum == category);
                            if (!categoryIsExists)
                                throw new ArgumentException(String.Format("Category for {0} not found", nameParts[0]));

                            if (contactInfoType == ContactInfoType.Address)
                            {
                                var addressPart = (AddressPart)Enum.Parse(typeof(AddressPart), nameParts[2]);

                                var findedAddress =
                                    contactInfos.Find(
                                        item =>
                                            (category == item.Category) && (item.InfoType == ContactInfoType.Address));

                                if (findedAddress == null)
                                {
                                    findedAddress = new ContactInfo
                                    {
                                        Category = category,
                                        InfoType = contactInfoType,
                                        Data = addressTemplateStr,
                                        ContactID = contact.ID
                                    };

                                    contactInfos.Add(findedAddress);
                                }

                                var addressParts = JObject.Parse(findedAddress.Data);

                                addressParts[addressPart.ToString().ToLower()] = GetValue(key);

                                findedAddress.Data = addressParts.ToString();

                                continue;
                            }

                            var fieldValue = GetValue(key);

                            if (String.IsNullOrEmpty(fieldValue)) continue;

                            contactInfos.Add(new ContactInfo
                            {
                                Category = category,
                                InfoType = contactInfoType,
                                Data = fieldValue,
                                ContactID = contact.ID,
                                IsPrimary = true
                            });
                        }
                        else if (String.Compare(key, "tag", true) == 0)
                        {
                            var tags = _context.Request.Form.GetValues("tag");

                            daoFactory.TagDao.SetTagToEntity(EntityType.Contact, contact.ID, tags);
                        }
                    }

                    contactInfos.ForEach(
                        item =>
                            fieldCollector[item.InfoType.ToLocalizedString()] =
                                PrepareteDataToView(item.InfoType, item.Data));

                    daoFactory.ContactInfoDao.SaveList(contactInfos, contact);

                    var notifyList = GetValue("notify_list");

                    if (!String.IsNullOrEmpty(notifyList))
                        NotifyClient.Instance.SendAboutCreateNewContact(
                            notifyList
                                .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                                .Select(item => new Guid(item)).ToList(), contact.ID, contact.GetTitle(), fieldCollector);

                    var managersList = GetValue("managers_list");
                    SetPermission(contact, managersList);

                    if (contact is Person && !String.IsNullOrEmpty(companyName))
                        AssignPersonToCompany((Person)contact, companyName, managersList, daoFactory);

                    if (contact is Company && !String.IsNullOrEmpty(firstName) && !String.IsNullOrEmpty(lastName))
                        AssignCompanyToPerson((Company)contact, firstName, lastName, managersList, daoFactory);

                    SecurityContext.Logout();

                    var newURL = new UriBuilder(GetValue("return_url")).Uri.AbsoluteUri;
                    context.Response.Buffer = true;
                    context.Response.Status = "302 Object moved";
                    context.Response.AddHeader("Location", newURL);
                    context.Response.Write("<HTML><Head>");
                    context.Response.Write(String.Format("<META HTTP-EQUIV=Refresh CONTENT=\"0;URL={0}\">", newURL));
                    context.Response.Write(String.Format("<Script>window.location='{0}';</Script>", newURL));
                    context.Response.Write("</Head>");
                    context.Response.Write("</HTML>");
                }
            }
            catch (Exception error)
            {
                LogManager.GetLogger("ASC.CRM").Error(error);
                context.Response.StatusCode = 400;
                context.Response.Write(HttpUtility.HtmlEncode(error.Message));
            }
        }

        private String PrepareteDataToView(ContactInfoType contactInfoType, String data)
        {
            if (contactInfoType != ContactInfoType.Address) return data;

            var addressParts = JObject.Parse(data);

            var address = new StringBuilder();

            foreach (AddressPart addressPartEnum in Enum.GetValues(typeof(AddressPart)))
                address.Append(addressParts[addressPartEnum.ToString().ToLower()] + " ");

            return address.ToString();
        }

        public bool IsReusable
        {
            get { return false; }
        }

        protected void SetPermission(Contact contact, String privateList)
        {
            if (String.IsNullOrEmpty(privateList)) return;

            var selectedUsers = privateList
                .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(item => new Guid(item)).ToList();

            CRMSecurity.SetAccessTo(contact, selectedUsers);
        }

        protected void AssignCompanyToPerson(Company company, String firstName, String lastName, String privateList, DaoFactory daoFactory)
        {
            var person = new Person
            {
                FirstName = firstName,
                LastName = lastName,
                CompanyID = company.ID
            };
            person.ID = daoFactory.ContactDao.SaveContact(person);
            SetPermission(person, privateList);
        }


        protected void AssignPersonToCompany(Person person, String companyName, String privateList, DaoFactory daoFactory)
        {
            Company company;

            var findedCompanies = daoFactory.ContactDao.GetContactsByName(companyName, true).ToList();

            if (findedCompanies.Count == 0)
            {
                company = new Company
                {
                    CompanyName = companyName
                };

                company.ID = daoFactory.ContactDao.SaveContact(company);

                SetPermission(company, privateList);
            }
            else
            {
                company = (Company)findedCompanies[0];
            }

            daoFactory.ContactDao.AddMember(person.ID, company.ID);
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTCP_Report_Receiver.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class holds receiver report info.
    /// </summary>
    public class RTCP_Report_Receiver
    {
        #region Members

        private readonly uint m_CumulativePacketsLost;
        private readonly uint m_DelaySinceLastSR;
        private readonly uint m_ExtHigestSeqNumber;
        private readonly uint m_FractionLost;
        private readonly uint m_Jitter;
        private readonly uint m_LastSR;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the fraction of RTP data packets from source SSRC lost since the previous SR or 
        /// RR packet was sent.
        /// </summary>
        public uint FractionLost
        {
            get { return m_FractionLost; }
        }

        /// <summary>
        /// Gets total number of RTP data packets from source SSRC that have
        /// been lost since the beginning of reception.
        /// </summary>
        public uint CumulativePacketsLost
        {
            get { return m_CumulativePacketsLost; }
        }

        /// <summary>
        /// Gets extended highest sequence number received.
        /// </summary>
        public uint ExtendedSequenceNumber
        {
            get { return m_ExtHigestSeqNumber; }
        }

        /// <summary>
        /// Gets an estimate of the statistical variance of the RTP data packet
        /// interarrival time, measured in timestamp units and expressed as an
        /// unsigned integer.
        /// </summary>
        public uint Jitter
        {
            get { return m_Jitter; }
        }

        /// <summary>
        /// Gets when last sender report(SR) was recieved.
        /// </summary>
        public uint LastSR
        {
            get { return m_LastSR; }
        }

        /// <summary>
        /// Gets delay since last sender report(SR) was received.
        /// </summary>
        public uint DelaySinceLastSR
        {
            get { return m_DelaySinceLastSR; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="rr">RTCP RR report.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>rr</b> is null reference.</exception>
        internal RTCP_Report_Receiver(RTCP_Packet_ReportBlock rr)
        {
            if (rr == null)
            {
                throw new ArgumentNullException("rr");
            }

            m_FractionLost = rr.FractionLost;
            m_CumulativePacketsLost = rr.CumulativePacketsLost;
            m_ExtHigestSeqNumber = rr.ExtendedHighestSeqNo;
            m_Jitter = rr.Jitter;
            m_LastSR = rr.LastSR;
            m_DelaySinceLastSR = rr.DelaySinceLastSR;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Socket.IO/app/controllers/voip.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = (voip) => {
    const router = require('express').Router();

    router
        .post("/enqueue", (req, res) => {
            const { numberId, callId, agent } = req.body;
            voip.enqueue(numberId, callId, agent);
            res.end();
        })
        .post("/incoming", (req, res) => {
            const { callId, agent } = req.body;
            voip.incoming(callId, agent);
            res.end();
        })
        .post("/miss", (req, res) => {
            const { numberId, callId, agent } = req.body;
            voip.miss(numberId, callId, agent);
            res.end();
        })
        .post("/getAgent", (req, res) => {
            const { numberId, contactsResponsibles } = req.body;
            const result = voip.getAgent(numberId, contactsResponsibles);
            res.send(JSON.stringify({item1: result.result, item2: result.isAnyNotOffline}));
        })
        .post("/reload", (req, res) => {
            const { numberRoom, agentId } = req.body;
            voip.reload(numberRoom, agentId);
            res.end();
        });

    return router;
}

<|start_filename|>common/ASC.Core.Common/Tenants/TenantCookieSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;

namespace ASC.Core.Tenants
{
    [Serializable]
    [DataContract]
    public class TenantCookieSettings : BaseSettings<TenantCookieSettings>
    {
        [DataMember(Name = "Index")]
        public int Index { get; set; }

        [DataMember(Name = "LifeTime")]
        public int LifeTime { get; set; }

        private static readonly bool IsVisibleSettings;

        static TenantCookieSettings()
        {
            IsVisibleSettings = !(ConfigurationManagerExtension.AppSettings["web.hide-settings"] ?? string.Empty)
                        .Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries)
                        .Contains("CookieSettings", StringComparer.CurrentCultureIgnoreCase);
        }

        public override ISettings GetDefault()
        {
            return GetInstance();
        }

        public static TenantCookieSettings GetInstance()
        {
            return new TenantCookieSettings();
        }

        public override Guid ID
        {
            get { return new Guid("{16FB8E67-E96D-4B22-B217-C80F25C5DE1B}"); }
        }


        public bool IsDefault()
        {
            var defaultSettings = GetInstance();

            return LifeTime == defaultSettings.LifeTime;
        }


        public static TenantCookieSettings GetForTenant(int tenantId)
        {
            return IsVisibleSettings
                       ? LoadForTenant(tenantId)
                       : GetInstance();
        }

        public static void SetForTenant(int tenantId, TenantCookieSettings settings = null)
        {
            if (!IsVisibleSettings) return;
            (settings ?? GetInstance()).SaveForTenant(tenantId);
        }

        public static TenantCookieSettings GetForUser(Guid userId)
        {
            return IsVisibleSettings
                       ? LoadForUser(userId)
                       : GetInstance();
        }

        public static TenantCookieSettings GetForUser(int tenantId, Guid userId)
        {
            return IsVisibleSettings
                       ? SettingsManager.Instance.LoadSettingsFor<TenantCookieSettings>(tenantId, userId)
                       : GetInstance();
        }

        public static void SetForUser(Guid userId, TenantCookieSettings settings = null)
        {
            if (!IsVisibleSettings) return;
            (settings ?? GetInstance()).SaveForUser(userId);
        }

        public static DateTime GetExpiresTime(int tenantId)
        {
            var settingsTenant = GetForTenant(tenantId);
            var expires = settingsTenant.IsDefault() ? DateTime.UtcNow.AddYears(1) : DateTime.UtcNow.AddMinutes(settingsTenant.LifeTime);
            return expires;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Utils/Parser.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;

using ASC.Mail.Data.Contracts;
using ASC.Web.Core.Utility;
using ASC.Web.Studio.PublicResources;

using MimeKit;

namespace ASC.Mail.Utils
{
    public static class Parser
    {
        private static readonly Regex RegxWhiteSpaces = new Regex(@"\s+", RegexOptions.Compiled | RegexOptions.CultureInvariant);
        private static readonly Regex RegxClean = new Regex(@"(\(((\\\))|[^)])*\))", RegexOptions.Compiled | RegexOptions.CultureInvariant);
        //private static readonly Regex RegxEmail = new Regex("<(.|[.])*?>", RegexOptions.Compiled | RegexOptions.CultureInvariant);
        private static readonly Regex RegxDomain = new Regex(@"(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.)+[a-zA-Z]{2,63}\.?$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        private static readonly Regex RegxEmailLocalPart = new Regex(@"^([a-zA-Z0-9]+)([_\-\.\+][a-zA-Z0-9]+)*$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase);
        private static readonly Regex RegxNoneAscii = new Regex(@"[^\x00-\x7F]+", RegexOptions.Compiled | RegexOptions.Singleline);

        /// <summary>
        /// Parses the address.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        public static Address ParseAddress(string input)
        {
            try
            {
                var addressObj = MailboxAddress.Parse(ParserOptions.Default, input);

                var adr = new MailAddress(addressObj.Address, addressObj.Name);

                var address = new Address(addressObj.Address, addressObj.Name)
                {
                    LocalPart = adr.User,
                    Domain = adr.Host
                };

                if (!RegxEmailLocalPart.IsMatch(address.LocalPart))
                    throw new Exception("Local-part is invalid");

                if (!RegxDomain.IsMatch(address.Domain))
                    throw new Exception("Domain is invalid");

                return address;
            }
            catch (Exception ex)
            {
                throw new Exception("Parse failed", ex);
            }
        }

        public static bool TryParseAddress(string input, out Address address)
        {
            try
            {
                address = ParseAddress(input);

                return true;
            }
            catch (Exception)
            {
                address = null;
                return false;
            }
        }

        /// <summary>
        /// Check email's local part validity.
        /// </summary>
        /// <param name="input">Email's local part.</param>
        /// <returns>true - valid, false - invalid</returns>
        public static bool IsEmailLocalPartValid(string input)
        {
            try
            {
                var address = ParseAddress(input + "@test.com");

                return address != null;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Check domain validity.
        /// </summary>
        /// <param name="input">Domain string.</param>
        /// <returns>true - valid, false - invalid</returns>
        public static bool IsDomainValid(string input)
        {
            try
            {
                var address = ParseAddress("test@" + input);

                return address != null;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// Removes the white spaces.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        internal static string RemoveWhiteSpaces(string input)
        {
            return RegxWhiteSpaces.Replace(input, "");
        }

        /// <summary>
        /// Cleans the specified input.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        internal static string Clean(string input)
        {
            return RegxClean.Replace(input, "").Trim(' ');
        }

        /// <summary>
        /// Get valid password or throw exception.
        /// </summary>
        /// <param name="password">String contains valid password according to portal settings</param>
        /// <returns>trimmed password or exception</returns>
        public static string GetValidPassword(string password)
        {
            var trimPwd = password.Trim();

            if (string.IsNullOrEmpty(trimPwd))
                throw new ArgumentException(Resource.ErrorPasswordEmpty);

            var pwdSettings = PasswordSettings.Load();

            if (!PasswordSettings.CheckPasswordRegex(pwdSettings, trimPwd)
                || RegxNoneAscii.IsMatch(trimPwd)
                || RegxWhiteSpaces.IsMatch(trimPwd))
            {
                throw new ArgumentException(GeneratePasswordErrorMessage(pwdSettings));
            }

            return trimPwd;
        }

        internal static string GeneratePasswordErrorMessage(PasswordSettings passwordSettings)
        {
            var error = new StringBuilder();

            error.AppendFormat("{0} ", Resource.ErrorPasswordMessage);
            error.AppendFormat(Resource.ErrorPasswordLength, passwordSettings.MinLength, PasswordSettings.MaxLength);

            error.AppendFormat(", {0}", Resource.ErrorPasswordOnlyLatinLetters);
            error.AppendFormat(", {0}", Resource.ErrorPasswordNoSpaces);

            if (passwordSettings.UpperCase)
                error.AppendFormat(", {0}", Resource.ErrorPasswordNoUpperCase);
            if (passwordSettings.Digits)
                error.AppendFormat(", {0}", Resource.ErrorPasswordNoDigits);
            if (passwordSettings.SpecSymbols)
                error.AppendFormat(", {0}", Resource.ErrorPasswordNoSpecialSymbols);

            return error.ToString();
        }

        public static List<MailAddress> ToMailAddresses(this List<string> addresses)
        {
            var toList = new List<MailAddress>();

            foreach (var strAddress in addresses)
            {
                Address address;

                if (!TryParseAddress(strAddress, out address))
                    throw new Exception(string.Format("Address '{0}' is invalid", strAddress));

                toList.Add(new MailAddress(address.Email, address.Name));
            }

            return toList;
        }
    }
}


<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/Login.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Security;
using System.Web.Services;
using System.Web.SessionState;

using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.FederatedLogin.Profile;

namespace ASC.FederatedLogin
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class Login : IHttpHandler, IRequiresSessionState
    {
        private Dictionary<string, string> _params;

        public void ProcessRequest(HttpContext context)
        {
            context.PushRewritenUri();

            if (string.IsNullOrEmpty(context.Request["p"]))
            {
                _params = new Dictionary<string, string>(context.Request.QueryString.Count);
                //Form params and redirect
                foreach (var key in context.Request.QueryString.AllKeys)
                {
                    _params.Add(key, context.Request.QueryString[key]);
                }

                //Pack and redirect
                var uriBuilder = new UriBuilder(context.Request.GetUrlRewriter());
                var token = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(new JavaScriptSerializer().Serialize(_params)));
                uriBuilder.Query = "p=" + token;
                context.Response.Redirect(uriBuilder.Uri.ToString(), true);
            }
            else
            {
                _params = ((Dictionary<string, object>)new JavaScriptSerializer().DeserializeObject(
                    Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(context.Request["p"])))).ToDictionary(x => x.Key, y => (string)y.Value);
            }

            if (!string.IsNullOrEmpty(Auth))
            {
                try
                {
                    var profile = ProviderManager.Process(Auth, context, _params);
                    if (profile != null)
                    {
                        SendClientData(context, profile);
                    }
                }
                catch (ThreadAbortException)
                {
                    //Thats is responce ending
                }
                catch (Exception ex)
                {
                    SendClientData(context, LoginProfile.FromError(ex));
                }
            }
            else
            {
                //Render xrds
                RenderXrds(context);
            }
            context.PopRewritenUri();
        }

        protected bool Minimal
        {
            get
            {
                if (_params.ContainsKey("min"))
                {
                    bool result;
                    bool.TryParse(_params.Get("min"), out result);
                    return result;
                }
                return false;
            }
        }

        protected string Callback
        {
            get { return _params.Get("callback") ?? "loginCallback"; }
        }

        private void RenderXrds(HttpContext context)
        {
            var xrdsloginuri = new Uri(context.Request.GetUrlRewriter(),
                                       new Uri(context.Request.GetUrlRewriter().AbsolutePath, UriKind.Relative)) + "?auth=openid&returnurl=" + ReturnUrl;
            var xrdsimageuri = new Uri(context.Request.GetUrlRewriter(),
                                       new Uri(context.Request.ApplicationPath, UriKind.Relative)) + "openid.gif";
            XrdsHelper.RenderXrds(context.Response, xrdsloginuri, xrdsimageuri);
        }

        protected LoginMode Mode
        {
            get
            {
                if (!string.IsNullOrEmpty(_params.Get("mode")))
                {
                    return (LoginMode)Enum.Parse(typeof(LoginMode), _params.Get("mode"), true);
                }
                return LoginMode.Popup;
            }
        }

        protected string ReturnUrl
        {
            get { return _params.Get("returnurl") ?? FormsAuthentication.LoginUrl; }
        }

        protected string Auth
        {
            get { return _params.Get("auth"); }
        }

        public bool IsReusable
        {
            get { return false; }
        }


        private void SendClientData(HttpContext context, LoginProfile profile)
        {
            switch (Mode)
            {
                case LoginMode.Redirect:
                    RedirectToReturnUrl(context, profile);
                    break;
                case LoginMode.Popup:
                    SendJsCallback(context, profile);
                    break;
            }
        }

        private void SendJsCallback(HttpContext context, LoginProfile profile)
        {
            //Render a page
            context.Response.ContentType = "text/html";
            context.Response.Write(JsCallbackHelper.GetCallbackPage().Replace("%PROFILE%", profile.ToJson()).Replace("%CALLBACK%", Callback));
        }

        private void RedirectToReturnUrl(HttpContext context, LoginProfile profile)
        {
            var useMinimalProfile = Minimal;
            if (useMinimalProfile)
                profile = profile.GetMinimalProfile(); //Only id and provider

            if (context.Session != null && !useMinimalProfile)
            {
                //Store in session
                context.Response.Redirect(new Uri(ReturnUrl, UriKind.Absolute).AddProfileSession(profile, context).ToString(), true);
            }
            else if (HttpRuntime.Cache != null && !useMinimalProfile)
            {
                context.Response.Redirect(new Uri(ReturnUrl, UriKind.Absolute).AddProfileCache(profile).ToString(), true);
            }
            else
            {
                context.Response.Redirect(new Uri(ReturnUrl, UriKind.Absolute).AddProfile(profile).ToString(), true);
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Utils/PostfixMaildirUtil.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Mail.Server.Utils
{
    public static class PostfixMaildirUtil
    {
        public static string GenerateMaildirPath(string domain, string localpart, DateTime creationdate)
        {
            var maildir = domain + "/";

            if (localpart.Length >= 3)
            {
                maildir += string.Format("{0}/{1}/{2}/", localpart[0], localpart[1], localpart[2]);
            }
            else if (localpart.Length == 2)
            {
                maildir += string.Format("{0}/{1}/{2}/", localpart[0], localpart[1], localpart[1]);
            }
            else
            {
                maildir += string.Format("{0}/{1}/{2}/", localpart[0], localpart[0], localpart[0]);
            }

            maildir += string.Format("{0}-{1}/", localpart, creationdate.ToString("yyyy.MM.dd.HH.mm.ss"));

            return maildir.ToLower();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/js/tariffstandalone.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var TariffStandalone = new function () {
    var isInit = false;

    var init = function () {
        if (isInit === false) {
            isInit = true;
        }


        uploadInit();
    };

    var uploadInit = function () {
        jq("#licenseKey").click(function (e) {
            e.preventDefault();
            jq("#uploadButton").click();
        });

        var upload = jq("#uploadButton")
            .fileupload({
                url: "ajaxupload.ashx?type=ASC.Web.Studio.HttpHandlers.LicenseUploader,ASC.Web.Studio",
            })
            .bind("fileuploadstart", function () {
                jq("#licenseKeyText").removeClass("error");
                LoadingBanner.showLoaderBtn(".step");
            })
            .bind("fileuploaddone", function (e, data) {
                LoadingBanner.hideLoaderBtn(".step");
                try {
                    var result = jq.parseJSON(data.result);
                } catch (e) {
                    result = {Success: false};
                }

                var licenseResult = result.Message;
                if (!result.Success) {
                    toastr.error(licenseResult);
                    licenseResult = "";
                }
                jq("#licenseKeyText").html(licenseResult);

                licenseKeyEdit();
            });
    };

    var licenseKeyEdit = function () {
        var err = !jq("#licenseKeyText").text().length;
        jq("#licenseKeyText").toggleClass("error", err);

        if (jq("#policyAccepted").length && !jq("#policyAccepted").is(":checked")) {
            err = true;
        }
        jq("#activateButton").toggleClass("disable", err);
    };

    var activate = function () {
        var licenseKey = jq("#licenseKeyText").text();

        if (jq("#licenseKeyText").length && !licenseKey.length) {
            var res = { Status: 0, Message: ASC.Resources.Master.ResourceJS.LicenseKeyError };

            onActivate(res);
            return;
        }

        AjaxPro.onLoading = function (b) {
            if (b) {
                LoadingBanner.showLoaderBtn("#activatePanel");
            } else {
                LoadingBanner.hideLoaderBtn("#activatePanel");
            }
        };
        TariffStandaloneController.ActivateLicenseKey(function (result) {
            onActivate(result.value);
        });
    };

    var onActivate = function (res) {
        if (res.Status) {
            toastr.success(ASC.Resources.Master.ResourceJS.OperationSuccededMsg);
            setTimeout(function () {
                location.reload(true);
            }, 500);
            return;
        }

        toastr.error(res.Message);
    };

    return {
        init: init,

        activate: activate,
        licenseKeyEdit: licenseKeyEdit,
    };
};

jq(function () {
    TariffStandalone.init();

    jq("#activatePanel").on("click", "#activateButton:not(.disable)", TariffStandalone.activate);

    jq("#policyAccepted").click(TariffStandalone.licenseKeyEdit);
});

<|start_filename|>common/ASC.Data.Storage/DiscStorage/DiscDataStore.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

using ASC.Common;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Encryption;
using ASC.Data.Storage.Configuration;
using ASC.Data.Storage.Encryption;

namespace ASC.Data.Storage.DiscStorage
{
    public class DiscDataStore : BaseStorage
    {
        private const int BufferSize = 8192;
        private readonly Dictionary<string, MappedPath> _mappedPaths = new Dictionary<string, MappedPath>();

        private readonly ICrypt crypt;

        public DiscDataStore(string tenant, HandlerConfigurationElement handlerConfig, ModuleConfigurationElement moduleConfig)
        {
            _tenant = tenant;
            //Fill map path
            _modulename = moduleConfig.Name;
            _dataList = new DataList(moduleConfig);
            foreach (DomainConfigurationElement domain in moduleConfig.Domains)
            {
                _mappedPaths.Add(domain.Name, new MappedPath(tenant, moduleConfig.AppendTenant, domain.Path, handlerConfig.GetProperties()));
            }
            //Add default
            _mappedPaths.Add(string.Empty, new MappedPath(tenant, moduleConfig.AppendTenant, PathUtils.Normalize(moduleConfig.Path), handlerConfig.GetProperties()));

            //Make expires
            _domainsExpires =
                moduleConfig.Domains.Cast<DomainConfigurationElement>().Where(x => x.Expires != TimeSpan.Zero).
                    ToDictionary(x => x.Name,
                                 y => y.Expires);
            _domainsExpires.Add(string.Empty, moduleConfig.Expires);

            var settings = moduleConfig.DisabledEncryption ? new EncryptionSettings() : EncryptionSettings.Load();

            crypt = EncryptionFactory.GetCrypt(moduleConfig.Name, settings);
        }

        public String GetPhysicalPath(string domain, string path)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }

            var pathMap = GetPath(domain);

            return (pathMap.PhysicalPath + EnsureLeadingSlash(path)).Replace('\\', '/');
        }

        public override bool IsSupportInternalUri
        {
            get { return false; }
        }

        public override Stream GetReadStream(string domain, string path)
        {
            return GetReadStream(domain, path, true);
        }

        public Stream GetReadStream(string domain, string path, bool withDecription)
        {
            if (path == null) throw new ArgumentNullException("path");
            var target = GetTarget(domain, path);

            if (File.Exists(target))
            {
                return withDecription ? crypt.GetReadStream(target) : File.OpenRead(target);
            }
            throw new FileNotFoundException("File not found", Path.GetFullPath(target));
        }


        public override Stream GetReadStream(string domain, string path, int offset)
        {
            if (path == null) throw new ArgumentNullException("path");
            var target = GetTarget(domain, path);

            if (File.Exists(target))
            {
                var stream = crypt.GetReadStream(target);
                if (0 < offset && stream.CanSeek) stream.Seek(offset, SeekOrigin.Begin);
                return stream;
            }
            throw new FileNotFoundException("File not found", Path.GetFullPath(target));
        }

        public override Task<Stream> GetReadStreamAsync(string domain, string path, int offset)
        {
            return Task.FromResult(GetReadStream(domain, path, offset));
        }

        protected override Uri SaveWithAutoAttachment(string domain, string path, Stream stream, string attachmentFileName)
        {
            return Save(domain, path, stream);
        }

        public override Uri Save(string domain, string path, Stream stream, string contentType, string contentDisposition)
        {
            return Save(domain, path, stream);
        }

        public override Uri Save(string domain, string path, Stream stream, string contentEncoding, int cacheDays)
        {
            return Save(domain, path, stream);
        }

        public override Uri Save(string domain, string path, Stream stream)
        {
            LogManager.GetLogger("ASC").Debug("Save " + path);
            var buffered = stream.GetBuffered();
            if (QuotaController != null)
            {
                QuotaController.QuotaUsedCheck(buffered.Length);
            }

            if (path == null) throw new ArgumentNullException("path");
            if (buffered == null) throw new ArgumentNullException("stream");

            //Try seek to start
            if (buffered.CanSeek)
            {
                buffered.Seek(0, SeekOrigin.Begin);
            }
            //Lookup domain
            var target = GetTarget(domain, path);
            CreateDirectory(target);
            //Copy stream

            //optimaze disk file copy
            var fileStream = buffered as FileStream;

            long fslen;

            if (fileStream != null && WorkContext.IsMono)
            {
                File.Copy(fileStream.Name, target, true);
                fslen = fileStream.Length;
            }
            else
            {
                using (var fs = File.Open(target, FileMode.Create))
                {
                    var buffer = new byte[BufferSize];
                    int readed;
                    while ((readed = buffered.Read(buffer, 0, BufferSize)) != 0)
                    {
                        fs.Write(buffer, 0, readed);
                    }
                    fslen = fs.Length;
                }
            }

            QuotaUsedAdd(domain, fslen);

            crypt.EncryptFile(target);

            return GetUri(domain, path);
        }

        public override Uri Save(string domain, string path, Stream stream, ACL acl)
        {
            return Save(domain, path, stream);
        }

        public override bool IsSupportedPreSignedUri
        {
            get
            {
                return false;
            }
        }

        #region chunking

        public override string InitiateChunkedUpload(string domain, string path)
        {
            var target = GetTarget(domain, path);
            CreateDirectory(target);
            return target;
        }

        public override string UploadChunk(string domain, string path, string uploadId, Stream stream, long defaultChunkSize, int chunkNumber, long chunkLength)
        {
            var target = GetTarget(domain, path);
            var mode = chunkNumber == 0 ? FileMode.Create : FileMode.Append;
            using (var fs = new FileStream(target, mode))
            {
                var buffer = new byte[BufferSize];
                int readed;
                while ((readed = stream.Read(buffer, 0, BufferSize)) != 0)
                {
                    fs.Write(buffer, 0, readed);
                }
            }
            return string.Format("{0}_{1}", chunkNumber, uploadId);
        }

        public override Uri FinalizeChunkedUpload(string domain, string path, string uploadId, Dictionary<int, string> eTags)
        {
            var target = GetTarget(domain, path);

            if (QuotaController != null)
            {
                if (!File.Exists(target))
                {
                    throw new FileNotFoundException("file not found " + target);
                }

                var size = new FileInfo(target).Length;
                QuotaUsedAdd(domain, size);
            }

            crypt.EncryptFile(target);

            return GetUri(domain, path);
        }

        public override void AbortChunkedUpload(string domain, string path, string uploadId)
        {
            var target = GetTarget(domain, path);
            if (File.Exists(target))
            {
                File.Delete(target);
            }
        }

        public override bool IsSupportChunking
        {
            get { return true; }
        }

        #endregion

        public override void Delete(string domain, string path)
        {
            if (path == null) throw new ArgumentNullException("path");
            var target = GetTarget(domain, path);

            if (File.Exists(target))
            {
                var size = crypt.GetFileSize(target);
                File.Delete(target);

                QuotaUsedDelete(domain, size);
            }
            else
            {
                throw new FileNotFoundException("file not found", target);
            }
        }

        public override void DeleteFiles(string domain, List<string> paths)
        {
            if (paths == null) throw new ArgumentNullException("paths");

            foreach (var path in paths)
            {
                var target = GetTarget(domain, path);

                if (!File.Exists(target))
                    continue;

                var size = crypt.GetFileSize(target);
                File.Delete(target);

                QuotaUsedDelete(domain, size);
            }
        }

        public override void DeleteFiles(string domain, string folderPath, string pattern, bool recursive)
        {
            if (folderPath == null) throw new ArgumentNullException("folderPath");

            //Return dirs
            var targetDir = GetTarget(domain, folderPath);
            if (Directory.Exists(targetDir))
            {
                var entries = Directory.GetFiles(targetDir, pattern, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                foreach (var entry in entries)
                {
                    var size = crypt.GetFileSize(entry);
                    File.Delete(entry);
                    QuotaUsedDelete(domain, size);
                }
            }
            else
            {
                throw new DirectoryNotFoundException(string.Format("Directory '{0}' not found", targetDir));
            }
        }

        public override void DeleteFiles(string domain, string folderPath, DateTime fromDate, DateTime toDate)
        {
            if (folderPath == null) throw new ArgumentNullException("folderPath");

            //Return dirs
            var targetDir = GetTarget(domain, folderPath);
            if (Directory.Exists(targetDir))
            {
                var entries = Directory.GetFiles(targetDir, "*", SearchOption.AllDirectories);
                foreach (var entry in entries)
                {
                    var fileInfo = new FileInfo(entry);
                    if (fileInfo.LastWriteTime >= fromDate && fileInfo.LastWriteTime <= toDate)
                    {
                        var size = crypt.GetFileSize(entry);
                        File.Delete(entry);
                        QuotaUsedDelete(domain, size);
                    }
                }
            }
            else
            {
                throw new DirectoryNotFoundException(string.Format("Directory '{0}' not found", targetDir));
            }
        }

        public override void MoveDirectory(string srcdomain, string srcdir, string newdomain, string newdir)
        {
            var target = GetTarget(srcdomain, srcdir);
            var newtarget = GetTarget(newdomain, newdir);
            var newtargetSub = newtarget.Remove(newtarget.LastIndexOf(Path.DirectorySeparatorChar));

            if (!Directory.Exists(newtargetSub))
            {
                Directory.CreateDirectory(newtargetSub);
            }
            Directory.Move(target, newtarget);
        }

        public override Uri Move(string srcdomain, string srcpath, string newdomain, string newpath, bool quotaCheckFileSize = true)
        {
            if (srcpath == null) throw new ArgumentNullException("srcpath");
            if (newpath == null) throw new ArgumentNullException("srcpath");
            var target = GetTarget(srcdomain, srcpath);
            var newtarget = GetTarget(newdomain, newpath);

            if (File.Exists(target))
            {
                if (!Directory.Exists(Path.GetDirectoryName(newtarget)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(newtarget));
                }

                var flength = crypt.GetFileSize(target);

                //Delete file if exists
                if (File.Exists(newtarget))
                {
                    File.Delete(newtarget);
                }
                File.Move(target, newtarget);

                QuotaUsedDelete(srcdomain, flength);
                QuotaUsedAdd(newdomain, flength, quotaCheckFileSize);
            }
            else
            {
                throw new FileNotFoundException("File not found", Path.GetFullPath(target));
            }
            return GetUri(newdomain, newpath);
        }

        public override bool IsDirectory(string domain, string path)
        {
            if (path == null) throw new ArgumentNullException("path");

            //Return dirs
            var targetDir = GetTarget(domain, path);
            if (!string.IsNullOrEmpty(targetDir) && !targetDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                targetDir += Path.DirectorySeparatorChar;
            }
            return !string.IsNullOrEmpty(targetDir) && Directory.Exists(targetDir);
        }

        public override void DeleteDirectory(string domain, string path)
        {
            if (path == null) throw new ArgumentNullException("path");

            //Return dirs
            var targetDir = GetTarget(domain, path);

            if (string.IsNullOrEmpty(targetDir)) throw new Exception("targetDir is null");

            if (!string.IsNullOrEmpty(targetDir) && !targetDir.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                targetDir += Path.DirectorySeparatorChar;
            }

            if (!Directory.Exists(targetDir)) return;

            var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.AllDirectories);
            var size = entries.Select(entry => crypt.GetFileSize(entry)).Sum();

            var subDirs = Directory.GetDirectories(targetDir, "*", SearchOption.AllDirectories).ToList();
            subDirs.Reverse();
            subDirs.ForEach(subdir => Directory.Delete(subdir, true));

            Directory.Delete(targetDir, true);

            QuotaUsedDelete(domain, size);
        }

        public override long GetFileSize(string domain, string path)
        {
            var target = GetTarget(domain, path);

            if (File.Exists(target))
            {
                return crypt.GetFileSize(target);
            }
            throw new FileNotFoundException("file not found " + target);
        }

        public override long GetDirectorySize(string domain, string path)
        {
            var target = GetTarget(domain, path);

            if (Directory.Exists(target))
            {
                return Directory.GetFiles(target, "*.*", SearchOption.AllDirectories)
                    .Select(entry => crypt.GetFileSize(entry))
                    .Sum();
            }

            throw new FileNotFoundException("directory not found " + target);
        }

        public override Uri SaveTemp(string domain, out string assignedPath, Stream stream)
        {
            assignedPath = Guid.NewGuid().ToString();
            return Save(domain, assignedPath, stream);
        }


        public override string SavePrivate(string domain, string path, Stream stream, DateTime expires)
        {
            return Save(domain, path, stream).ToString();
        }

        public override void DeleteExpired(string domain, string folderPath, TimeSpan oldThreshold)
        {
            if (folderPath == null) throw new ArgumentNullException("folderPath");

            //Return dirs
            var targetDir = GetTarget(domain, folderPath);
            if (!Directory.Exists(targetDir))
            {
                return;
            }

            var entries = Directory.GetFiles(targetDir, "*.*", SearchOption.TopDirectoryOnly);
            foreach (var entry in entries)
            {
                var finfo = new FileInfo(entry);
                if ((DateTime.UtcNow - finfo.CreationTimeUtc) > oldThreshold)
                {
                    var size = crypt.GetFileSize(entry);
                    File.Delete(entry);

                    QuotaUsedDelete(domain, size);
                }
            }
        }

        public override string GetUploadForm(string domain, string directoryPath, string redirectTo, long maxUploadSize, string contentType, string contentDisposition, string submitLabel)
        {
            throw new NotSupportedException("This operation supported only on s3 storage");
        }

        public override string GetUploadedUrl(string domain, string directoryPath)
        {
            throw new NotSupportedException("This operation supported only on s3 storage");
        }

        public override string GetUploadUrl()
        {
            throw new NotSupportedException("This operation supported only on s3 storage");
        }

        public override string GetPostParams(string domain, string directoryPath, long maxUploadSize, string contentType, string contentDisposition)
        {
            throw new NotSupportedException("This operation supported only on s3 storage");
        }


        public override string[] ListDirectoriesRelative(string domain, string path, bool recursive)
        {
            if (path == null) throw new ArgumentNullException("path");

            //Return dirs
            var targetDir = GetTarget(domain, path);
            if (!string.IsNullOrEmpty(targetDir) && !targetDir.EndsWith(Path.DirectorySeparatorChar.ToString())) targetDir += Path.DirectorySeparatorChar;
            if (Directory.Exists(targetDir))
            {
                var entries = Directory.GetDirectories(targetDir, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                return Array.ConvertAll(
                    entries,
                    x => x.Substring(targetDir.Length));
            }
            return new string[0];
        }

        public override string[] ListFilesRelative(string domain, string path, string pattern, bool recursive)
        {
            if (path == null) throw new ArgumentNullException("path");

            //Return dirs
            var targetDir = GetTarget(domain, path);
            if (!string.IsNullOrEmpty(targetDir) && !targetDir.EndsWith(Path.DirectorySeparatorChar.ToString())) targetDir += Path.DirectorySeparatorChar;
            if (Directory.Exists(targetDir))
            {
                var entries = Directory.GetFiles(targetDir, pattern, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                return Array.ConvertAll(
                    entries,
                    x => x.Substring(targetDir.Length));
            }
            return new string[0];
        }

        public override bool IsFile(string domain, string path)
        {
            if (path == null) throw new ArgumentNullException("path");

            //Return dirs
            var target = GetTarget(domain, path);
            var result = File.Exists(target);
            return result;
        }
        
        public override Task<bool> IsFileAsync(string domain, string path)
        {
            return Task.FromResult(IsFile(domain, path));
        }

        public override long ResetQuota(string domain)
        {
            if (QuotaController != null)
            {
                var size = GetUsedQuota(domain);
                QuotaController.QuotaUsedSet(_modulename, domain, _dataList.GetData(domain), size);
            }
            return 0;
        }

        public override long GetUsedQuota(string domain)
        {
            var target = GetTarget(domain, "");
            long size = 0;
            if (Directory.Exists(target))
            {
                var entries = Directory.GetFiles(target, "*.*", SearchOption.AllDirectories);
                size = entries.Select(entry => crypt.GetFileSize(entry)).Sum();
            }
            return size;
        }

        public override Uri Copy(string srcdomain, string srcpath, string newdomain, string newpath)
        {
            if (srcpath == null) throw new ArgumentNullException("srcpath");
            if (newpath == null) throw new ArgumentNullException("srcpath");
            var target = GetTarget(srcdomain, srcpath);
            var newtarget = GetTarget(newdomain, newpath);

            if (File.Exists(target))
            {
                if (!Directory.Exists(Path.GetDirectoryName(newtarget)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(newtarget));
                }

                File.Copy(target, newtarget, true);

                var flength = crypt.GetFileSize(target);
                QuotaUsedAdd(newdomain, flength);
            }
            else
            {
                throw new FileNotFoundException("File not found", Path.GetFullPath(target));
            }
            return GetUri(newdomain, newpath);
        }

        public override void CopyDirectory(string srcdomain, string srcdir, string newdomain, string newdir)
        {
            var target = GetTarget(srcdomain, srcdir);
            var newtarget = GetTarget(newdomain, newdir);

            var diSource = new DirectoryInfo(target);
            var diTarget = new DirectoryInfo(newtarget);

            CopyAll(diSource, diTarget, newdomain);
        }

        private void CopyAll(DirectoryInfo source, DirectoryInfo target, string newdomain)
        {
            // Check if the target directory exists, if not, create it.
            if (!Directory.Exists(target.FullName))
            {
                Directory.CreateDirectory(target.FullName);
            }

            // Copy each file into it's new directory.
            foreach (var fi in source.GetFiles())
            {
                var fp = Path.Combine(target.ToString(), fi.Name);
                fi.CopyTo(fp, true);
                var size = crypt.GetFileSize(fp);
                QuotaUsedAdd(newdomain, size);
            }

            // Copy each subdirectory using recursion.
            foreach (var diSourceSubDir in source.GetDirectories())
            {
                var nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
                CopyAll(diSourceSubDir, nextTargetSubDir, newdomain);
            }
        }


        private MappedPath GetPath(string domain)
        {
            if (domain != null)
                if (_mappedPaths.ContainsKey(domain))
                {
                    return _mappedPaths[domain];
                }
            return _mappedPaths[string.Empty].AppendDomain(domain);
        }

        public Stream GetWriteStream(string domain, string path)
        {
            return GetWriteStream(domain, path, FileMode.Create);
        }

        public Stream GetWriteStream(string domain, string path, FileMode fileMode)
        {
            if (path == null) throw new ArgumentNullException("path");
            var target = GetTarget(domain, path);
            CreateDirectory(target);
            return File.Open(target, fileMode);
        }

        private static void CreateDirectory(string target)
        {
            string targetDirectory = Path.GetDirectoryName(target);
            if (!Directory.Exists(targetDirectory))
            {
                Directory.CreateDirectory(targetDirectory);
            }
        }

        private string GetTarget(string domain, string path)
        {
            var pathMap = GetPath(domain);
            //Build Dir
            var target = Path.Combine(pathMap.PhysicalPath, PathUtils.Normalize(path));
            ValidatePath(target);
            return target;
        }

        private static void ValidatePath(string target)
        {
            if (Path.GetDirectoryName(target).IndexOfAny(Path.GetInvalidPathChars()) != -1 ||
                Path.GetFileName(target).IndexOfAny(Path.GetInvalidFileNameChars()) != -1)
            {
                //Throw
                throw new ArgumentException("bad path");
            }
        }


        public void Encrypt(string domain, string path)
        {
            if (path == null) throw new ArgumentNullException("path");

            var target = GetTarget(domain, path);

            if (File.Exists(target))
            {
                crypt.EncryptFile(target);
            }
            else
            {
                throw new FileNotFoundException("file not found", target);
            }
        }

        public void Decrypt(string domain, string path)
        {
            if (path == null) throw new ArgumentNullException("path");

            var target = GetTarget(domain, path);

            if (File.Exists(target))
            {
                crypt.DecryptFile(target);
            }
            else
            {
                throw new FileNotFoundException("file not found", target);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/SecurityAdapterProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Files.Core.Security;
using ASC.Web.Projects.Classes;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Projects.Engine
{
    public class SecurityAdapterProvider : IFileSecurityProvider
    {
        public IFileSecurity GetFileSecurity(string data)
        {
            int id;
            return int.TryParse(data, out id) ? GetFileSecurity(id) : null;
        }

        public Dictionary<object, IFileSecurity> GetFileSecurity(Dictionary<string, string> data)
        {
            var projectIds = data.Select(r =>
            {
                int id;
                if (!int.TryParse(r.Value, out id))
                {
                    id = -1;
                }
                return id;
            }).ToList();

            using (var scope = DIHelper.Resolve())
            {
                return scope.Resolve<EngineFactory>().ProjectEngine.GetByID(projectIds, false).
                    ToDictionary(
                        r =>
                        {
                            var folder = data.First(d => d.Value == r.ID.ToString());
                            if (!folder.Equals(default(KeyValuePair<string, string>)))
                            {
                                return (object)folder.Key;
                            }
                            return "";
                        },
                        r => (IFileSecurity)new SecurityAdapter(r));
            }
        }

        public IFileSecurity GetFileSecurity(int projectId)
        {
            return new SecurityAdapter(projectId);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/css/default/talk.text-overflow.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


div.dialog div.textfield div.value,
div.custom-select ul.options li.option{
  text-overflow:ellipsis;
  -o-text-overflow:ellipsis;
  -moz-text-overflow:ellipsis;
  -webkit-text-overflow:ellipsis;
}

div.custom-select div.title{
  text-overflow:ellipsis;
  -o-text-overflow:ellipsis;
  -moz-text-overflow:ellipsis;
  -webkit-text-overflow:ellipsis;
}

div.dialog div.head div.title{
  text-overflow:ellipsis;
  -o-text-overflow:ellipsis;
  -moz-text-overflow:ellipsis;
  -webkit-text-overflow:ellipsis;
}

li.group div.group-title,
li.contact div.contact-title,
li.contact div.mailing-title,
li.contact div.room-title,
div.group-dragable div.title,
div.contact-dragable div.title,
li.room.mailing li.contact div.title,
li.room.conference li.contact div.title{
  text-overflow:ellipsis;
  -o-text-overflow:ellipsis;
  -moz-text-overflow:ellipsis;
  -webkit-text-overflow:ellipsis;
}

li.tab div.container div.tab-title,
li.room.mailing.minimized li.contact div.title,
li.room.conference.minimized li.contact div.title{
  text-overflow:ellipsis;
  -o-text-overflow:ellipsis;
  -moz-text-overflow:ellipsis;
  -webkit-text-overflow:ellipsis;
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/Multilang/IMLangCodePages.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace MultiLanguage
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Security;

    [ComImport, Guid("359F3443-BD4A-11D0-B188-00AA0038C969"), InterfaceType((short) 1)]
    public interface IMLangCodePages
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void GetCharCodePages([In] ushort chSrc, out uint pdwCodePages);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void GetStrCodePages([In] ref ushort pszSrc, [In] int cchSrc, [In] uint dwPriorityCodePages, out uint pdwCodePages, out int pcchCodePages);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void CodePageToCodePages([In] uint uCodePage, out uint pdwCodePages);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void CodePagesToCodePage([In] uint dwCodePages, [In] uint uDefaultCodePage, out uint puCodePage);
    }
}


<|start_filename|>common/Tests/ASC.Common.Tests/Data/ExpTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#if DEBUG
using System.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ASC.Common.Tests.Data
{
    [TestClass]
    public class ExpTest
    {
        [TestMethod]
        public void JunctuinTest()
        {
            var exp = Exp.Eq("A", 0) & (Exp.Eq("B", 0) | Exp.Eq("C", 0));
            Assert.AreEqual(exp.ToString(), "A = ? and (B = ? or C = ?)");

            exp = Exp.Eq("A", 0) & (Exp.Eq("B", 0) & Exp.Eq("C", 0));
            Assert.AreEqual(exp.ToString(), "A = ? and B = ? and C = ?");

            exp = Exp.Eq("A", 0) | (Exp.Eq("B", 0) | Exp.Eq("C", 0));
            Assert.AreEqual(exp.ToString(), "A = ? or B = ? or C = ?");

            exp = (Exp.Eq("A", 0) & Exp.Eq("B", 0)) | Exp.Eq("C", 0);
            Assert.AreEqual(exp.ToString(), "(A = ? and B = ?) or C = ?");

            exp = (Exp.Eq("A", 0) & Exp.Eq("B", 0)) & Exp.Eq("C", 0) | Exp.Eq("D", 0);
            Assert.AreEqual(exp.ToString(), "(A = ? and B = ? and C = ?) or D = ?");

            exp = (Exp.Eq("A", 0) & Exp.Eq("B", 0)) | (Exp.Eq("C", 0) & Exp.Eq("D", 0));
            Assert.AreEqual(exp.ToString(), "(A = ? and B = ?) or (C = ? and D = ?)");

            exp = (Exp.Eq("A", 0) | Exp.Eq("B", 0)) & Exp.Eq("C", 0);
            Assert.AreEqual(exp.ToString(), "(A = ? or B = ?) and C = ?");

            exp = Exp.Eq("A", 0) | Exp.Eq("B", 0) & Exp.Eq("C", 0); // priority
            Assert.AreEqual(exp.ToString(), "A = ? or (B = ? and C = ?)");
        }

        [TestMethod]
        public void QueryTtest()
        {
            var query = new SqlQuery("Table1 t1")
                .From(new SqlQuery("Table2").Select("Id"), "t2")
                .Select("t1.Name")
                .Where(Exp.EqColumns("t1.Id", "t2.Id"));

            Assert.AreEqual("select t1.Name from Table1 t1, (select Id from Table2) as t2 where t1.Id = t2.Id", query.ToString());
        }

        [TestMethod]
        public void LGTest()
        {
            Assert.AreEqual("a < ?", Exp.Lt("a", 0).ToString());
            Assert.AreEqual("a <= ?", Exp.Le("a", 0).ToString());
            Assert.AreEqual("a > ?", Exp.Gt("a", 0).ToString());
            Assert.AreEqual("a >= ?", Exp.Ge("a", 0).ToString());
        }

        [TestMethod]
        public void InTest()
        {
            Assert.AreEqual("a = ?", Exp.In("a", new[] { 1 }).ToString());
            Assert.AreEqual("1 = 0", Exp.In("a", new int[0]).ToString());
            Assert.AreEqual("a in (?,?)", Exp.In("a", new[] { 1, 2 }).ToString());
            Assert.AreEqual("a in (select c)", Exp.In("a", new SqlQuery().Select("c")).ToString());

            Assert.AreEqual("a <> ?", (!Exp.In("a", new[] { 1 })).ToString());
            Assert.AreEqual("1 <> 0", (!Exp.In("a", new int[0])).ToString());
            Assert.AreEqual("a not in (?,?)", (!Exp.In("a", new[] { 1, 2 })).ToString());
            Assert.AreEqual("a not in (select c)", (!Exp.In("a", new SqlQuery().Select("c"))).ToString());
        }

        [TestMethod]
        public void NullTest()
        {
            Assert.AreEqual("a is null", Exp.Eq("a", null).ToString());
            Assert.AreEqual("a is not null", (!Exp.Eq("a", null)).ToString());
        }

        [TestMethod]
        public void SqlInsertTest()
        {
            var i = new SqlInsert("Table").InColumnValue("c1", 1);
            Assert.AreEqual("insert into Table(c1) values (?)", i.ToString());

            i = new SqlInsert("Table").ReplaceExists(true).InColumnValue("c1", 1);
            Assert.AreEqual("replace into Table(c1) values (?)", i.ToString());

            i = new SqlInsert("Table").IgnoreExists(true).InColumnValue("c1", 1);
            Assert.AreEqual("insert ignore into Table(c1) values (?)", i.ToString());

            i = new SqlInsert("Table").InColumns("c1", "c2").Values(1, 2);
            Assert.AreEqual("insert into Table(c1,c2) values (?,?)", i.ToString());

            i = new SqlInsert("Table").InColumns("c1", "c2").Values(1, 2, 3, 4);
            Assert.AreEqual("insert into Table(c1,c2) values (?,?),(?,?)", i.ToString());

            i = new SqlInsert("Table").InColumns("c1", "c2").Values(0, 2).Identity(0, 0, true);
            Assert.AreEqual("insert into Table(c2) values (?); select @@identity", i.ToString());

            i = new SqlInsert("Table").Values(0, 2);
            Assert.AreEqual("insert into Table values (?,?)", i.ToString());
        }

        [TestMethod]
        public void SqlUpdateTest()
        {
            var update = new SqlUpdate("Table")
                .Set("Column1", 1)
                .Set("Column1", 2)
                .Set("Column2", 3)
                .Set("Column3 = Column3 + 2");

            Assert.AreEqual("update Table set Column1 = ?, Column2 = ?, Column3 = Column3 + 2", update.ToString());

            update = new SqlUpdate("Table")
                .Set("Column1", 1)
                .Set("Column1", 2)
                .Set("Column3", new SqlQuery("Table2").Select("x").Where("y", 5));

            Assert.AreEqual("update Table set Column1 = ?, Column3 = (select x from Table2 where y = ?)", update.ToString());
        }

        [TestMethod]
        public void SqlUnionTest()
        {
            var union = new SqlQuery("t1").Select("c1").Where("c1", 4)
                .Union(new SqlQuery("t2").Select("c2").Where("c2", 7));

            Assert.AreEqual("select c1 from t1 where c1 = ? union select c2 from t2 where c2 = ?", union.ToString());
            Assert.AreEqual(4, union.GetParameters()[0]);
            Assert.AreEqual(7, union.GetParameters()[1]);
        }

        [TestMethod]
        public void SqlCreateTableTest()
        {
            var q = new SqlCreate.Table("t1")
                    .AddColumn("c1", DbType.String, 255);
            Assert.AreEqual("create table t1 (c1 string(255) null);\r\n", q.ToString());
        }
    }
}
#endif

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/ListPages.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Community.Modules.Wiki.Resources;
using ASC.Web.Community.Product;
using ASC.Web.Community.Wiki.Common;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Controls.Common;
using ASC.Web.UserControls.Wiki;
using ASC.Web.UserControls.Wiki.Data;

using Newtonsoft.Json;

namespace ASC.Web.Community.Wiki
{
    public partial class ListPages : WikiBasePage
    {
        private const int MaxNewResults = 25;

        public string categoryName
        {
            get { return Request["cat"]; }
        }

        protected bool isShowCat
        {
            get { return !isByUser && !string.IsNullOrEmpty(categoryName); }
        }

        protected bool isShowNew
        {
            get { return !isShowCat && Request["n"] != null; }
        }

        protected bool isShowFresh
        {
            get { return !isShowNew && Request["f"] != null; }
        }

        protected bool isByUser
        {
            get { return !byUserID.Equals(Guid.Empty); }
        }

        private Guid? m_byUserID;

        protected Guid byUserID
        {
            get
            {
                if (m_byUserID == null)
                {
                    try
                    {
                        m_byUserID = new Guid(Request["uid"]);
                    }
                    catch
                    {
                        m_byUserID = Guid.Empty;
                    }
                }

                return m_byUserID.Value;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (isShowCat)
            {
                WikiMaster.CurrentPageCaption = string.Format(WikiResource.menu_ListPagesCatFormat, categoryName);
            }

            if (!IsPostBack)
            {
                InitPageData();
            }
        }

        private void InitPageData()
        {
            if (isByUser || isShowNew || isShowFresh)
            {
                List<Page> dataSource;
                var emptyScreenCaption = string.Empty;
                var emptyScreenText = string.Empty;

                if (isByUser)
                {
                    dataSource = Wiki.GetPages(byUserID);
                }
                else if (isShowNew)
                {
                    dataSource = Wiki.GetNewPages(MaxNewResults);
                    emptyScreenCaption = WikiResource.EmptyScreenWikiNewPagesCaption;
                    emptyScreenText = WikiResource.EmptyScreenWikiNewPagesText;
                }
                else
                {
                    dataSource = Wiki.GetRecentEditedPages(MaxNewResults);
                    emptyScreenCaption = WikiResource.EmptyScreenWikiRecentlyEditedCaption;
                    emptyScreenText = WikiResource.EmptyScreenWikiRecentlyEditedText;
                }


                Page.RegisterInlineScript(String.Format(" wikiPages = {0}; ASC.Community.Wiki.InitListPages();",
                                               JsonConvert.SerializeObject(dataSource.ConvertAll(p =>
                                                   new
                                                   {
                                                       PageName = GetPageName(p),
                                                       ID = p.ID,
                                                       PageLink = GetPageViewLink(p),
                                                       Author = CoreContext.UserManager.GetUsers(p.UserID).RenderCustomProfileLink("", "linkMedium"),
                                                       PageDate = GetDate(p)
                                                   }))
                                               ), onReady: true);


                var emptyScreenControl = new EmptyScreenControl
                {
                    ID = "wikiListPagesEmpty",
                    ImgSrc = WebImageSupplier.GetAbsoluteWebPath("wikilogo150.png", WikiManager.ModuleId),
                    Header = emptyScreenCaption,
                    Describe = emptyScreenText,
                    CssClass = "display-none"
                };

                if (CommunitySecurity.CheckPermissions(Community.Wiki.Common.Constants.Action_AddPage))
                {
                    emptyScreenControl.ButtonHTML = String.Format("<a class='link underline blue plus' href='Default.aspx?action=New'>{0}</a>", WikiResource.menu_AddNewPage);
                }

                phListEmptyScreen.Controls.Add(emptyScreenControl);

            }
            else
            {
                List<Page> result;
                result = isShowCat ? Wiki.GetPages(categoryName) : Wiki.GetPages();

                result.RemoveAll(pemp => string.IsNullOrEmpty(pemp.PageName));


                Page.RegisterInlineScript(String.Format(" wikiCategoryAlfaList = '{0}'; wikiPages = {1}; ASC.Community.Wiki.InitListPagesByLetter();",
                                                WikiResource.wikiCategoryAlfaList,
                                                JsonConvert.SerializeObject(result.ConvertAll(p => new { PageName = GetPageName(p), ID = p.ID, PageLink = GetPageViewLink(p) }))
                                                ), onReady: true);


                var emptyScreenControl = new EmptyScreenControl
                {
                    ID = "wikiListPagesByLetterEmpty",
                    ImgSrc = WebImageSupplier.GetAbsoluteWebPath("wikilogo150.png", WikiManager.ModuleId),
                    Header = WikiResource.EmptyScreenWikiIndexCaption,
                    Describe = WikiResource.EmptyScreenWikiIndexText,
                    CssClass = "display-none"
                };

                if (CommunitySecurity.CheckPermissions(Community.Wiki.Common.Constants.Action_AddPage))
                {
                    emptyScreenControl.ButtonHTML = String.Format("<a class='link underline blue plus' href='Default.aspx?action=New'>{0}</a>", WikiResource.menu_AddNewPage);
                }

                phListEmptyScreen.Controls.Add(emptyScreenControl);
            }
        }


        protected string GetDate(Page page)
        {
            return string.Format("{0} {1}", page.Date.ToString("t"), page.Date.ToString("d"));
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/TariffUsage.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Tenants;
using ASC.Geolocation;
using ASC.Web.Core;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

using PhoneNumbers;

namespace ASC.Web.Studio.UserControls.Management
{
    [AjaxNamespace("TariffUsageController")]
    public partial class TariffUsage : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/TariffSettings/TariffUsage.ascx"; }
        }

        protected Dictionary<string, bool> ListStarRemark = new Dictionary<string, bool>();

        protected int UsersCount;
        protected long UsedSize;

        protected Tariff CurrentTariff;
        protected TenantQuota CurrentQuota;

        protected bool MonthIsDisable;
        protected bool YearIsDisable;
        protected int MinActiveUser;

        protected RegionInfo RegionDefault = new RegionInfo("US");
        protected RegionInfo CurrentRegion;
        protected string PhoneCountry = "US";
        private string CurrentOwnerId = null;

        protected List<RegionInfo> Regions = new List<RegionInfo>();

        protected bool InRuble
        {
            get { return "RU".Equals(CurrentRegion.Name); }
        }

        protected bool InEuro
        {
            get { return "EUR".Equals(CurrentRegion.ISOCurrencySymbol); }
        }

        protected decimal[] PricesPerUser
        {
            get
            {
                return InEuro
                           ? new[] { 4.25m, 2.40m, 1.60m }
                           : new[] { 5.0m, 3.0m, 2.0m };
            }
        }

        protected decimal[] FakePrices
        {
            get
            {
                return InEuro
                           ? new[] { 9.0m, 18.0m }
                           : new[] { 10.0m, 20.0m };
            }
        }

        private string _currencyFormat = "{currency}{price}";
        private IDictionary<string, Dictionary<string, decimal>> _priceInfo;

        private IEnumerable<TenantQuota> _quotaList;
        protected List<TenantQuota> QuotasYear;

        private TenantQuota _quotaForDisplay;

        protected TenantQuota QuotaForDisplay
        {
            get
            {
                if (_quotaForDisplay != null) return _quotaForDisplay;
                TenantQuota quota = null;
                if (CurrentQuota.Trial
                    || CurrentQuota.Free
                    || !CurrentQuota.Visible)
                {
                    var rightQuotaId = TenantExtra.GetRightQuotaId();
                    quota = _quotaList.FirstOrDefault(q => q.Id == rightQuotaId);
                }
                _quotaForDisplay = quota ?? CurrentQuota;
                return _quotaForDisplay;
            }
        }

        protected bool PeopleModuleAvailable
        {
            get
            {
                var peopleProduct = WebItemManager.Instance[WebItemManager.PeopleProductID];
                return peopleProduct != null && !peopleProduct.IsDisabled();
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page
                .RegisterBodyScripts("~/UserControls/Management/TariffSettings/js/tariffusage.js",
                    "~/js/asc/plugins/countries.js",
                    "~/js/asc/plugins/phonecontroller.js")
                .RegisterStyle(
                    "~/skins/default/phonecontroller.css",
                    "~/UserControls/Management/TariffSettings/css/tariff.less",
                    "~/UserControls/Management/TariffSettings/css/tariffusage.less")
                .RegisterClientScript(new CountriesResources());

            CurrentRegion = RegionDefault;
            Regions.Add(CurrentRegion);

            UsersCount = TenantStatisticsProvider.GetUsersCount();
            UsedSize = TenantStatisticsProvider.GetUsedSize();
            CurrentTariff = TenantExtra.GetCurrentTariff();
            CurrentQuota = TenantExtra.GetTenantQuota();

            if (_quotaList == null || !_quotaList.Any())
            {
                _quotaList = TenantExtra.GetTenantQuotas();
            }
            else if (!CurrentQuota.Trial)
            {
                CurrentQuota = _quotaList.FirstOrDefault(q => q.Id == CurrentQuota.Id) ?? CurrentQuota;
            }
            _quotaList = _quotaList.OrderBy(r => r.ActiveUsers).ToList().Where(r => !r.Trial);
            QuotasYear = _quotaList.Where(r => r.Year).ToList();

            MonthIsDisable = !CurrentQuota.Free && (CurrentQuota.Year || CurrentQuota.Year3) && CurrentTariff.State == TariffState.Paid;
            YearIsDisable = !CurrentQuota.Free && CurrentQuota.Year3 && CurrentTariff.State == TariffState.Paid;

            var minYearQuota = QuotasYear.FirstOrDefault(q => q.ActiveUsers >= UsersCount && q.MaxTotalSize >= UsedSize);
            MinActiveUser = minYearQuota != null ? minYearQuota.ActiveUsers : (QuotasYear.Count > 0 ? QuotasYear.Last().ActiveUsers : 0 + 1);

            downgradeInfoContainer.Options.IsPopup = true;
            AjaxPro.Utility.RegisterTypeForAjax(GetType());

            CurrencyCheck();
            CurrentOwnerId = CoreContext.TenantManager.GetCurrentTenant().OwnerId.ToString();
        }

        private void CurrencyCheck()
        {
            var findRegion = FindRegionInfo();

            CurrentRegion = findRegion ?? CurrentRegion;
            PhoneCountry = (findRegion ?? new RegionInfo(Thread.CurrentThread.CurrentCulture.LCID)).TwoLetterISORegionName;

            if (!CurrentRegion.Equals(RegionDefault))
            {
                Regions.Add(CurrentRegion);
            }

            var requestCur = Request["cur"];
            if (!string.IsNullOrEmpty(requestCur))
            {
                try
                {
                    CurrentRegion = new RegionInfo(requestCur);
                    if (!Regions.Contains(CurrentRegion))
                    {
                        Regions.Add(CurrentRegion);
                    }
                }
                catch
                {
                }
            }

            _priceInfo = CoreContext.TenantManager.GetProductPriceInfo(false);
            if (!_priceInfo.Values.Any(value => value.ContainsKey(CurrentRegion.ISOCurrencySymbol)))
            {
                Regions.Remove(CurrentRegion);
                CurrentRegion = RegionDefault;
            }

            if (InRuble)
            {
                _currencyFormat = "{price}{currency}";

                SetStar(string.Format(Resource.TariffsCurrencyRu, SetupInfo.ExchangeRateRuble));
            }
        }

        private static RegionInfo FindRegionInfo()
        {
            RegionInfo ri = null;

            var ownerId = CoreContext.TenantManager.GetCurrentTenant().OwnerId;
            var owner = CoreContext.UserManager.GetUsers(ownerId);
            if (!string.IsNullOrEmpty(owner.MobilePhone))
            {
                try
                {
                    var phoneUtil = PhoneNumberUtil.GetInstance();
                    var number = phoneUtil.Parse("+" + owner.MobilePhone.TrimStart('+'), "en-US");
                    var regionCode = phoneUtil.GetRegionCodeForNumber(number);
                    if (!string.IsNullOrEmpty(regionCode))
                    {
                        ri = new RegionInfo(regionCode);
                    }
                }
                catch (Exception err)
                {
                    LogManager.GetLogger("ASC.Web.Tariff").WarnFormat("Can not find country by phone {0}: {1}", owner.MobilePhone, err);
                }
            }

            if (ri == null)
            {
                var geoinfo = new GeolocationHelper("teamlabsite").GetIPGeolocationFromHttpContext();
                if (!string.IsNullOrEmpty(geoinfo.Key))
                {
                    try
                    {
                        ri = new RegionInfo(geoinfo.Key);
                    }
                    catch (Exception)
                    {
                        // ignore
                    }
                }
            }
            return ri;
        }

        protected string TariffDescription()
        {
            if (CurrentQuota.Trial)
            {
                if (CurrentTariff.State == TariffState.Trial)
                {
                    return "<b>" + Resource.TariffTrial + "</b> "
                           + (CurrentTariff.DueDate.Date != DateTime.MaxValue.Date
                                  ? string.Format(Resource.TariffExpiredDate, CurrentTariff.DueDate.Date.ToLongDateString())
                                  : "")
                           + "<br />" + Resource.TariffChooseLabel;
                }
                return String.Format(Resource.TariffTrialOverdue.HtmlEncode(),
                                     "<span class='tarifff-marked'>",
                                     "</span>",
                                     "<br />", string.Empty, string.Empty);
            }

            if (CurrentQuota.Free)
            {
                return "<b>" + Resource.TariffFree + "</b><br />" + Resource.TariffChooseLabel;
            }

            if (CurrentTariff.State == TariffState.Paid
                && CurrentTariff.DueDate.Date >= DateTime.Today)
            {
                if (CurrentQuota.NonProfit)
                {
                    return "<b>" + UserControlsCommonResource.TariffNonProfit + "</b>";
                }

                var str = "<b>"
                          + String.Format(UserControlsCommonResource.TariffPaidPlan,
                                          TenantExtra.GetPrevUsersCount(CurrentQuota),
                                          CurrentQuota.ActiveUsers)
                          + "</b> ";
                if (CurrentTariff.DueDate.Date != DateTime.MaxValue.Date)
                    str += string.Format(Resource.TariffExpiredDate, CurrentTariff.DueDate.Date.ToLongDateString());

                if (CurrentTariff.Autorenewal) return str;
                str += "<br />" + Resource.TariffCanProlong;
                return str;
            }

            return String.Format(UserControlsCommonResource.TariffOverduePlan.HtmlEncode(),
                                 TenantExtra.GetPrevUsersCount(CurrentQuota),
                                 CurrentQuota.ActiveUsers,
                                 "<span class='tariff-marked'>",
                                 "</span>",
                                 "<br />");
        }

        protected TenantQuota GetQuotaMonth(TenantQuota quota)
        {
            return _quotaList.FirstOrDefault(r =>
                                             r.ActiveUsers == quota.ActiveUsers
                                             && (!r.Year || quota.Free)
                                             && !r.Year3);
        }

        protected TenantQuota GetQuotaYear3(TenantQuota quota)
        {
            return _quotaList.FirstOrDefault(r =>
                                             r.ActiveUsers == quota.ActiveUsers
                                             && r.Year3);
        }

        protected Tuple<string, string, string> GetBuyAttr(TenantQuota quota)
        {
            var cssList = new List<string>();
            var getHref = true;
            var text = Resource.TariffButtonBuy;

            if (quota != null)
            {
                cssList.Add(CurrentTariff.State >= TariffState.NotPaid ? "red" : "blue");

                if (quota.ActiveUsers < UsersCount || quota.MaxTotalSize < UsedSize)
                {
                    cssList.Add("disable");
                    getHref = false;
                }
                else if (Equals(quota.Id, CurrentQuota.Id))
                {
                    text = Resource.TariffButtonExtend;
                    if (!CurrentTariff.Prolongable)
                    {
                        cssList.Add("disable");
                        getHref = false;
                    }
                    else if (CurrentTariff.Autorenewal)
                    {
                        cssList.Add("disable");
                        getHref = false;
                        text = Resource.TariffEnabledAutorenew + SetStar(Resource.TariffRemarkProlongEnable);
                    }
                }
                else if (CurrentTariff.Prolongable)
                {
                    text = Resource.TariffButtonBuy + SetStar(Resource.TariffRemarkProlongDisable);
                }
                else if (CurrentTariff.State == TariffState.Paid
                    && quota.ActiveUsers < CurrentQuota.ActiveUsers)
                {
                    cssList.Add("disable");
                    getHref = false;
                    text = Resource.TariffButtonBuy + SetStar(CurrentQuota.Year3 ? Resource.TariffRemarkDisabledYear : Resource.TariffRemarkDisabledMonth);
                }

                if (!quota.Year3)
                {
                    if (quota.Year && YearIsDisable || !quota.Year && MonthIsDisable)
                    {
                        cssList.Add("disable");
                        getHref = false;
                        text = Resource.TariffButtonBuy;
                    }
                }
            }
            else
            {
                cssList.Add("disable");
                getHref = false;
            }

            var href = getHref ? GetShoppingUri(quota) : string.Empty;
            var cssClass = string.Join(" ", cssList.Distinct());
            var result = new Tuple<string, string, string>(cssClass, href, text);
            return result;
        }

        private string GetShoppingUri(TenantQuota quota)
        {
            var uri = string.Empty;
            if (quota != null)
            {
                try
                {
                    var link = CoreContext.PaymentManager.GetShoppingUri(quota.Id, true, null, CurrentRegion.ISOCurrencySymbol, Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName, CurrentOwnerId);
                    if (link == null)
                    {
                        LogManager.GetLogger("ASC.Web.Billing").Info(string.Format("GetShoppingUri return null for tenant {0} and quota {1}", TenantProvider.CurrentTenantID, quota.Id));
                    }
                    else
                    {
                        uri = link.ToString();
                    }
                }
                catch (Exception ex)
                {
                    LogManager.GetLogger("ASC").Info(string.Format("GetShoppingUri: {0} tenant {1} quota {2} currency {3} Language {4}",
                        ex.Message, TenantProvider.CurrentTenantID, quota.Id, CurrentRegion.ISOCurrencySymbol, Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName),
                        ex);
                }
            }
            return uri;
        }

        protected string SetStar(string starType, bool withHighlight = false)
        {
            if (!ListStarRemark.Keys.Contains(starType))
            {
                ListStarRemark.Add(starType, withHighlight);
            }

            return GetStar(starType);
        }

        protected string GetStar(string starType)
        {
            if (!ListStarRemark.Keys.Contains(starType))
            {
                return null;
            }

            var result = string.Empty;
            for (var i = 0; i < ListStarRemark.Keys.ToList().IndexOf(starType) + 1; i++)
            {
                result += "*";
            }

            return result;
        }

        protected string GetRemarks()
        {
            var result = string.Empty;
            if (QuotasYear.Count == 0) return result;

            foreach (var starType in ListStarRemark)
            {
                if (!string.IsNullOrEmpty(result))
                    result += "<br />";

                if (starType.Value)
                    result += "<span class=\"tariff-remark-highlight\">";
                result += GetStar(starType.Key) + " ";
                result += starType.Key;
                if (starType.Value)
                    result += "</span>";
            }

            return result;
        }

        protected string GetSaleDate()
        {
            DateTime date;
            if (!DateTime.TryParse(ConfigurationManagerExtension.AppSettings["web.payment-sale"], out date))
            {
                date = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1).AddMonths(1).AddDays(-1);
            }

            return date.ToString(Thread.CurrentThread.CurrentCulture.DateTimeFormat.MonthDayPattern);
        }

        protected string GetPriceString(decimal price, bool rubleRate = true, string currencySymbol = null)
        {
            if (rubleRate && InRuble)
            {
                price = price * SetupInfo.ExchangeRateRuble;
            }

            var priceString = InEuro && Math.Truncate(price) != price
                                  ? price.ToString(CultureInfo.InvariantCulture)
                                  : ((int)price).ToString(CultureInfo.InvariantCulture);

            return _currencyFormat
                .Replace("{currency}", "<span class='tariff-price-cur'>" + (currencySymbol ?? CurrentRegion.CurrencySymbol) + "</span>")
                .Replace("{price}", priceString);
        }

        protected string GetPriceString(TenantQuota quota)
        {
            if (!string.IsNullOrEmpty(quota.AvangateId) && _priceInfo.ContainsKey(quota.AvangateId))
            {
                var prices = _priceInfo[quota.AvangateId];
                if (prices.ContainsKey(CurrentRegion.ISOCurrencySymbol))
                {
                    return GetPriceString(prices[CurrentRegion.ISOCurrencySymbol], false);
                }
                return GetPriceString(quota.Price, false, RegionDefault.CurrencySymbol);
            }
            return GetPriceString(quota.Price);
        }

        protected decimal GetPrice(TenantQuota quota)
        {
            if (!string.IsNullOrEmpty(quota.AvangateId) && _priceInfo.ContainsKey(quota.AvangateId))
            {
                var prices = _priceInfo[quota.AvangateId];
                if (prices.ContainsKey(CurrentRegion.ISOCurrencySymbol))
                {
                    return prices[CurrentRegion.ISOCurrencySymbol];
                }
                return quota.Price;
            }
            return quota.Price;
        }

        protected decimal GetSaleValue(decimal priceMonth, TenantQuota quota)
        {
            var price = GetPrice(quota);

            var period = quota.Year ? 12 : 36;
            return priceMonth * period - price;
        }

        protected string GetPerUserPrice(TenantQuota quota)
        {
            var price = PricesPerUser[quota == null ? 0 : quota.Year ? 1 : quota.Year3 ? 2 : 0];
            return GetPriceString(price, InRuble);
        }

        [AjaxMethod]
        public void RequestTariff(string fname, string lname, string title, string email, string phone, string ctitle, string csize, string site, string message)
        {
            var key = HttpContext.Current.Request.UserHostAddress + "requesttariff";
            var count = Convert.ToInt32(HttpContext.Current.Cache[key]);
            if (2 < count)
            {
                throw new ArgumentOutOfRangeException("Messages count", "Rate limit exceeded.");
            }
            HttpContext.Current.Cache.Insert(key, ++count, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(2));

            StudioNotifyService.Instance.SendRequestTariff(false, fname, lname, title, email, phone, ctitle, csize, site, message);
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Notify/DirectSubscriptionProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Notify.Model;
using ASC.Notify.Recipients;

namespace ASC.Core.Notify
{
    public class DirectSubscriptionProvider : ISubscriptionProvider
    {
        private readonly IRecipientProvider recipientProvider;
        private readonly SubscriptionManager subscriptionManager;
        private readonly string sourceID;


        public DirectSubscriptionProvider(string sourceID, SubscriptionManager subscriptionManager, IRecipientProvider recipientProvider)
        {
            if (string.IsNullOrEmpty(sourceID)) throw new ArgumentNullException("sourceID");
            if (subscriptionManager == null) throw new ArgumentNullException("subscriptionManager");
            if (recipientProvider == null) throw new ArgumentNullException("recipientProvider");

            this.sourceID = sourceID;
            this.subscriptionManager = subscriptionManager;
            this.recipientProvider = recipientProvider;
        }


        public object GetSubscriptionRecord(INotifyAction action, IRecipient recipient, string objectID)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            return subscriptionManager.GetSubscriptionRecord(sourceID, action.ID, recipient.ID, objectID);
        }

        public string[] GetSubscriptions(INotifyAction action, IRecipient recipient, bool checkSubscribe = true)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            return subscriptionManager.GetSubscriptions(sourceID, action.ID, recipient.ID, checkSubscribe);
        }

        public IRecipient[] GetRecipients(INotifyAction action, string objectID)
        {
            if (action == null) throw new ArgumentNullException("action");

            return subscriptionManager.GetRecipients(sourceID, action.ID, objectID)
                .Select(r => recipientProvider.GetRecipient(r))
                .Where(r => r != null)
                .ToArray();
        }

        public string[] GetSubscriptionMethod(INotifyAction action, IRecipient recipient)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            return subscriptionManager.GetSubscriptionMethod(sourceID, action.ID, recipient.ID);
        }

        public void UpdateSubscriptionMethod(INotifyAction action, IRecipient recipient, params string[] senderNames)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");
            subscriptionManager.UpdateSubscriptionMethod(sourceID, action.ID, recipient.ID, senderNames);
        }

        public bool IsUnsubscribe(IDirectRecipient recipient, INotifyAction action, string objectID)
        {
            if (recipient == null) throw new ArgumentNullException("recipient");
            if (action == null) throw new ArgumentNullException("action");

            return subscriptionManager.IsUnsubscribe(sourceID, recipient.ID, action.ID, objectID);
        }

        public void Subscribe(INotifyAction action, string objectID, IRecipient recipient)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            subscriptionManager.Subscribe(sourceID, action.ID, objectID, recipient.ID);
        }

        public void UnSubscribe(INotifyAction action, string objectID, IRecipient recipient)
        {
            if (action == null) throw new ArgumentNullException("action");
            if (recipient == null) throw new ArgumentNullException("recipient");

            subscriptionManager.Unsubscribe(sourceID, action.ID, objectID, recipient.ID);
        }

        public void UnSubscribe(INotifyAction action)
        {
            if (action == null) throw new ArgumentNullException("action");

            subscriptionManager.UnsubscribeAll(sourceID, action.ID);
        }

        public void UnSubscribe(INotifyAction action, string objectID)
        {
            if (action == null) throw new ArgumentNullException("action");

            subscriptionManager.UnsubscribeAll(sourceID, action.ID, objectID);
        }

        [Obsolete("Use UnSubscribe(INotifyAction, string, IRecipient)", true)]
        public void UnSubscribe(INotifyAction action, IRecipient recipient)
        {
            throw new NotSupportedException("use UnSubscribe(INotifyAction, string, IRecipient )");
        }
    }
}

<|start_filename|>common/ASC.Data.Storage/Extensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Threading;

using ASC.Common;
using ASC.Data.Storage;

public static class Extensions
{
    private const int BufferSize = 2048;//NOTE: set to 2048 to fit in minimum tcp window

    public static Stream IronReadStream(this IDataStore store, string domain, string path, int tryCount)
    {
        var ms = TempStream.Create();
        IronReadToStream(store, domain, path, tryCount, ms);
        ms.Seek(0, SeekOrigin.Begin);
        return ms;
    }

    public static void IronReadToStream(this IDataStore store, string domain, string path, int tryCount, Stream readTo)
    {
        if (tryCount < 1) throw new ArgumentOutOfRangeException("tryCount", "Must be greater or equal 1.");
        if (!readTo.CanWrite) throw new ArgumentException("stream cannot be written", "readTo");

        var tryCurrent = 0;
        var offset = 0;

        while (tryCurrent < tryCount)
        {
            try
            {
                tryCurrent++;
                using (var stream = store.GetReadStream(domain, path, offset))
                {
                    var buffer = new byte[BufferSize];
                    var readed = 0;
                    while ((readed = stream.Read(buffer, 0, BufferSize)) > 0)
                    {
                        readTo.Write(buffer, 0, readed);
                        offset += readed;
                    }
                }
                break;
            }
            catch (Exception ex)
            {
                if (tryCurrent >= tryCount)
                {
                    throw new IOException("Can not read stream. Tries count: " + tryCurrent + ".", ex);
                }
                Thread.Sleep(tryCount * 50);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/SingleSignOnSettings/SsoSettingsV2.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;

namespace ASC.Web.Studio.UserControls.Management.SingleSignOnSettings
{
    [Serializable]
    [DataContract]
    public class SsoSettingsV2 : BaseSettings<SsoSettingsV2>
    {
        public override Guid ID
        {
            get { return new Guid("{1500187F-B8AB-406F-97B8-04BFE8261DBE}"); }
        }

        public const string SSO_SP_LOGIN_LABEL = "Single Sign-on";

        public override ISettings GetDefault()
        {
            return new SsoSettingsV2
            {
                EnableSso = false,

                IdpSettings = new SsoIdpSettings
                {
                    EntityId = string.Empty,
                    SsoUrl = string.Empty,
                    SsoBinding = SsoBindingType.Saml20HttpPost,
                    SloUrl = string.Empty,
                    SloBinding = SsoBindingType.Saml20HttpPost,
                    NameIdFormat = SsoNameIdFormatType.Saml20Transient
                },

                IdpCertificates = new List<SsoCertificate>(),
                IdpCertificateAdvanced = new SsoIdpCertificateAdvanced
                {
                    DecryptAlgorithm = SsoEncryptAlgorithmType.AES_128,
                    DecryptAssertions = false,
                    VerifyAlgorithm = SsoSigningAlgorithmType.RSA_SHA1,
                    VerifyAuthResponsesSign = false,
                    VerifyLogoutRequestsSign = false,
                    VerifyLogoutResponsesSign = false
                },

                SpCertificates = new List<SsoCertificate>(),
                SpCertificateAdvanced = new SsoSpCertificateAdvanced
                {
                    DecryptAlgorithm = SsoEncryptAlgorithmType.AES_128,
                    EncryptAlgorithm = SsoEncryptAlgorithmType.AES_128,
                    EncryptAssertions = false,
                    SigningAlgorithm = SsoSigningAlgorithmType.RSA_SHA1,
                    SignAuthRequests = false,
                    SignLogoutRequests = false,
                    SignLogoutResponses = false
                },

                FieldMapping = new SsoFieldMapping
                {
                    FirstName = "givenName",
                    LastName = "sn",
                    Email = "mail",
                    Title = "title",
                    Location = "l",
                    Phone = "mobile"
                },
                SpLoginLabel = SSO_SP_LOGIN_LABEL,
                HideAuthPage = false
            };
        }

        [DataMember]
        public bool EnableSso { get; set; }

        [DataMember]
        public SsoIdpSettings IdpSettings { get; set; }

        [DataMember]
        public List<SsoCertificate> IdpCertificates { get; set; }

        [DataMember]
        public SsoIdpCertificateAdvanced IdpCertificateAdvanced { get; set; }

        [DataMember]
        public string SpLoginLabel { get; set; }

        [DataMember]
        public List<SsoCertificate> SpCertificates { get; set; }

        [DataMember]
        public SsoSpCertificateAdvanced SpCertificateAdvanced { get; set; }

        [DataMember]
        public SsoFieldMapping FieldMapping { get; set; }

        [DataMember]
        public bool HideAuthPage { get; set; }
    }


    #region SpSettings

    [Serializable]
    [DataContract]
    public class SsoIdpSettings
    {
        [DataMember]
        public string EntityId { get; set; }

        [DataMember]
        public string SsoUrl { get; set; }

        [DataMember]
        public string SsoBinding { get; set; }

        [DataMember]
        public string SloUrl { get; set; }

        [DataMember]
        public string SloBinding { get; set; }

        [DataMember]
        public string NameIdFormat { get; set; }
    }

    #endregion


    #region FieldsMapping

    [Serializable]
    [DataContract]
    public class SsoFieldMapping
    {
        [DataMember]
        public string FirstName { get; set; }

        [DataMember]
        public string LastName { get; set; }

        [DataMember]
        public string Email { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Location { get; set; }

        [DataMember]
        public string Phone { get; set; }
    }

    #endregion


    #region Certificates

    [Serializable]
    [DataContract]
    public class SsoCertificate
    {
        [DataMember]
        public bool SelfSigned { get; set; }

        [DataMember]
        public string Crt { get; set; }

        [DataMember]
        public string Key { get; set; }

        [DataMember]
        public string Action { get; set; }

        [DataMember]
        public string DomainName { get; set; }

        [DataMember]
        public DateTime StartDate { get; set; }

        [DataMember]
        public DateTime ExpiredDate { get; set; }
    }

    [Serializable]
    [DataContract]
    public class SsoIdpCertificateAdvanced
    {
        [DataMember]
        public string VerifyAlgorithm { get; set; }

        [DataMember]
        public bool VerifyAuthResponsesSign { get; set; }

        [DataMember]
        public bool VerifyLogoutRequestsSign { get; set; }

        [DataMember]
        public bool VerifyLogoutResponsesSign { get; set; }

        [DataMember]
        public string DecryptAlgorithm { get; set; }

        [DataMember]
        public bool DecryptAssertions { get; set; }
    }

    [Serializable]
    [DataContract]
    public class SsoSpCertificateAdvanced
    {
        [DataMember]
        public string SigningAlgorithm { get; set; }

        [DataMember]
        public bool SignAuthRequests { get; set; }

        [DataMember]
        public bool SignLogoutRequests { get; set; }

        [DataMember]
        public bool SignLogoutResponses { get; set; }

        [DataMember]
        public string EncryptAlgorithm { get; set; }

        [DataMember]
        public string DecryptAlgorithm { get; set; }


        [DataMember]
        public bool EncryptAssertions { get; set; }
    }

    #endregion


    #region Types

    [Serializable]
    [DataContract]
    public class SsoNameIdFormatType
    {
        [DataMember]
        public const string Saml11Unspecified = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified";

        [DataMember]
        public const string Saml11EmailAddress = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";

        [DataMember]
        public const string Saml20Entity = "urn:oasis:names:tc:SAML:2.0:nameid-format:entity";

        [DataMember]
        public const string Saml20Transient = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";

        [DataMember]
        public const string Saml20Persistent = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent";

        [DataMember]
        public const string Saml20Encrypted = "urn:oasis:names:tc:SAML:2.0:nameid-format:encrypted";

        [DataMember]
        public const string Saml20Unspecified = "urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified";

        [DataMember]
        public const string Saml11X509SubjectName = "urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName";

        [DataMember]
        public const string Saml11WindowsDomainQualifiedName = "urn:oasis:names:tc:SAML:1.1:nameid-format:WindowsDomainQualifiedName";

        [DataMember]
        public const string Saml20Kerberos = "urn:oasis:names:tc:SAML:2.0:nameid-format:kerberos";
    }

    [Serializable]
    [DataContract]
    public class SsoBindingType
    {
        [DataMember]
        public const string Saml20HttpPost = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";

        [DataMember]
        public const string Saml20HttpRedirect = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";
    }

    [Serializable]
    [DataContract]
    public class SsoMetadata
    {

        [DataMember]
        public const string BaseUrl = "";

        [DataMember]
        public const string MetadataUrl = "/sso/metadata";

        [DataMember]
        public const string EntityId = "/sso/metadata";

        [DataMember]
        public const string ConsumerUrl = "/sso/acs";

        [DataMember]
        public const string LogoutUrl = "/sso/slo/callback";

    }

    [Serializable]
    [DataContract]
    public class SsoSigningAlgorithmType
    {
        [DataMember]
        public const string RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";

        [DataMember]
        public const string RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

        [DataMember]
        public const string RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512";
    }

    [Serializable]
    [DataContract]
    public class SsoEncryptAlgorithmType
    {
        [DataMember]
        public const string AES_128 = "http://www.w3.org/2001/04/xmlenc#aes128-cbc";

        [DataMember]
        public const string AES_256 = "http://www.w3.org/2001/04/xmlenc#aes256-cbc";

        [DataMember]
        public const string TRI_DEC = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc";
    }

    [Serializable]
    [DataContract]
    public class SsoSpCertificateActionType
    {
        [DataMember]
        public const string Signing = "signing";

        [DataMember]
        public const string Encrypt = "encrypt";

        [DataMember]
        public const string SigningAndEncrypt = "signing and encrypt";
    }

    [Serializable]
    [DataContract]
    public class SsoIdpCertificateActionType
    {
        [DataMember]
        public const string Verification = "verification";

        [DataMember]
        public const string Decrypt = "decrypt";

        [DataMember]
        public const string VerificationAndDecrypt = "verification and decrypt";
    }

    #endregion
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/BookmarkingUserControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;

using AjaxPro;

using ASC.Bookmarking;
using ASC.Bookmarking.Business.Permissions;
using ASC.Bookmarking.Common;
using ASC.Bookmarking.Pojo;
using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Community.Modules.Bookmarking.UserControls.Resources;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Controls.Common;
using ASC.Web.Studio.UserControls.Common.ViewSwitcher;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Bookmarking.Common;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;
using ASC.Web.UserControls.Bookmarking.Common.Util;
using ASC.Web.UserControls.Bookmarking.Util;

using HtmlAgilityPack;

namespace ASC.Web.UserControls.Bookmarking
{
    [AjaxNamespace("BookmarkPage")]
    public partial class BookmarkingUserControl : UserControl
    {
        #region Fields

        private readonly BookmarkingServiceHelper _serviceHelper = BookmarkingServiceHelper.GetCurrentInstanse();

        public IList<Bookmark> Bookmarks { get; set; }

        public int BookmarkPageCounter
        {
            get { return ViewState["PageSize"] != null ? Convert.ToInt32(ViewState["PageSize"]) : 20; }
            set { ViewState["PageSize"] = value; }
        }

        #endregion

        #region Init

        protected void Page_Load(object sender, EventArgs e)
        {

            Utility.RegisterTypeForAjax(typeof(BookmarkingUserControl));
            Utility.RegisterTypeForAjax(typeof(SingleBookmarkUserControl));

            BookmarkPageCounter = string.IsNullOrEmpty(Request["size"]) ? 20 : Convert.ToInt32(Request["size"]);

            var createBookmark = LoadControl(BookmarkUserControlPath.CreateBookmarkUserControlPath) as CreateBookmarkUserControl;
            CreateBookmarkPanel.Controls.Add(createBookmark);

            var removePopup = LoadControl(BookmarkingRemoverFromFavouritePopup.Location) as BookmarkingRemoverFromFavouritePopup;
            BookmarkingRemoveFromFavouritePopupContainer.Controls.Add(removePopup);

            InitSettings();

            var SortControl = new ViewSwitcher { SortItemsHeader = BookmarkingUCResource.ShowLabel };

            _serviceHelper.InitServiceHelper(SortControl);
            BookmarkingSortPanel.Controls.Add(SortControl);

            if (Bookmarks == null)
            {
                Bookmarks = _serviceHelper.GetBookmarks(BookmarkPageCounter);
            }

            if (Bookmarks == null || Bookmarks.Count == 0)
            {
                var hidePanelsFlag = false;

                var currentUser = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);

                var emptyScreenControl = new EmptyScreenControl
                {
                    ImgSrc = WebImageSupplier.GetAbsoluteWebPath("bookmarks_icon.png", BookmarkingSettings.ModuleId),
                    Describe = currentUser.IsVisitor() ? BookmarkingUCResource.EmptyScreenTextVisitor : BookmarkingUCResource.EmptyScreenText
                };

                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                if (displayMode.Equals(BookmarkDisplayMode.SearchBookmarks))
                {
                    hidePanelsFlag = true;

                    emptyScreenControl.Header = BookmarkingUCResource.EmptyScreenSearchCaption;
                }
                else
                {
                    var sortBy = Request.QueryString[BookmarkingRequestConstants.SortByParam];
                    if (string.IsNullOrEmpty(sortBy)
                        || BookmarkingRequestConstants.MostRecentParam.Equals(sortBy)
                        || BookmarkingRequestConstants.PopularityParam.Equals(sortBy))
                    {
                        hidePanelsFlag = true;

                        emptyScreenControl.Header = BookmarkingUCResource.EmptyScreenCaption;

                        if (BookmarkingPermissionsCheck.PermissionCheckCreateBookmark())
                        {
                            emptyScreenControl.ButtonHTML = String.Format("<a class='link underline blue plus' href='CreateBookmark.aspx'>{0}</a>", BookmarkingUCResource.EmptyScreenLink);
                        }
                    }
                    else
                    {
                        emptyScreenControl.Header = BookmarkingUCResource.EmptyScreenSearchCaption;
                    }
                }

                BookmarksHolder.Controls.Add(emptyScreenControl);
                if (hidePanelsFlag)
                {
                    BookmarkingSortPanel.Visible = false;
                    CreateBookmarkPanel.Visible = false;
                    BookmarksMainPanel.Visible = false;
                }
            }
            else
            {
                LoadBookmarks(Bookmarks);
            }
            InitScripts();
        }

        private void InitSettings()
        {
            BookmarkingSettings.ThumbnailAbsolutePath = Server.MapPath("~/");
            BookmarkingSettings.ThumbnailAbsoluteFilePath = BookmarkingSettings.ThumbnailAbsolutePath + BookmarkingSettings.ThumbnailRelativePath;
        }

        #endregion

        #region Load & Refresh Bookmarks

        private void LoadBookmarks(IList<Bookmark> bookmarks)
        {
            var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

            if (!BookmarkDisplayMode.SelectedBookmark.Equals(displayMode))
            {
                AddBookmarksListToPlaceHolder(bookmarks, BookmarksHolder);
            }
        }

        private void AddBookmarksListToPlaceHolder(IList<Bookmark> bookmarks, HtmlGenericControl p)
        {
            foreach (var b in bookmarks)
            {
                var c = LoadControl(BookmarkUserControlPath.SingleBookmarkUserControlPath) as BookmarkInfoBase;
                c.Bookmark = b;
                //c.UserBookmark = ServiceHelper.GetCurrentUserBookmark(b);
                c.UserBookmark = _serviceHelper.GetCurrentUserBookmark(b.UserBookmarks);
                p.Controls.Add(c);
            }
        }

        #endregion

        #region Remove From Favourites

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object RemoveBookmarkFromFavouriteInFavouriteMode(int userBookmarkID)
        {
            _serviceHelper.RemoveBookmarkFromFavourite(userBookmarkID);
            return null;
        }

        /// <summary>
        /// Removes bookmark from favourite. If after removing user bookmark raiting of this bookmark is 0, the bookmark will be removed completely.
        /// </summary>
        /// <param name="userBookmarkID"></param>
        /// <param name="uniqueID"></param>
        /// <returns>
        /// 1. null, if the bookmark was removed completely on the BookmarkInfo page.
        /// 2. string.Empty, is the bookmark was removed completely on the FavouriteBookmarks page.
        /// 3. Original bookmark in html.
        /// </returns>
        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object RemoveBookmarkFromFavourite(int userBookmarkID, string uniqueID)
        {
            var b = _serviceHelper.RemoveBookmarkFromFavourite(userBookmarkID);

            var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

            if (b == null)
            {
                return BookmarkDisplayMode.SelectedBookmark == displayMode ? null : string.Empty;
            }
            var userBookmarks = _serviceHelper.GetUserBookmarks(b);
            if (userBookmarks == null || userBookmarks.Count == 0)
            {
                return BookmarkDisplayMode.SelectedBookmark == displayMode ? null : string.Empty;
            }
            return new { Bookmark = GetBookmarkAsString(b, new Guid(uniqueID)), ID = _serviceHelper.GetCurrentUserID() };
        }

        private object GetBookmarkAsString(Bookmark b, Guid uniqueID)
        {
            var sb = new StringBuilder();
            using (var sw = new StringWriter(sb))
            {
                using (var textWriter = new HtmlTextWriter(sw))
                {
                    try
                    {
                        var c = LoadControl(BookmarkUserControlPath.SingleBookmarkUserControlPath) as BookmarkInfoBase;
                        c.Bookmark = b;
                        c.UserBookmark = _serviceHelper.GetCurrentUserBookmark(b);
                        c.UniqueId = uniqueID;
                        c.InitUserControl();
                        c.RenderControl(textWriter);
                    }
                    catch
                    {
                    }
                }
            }
            return sb.ToString();
        }

        #endregion

        #region Save Bookmark

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object SaveBookmark(string BookmarkUrl, string BookmarkName, string BookmarkDescription, string BookmarkTags)
        {
            var url = UpdateURL(BookmarkUrl);
            var b = _serviceHelper.AddBookmark(url, BookmarkName, BookmarkDescription, BookmarkTags);
            return GetBookmarkAsString(b, Guid.NewGuid());
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object SaveBookmarkAjax(string BookmarkUrl, string BookmarkName, string BookmarkDescription, string BookmarkTags, string uniqueID)
        {
            var url = UpdateURL(BookmarkUrl);

            var b = _serviceHelper.AddBookmark(url, BookmarkName, BookmarkDescription, BookmarkTags);
            b = _serviceHelper.GetBookmarkWithUserBookmarks(url);

            var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

            var bookmarkString = GetBookmarkAsString(b, new Guid(uniqueID));

            if (BookmarkDisplayMode.SelectedBookmark == displayMode)
            {
                var userImage = BookmarkingServiceHelper.GetHTMLUserAvatar();
                var userPageLink = BookmarkingServiceHelper.GetUserPageLink();
                var ub = _serviceHelper.GetCurrentUserBookmark(b);

                var userBookmarkDescription = BookmarkingServiceHelper.GetUserBookmarkDescriptionIfChanged(ub);
                var dateAdded = BookmarkingConverter.GetDateAsString(ub.DateAdded);
                var divID = ub.UserID.ToString();
                var userBookmarks = _serviceHelper.GetUserBookmarks(b);
                var addedBy = new BookmarkAddedByUserContorl().GetAddedByTableItem(userBookmarks.Count % 2 != 0, userImage, userPageLink, userBookmarkDescription, dateAdded, divID);
                return new { BookmarkString = bookmarkString, AddedBy = addedBy, DivID = divID };
            }
            return new { BookmarkString = bookmarkString, AddedBy = string.Empty };
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void RemoveBookmark(int userBookmarkID)
        {
            _serviceHelper.RemoveBookmark(userBookmarkID);
        }

        private static string UpdateURL(string URL)
        {
            if (URL == null)
            {
                return BookmarkingRequestConstants.Default_URL;
            }
            if (URL.StartsWith(BookmarkingRequestConstants.URL_Prefix) || URL.StartsWith(BookmarkingRequestConstants.URL_HTTPS_Prefix))
            {
                return URL;
            }
            URL = BookmarkingRequestConstants.URL_Prefix + URL;
            return URL;
        }

        #endregion

        #region Tags Autocomplete Popup Box

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public AjaxResponse GetSuggest(string text, string varName, int limit)
        {
            var resp = new AjaxResponse();

            var startSymbols = text;
            var ind = startSymbols.LastIndexOf(",");
            if (ind != -1)
                startSymbols = startSymbols.Substring(ind + 1);

            startSymbols = startSymbols.Trim();

            IList<Tag> tags = new List<Tag>();
            if (!string.IsNullOrEmpty(startSymbols))
            {
                tags = _serviceHelper.GetAllTags(startSymbols, limit);
            }

            var resNames = new StringBuilder();
            var resHelps = new StringBuilder();

            foreach (var tag in tags)
            {
                resNames.Append(tag.Name);
                resNames.Append("$");
                resHelps.Append(tag.TagID);
                resHelps.Append("$");
            }

            resp.rs1 = resNames.ToString().TrimEnd('$');
            resp.rs2 = resHelps.ToString().TrimEnd('$');
            resp.rs3 = text;
            resp.rs4 = varName;

            return resp;
        }

        #endregion

        #region Ajax Request: get bookmark info and create a thumbnail

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object GetBookmarkByUrl(string url)
        {
            //Create thumbnail if it doesn't exists
            ThumbnailHelper.Instance.MakeThumbnail(url, true, true, HttpContext.Current, TenantProvider.CurrentTenantID);

            var b = _serviceHelper.GetBookmarkByUrl(url);
            return GetBookmarkByUrl(b, url);
        }

        private static object GetBookmarkByUrl(Bookmark b, string url)
        {
            var tags = string.Empty;
            if (b != null)
            {
                tags = BookmarkingServiceHelper.ConvertBookmarkToTagsString(b);
                var raitingHtml = new BookmarkRaitingUserControl().GetBookmarkRaiting(b);
                return new { Name = b.Name, Description = b.Description, Tags = tags, IsNewBookmark = false, Raiting = raitingHtml };
            }
            var title = GetWebSiteTitleByUrl(url);
            return new { Name = title[0], Description = title[1], Tags = tags, IsNewBookmark = true, Raiting = string.Empty };
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object GetUserBookmarkByUrl(string url)
        {
            //Create bookmark thumbnail
            ThumbnailHelper.Instance.MakeThumbnail(url, true, true, HttpContext.Current, TenantProvider.CurrentTenantID);

            var b = _serviceHelper.GetBookmarkWithUserBookmarks(url);

            if (b == null)
            {
                var title = GetWebSiteTitleByUrl(url);
                return new { Name = title[0], Description = title[1], Tags = string.Empty, IsNewBookmark = true, Raiting = string.Empty };
            }

            var userBookmark = _serviceHelper.GetCurrentUserBookmark(b.UserBookmarks);
            if (userBookmark == null)
            {
                return GetBookmarkByUrl(b, url);
            }

            var tags = string.Empty;

            tags = BookmarkingServiceHelper.ConvertBookmarkToTagsString(b);

            var raitingHtml = new BookmarkRaitingUserControl().GetBookmarkRaiting(b);
            return new { Name = userBookmark.Name, Description = userBookmark.Description, Tags = tags, IsNewBookmark = false, Raiting = raitingHtml };
        }

        private static string[] GetWebSiteTitleByUrl(string url)
        {
            var emptyResult = new[] { string.Empty, string.Empty };

            try
            {
                var request = WebRequest.Create(url);
                request.Timeout = BookmarkingSettings.PingTimeout;
                using (var response = request.GetResponse())
                using (var stream = response.GetResponseStream())
                {
                    var encStr = ((HttpWebResponse)(response)).CharacterSet;
                    StreamReader sr;
                    string text;
                    Encoding encoding;
                    var e = Encoding.GetEncoding("ISO-8859-1").BodyName;
                    if (!String.IsNullOrEmpty(encStr) && !e.ToLower().Equals(encStr.ToLower()))
                    {
                        encoding = Encoding.GetEncoding(encStr);
                        using (sr = new StreamReader(stream, encoding))
                        {
                            text = sr.ReadToEnd();
                        }
                    }
                    else
                    {
                        encoding = BookmarkingSettings.PageTitleEncoding;

                        using (sr = new StreamReader(stream, encoding))
                        {
                            text = sr.ReadToEnd();
                        }

                        var htmlEncoding = new HtmlDocument().DetectEncodingHtml(text);
                        if (htmlEncoding != null)
                        {
                            encoding = htmlEncoding;
                            var req = WebRequest.Create(url);
                            using (var resp = req.GetResponse())
                            using (var respstream = resp.GetResponseStream())
                            using (sr = new StreamReader(respstream, encoding))
                            {
                                text = sr.ReadToEnd();
                            }
                        }
                        else
                        {
                            var doc = new HtmlDocument();
                            doc.Load(WebRequest.Create(url).GetResponse().GetResponseStream());
                            var encodingNode = doc.DocumentNode.SelectSingleNode(string.Format("//meta[{0}]", GetXpathArgumentIgnoreCase("charset")));
                            if (encodingNode != null)
                            {
                                var encodingAttr = encodingNode.Attributes["charset"];
                                if (encodingAttr != null)
                                {
                                    var encodingVal = encodingAttr.Value;
                                    if (!string.IsNullOrEmpty(encodingVal))
                                    {
                                        encoding = Encoding.GetEncoding(encodingVal);

                                        using (var resp = WebRequest.Create(url).GetResponse())
                                        using (var respstream = resp.GetResponseStream())
                                        using (sr = new StreamReader(respstream, encoding))
                                        {
                                            text = sr.ReadToEnd();
                                        }
                                    }
                                }
                            }
                        }
                    }
                    var d = new HtmlDocument { OptionReadEncoding = false };
                    d.LoadHtml(text);
                    var titleNode = d.DocumentNode.SelectSingleNode("//title");
                    var title = string.Empty;
                    if (titleNode != null)
                    {
                        title = titleNode.InnerText;
                    }

                    var description = string.Empty;
                    var descriptionNode = d.DocumentNode.SelectSingleNode(string.Format("//meta[{0}]", GetXpathArgumentIgnoreCase("name", "description")));
                    if (descriptionNode != null)
                    {
                        var content = descriptionNode.Attributes["content"];
                        if (content != null)
                        {
                            description = content.Value;
                        }
                    }

                    title = BookmarkingServiceHelper.EncodeUserData(title);
                    description = BookmarkingServiceHelper.EncodeUserData(description);

                    return new[] { title, description };
                }
            }
            catch (Exception err)
            {
                LogManager.GetLogger("ASC.Web.Bookmarking").ErrorFormat("Url: {0} err: {1}", url, err);
            }
            return emptyResult;
        }

        private static string GetXpathArgumentIgnoreCase(string argName, string argValue)
        {
            return string.Format("translate(@{0},'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='{1}'", argName, argValue.ToLower());
        }

        private static string GetXpathArgumentIgnoreCase(string argName)
        {
            return string.Format("translate(@{0},'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')", argName);
        }

        #endregion

        #region Update Thumbnail On The Client

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object UpdateThumbnailImageSrc()
        {
            try
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                if (displayMode != BookmarkDisplayMode.AllBookmarks
                    && displayMode != BookmarkDisplayMode.SelectedBookmark
                    && displayMode != BookmarkDisplayMode.Favourites)
                {
                    return new { url = string.Empty, thumbnailUrl = string.Empty };
                }
                var bookmarkUrl = UpdateURL(_serviceHelper.BookmarkToAdd.URL);
                ThumbnailHelper.Instance.MakeThumbnail(bookmarkUrl, true, true, HttpContext.Current, TenantProvider.CurrentTenantID);

                var thumbnailUrlByDisplayMode = BookmarkingServiceHelper.GetThumbnailUrlForUpdate(bookmarkUrl);
                if (string.IsNullOrEmpty(thumbnailUrlByDisplayMode))
                {
                    return null;
                }

                var result = new { url = HttpUtility.HtmlDecode(bookmarkUrl), thumbnailUrl = thumbnailUrlByDisplayMode };
                return result;
            }
            catch
            {
                return null;
            }

        }

        #region Thumbnails

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void MakeThumbnail(string url)
        {
            ThumbnailHelper.Instance.MakeThumbnail(url, true, true, HttpContext.Current, TenantProvider.CurrentTenantID);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void GenerateAllThumbnails(bool overrideFlag)
        {
            BookmarkingServiceHelper.GenerateAllThumbnails(overrideFlag);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void UpdateBookmarkThumbnail(int bookmarkID)
        {
            BookmarkingServiceHelper.UpdateBookmarkThumbnail(bookmarkID);
        }

        #endregion


        #endregion

        #region Subscriptions

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public bool IsSubscribedOnRecentBookmarks()
        {
            return _serviceHelper.IsSubscribed(_serviceHelper.SubscriptionRecentBookmarkID, BookmarkingBusinessConstants.NotifyActionNewBookmark);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public bool IsSubscribedOnBookmarkComments()
        {
            return _serviceHelper.IsSubscribed(_serviceHelper.SubscriptionBookmarkCommentsID, BookmarkingBusinessConstants.NotifyActionNewComment);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void SubscribeOnRecentBookmarks()
        {
            _serviceHelper.Subscribe(_serviceHelper.SubscriptionRecentBookmarkID, BookmarkingBusinessConstants.NotifyActionNewBookmark);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void SubscribeOnBookmarkComments()
        {
            _serviceHelper.Subscribe(_serviceHelper.SubscriptionBookmarkCommentsID, BookmarkingBusinessConstants.NotifyActionNewComment);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void UnSubscribeOnRecentBookmarks()
        {
            _serviceHelper.UnSubscribe(_serviceHelper.SubscriptionRecentBookmarkID, BookmarkingBusinessConstants.NotifyActionNewBookmark);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void UnSubscribeOnBookmarkComments()
        {
            _serviceHelper.UnSubscribe(_serviceHelper.SubscriptionBookmarkCommentsID, BookmarkingBusinessConstants.NotifyActionNewComment);
        }

        #endregion

        public string GetCreateBookmarkPageUrl()
        {
            return BookmarkingServiceHelper.GetCreateBookmarkPageUrl();
        }

        public bool ShowCreateBookmarkLink()
        {
            var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

            switch (displayMode)
            {
                case BookmarkDisplayMode.AllBookmarks:
                    return true;
                case BookmarkDisplayMode.Favourites:
                    return true;
                case BookmarkDisplayMode.SearchByTag:
                    return true;
            }
            return false;
        }

        public bool PermissionCheckCreateBookmark()
        {
            return BookmarkingPermissionsCheck.PermissionCheckCreateBookmark();
        }

        public bool IsSelectedBookmarkDisplayMode()
        {
            return _serviceHelper.IsSelectedBookmarkDisplayMode();
        }

        private void InitScripts()
        {
            var jsResource = new StringBuilder();
            jsResource.Append("jq('#tableForNavigation select').val(" + BookmarkPageCounter + ").change(function(evt) {changeBookmarksCountOfRows(this.value);}).tlCombobox();");
            Page.RegisterInlineScript(jsResource.ToString(), true);
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailFolder.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Mail.Enums;

namespace ASC.Mail.Data.Contracts
{
    public class MailFolder : IEquatable<MailFolder>
    {
        public static bool IsIdOk(FolderType folderType)
        {
            return folderType >= FolderType.Inbox && folderType <= FolderType.Templates;
        }

        public FolderType Folder { get; private set; }
        public string Name { get; private set; }
        public string[] Tags { get; private set; }

        public MailFolder(FolderType folder, string name, string[] tags = null)
        {
            if (!IsIdOk(folder))
                throw new ArgumentException(@"Incorrect folder id", "folder");

            Folder = folder;
            Name = name;
            Tags = tags ?? new string[] { };
        }

        public bool Equals(MailFolder other)
        {
            if (other == null) return false;

            return Folder == other.Folder
                   && string.Equals(Name, other.Name, StringComparison.InvariantCultureIgnoreCase)
                   && Tags == other.Tags;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;
            return Equals(obj as ContactInfo);
        }

        public override int GetHashCode()
        {
            return Folder.GetHashCode() ^ Name.GetHashCode() ^ Tags.GetHashCode();
        }
    }
}


<|start_filename|>module/ASC.ElasticSearch/Core/Wrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.ElasticSearch.Core;

using Nest;

using Newtonsoft.Json.Linq;

namespace ASC.ElasticSearch
{
    public abstract class Wrapper
    {
        protected internal abstract string Table { get; }

        protected internal virtual string IndexName
        {
            get { return Table; }
        }

        [ColumnId("id")]
        public virtual int Id { get; set; }

        [ColumnTenantId("tenant_id")]
        public virtual int TenantId { get; set; }

        [ColumnLastModified("last_modified_on"), Date]
        public virtual DateTime LastModifiedOn { get; set; }

        private List<PropertyInfo> orderedProperties;

        private List<PropertyInfo> OrderedProperties
        {
            get
            {
                return orderedProperties ?? (orderedProperties = GetType()
                    .GetProperties()
                    .Where(r =>
                    {
                        var column = r.GetCustomAttribute<ColumnAttribute>();
                        return column != null && !string.IsNullOrEmpty(column.ColumnName);
                    })
                    .OrderBy(r => r.GetCustomAttribute<ColumnAttribute>().Order)
                    .ToList());
            }
        }

        private List<ColumnAttribute> columns;

        private List<ColumnAttribute> Columns
        {
            get
            {
                return columns ?? (columns = OrderedProperties
                    .Select(r => r.GetCustomAttribute<ColumnAttribute>())
                    .ToList());
            }
        }

        internal Converter<object[], Wrapper> GetDataConverter(bool sub = false)
        {
            return data =>
            {
                var result = Activator.CreateInstance(GetType());

                var i = 0;
                var props = OrderedProperties;
                for (; i < props.Count; i++)
                {
                    if (data[i] == null) continue;
                    object newValue;
                    if (props[i].PropertyType == typeof(Guid))
                    {
                        newValue = Guid.Parse(data[i].ToString());
                    }
                    else if (props[i].PropertyType == typeof(bool))
                    {
                        try
                        {
                            newValue = Convert.ToBoolean(data[i]);
                        }
                        catch (Exception)
                        {
                            newValue = data[i] != null;
                        }
                    }
                    else
                    {
                        try
                        {
                            newValue = Convert.ChangeType(data[i], props[i].PropertyType);
                        }
                        catch (Exception)
                        {
                            newValue = Activator.CreateInstance(props[i].PropertyType);
                        }
                    }
                    props[i].SetValue(result, newValue);
                }

                var joins = GetType()
                    .GetProperties()
                    .Where(r => r.GetCustomAttribute<JoinAttribute>() != null)
                    .ToList();

                if (!joins.Any()) return (Wrapper)result;

                data = data.Skip(i).ToArray();

                foreach (var join in joins)
                {
                    Wrapper joinWrapper;

                    if (join.PropertyType.IsGenericType)
                    {
                        joinWrapper = Activator.CreateInstance(join.PropertyType.GenericTypeArguments[0]) as Wrapper;
                    }
                    else
                    {
                        joinWrapper = Activator.CreateInstance(join.PropertyType) as Wrapper;
                    }

                    if (joinWrapper == null) continue;

                    var joinAttr = join.GetCustomAttribute<JoinAttribute>();
                    var joinSub = sub || joinAttr.JoinType == JoinTypeEnum.Sub;
                    List<object[]> newArray;
                    if (joinSub && join.PropertyType.IsGenericType)
                    {
                        newArray = data[0] == null
                            ? new List<object[]>()
                            : JArray.Parse(data[0].ToString()).Select(r => ((JArray)r).Select(q => (object)q).ToArray()).ToList();
                    }
                    else
                    {
                        newArray = new List<object[]> { data };
                    }

                    var newArrayValue = newArray.ConvertAll(joinWrapper.GetDataConverter(joinSub));

                    object newValue;

                    if (joinSub && join.PropertyType.IsGenericType)
                    {
                        var list = (IList)Activator.CreateInstance(join.PropertyType);
                        foreach (var item in newArrayValue)
                        {
                            list.Add(item);
                        }

                        newValue = list;
                    }
                    else
                    {
                        newValue = Convert.ChangeType(newArrayValue.First(), join.PropertyType);
                    }

                    join.SetValue(result, newValue);

                    var skipCount = joinSub
                        ? 1
                        : joinWrapper.OrderedProperties.Count;

                    data = data.Skip(skipCount).ToArray();
                }

                return (Wrapper)result;
            };
        }

        internal string GetColumnName(ColumnTypeEnum columnType, string alias)
        {
            var column = Columns.FirstOrDefault(r => r.ColumnType == columnType);
            if (column == null || string.IsNullOrEmpty(column.ColumnName)) return null;
            return alias + "." + column.ColumnName;
        }

        internal bool TryGetColumnName(ColumnTypeEnum columnType, string alias, out string columnName)
        {
            columnName = GetColumnName(columnType, alias);
            return columnName != null;
        }

        internal bool TryGetColumnNames(List<ColumnTypeEnum> columnType, string alias, out List<string> columnName)
        {
            columnName = new List<string>();
            foreach (var cType in columnType)
            {
                var type = cType;
                var column = Columns.Where(r => r.ColumnType == type);
                columnName.AddRange(column.Select(r => alias + "." + r.ColumnName));
            }

            return columnName.Any();
        }

        internal string[] GetColumnNames(string alias)
        {
            return Columns
                .Select(r => alias + "." + r.ColumnName)
                .ToArray();
        }

        internal string[] GetContentProperties()
        {
            var result = OrderedProperties
                .Where(r => r.GetCustomAttribute<ColumnAttribute>().ColumnType == ColumnTypeEnum.Content)
                .Select(r => ToLowerCamelCase(r.Name))
                .ToList();

            if (this is WrapperWithDoc && SearchSettings.CanSearchByContent(GetType()))
            {
                result.Add("document.attachment.content");
            }

            foreach (var join in GetJoins())
            {
                var joinType = join.Value.Name;
                var joinAttr = join.Value.GetCustomAttribute<JoinAttribute>().JoinType;
                result.AddRange(join.Key.GetContentProperties()
                    .Select(r => (joinAttr == JoinTypeEnum.Sub ? joinAttr + ":" : "") + ToLowerCamelCase(joinType) + "." + r));
            }

            return result.ToArray();
        }

        internal Dictionary<Wrapper, PropertyInfo> GetJoins()
        {
            var result = new Dictionary<Wrapper, PropertyInfo>();

            var joins = GetType()
                .GetProperties()
                .Where(r => r.GetCustomAttribute<JoinAttribute>() != null)
                .ToList();

            foreach (var join in joins)
            {
                Wrapper joinWrapper;
                if (join.PropertyType.IsGenericType)
                {
                    joinWrapper = Activator.CreateInstance(join.PropertyType.GenericTypeArguments[0]) as Wrapper;
                }
                else
                {
                    joinWrapper = Activator.CreateInstance(join.PropertyType) as Wrapper;
                }

                if (joinWrapper == null) continue;

                result.Add(joinWrapper, join);
            }

            return result;
        }

        internal void AddConditions(string alias, SqlQuery subQuery)
        {
            foreach (var con in GetConditions(alias))
            {
                var arr = con.Value as Array;

                if (arr != null)
                {
                    subQuery.Where(Exp.In(con.Key, arr));
                }
                else
                {
                    subQuery.Where(con.Key, con.Value);
                }
            }
        }

        private Dictionary<string, object> GetConditions(string alias)
        {
            var result = new Dictionary<string, object>();

            var conditions = Columns.OfType<ColumnConditionAttribute>();

            foreach (var con in conditions.Where(r => r.Value != null))
            {
                result.Add(alias + "." + con.ColumnName, con.Value);
            }

            return result;
        }

        internal string ToLowerCamelCase(string value)
        {
            return char.ToLowerInvariant(value[0]) + value.Substring(1);
        }

        internal Func<PropertiesDescriptor<T>, IPromise<IProperties>> GetProperties<T>() where T : Wrapper
        {
            var analyzers = GetAnalyzers();

            return p =>
            {
                foreach (var c in analyzers)
                {
                    var c1 = c;
                    string analyzer;

                    if (c.Value.CharFilter != CharFilter.io)
                    {
                        analyzer = c.Key;
                    }
                    else
                    {
                        analyzer = c1.Value.Analyzer + "custom";
                    }

                    p.Text(s => s.Name(c1.Key).Analyzer(analyzer));
                }
                if (this is WrapperWithDoc)
                {
                    p.Object<Document>(
                        r => r.Name("document").Properties(
                        q => q.Object<Attachment>(
                        a => a.Name("attachment").Properties(
                        w => w.Text(
                        t => t.Name("content").Analyzer("document"))))));
                }
                return p;
            };
        }

        internal Dictionary<string, ColumnAttribute> GetAnalyzers()
        {
            var result = new Dictionary<string, ColumnAttribute>();

            foreach (var prop in OrderedProperties)
            {
                var column = prop.GetCustomAttribute<ColumnAttribute>();

                if (column == null || column.ColumnType != ColumnTypeEnum.Content || column.Analyzer == Analyzer.standard) continue;

                result.Add(prop.Name.ToLowerInvariant()[0] + prop.Name.Substring(1), column);
            }

            return result;
        }

        internal Dictionary<Type, string> GetNested()
        {
            var result = new Dictionary<Type, string>();

            var joins = GetType().GetProperties().Where(r =>
            {
                var attr = r.GetCustomAttribute<JoinAttribute>();
                return attr != null;
            });

            foreach (var prop in joins)
            {
                result.Add(prop.PropertyType, prop.Name);
            }

            return result;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/core/asc.listscript.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var ListScript = new function() {
this.list = [
        "3rdparty/extjs/ext-all.js",
"3rdparty/jquery/jscrollpane/jquery.jscrollpane.js",
"3rdparty/jquery/jquery-1.7.1.min.js",
"3rdparty/jquery/jscrollpane/jquery.jscrollpane.min.js",
"3rdparty/jquery/mousewheel/jquery.mousewheel.js",
"3rdparty/sockjs/sockjs-0.3.min.js",
"3rdparty/underscore/underscore-min.js",
"3rdparty/xregexp/xregexp-all-min.js",
"apps/api/documents/api.js",
"apps/documenteditor/embed/app-all.js",
"apps/documenteditor/main/app-all.js",
"apps/documenteditor/main/locale/de.js",
"apps/documenteditor/main/locale/en.js",
"apps/documenteditor/main/locale/es.js",
"apps/documenteditor/main/locale/fr.js",
"apps/documenteditor/main/locale/it.js",
"apps/documenteditor/main/locale/lv.js",
"apps/documenteditor/main/locale/ru.js",
"apps/spreadsheeteditor/embed/app-all.js",
"apps/spreadsheeteditor/main/app-all.js",
"apps/spreadsheeteditor/main/locale/de.js",
"apps/spreadsheeteditor/main/locale/en.js",
"apps/spreadsheeteditor/main/locale/es.js",
"apps/spreadsheeteditor/main/locale/fr.js",
"apps/spreadsheeteditor/main/locale/it.js",
"apps/spreadsheeteditor/main/locale/lv.js",
"apps/spreadsheeteditor/main/locale/ru.js",
"sdk/OfficeWebCommon/docscoapisettings.js",
"sdk/OfficeWebCommon/MobileDownloader/downloaderfiles.js",
"sdk/OfficeWebExcel/sdk-all.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/arial.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/arialbd.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/arialbi.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/ariali.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CALIBRI.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CALIBRIB.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CALIBRII.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CALIBRIZ.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CAMBRIA.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CAMBRIAB.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CAMBRIAI.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/CAMBRIAZ.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/cour.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/courbd.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/courbi.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/couri.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/symbol.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/times.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/timesbd.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/timesbi.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/timesi.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/wingding.js",
"sdk/OfficeWebWord/FontsFreeType/FontFiles/WINGDNG3.js",
"sdk/OfficeWebWord/WebWord/sdk-all.js"

        ];
};

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/DataInterfaces/ITaskDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Collections.Generic;

using ASC.Common.Data.Sql.Expressions;
using ASC.Projects.Core.Domain;

#endregion

namespace ASC.Projects.Core.DataInterfaces
{
    public interface ITaskDao
    {
        List<Task> GetAll();

        List<Task> GetByProject(int projectId, TaskStatus? status, Guid participant);

        List<Task> GetByResponsible(Guid responsibleId, IEnumerable<TaskStatus> statuses);

        List<Task> GetMilestoneTasks(int milestoneId);

        List<Task> GetByFilter(TaskFilter filter, bool isAdmin, bool checkAccess);

        TaskFilterCountOperationResult GetByFilterCount(TaskFilter filter, bool isAdmin, bool checkAccess);

        List<Tuple<Guid, int, int>> GetByFilterCountForReport(TaskFilter filter, bool isAdmin, bool checkAccess);

        IEnumerable<TaskFilterCountOperationResult> GetByFilterCountForStatistic(TaskFilter filter, bool isAdmin, bool checkAccess);

        List<Task> GetById(ICollection<int> ids);

        Task GetById(int id);

        bool IsExists(int id);

        List<object[]> GetTasksForReminder(DateTime deadline);


        Task Create(Task task);
        Task Update(Task task);

        void Delete(Task task);


        void SaveRecurrence(Task task, string cron, DateTime startDate, DateTime endDate);

        void DeleteReccurence(int taskId);

        List<object[]> GetRecurrence(DateTime date);


        void AddLink(TaskLink link);

        void RemoveLink(TaskLink link);

        IEnumerable<TaskLink> GetLinks(int taskID);

        IEnumerable<TaskLink> GetLinks(List<Task> tasks);

        bool IsExistLink(TaskLink link);

        List<Task> GetTasks(Exp where);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Common/Constants.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Notify.Model;
using ASC.Web.Community.Modules.Wiki.Resources;

using AuthAction = ASC.Common.Security.Authorizing.Action;

namespace ASC.Web.Community.Wiki.Common
{
    public class Constants
    {
        public static readonly AuthAction Action_AddPage = new AuthAction(new Guid("D49F4E30-DA10-4b39-BC6D-B41EF6E039D3"), "New Page");
        public static readonly AuthAction Action_EditPage = new AuthAction(new Guid("D852B66F-6719-45e1-8657-18F0BB791690"), "Edit page");
        public static readonly AuthAction Action_RemovePage = new AuthAction(new Guid("557D6503-633B-4490-A14C-6473147CE2B3"), "Delete page");
        public static readonly AuthAction Action_UploadFile = new AuthAction(new Guid("088D5940-A80F-4403-9741-D610718CE95C"), "Upload file");
        public static readonly AuthAction Action_RemoveFile = new AuthAction(new Guid("7CB5C0D1-D254-433f-ABE3-FF23373EC631"), "Delete file");
        public static readonly AuthAction Action_AddComment = new AuthAction(new Guid("C426C349-9AD4-47cd-9B8F-99FC30675951"), "Add Comment");
        public static readonly AuthAction Action_EditRemoveComment = new AuthAction(new Guid("B630D29B-1844-4bda-BBBE-CF5542DF3559"), "Edit/Delete comment");

        public static INotifyAction NewPage = new NotifyAction("new wiki page", WikiResource.NotifyAction_NewPage);
        public static INotifyAction EditPage = new NotifyAction("edit wiki page", WikiResource.NotifyAction_ChangePage);
        public static INotifyAction AddPageToCat = new NotifyAction("add page to cat", WikiResource.NotifyAction_AddPageToCat);

        public static string TagPageName = "PageName";
        public static string TagURL = "URL";

        public static string TagUserName = "UserName";
        public static string TagUserURL = "UserURL";
        public static string TagDate = "Date";

        public static string TagPostPreview = "PagePreview";
        public static string TagCommentBody = "CommentBody";

        public static string TagChangePageType = "ChangeType";
        public static string TagCatName = "CategoryName";

    }
}

<|start_filename|>common/ASC.Common/Notify/Model/NotifyAction.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Notify.Model
{
    [Serializable]
    public class NotifyAction : INotifyAction
    {
        public string ID { get; private set; }

        public string Name { get; private set; }


        public NotifyAction(string id)
            : this(id, null)
        {
        }

        public NotifyAction(string id, string name)
        {
            if (id == null) throw new ArgumentNullException("id");

            ID = id;
            Name = name;
        }

        public override bool Equals(object obj)
        {
            var a = obj as INotifyAction;
            return a != null && a.ID == ID;
        }

        public override int GetHashCode()
        {
            return ID.GetHashCode();
        }

        public override string ToString()
        {
            return String.Format("action: {0}", ID);
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Batch/ApiBatchHttpHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mime;
using System.Text;
using System.Web;
using System.Web.Routing;

using ASC.Api.Collections;
using ASC.Api.Impl;
using ASC.Api.Interfaces;

using Autofac;

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace ASC.Api.Batch
{
    public class ApiBatchHttpHandler : ApiHttpHandlerBase
    {
        public ApiBatchHttpHandler(RouteData routeData)
            : base(routeData)
        {
        }

        protected override void DoProcess(HttpContextBase context)
        {
            //Read body
            var batch = context.Request["batch"];
            IEnumerable<ApiBatchRequest> requests = null;
            if (!string.IsNullOrEmpty(batch))
            {
                requests = JsonConvert.DeserializeObject<IEnumerable<ApiBatchRequest>>(batch, new JsonSerializerSettings
                {
                    DefaultValueHandling = DefaultValueHandling.Ignore,
                    ContractResolver = new CamelCasePropertyNamesContractResolver()
                });

            }
            else
            {
                if (!"GET".Equals(context.Request.HttpMethod, StringComparison.InvariantCultureIgnoreCase))
                {
                    //Try bind form
                    requests = Utils.Binder.Bind<IEnumerable<ApiBatchRequest>>(context.Request.Form);
                }
            }

            if (requests != null && requests.Any())
            {
                try
                {
                    Log.Debug("processing batch started");
                    ProcessBatch(context, requests);
                    Log.Debug("processing batch finished");
                }
                catch (Exception e)
                {
                    Log.Error("batch process error", e);
                    //Set status to error
                    SetError(context, e, HttpStatusCode.InternalServerError);
                    //Try respond again
                    RespondTo(null, context);
                }
            }
            else
            {
                ApiResponce.Error = new ErrorWrapper(new InvalidOperationException("no batch specified"));
            }

            RespondTo(null, context);
        }

        private void ProcessBatch(HttpContextBase context, IEnumerable<ApiBatchRequest> requests)
        {
            var resonse = requests.OrderBy(x => x.Order).Select(x => ProcessBatchRequest(context, x)).ToList();

            ApiResponce.Response = resonse;
            PostProcessResponse(context, resonse);
        }

        internal ApiBatchResponse ProcessBatchRequest(HttpContextBase context, ApiBatchRequest apiBatchRequest)
        {
            if (context.Request == null) throw new InvalidOperationException("Request is empty");
            if (context.Request.Url == null) throw new InvalidOperationException("Url is empty");

            using (var writer = new StringWriter())
            {
                var path = apiBatchRequest.RelativeUrl;
                if (context.Request.ApplicationPath != null && path.StartsWith(context.Request.ApplicationPath))
                {
                    path = path.Substring(context.Request.ApplicationPath.Length);
                }
                var uri = new Uri(context.Request.Url, "/" + path.TrimStart('/'));

                var workerRequest = new ApiWorkerRequest(Uri.UnescapeDataString(uri.AbsolutePath.TrimStart('/')), uri.Query.TrimStart('?'), writer, context, new ContentType(apiBatchRequest.BodyContentType));
                workerRequest.HttpVerb = apiBatchRequest.Method;

                if (!string.IsNullOrEmpty(apiBatchRequest.Body))
                {
                    var contentType = new ContentType(apiBatchRequest.BodyContentType);
                    var encoding = Encoding.GetEncoding(contentType.CharSet);
                    workerRequest.EntityBody = encoding.GetBytes(apiBatchRequest.Body);
                }
                var workContext = new HttpContext(workerRequest) { Handler = this };
                var newContext = new HttpContextWrapper(workContext);

                //Make a faked request
                var routeData = RouteTable.Routes.GetRouteData(newContext);
                if (routeData != null)
                {
                    //Construct new context
                    Container.BeginLifetimeScope().Resolve<IApiHttpHandler>(new TypedParameter(typeof(RouteData), routeData)).Process(newContext);
                    newContext.Response.Flush();

                    //Form response
                    var response = new ApiBatchResponse(apiBatchRequest)
                    {
                        Data = writer.GetStringBuilder().ToString(),
                        Headers = new ItemDictionary<string, string>()
                    };
                    foreach (var responseHeaderKey in workerRequest.ResponseHeaders.AllKeys)
                    {
                        response.Headers.Add(responseHeaderKey, workerRequest.ResponseHeaders[responseHeaderKey]);
                    }
                    response.Status = workerRequest.HttpStatus;
                    response.Name = apiBatchRequest.Name;
                    return response;
                }

            }
            return null;
        }
    }
}

<|start_filename|>common/ASC.Common/Data/Sql/SqlDelete.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region usings

using System.Diagnostics;
using System.Text;

using ASC.Common.Data.Sql.Expressions;

#endregion

namespace ASC.Common.Data.Sql
{
    [DebuggerTypeProxy(typeof(SqlDebugView))]
    public class SqlDelete : ISqlInstruction
    {
        private readonly string table;
        private Exp where = Exp.Empty;

        public SqlDelete(string table)
        {
            this.table = table;
        }

        #region ISqlInstruction Members

        public string ToString(ISqlDialect dialect)
        {
            var sql = new StringBuilder();
            sql.AppendFormat("delete from {0}", table);
            if (where != Exp.Empty) sql.AppendFormat(" where {0}", where.ToString(dialect));
            return sql.ToString();
        }

        public object[] GetParameters()
        {
            return where != Exp.Empty ? where.GetParameters() : new object[0];
        }

        #endregion

        public SqlDelete Where(Exp where)
        {
            this.where = this.where & where;
            return this;
        }

        public SqlDelete Where(string column, object value)
        {
            return Where(Exp.Eq(column, value));
        }

        public override string ToString()
        {
            return ToString(SqlDialect.Default);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/dropdown.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function($) {
    window.dropdown = {
        unregHide: function(hide) {
            $(window).unbind('.dropdown', hide);
            $('iframe').each(function() {
                try {
                    if ($(this)[0].contentWindow.document) {
                        $($(this)[0].contentWindow.document).off(".dropdown", hide);
                    }
                } catch(e) {
                }
            });
        },

        regHide: function(hide) {
            dropdown.unregHide(hide);
            setImmediate(function() {
                $(window).on("contextmenu.dropdown click.dropdown resize.dropdown", hide);
                $('iframe').each(function() {
                    try {
                        if ($(this)[0].contentWindow.document) {
                            $($(this)[0].contentWindow.document).on("contextmenu.dropdown click.dropdown", hide);
                        }
                    } catch(e) {
                    }
                });
            });
        },

        unregScroll: function(scroll) {
            $(window).off('.dropdown', scroll);
        },

        regScroll: function(scroll) {
            $(window).on('scroll.dropdown', scroll);
        },

        onClick: function(event) {
            event.preventDefault();
            event.stopPropagation();
            // initiate global event for other dropdowns close
            $(window).click();
        }
    };
})(jQuery);

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/AccountInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

namespace ASC.Mail.Data.Contracts
{
    public class AccountInfo
    {
        public int Id { get; set; }

        public string Email { get; set; }

        public bool Enabled { get; set; }

        public bool QuotaError { get; set; }

        public bool AuthError { get; set; }

        public bool OAuthConnection { get; set; }

        public string Name { get; set; }

        public string EMailInFolder { get; set; }

        public bool IsTeamlabMailbox { get; set; }

        public MailSignatureData Signature { get; set; }

        public MailAutoreplyData Autoreply { get; set; }

        public List<MailAddressInfo> Aliases { get; set; }

        public List<MailAddressInfo> Groups { get; set; }

        public bool IsSharedDomainMailbox { get; set; }

        public override string ToString()
        {
            return Name + " <" + Email + ">";
        }

        public AccountInfo(int id, string address, string name, bool enabled,
            bool quotaError, MailBoxData.AuthProblemType authError, MailSignatureData signature, MailAutoreplyData autoreply,
            bool oauthConnection, string emailInFolder, bool isTeamlabMailbox, bool isSharedDomainMailbox)
        {
            Id = id;
            Email = address;
            Name = name;
            Enabled = enabled;
            QuotaError = quotaError;
            AuthError = authError > MailBoxData.AuthProblemType.NoProblems;
            Autoreply = autoreply;
            Signature = signature;
            Aliases = new List<MailAddressInfo>();
            Groups = new List<MailAddressInfo>();
            OAuthConnection = oauthConnection;
            EMailInFolder = emailInFolder;
            IsTeamlabMailbox = isTeamlabMailbox;
            IsSharedDomainMailbox = isSharedDomainMailbox;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/js/asc/core/basetemplate.master.init.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var defineBodyMediaClass = function () {
    var $body = jq("body"),
               list = [
               { min: 0,    max: 1024, classname: 'media-width-0-1024' },
               { min: 0,    max: 1030, classname: 'media-width-0-1030' },
               { min: 0,    max: 1048, classname: 'media-width-0-1048' },
               { min: 0,    max: 1072, classname: 'media-width-0-1072' },
               { min: 0,    max: 1080, classname: 'media-width-0-1080' },
               { min: 0,    max: 1096, classname: 'media-width-0-1096' },

               { min: 0,    max: 1100, classname: 'media-width-0-1100' },
               { min: 0,    max: 1120, classname: 'media-width-0-1120' },
               { min: 0,    max: 1140, classname: 'media-width-0-1140' },
               { min: 0,    max: 1144, classname: 'media-width-0-1144' },
               { min: 0,    max: 1150, classname: 'media-width-0-1150' },
               { min: 0,    max: 1160, classname: 'media-width-0-1160' },
               { min: 0,    max: 1180, classname: 'media-width-0-1180' },

               { min: 0,    max: 1200, classname: 'media-width-0-1200' },
               { min: 0,    max: 1210, classname: 'media-width-0-1210' },
               { min: 1145, max: 0,    classname: 'media-width-1145-0' },
               { min: 0,    max: 1250, classname: 'media-width-0-1250' },
               { min: 0,    max: 1260, classname: 'media-width-0-1260' },
               { min: 0,    max: 1270, classname: 'media-width-0-1270' },

               { min: 0,    max: 1300, classname: 'media-width-0-1300' },
               { min: 0,    max: 1340, classname: 'media-width-0-1340' },
               { min: 0,    max: 1350, classname: 'media-width-0-1350' },
               { min: 0,    max: 1390, classname: 'media-width-0-1390' },

               { min: 0,    max: 1400, classname: 'media-width-0-1400' },
               { min: 0,    max: 1410, classname: 'media-width-0-1410' },
               { min: 0,    max: 1420, classname: 'media-width-0-1420' },
               { min: 0,    max: 1450, classname: 'media-width-0-1450' },
               { min: 0,    max: 1470, classname: 'media-width-0-1470' },

               { min: 0,    max: 1500, classname: 'media-width-0-1500' },
               { min: 0,    max: 1575, classname: 'media-width-0-1575' },
              
               { min: 0,    max: 1620, classname: 'media-width-0-1620' },
               { min: 0,    max: 1650, classname: 'media-width-0-1650' },
               { min: 1620, max: 0,    classname: 'media-width-1620-0' },


               ],

        width = jq("#studioPageContent").width() - jq(".mainPageTableSidePanel").width() + 240;

    if ($body.hasClass("sailfish")) {
        return;
    }


    for (var i = 0, n = list.length; i < n; i++) {
        if (width >= list[i].min && (list[i].max == 0 || width < list[i].max)) {
            if (!$body.hasClass(list[i].classname))
                $body.addClass(list[i].classname);
        } else {
            if ($body.hasClass(list[i].classname))
                $body.removeClass(list[i].classname);
        }
    }
    $body.removeClass('media-width-min');
};


(function() {
    // init jQuery Datepicker
    if (jQuery && jQuery.datepicker) {
        jQuery.datepicker.setDefaults({
            //changeMonth: true,
            //changeYear: true,
            prevText: "",
            nextText: "",
            firstDay: ASC.Resources.Master.FirstDay,
            dateFormat: ASC.Resources.Master.DatepickerDatePattern,
            dayNamesMin: ASC.Resources.Master.DayNames,
            dayNamesShort: ASC.Resources.Master.DayNames,
            dayNames: ASC.Resources.Master.DayNamesFull,
            monthNamesShort: ASC.Resources.Master.MonthNames,
            monthNames: ASC.Resources.Master.MonthNamesFull
        });
    }

    // init API Manager
    ServiceHelper.init(ASC.Resources.Master.ApiPath);
    ServiceFactory.init({
        responses: {
            isme: ASC.Resources.Master.ApiResponsesMyProfile
        },
        portaldatetime: {
            utcoffsettotalminutes: ASC.Resources.Master.CurrentTenantTimeZone.UtcOffset,
            displayname: ASC.Resources.Master.CurrentTenantTimeZone.DisplayName
        },
        names: {
            months: ASC.Resources.Master.MonthNamesFull,
            shortmonths: ASC.Resources.Master.MonthNames,
            days: ASC.Resources.Master.DayNamesFull,
            shortdays: ASC.Resources.Master.DayNames
        },
        formats: {
            datetime: ASC.Resources.Master.DateTimePattern,
            time: ASC.Resources.Master.TimePattern,
            date: ASC.Resources.Master.DatePattern
        },
        avatars: {
            small: ASC.Resources.Master.AvatarSmall,
            medium: ASC.Resources.Master.AvatarMedium,
            large: ASC.Resources.Master.AvatarLarge
        },
        supportedfiles: {
            imgs: ASC.Files.Utility.Resource.ExtsImagePreviewed,
            docs: ASC.Files.Utility.Resource.ExtsWebPreviewed
        }
    });
    Teamlab.init();

    // init LoadingBanner
    LoadingBanner.strLoading = ASC.Resources.Master.ResourceJS.LoadingProcessing;
    LoadingBanner.strDescription = ASC.Resources.Master.ResourceJS.LoadingDescription;

    // init image zoom
    StudioManager.initImageZoom();

    //for ie10 css
    if (jq.browser.msie && jq.browser.version == 10) {
        jq("body").addClass("ie10");
    }

    //settings preloaded
    jq.blockUI.defaults.css = {};
    jq.blockUI.defaults.overlayCSS = {};
    jq.blockUI.defaults.fadeOut = 0;
    jq.blockUI.defaults.fadeIn = 0;
    jq.blockUI.defaults.message = "<div class=\"loader-text-block\">" + ASC.Resources.Master.ResourceJS.LoadingPleaseWait + "</div>";

    if (jq("#studio_sidePanel").length) {
        LeftMenuManager.init(StudioManager.getBasePathToModule(), jq(".menu-list .menu-item.sub-list, .menu-list>.menu-item.sub-list>.menu-sub-list>.menu-sub-item"));
        LeftMenuManager.restoreLeftMenu();

        jq(".support-link").on("click", function() {
            jq(".support .expander").trigger("click");
        });
    }
    // init page-menu actions
    LeftMenuManager.bindEvents();

    var isDesktop = jq("body").hasClass("desktop");

    // init RenderPromoBar
    if (ASC.Resources.Master.SetupInfoNotifyAddress &&
        ASC.Resources.Master.IsAuthenticated == true &&
        ASC.Resources.Master.ApiResponsesMyProfile.response && 
        ASC.Resources.Master.ShowPromotions) {

        Teamlab.getBarPromotions({}, isDesktop, {
            success: function(params, content) {
                try {
                    if (content) {
                        eval(content);
                    }
                } catch (e) {
                    console.error(e);
                }
            }
        });
    }

    var tipsWasClosed = false;
    if (window.sessionStorage)
        tipsWasClosed = !!window.sessionStorage.getItem("tipsWasClosed");

    // init Tips
    if (!tipsWasClosed &&
        ASC.Resources.Master.SetupInfoTipsAddress &&
        ASC.Resources.Master.IsAuthenticated == true &&
        ASC.Resources.Master.ApiResponsesMyProfile.response &&
        !ASC.Resources.Master.ApiResponsesMyProfile.response.isOutsider &&
        ASC.Resources.Master.ShowTips) {

        Teamlab.getBarTips({}, isDesktop, {
            success: function (params, content) {
                try {
                    if (content) {
                        eval(content);
                    }
                } catch (e) {
                    console.error(e);
                }
            }
        });
    }

    var studioUserProfileInfo = new PopupBox("pb_StudioUserProfileInfo", 320, 140, "tintLight", "borderBaseShadow", "",
        {
            apiMethodName: "Teamlab.getProfile",
            tmplName: "userProfileCardTmpl"
        });

    jq(".userLink").each(function() {
        var id = jq(this).attr("id");
        if (id != null && id != "") {
            studioUserProfileInfo.RegistryElement(id, "\"" + jq(this).attr("data-uid") + "\"");
        }
    });

    jq("#commonLogout").click(function() {
        if (typeof SmallChat != "undefined" && SmallChat.logoutEvent) {
            SmallChat.logoutEvent();
        }
        return true;
    });



    var isRetina = function () {
        if (window.devicePixelRatio > 1)
            return true;

        var mediaQuery = "(-webkit-min-device-pixel-ratio: 1.5),\
            (min--moz-device-pixel-ratio: 1.5),\
            (-o-min-device-pixel-ratio: 3/2),\
            (min-resolution: 1.5dppx),\
            (min-device-pixel-ratio: 1.5)";

        if (window.matchMedia && window.matchMedia(mediaQuery).matches)
            return true;
        return false;
    };

    if (isRetina() && jq.cookies.get("is_retina") == null) {
        jq.cookies.set("is_retina", true, { path: '/' });
    }



    /***workaround for media screen***/
    defineBodyMediaClass();
    /******/

    /***resizable left navigation menu***/
    var sidePanelMinW = 240,
        mainPageContentMinOuterW = // 711
               1024 // min-width for #studioPageContent
               - 24 * 2 // - padding for .mainPageLayout
               - sidePanelMinW // 240
               - 24 - 1;//  - 'padding-right' - 'border-width' for .mainPageTableSidePanel 

    var setResizableMaxWidth = function () {
        var sidePanelMaxW = jq("#studioPageContent").width()
                 - 24 * 2 // - padding for .mainPageLayout
                 - mainPageContentMinOuterW
                 - 24 - 1; // - 'padding-right' - 'border-width' for .mainPageTableSidePanel 

        jq(".mainPageTableSidePanel").resizable("option", "maxWidth", sidePanelMaxW);
    }


    if (jq(".mainPageTableSidePanel").length == 1) {
        jq(".mainPageTableSidePanel").resizable({
            maxWidth: sidePanelMinW,
            minWidth: sidePanelMinW,
            handles: 'e',
            start: function (event) {
                jq("body:not(.media-width-min)").addClass('media-width-min');
                jq(".popup_helper").hide();
            },
            resize: function (event, ui) {
                jq("#studio_sidePanel").css("width", ui.size.width);

                if (jq('body').hasClass('desktop')){
                    var columnWidth = jq("#studio_sidePanel").outerWidth();
                    jq("#studioPageContent").css("grid-template-columns", columnWidth + "px 1px 1fr");
                }

                jq(window).trigger("resizeSidePanel", [event, ui]);
            },
            create: function () {
            },
            stop: function (event, ui) {
            }
        });
        setResizableMaxWidth();
    }
    /******/



    jq(window).on("resize", function () {
        // hide all popup's
        jq(".studio-action-panel:not(.freeze-display)").hide();

        jq("body:not(.media-width-min)").addClass('media-width-min');

        clearTimeout(jq.data(this, 'resizeWinTimer'));
        jq.data(this, 'resizeWinTimer', setTimeout(function () {

            defineBodyMediaClass();

            /***resizable left navigation menu***/
            if (jq(".mainPageTableSidePanel").length == 1) {
                setResizableMaxWidth();
                if (jq("#studioPageContent").width() < jq(".mainPageTable.with-mainPageTableSidePanel").width() ||
                    jq(".mainPageTable.with-mainPageTableSidePanel .mainPageContent").outerWidth() < mainPageContentMinOuterW) {
                    jq("#studio_sidePanel").width(sidePanelMinW);
                    jq(".mainPageTableSidePanel").width(sidePanelMinW);
                }
            }
            /******/

            jq(window).trigger("resizeWinTimer", null);

            jq("table.mainPageTable").tlBlock('resize');


            jq("div.advansed-filter").each(function () {
                jq(this).advansedFilter('resize');
            });

        }, 51));

        clearTimeout(jq.data(this, 'resizeWinTimerWithMaxDelay'));
        jq.data(this, 'resizeWinTimerWithMaxDelay', setTimeout(function () {
            defineBodyMediaClass();

            jq(window).trigger("resizeWinTimerWithMaxDelay", null);

            jq("table.mainPageTable").tlBlock('resize');
        }, 91));
    });

    var navContent = jq("#studioPageContent nav > .nav-content");
    var navContentScrollPosition = navContent.scrollTop();
    var pageContent = jq("#studioPageContent main > .page-content");
    var pageContentScrollPosition = pageContent.scrollTop();

    var hideContextMenu = function() {
        pageContent.find(".studio-action-panel, .popup_helper, .advanced-selector-container").hide();
        jq("#studioPageContent main .menu-small.active").removeClass("active");
        jq("#studioPageContent main .entity-menu.active").removeClass("active");
        jq('#ui-datepicker-div, .asc-popupmenu').hide();
    };

    navContent.on("scroll", function() {
        var newPosition = navContent.scrollTop();
        if (navContentScrollPosition != newPosition) {
            navContentScrollPosition = newPosition;
            hideContextMenu();
        }
    });

    pageContent.on("scroll", function () {
        var newPosition = pageContent.scrollTop();
        if (pageContentScrollPosition != newPosition) {
            pageContentScrollPosition = newPosition;
            hideContextMenu();
        }
    });

})();


jq("table.mainPageTable").tlBlock();

//hack for resizing filter
setTimeout("jq(window).resize()", 500);

jq(window).one("resize", function () {
    clearTimeout(jq.data(this, 'resizeWinTimer'));
    jq.data(this, 'resizeWinTimer', setTimeout(function () {
        defineBodyMediaClass();
    }, 51));
});

// init uvOptions
var uvOptions = {
    custom_fields: {
        "premium": ASC.Resources.Master.TenantIsPremium
    }
};

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/js/projectteam.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.Projects.ProjectTeam = (function() {
    var projectId = null,
        managerId = null,
        myGUID = null,
        baseObject,
        master,
        pmProjectTeamModulePermissionOffClass = "pm-projectTeam-modulePermissionOff",
        $teamContainer,
        teamlab,
        loadingBanner,
        clickEventName = "click",
        project,
        handler,
        mailModuleEnabled;

    var init = function () {
        teamlab = Teamlab;
        loadingBanner = LoadingBanner;
        baseObject = ASC.Projects;
        master = baseObject.Master;
        myGUID = teamlab.profile.id;
        projectId = parseInt(jq.getURLParam("prjID"));

        baseObject.ProjectsAdvansedFilter.hide();
        baseObject.Base.clearTables();

        handler = teamlab.bind(teamlab.events.getPrjProject, function (params, prj) {
            managerId = prj.responsibleId;
            var team = baseObject.Master.TeamWithBlockedUsers.sort(function(item1, item2) {
                return item1.isTerminated - item2.isTerminated;
            }).map(mapTeamMember);

            var isRetina = jq.cookies.get("is_retina");
            jq(".tab1").html(jq.tmpl("projects_team",
            {
                project: prj,
                team: team,
                manager: prj.responsible,
                isRetina: isRetina
            })).show();

            jq("#descriptionTab").show();
            project = prj;

            // calculate width
            jq(window).resize(calculateWidthBlockUserInfo);


            //--change partisipant security
            $teamContainer = jq("#team_container");

            jq("#CommonListContainer").show();
            ASC.Projects.Base.initActionPanel(showEntityMenu, $teamContainer);

            $teamContainer.on(clickEventName, ".right-checker", function () {
                var cheker = jq(this);
                if (cheker.closest("tr").hasClass("disable") || cheker.hasClass("no-dotted")) {
                    return;
                }
                var data = {
                    userId: jq(this).closest(".pm-projectTeam-participantContainer").attr("data-partisipantId"),
                    security: cheker.attr("data-flag"),
                    visible: cheker.hasClass(pmProjectTeamModulePermissionOffClass)
                };
                teamlab.setTeamSecurity({ partisipant: data.userId, securityFlag: data.security }, projectId, data, { success: onUpdateTeam });
            });

            //--menu actions
            function manageTeam(event, team) {
                var userIDs = new Array();

                jq(team).each(function (i, el) { userIDs.push(el.id); });

                var data = {
                    participants: userIDs,
                    notify: true
                };

                teamlab.updatePrjTeam({ projectId: projectId }, projectId, data,
                    {
                        before: loadingBanner.displayLoading,
                        success: onUpdateTeam,
                        after: loadingBanner.hideLoading
                    });
            };

            calculateWidthBlockUserInfo();

            var teamUserIds = master.TeamWithBlockedUsers
                .map(function (item) {
                    return item.id;
                })
                .filter(function (item) {
                    return item !== managerId;
                });

            if (teamUserIds.indexOf(managerId) < 0) {
                teamUserIds.push(managerId);
            }

            // userselector for the team

            jq("#pm-projectTeam-Selector").useradvancedSelector({
                showGroups: true,
                itemsSelectedIds: teamUserIds,
                itemsDisabledIds: [managerId]
            }).on("showList", manageTeam);

            jq('#PrivateProjectHelp').off("click").on("click", function () {
                jq(this).helper({ BlockHelperID: 'AnswerForPrivateProjectTeam' });
            });
            jq('#RestrictAccessHelp').off("click").on("click", function () {
                jq(this).helper({ BlockHelperID: 'AnswerForRestrictAccessTeam' });
            });

            if (isRetina) {
                teamlab.getUserPhoto({}, prj.responsible.id,
                    {
                        success: function(params, data) {
                            if (data && typeof(data.max) === "string" && data.max.indexOf("default") === -1) {
                                jq(".managerAvatar").attr("src", data.max);
                            }
                        }
                    });
            }
        });

        teamlab.getWebItemSecurityInfo({}, "2A923037-8B2D-487b-9A22-5AC0918ACF3F",
        {
            success: function(params, data) {
                mailModuleEnabled = data[0].enabled;
            }
        });
    };

    function showEntityMenu(selectedActionCombobox) {
        var userId = selectedActionCombobox.attr("data-partisipantid"),
            user = master.TeamWithBlockedUsers.find(function (item) { return item.id === userId });
        var ActionMenuItem = ASC.Projects.ActionMenuItem;
        var resources = ASC.Projects.Resources;
        var menuItems = [];

        if (!user.isVisitor) {
            if (project.canCreateTask && !user.isTerminated) {
                menuItems.push(new ActionMenuItem("team_task", resources.TaskResource.AddNewTask, teamAddNewTask.bind(null, userId), "new-task"));
            }
            if (!teamlab.profile.isVisitor) {
                menuItems.push(new ActionMenuItem("team_reportOpen", resources.ReportResource.ReportOpenTasks, teamReportOpenTasksHandler.bind(null, userId), "open-tasks-report"));
                menuItems.push(new ActionMenuItem("team_reportClosed", resources.ReportResource.ReportClosedTasks, teamReportClosedTasksHandler.bind(null, userId), "closed-tasks-report"));
            }

            if (menuItems.length) {
                menuItems.push(new ActionMenuItem(null, null, null, null, true));
            }

            menuItems.push(new ActionMenuItem("team_view", resources.ProjectsJSResource.ViewAllOpenTasks, teamViewOpenTasksHandler.bind(null, userId), "preview"));
        }

        if (teamlab.profile.id !== userId) {
            if (user.email) {
                menuItems.push(new ActionMenuItem("team_email", resources.ProjectResource.ClosedProjectTeamWriteMail, teamSendEmailHandler.bind(null, user.email), "email"));
            }

            menuItems.push(new ActionMenuItem("team_jabber", resources.ProjectResource.ClosedProjectTeamWriteInMessenger, teamWriteJabberHandler.bind(null, user.userName), "chat"));

            if (project.security.canEditTeam && userId !== project.responsibleId) {
                if (menuItems.length >= 3) {
                    menuItems.push(new ActionMenuItem(null, null, null, null, true));
                }

                menuItems.push(new ActionMenuItem("team_remove", resources.ProjectsCommonResource.RemoveMemberFromTeam, teamRemoveHanlder.bind(null, userId), "user"));
            }
        }

        return { menuItems: menuItems };
    }

    function teamAddNewTask(userId) {
        var user = master.TeamWithBlockedUsers.find(function (item) { return item.id === userId });
        baseObject.TaskAction.showCreateNewTaskForm({ responsibles: [user] });
        return false;
    };

    function teamViewOpenTasksHandler(userId) {
        var url = "Tasks.aspx#sortBy=deadline&sortOrder=ascending&tasks_responsible=" + userId;
        window.open(url, "displayOpenUserTasks", "status=yes,toolbar=yes,menubar=yes,scrollbars=yes,resizable=yes,location=yes,directories=yes,menubar=yes,copyhistory=yes");
        return false;
    };

    function teamWriteJabberHandler(userName) {
        ASC.Controls.JabberClient.open(userName);
        return false;
    };

    function teamReportOpenTasksHandler(userId) {
        ASC.Projects.ReportGenerator.generate("generatedreport.aspx?reportType=10&ftime=absolute&fu=" + userId + "&fms=open|closed&fts=open");
    };

    function teamReportClosedTasksHandler(userId) {
        ASC.Projects.ReportGenerator.generate("generatedreport.aspx?reportType=10&ftime=absolute&fu=" + userId + "&fms=open|closed&fts=closed");
    };

    function teamSendEmailHandler(userEmail) {
        if (mailModuleEnabled && !teamlab.profile.isVisitor) {
            window.open('../../addons/mail/#composeto/email=' + userEmail, "_blank");
        } else {
            window.location.href = "mailto:" + userEmail;
        }
        return false;
    };

    function teamRemoveHanlder(userId) {
        teamlab.removePrjProjectTeamPerson({ userId: userId }, projectId, { userId: userId }, { success: onRemoveMember });
        return false;
    };

    function onRemoveMember(params, user) {
        jq("tr[data-partisipantid='" + params.userId + "']").remove();

        jq("#pm-projectTeam-Selector").useradvancedSelector("unselect", [params.userId]);

        for (var i = 0, teamLength = master.Team.length; i < teamLength; i++) {
            if (master.Team[i].id == params.userId) {
                master.Team.splice([i], 1);
                break;
            }
        }

        for (var i = 0, teamLength = master.TeamWithBlockedUsers.length; i < teamLength; i++) {
            if (master.TeamWithBlockedUsers[i].id == params.userId) {
                master.TeamWithBlockedUsers.splice([i], 1);
                break;
            }
        }

        baseObject.TaskAction.onUpdateProjectTeam();
    };

    function updateCommonData(team) {
        master.TeamWithBlockedUsers = team;
        master.Team = baseObject.Common.removeBlockedUsersFromTeam(master.TeamWithBlockedUsers);
        baseObject.TaskAction.onUpdateProjectTeam();
    };

    function onUpdateTeam(params, team) {
        team = teamlab.create('prj-projectpersons', null, team);
        displayTeam(team);
        updateCommonData(team);
    };

    function calculateWidthBlockUserInfo(){
        var windowWidth = jq(window).width() - 24 * 2,
            mainBlockWidth = parseInt(jq(".mainPageLayout").css("min-width"), 10),
            newWidth = (windowWidth < mainBlockWidth) ? mainBlockWidth : windowWidth;

        var rightSettingCell = jq(".right-settings");
        if (rightSettingCell.length) {
            newWidth -= rightSettingCell.width();
        }
        $teamContainer.find(".user-info-container").each(
                function() {
                    jq(this).css("max-width", newWidth
                        - 24 * 2 - 24  // padding in blocks
                        - jq(".mainPageTableSidePanel").width()
                        - jq(".menupoint-container").width()
                        - jq(".pm-projectTeam-userPhotoContainer").outerWidth(true)
                        + "px");
                }
        );

        if (jq.browser.msie) {
            $teamContainer.find(".user-info-container").each(
                function() {
                    jq(this).css("width", newWidth + "px");
                }
            );
            $teamContainer.find(".user-info").each(
                function() {
                    jq(this).css("width", newWidth + 50 + "px");
                }
            );
        }
    };

    function displayTeam(team) {
        $teamContainer.html(memberTemplate(team, project));
    };

    function memberTemplate(team, project) {
        return jq.tmpl('memberTemplate',
        {
            team: team.map(mapTeamMember),
            project: project,
            isRetina: jq.cookies.get("is_retina")
        });
    }

    function mapTeamMember(item) {
        var resources = ASC.Projects.Resources;
        item = jq.extend({}, item, window.UserManager.getUser(item.id));
        item.isManager = managerId === item.id;
        item.isProjectAdmin = item.groups && item.groups.indexOf(master.ProjectsProductID) > -1;
        return jq.extend({
            security: [
                security(item.canReadMessages, "Messages", resources.MessageResource.Messages),
                security(item.canReadFiles, "Files", resources.ProjectsFileResource.Documents),
                security(item.canReadTasks, "Tasks", resources.TaskResource.AllTasks),
                security(item.canReadMilestones, "Milestone", resources.MilestoneResource.Milestones),
                security(item.canReadContacts, "Contacts", resources.ProjectsCommonResource.ModuleContacts, item.isVisitor)
            ]
        }, item);
    }

    function security(check, flag, title, defaultDisabled) {
        var result = { check: check, flag: flag, title: title };
        if (typeof defaultDisabled === "boolean") {
            result.defaultDisabled = defaultDisabled;
        }
        return result;
    }

    function unbindListEvents() {
        teamlab.unbind(handler);
        $teamContainer.off(clickEventName);
    }

    return {
        init: init,
        unbindListEvents: unbindListEvents,
        mapTeamMember: mapTeamMember
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/SingleSignOnSettings/css/singlesignonsettings.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/

#ssoIdPCertificateContainer.disable .link.delete,
#ssoIdPCertificateContainer.disable .link.edit,
#ssoSPCertificateContainer.disable .link.delete,
#ssoSPCertificateContainer.disable .link.edit {
    cursor: default;
}
.sso-settings-main-container.disable #ssoSPSettingsSpoiler,
.sso-settings-main-container.disable #ssoSPMetadataSpoiler {
    display: none;
}
#ssoSPCertificateContainer,
#ssoIdPCertificateContainer {
    display: inline-block;
}
#ssoIdPCertificateContainer .delete, #ssoIdPCertificateContainer .edit,
#ssoSPCertificateContainer .delete, #ssoSPCertificateContainer .edit {
    float: right;
    margin-left: 6px;
}
#ssoIdPCertificateContainer .edit::after,
#ssoSPCertificateContainer .edit::after
{
    display: none
}
#ssoIdPCertificateContainer .action,
#ssoSPCertificateContainer .action
{
    margin-left: 6px;
    float: left;
    width: 59px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
#ssoIdPCertificateContainer .domain,
#ssoSPCertificateContainer .domain
{
    margin-right: 6px;
    width: 73px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    float: left;
}
#ssoIdPCertificateContainer .expires,
#ssoSPCertificateContainer .expires
{
    margin-right: 6px;
    float: left;
}
#ssoIdPCertificateContainer .crt-data-row,
#ssoSPCertificateContainer .crt-data-row
{
    display: inline-block;
    width:350px;
    margin-top: 8px;
}
.crt-data-row .domain.green {
    color: #66bb6a;
}
.crt-data-row .expires.red {
    color: #bf3703;
}
.ssoSelectMetadataBtnContainer {
    overflow: hidden;
}
#ssoSelectMetadataBtn {
    max-width: 60px;
    position: relative;
}
#ssoSelectMetadataInput{
    height: 100%;
}
#ssoIdpPublicCertificate,
#ssoSpPublicCertificate,
#ssoSpPrivateKey {
    width: calc(100% - 6px);
    max-width: calc(100% - 6px);
    min-width: calc(100% - 6px);
}
#ssoSpCertificateActionType,
#ssoIdpCertificateActionType,
input[type="text" i] {
    width: 100%;
}
.requiredFieldError textarea {
    border-color: #c00;
}
input.error {
    border-color: #c00;
}
.upload-svg {
    fill: #50565c;
    width: 13px;
    height: 13px;
}
#ssoUploadMetadataBtn{
    vertical-align: top;
}

.sso-settings-label-checkbox {
    width: calc(100% - 20px);
    margin: 0 2px 22px 0;
    float: left;
    clear: both;
}

.top-indent-big{
    margin-top: 20px;
}
.top-indent-big .link.dotted {
    display: inline-block;
    margin-top: 5px;
    vertical-align: top;
}
.top-indent-big .sso-settings-title {
    max-width: 276px;
}


.settings-checkbox-text {
    display: inline-block;
    width: calc(100% - 50px);
    vertical-align: top;
    margin-left: 5px;
}
#ssoNameIdFormat {
    width: 350px;
    overflow: hidden !important;
    white-space: nowrap;
    text-overflow: ellipsis;
}
#ssoSigningAlgorithm {
    margin-bottom: 8px;
}
#ssoSpCertificateGenerateBtn
{
    float: right;
    margin-bottom:3px;
}
.link.dotted {
    border-bottom: 1px dotted;
}
.algorithm-select-container{
    padding-top: 5px;
}
.algorithm-select-container select{
    width: 100%;
}
.certificate-spoiler,
.certificate-btn-container {
    margin-top: 10px;
}
.sso-spoiler-link,
.sso-settings-spoiler-link {
    margin-left: 16px;
}

.sso-settings-title {
    display: inline-block;
    margin: 0 0 20px 0;
}

.sso-main-container .sso-settings-block {
    margin: 20px 0 0 0;
}
.sso-main-container .sso-attribute-block {
    margin: 8px 0 0 0;
}

.ssoUploadMetadataContainer > div {
    display: flex;
    justify-content: space-between;
}

.ssoUploadMetadataContainer .withUploadBtn input[type="text"] {
    width: calc(100% - 52px);
}
.ssoUploadMetadataContainer .withUploadBtn {
    width: 225px;
}

.sso-settings-block {
    margin: 14px 0 0 0;
}

.button.uploadBtn input[type="file"], .button:visited.uploadBtn input[type="file"], .button:active.uploadBtn input[type="file"] {
    position: absolute;
    height: 48px;
    left: 0;
    top: 0;
    cursor: pointer;
    width: 100%;
    opacity: 0;
}

.sso-settings-container {
    clear: both;
}

.sso-settings-disabled {
    color: #d1d1d1;
    cursor: default;
    -moz-user-select: -moz-none;
    -moz-user-select: none;
    -o-user-select: none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.sso-settings-block {
    clear: both;
    margin: 14px 0 0 0;
}

.sso-settings-container .textEdit {
    padding: 1px;
    width: 350px;
}

.radio-container {
    display: block;
    vertical-align: bottom;
    margin-top: 10px;
}
.radio-container span{
    display: inline-block;
    vertical-align: bottom;
}
.radio-container span:first-child {
    margin-right: 5px;
}
.sso-settings-block input[type=radio] + label {
    width: auto;
    margin: 0;
}

.sso-settings-text {
    padding: 0 0 4px 0;
    font-weight: bold;
}

.sso-settings-public-key-area, .sso-settings-client-public-key-area {
    resize: none;
    width: 350px;
}

.sso-settings-loader {
    width: 12px;
    height: 12px;
    background: url(images/loader_12.gif) no-repeat transparent;
    margin: 10px 5px 0 0;
    float: left;
}

.sso-settings-status {
    margin: 7px 0 0 0;
    float: left;
}

#ssoCertFile {
    margin: 10px 0;
    display: none;
}

#ssoCertFile .name {
    width: 170px;
    display: inline-block;
}

#ssoCertFile .trash {
    display: inline-block;
    float: none;
    margin: 0;
    vertical-align: middle;
    cursor: pointer;
}

.sso-required-field {
    color: #c00;
    font-size: 12px;
    vertical-align: text-top;
    height: 16px;
    width: 6px;
    display: inline-block;
    margin-top: -4px;
    margin-left: -2px;
}

.sso-link-not-active {
   pointer-events: none;
   cursor: default !important;
   color: #b2b2b2 !important;
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/DataInterfaces/ITimeSpendDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Projects.Core.Domain;

namespace ASC.Projects.Core.DataInterfaces
{
    public interface ITimeSpendDao
    {
        List<TimeSpend> GetByTask(int taskId);

        List<TimeSpend> GetByProject(int projectId);

        TimeSpend GetById(int id);

        List<TimeSpend> GetByFilter(TaskFilter filter, bool isAdmin, bool checkAccess);

        int GetByFilterCount(TaskFilter filter, bool isAdmin, bool checkAccess);

        float GetByFilterTotal(TaskFilter filter, bool isAdmin, bool checkAccess);

        TimeSpend Save(TimeSpend timeSpend);

        void Delete(int id);
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Calendar/iCalParser/Emitter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/*
 *   ICalParser is a general purpose .Net parser for iCalendar format files (RFC 2445)
 * 
 *   Copyright (C) 2004  <NAME>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

namespace ASC.Api.Calendar.iCalParser
{
    /// <summary>
    /// Defines all of the basic operations that must be implemented by parser emitters.
    /// </summary>
    /// <remarks>
    /// 
    /// </remarks>
    public interface IEmitter
    {
        void doIntro();
        void doOutro();
        void doEnd(Token t);
        void doResourceBegin(Token t);
        void doBegin(Token t);
        void doComponentBegin(Token t);
        void doComponent();
        void doEndComponent();
        void doID(Token t);
        void doSymbolic(Token t);
        void doResource(Token t);
        void doURIResource(Token t);
        void doMailto(Token t);
        void doValueProperty(Token t, Token iprop);
        void doIprop(Token t, Token iprop);
        void doRest(Token t, Token id);
        void doAttribute(Token t1, Token t2);
        Parser VParser { get; set; }
        void emit(string val);
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Calendar/Wrappers/Permissions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ASC.Api.Calendar.Wrappers
{
    [DataContract(Name = "permissions", Namespace = "")]
    public class Permissions
    {
        [DataMember(Name = "users")]
        public List<UserParams> UserParams { get; set; }

        public Permissions()
        {
            this.UserParams = new List<UserParams>();
        }

        public static object GetSample()
        {
            return new { users = new List<object>() { ASC.Api.Calendar.Wrappers.UserParams.GetSample() } };
        }
    }

    [DataContract(Name = "permissions", Namespace = "")]
    public class CalendarPermissions : Permissions
    {
        [DataMember(Name = "data")]
        public PublicItemCollection Data { get; set; }

        public new static object GetSample()
        {
            return new { data = PublicItemCollection.GetSample() };
        }
    }

    [DataContract(Name = "userparams", Namespace = "")]
    public class UserParams
    {
        [DataMember(Name = "objectId")]
        public Guid Id { get; set; }

        [DataMember(Name = "name")]
        public string Name { get; set; }

        public static object GetSample()
        {
            return new { objectId = "2fdfe577-3c26-4736-9df9-b5a683bb8520", name = "<NAME>" };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Controls/Tree/treebuilder.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC.Files.Tree = (function () {
    var isInit = false;
    var treeViewContainer;
    var treeViewSelector;

    var pathParts = new Array();
    var folderIdCurrentRoot = null;

    var displayFavoritesStatus = false;
    var displayRecentStatus = false;
    var displayTemplatesStatus = false;
    var displayPrivacy = false;

    var init = function () {
        if (isInit === false) {
            isInit = true;

            var rootId = null;
            if (jq(".files-content-panel").attr("data-rootid")) {
                ASC.Files.Tree.folderIdCurrentRoot = jq(".files-content-panel").attr("data-rootid");
                rootId = ASC.Files.Constants.FOLDER_ID_PROJECT;
            }

            treeViewContainer = new ASC.Files.TreePrototype("#treeViewContainer", rootId);
            treeViewContainer.clickOnFolder = gotoFolder;
            if (rootId) {
                treeViewContainer.expandFolder(rootId);
            }

            treeViewSelector = new ASC.Files.TreePrototype("#treeViewSelector");
            treeViewSelector.clickOnFolder = movetoFolder;

            var selectorPrivacyData = treeViewSelector.getFolderData(ASC.Files.Constants.FOLDER_ID_PRIVACY);
            if (selectorPrivacyData) {
                displayPrivacy = true;
                selectorPrivacyData.entryObject.addClass("privacy-node");
            }

            var favoritesData = treeViewContainer.getFolderData(ASC.Files.Constants.FOLDER_ID_FAVORITES);
            if (favoritesData) {
                displayFavoritesStatus = !favoritesData.entryObject.hasClass("display-none");
            }

            var recentData = treeViewContainer.getFolderData(ASC.Files.Constants.FOLDER_ID_RECENT);
            if (recentData) {
                displayRecentStatus = !recentData.entryObject.hasClass("display-none");
            }

            var templatesData = treeViewContainer.getFolderData(ASC.Files.Constants.FOLDER_ID_TEMPLATES);
            if (templatesData) {
                displayTemplatesStatus = !templatesData.entryObject.hasClass("display-none");
            }
        }
    };

    var getFolderTitle = function (folderId) {
        return treeViewContainer.getFolderTitle(folderId) || treeViewSelector.getFolderTitle(folderId);
    };

    var getParentId = function (folderId) {
        return treeViewContainer.getParentId(folderId);
    };

    var getFolderData = function (folderId) {
        return treeViewContainer.getFolderData(folderId);
    };

    var updateTreePath = function () {
        for (var i = 0; i < ASC.Files.Tree.pathParts.length - 1; i++) {
            var parentId = ASC.Files.Tree.pathParts[i];
            if (!treeViewContainer.getFolderData(ASC.Files.Tree.pathParts[i + 1])) {
                treeViewContainer.resetFolder(parentId);
            }
            treeViewContainer.expandFolder(parentId, true, true);
        }

        treeViewContainer.setCurrent(ASC.Files.Folders.currentFolder.id);
        if (ASC.Files.Tree.pathParts.length != 1
            || treeViewSelector.getFolderData(ASC.Files.Folders.currentFolder.id)) {
            treeViewSelector.setCurrent(ASC.Files.Folders.currentFolder.id);
        }
    };

    var showSelect = function () {
        treeViewSelector.rollUp();
        treeViewSelector.setCurrent(ASC.Files.Folders.currentFolder.id);

        if (displayPrivacy) {
            var needPrivacy = ASC.Files.Folders.folderContainer == "privacy";
            treeViewSelector.entryObject().toggleClass("only-privacy", needPrivacy);
        }
    };

    var getPathTitle = function (folderId) {
        var folderTitle = treeViewSelector.getFolderTitle(folderId);
        var path = treeViewSelector.getPath(folderId);

        var pathId = jq(path).map(function (i, fId) {
            return treeViewSelector.getFolderTitle(fId);
        });
        pathId.push(folderTitle);
        var pathTitle = pathId.toArray().join(" > ");

        return pathTitle;
    };

    var resetFolder = function (folderId) {
        if (!ASC.Files.Common.isCorrectId(folderId)) {
            return false;
        }

        var beOpened = treeViewContainer.resetFolder(folderId);
        treeViewSelector.resetFolder(folderId);

        if (ASC.Files.ThirdParty) {
            ASC.Files.ThirdParty.docuSignFolderSelectorReset(folderId);
        }

        return beOpened;
    };

    var reloadFolder = function (folderId) {
        var beOpened = ASC.Files.Tree.resetFolder(folderId);

        if (beOpened) {
            treeViewContainer.expandFolder(folderId);
        }
    };

    var gotoFolder = function (folderId) {
        if (ASC.Files.Tree.folderIdCurrentRoot
            && ASC.Files.Tree.folderIdCurrentRoot != ASC.Files.Constants.FOLDER_ID_PROJECT) {

            var toParent = jq.inArray(folderId + "", ASC.Files.Tree.pathParts) != -1;
            if (!toParent) {
                var path = treeViewContainer.getPath(folderId);
                var toChild = (jq.inArray(ASC.Files.Folders.currentFolder.id, path) != -1);

                if (!toChild) {
                    var rootFolderId = folderId;
                    if (path.length) {
                        rootFolderId = path[0];
                    }
                    var rootFolderData = treeViewContainer.getFolderData(rootFolderId);

                    var href = rootFolderData.folderUrl;
                    href = href.substring(0, href.lastIndexOf("#"));
                    href = href + "#" + ASC.Files.Common.getCorrectHash(folderId);
                    location.href = href;
                    return;
                }
            }
        }

        ASC.Files.Filter.clearFilter(true);
        ASC.Files.Anchor.navigationSet(folderId);
        return;
    };

    var movetoFolder = function (folderId) {
        var folderData = treeViewSelector.getFolderData(folderId);

        if (ASC.Files.UI.accessEdit(folderData)) {

            var folderTitle = treeViewSelector.getFolderTitle(folderId);
            var path = treeViewSelector.getPath(folderId);
            path.push(folderId);

            ASC.Files.Folders.curItemFolderMoveTo(folderId, folderTitle, path);

            return true;
        } else {
            var errorString = ASC.Files.FilesJSResource.ErrorMassage_SecurityException;
            if (folderId == ASC.Files.Constants.FOLDER_ID_PROJECT
                || folderId == ASC.Files.Constants.FOLDER_ID_SHARE) {
                errorString = ASC.Files.FilesJSResource.ErrorMassage_SecurityException_PrivateRoot;
            }
            ASC.Files.UI.displayInfoPanel(errorString, true);

            treeViewSelector.expandFolder(folderId);
            return false;
        }
    };

    var displayFavorites = function (set) {
        if (set === undefined) {
            return displayFavoritesStatus;
        }

        displayFavoritesStatus = (set === true);

        var favoritesContainer = treeViewContainer.getFolderData(ASC.Files.Constants.FOLDER_ID_FAVORITES).entryObject;
        favoritesContainer.toggleClass("display-none", !displayFavoritesStatus);

        return displayFavoritesStatus;
    };

    var displayRecent = function (set) {
        if (set === undefined) {
            return displayRecentStatus;
        }

        displayRecentStatus = (set === true);

        var recentContainer = treeViewContainer.getFolderData(ASC.Files.Constants.FOLDER_ID_RECENT).entryObject;
        recentContainer.toggleClass("display-none", !displayRecentStatus);

        return displayRecentStatus;
    };

    var displayTemplates = function (set) {
        if (set === undefined) {
            return displayTemplatesStatus;
        }

        displayTemplatesStatus = (set === true);

        var templatesContainer = treeViewContainer.getFolderData(ASC.Files.Constants.FOLDER_ID_TEMPLATES).entryObject;
        templatesContainer.toggleClass("display-none", !displayTemplatesStatus);

        return displayTemplatesStatus;
    };

    return {
        init: init,
        resetFolder: resetFolder,
        reloadFolder: reloadFolder,

        getFolderTitle: getFolderTitle,
        getParentId: getParentId,

        pathParts: pathParts,

        folderIdCurrentRoot: folderIdCurrentRoot,

        updateTreePath: updateTreePath,

        showSelect: showSelect,
        getPathTitle: getPathTitle,
        getFolderData: getFolderData,

        displayFavorites: displayFavorites,
        displayRecent: displayRecent,
        displayTemplates: displayTemplates,
    };
})();

(function ($) {
    $(function () {

        if (jq("#treeViewPanelSelector").length == 0)
            return;

        ASC.Files.Tree.init();
    });
})(jQuery);

<|start_filename|>common/ASC.ActiveDirectory/Base/LdapNotifyHelper.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using ASC.ActiveDirectory.Base.Settings;
using ASC.ActiveDirectory.ComplexOperations;
using ASC.Common.DependencyInjection;
using ASC.Common.Threading;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Notify;
using ASC.Notify.Model;

using Autofac;

namespace ASC.ActiveDirectory.Base
{
    public static class LdapNotifyHelper
    {
        private static readonly Dictionary<int, Tuple<INotifyClient, LdapNotifySource>> clients;
        private static readonly DistributedTaskQueue ldapTasks;

        private static IContainer Builder { get; set; }
        private static INotifySource studioNotify;
        private static INotifyClient notifyClient;

        public static INotifyClient StudioNotifyClient
        {
            get
            {
                if (studioNotify == null)
                {
                    studioNotify = Builder.Resolve<INotifySource>();
                }

                if (notifyClient == null)
                {
                    notifyClient = WorkContext.NotifyContext.NotifyService.RegisterClient(studioNotify);
                }

                return notifyClient;
            }
        }

        static LdapNotifyHelper()
        {
            var container = AutofacConfigLoader.Load("ldap");
            if (container != null)
            {
                Builder = container.Build();
            }

            clients = new Dictionary<int, Tuple<INotifyClient, LdapNotifySource>>();
            ldapTasks = new DistributedTaskQueue("ldapAutoSyncOperations");
        }

        public static void RegisterAll()
        {
            var task = new Task(() =>
            {
                var tenants = CoreContext.TenantManager.GetTenants();
                foreach (var t in tenants)
                {
                    var tId = t.TenantId;

                    var ldapSettings = LdapSettings.LoadForTenant(tId);
                    if (!ldapSettings.EnableLdapAuthentication) continue;

                    var cronSettings = LdapCronSettings.LoadForTenant(tId);
                    if (string.IsNullOrEmpty(cronSettings.Cron)) continue;

                    RegisterAutoSync(t, cronSettings.Cron);
                }
            }, TaskCreationOptions.LongRunning);

            task.Start();
        }

        public static void RegisterAutoSync(Tenant tenant, string cron)
        {
            if (!clients.ContainsKey(tenant.TenantId))
            {
                var source = new LdapNotifySource(tenant);
                var client = WorkContext.NotifyContext.NotifyService.RegisterClient(source);
                client.RegisterSendMethod(source.AutoSync, cron);
                clients.Add(tenant.TenantId, new Tuple<INotifyClient, LdapNotifySource>(client, source));
            }
        }

        public static void UnregisterAutoSync(Tenant tenant)
        {
            if (clients.ContainsKey(tenant.TenantId))
            {
                var client = clients[tenant.TenantId];
                client.Item1.UnregisterSendMethod(client.Item2.AutoSync);
                clients.Remove(tenant.TenantId);
            }
        }

        public static void AutoSync(Tenant tenant)
        {
            var ldapSettings = LdapSettings.LoadForTenant(tenant.TenantId);

            if (!ldapSettings.EnableLdapAuthentication)
            {
                var cronSettings = LdapCronSettings.LoadForTenant(tenant.TenantId);
                cronSettings.Cron = "";
                cronSettings.SaveForTenant(tenant.TenantId);
                UnregisterAutoSync(tenant);
                return;
            }

            var op = new LdapSaveSyncOperation(ldapSettings, tenant, LdapOperationType.Sync);
            ldapTasks.QueueTask(op.RunJob, op.GetDistributedTask());
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/BalanceMode.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net
{
    /// <summary>
    /// This enum specified balance mode.
    /// </summary>
    public enum BalanceMode
    {
        /// <summary>
        /// Operation is load balanched by all workers.
        /// </summary>
        LoadBalance,

        /// <summary>
        /// Operation will be handed over to next worker, if last one fails.
        /// </summary>
        FailOver,
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/EmptyScreens/js/dashboard.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


jq(function () {

    var hash = window.location.hash;

    if (hash && hash.indexOf("#preview") == 0) {
        return;
    } else {
        jq("#dashboardBackdrop, #dashboardContent").removeClass("display-none");
    }

    jq("#dashboardContent .close").on("click", function () {
        jq("[blank-page]").remove();
        var href = jq(this).attr("href");
        if (href) {
            location.href = href;
        }
    });

    jq(document).keyup(function (event) {
        var code;

        if (event.keyCode) {
            code = event.keyCode;
        } else if (event.which) {
            code = event.which;
        }

        if (code == 27) {
            jq("#dashboardContent .close").click();
        }
    });

    jq("#dashboardContent .slick-carousel").slick({
        slidesToShow: 1,
        slidesToScroll: 1,
        arrows: true,
        dots: true,
        fade: true,
        centerMode: true
    });

    jq("#dashboardContent .slick-next").focus();

});

<|start_filename|>common/ASC.ActiveDirectory/Base/Expressions/Expression.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;

namespace ASC.ActiveDirectory.Base.Expressions
{
    public class Expression : ICloneable
    {
        private readonly Op _op;
        private bool _negative;
        private readonly string _attributeName;
        private readonly string _attributeValue;

        private const string EQUIAL = "=";
        private const string APPROXIMATELY_EQUIAL = "~=";
        private const string GREATER = ">";
        private const string GREATER_OR_EQUAL = ">=";
        private const string LESS = "<";
        private const string LESS_OR_EQUAL = "<=";

        internal Expression()
        {
        }

        public string Name
        {
            get { return _attributeName; }
        }

        public string Value
        {
            get { return _attributeValue; }
        }

        public Op Operation
        {
            get { return _op; }
        }

        /// <summary>
        /// To specify unary operations
        /// </summary>
        /// <param name="op">Operator</param>
        /// <param name="attrbuteName">Attribute name</param>
        public Expression(string attrbuteName, Op op)
        {
            if (op != Op.Exists && op != Op.NotExists)
                throw new ArgumentException("op");

            if (string.IsNullOrEmpty(attrbuteName))
                throw new ArgumentException("attrbuteName");

            _op = op;
            _attributeName = attrbuteName;
            _attributeValue = "*";
        }

        /// <summary>
        /// To specify binary operations
        /// </summary>
        /// <param name="op">Operator</param>
        /// <param name="attrbuteName">Attribute name</param>
        /// <param name="attrbuteValue">Attribute value</param>
        public Expression(string attrbuteName, Op op, string attrbuteValue)
        {
            if (op == Op.Exists || op == Op.NotExists)
                throw new ArgumentException("op");

            if (string.IsNullOrEmpty(attrbuteName))
                throw new ArgumentException("attrbuteName");

            _op = op;
            _attributeName = attrbuteName;
            _attributeValue = attrbuteValue;
        }

        /// <summary>
        /// Expression as a string
        /// </summary>
        /// <returns>Expression string</returns>
        public override string ToString()
        {
            string sop;
            switch (_op)
            {
                case Op.NotExists:
                case Op.Exists:
                case Op.Equal:
                case Op.NotEqual:
                    sop = EQUIAL;
                    break;
                case Op.Greater:
                    sop = GREATER;
                    break;
                case Op.GreaterOrEqual:
                    sop = GREATER_OR_EQUAL;
                    break;
                case Op.Less:
                    sop = LESS;
                    break;
                case Op.LessOrEqual:
                    sop = LESS_OR_EQUAL;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            var expressionString = "({0}{1}{2}{3})";
            expressionString = string.Format(expressionString,
                //positive or negative
                (((int)_op & 0x010000) == 0x010000 || _negative) ? "!" : "", _attributeName, sop,
                EscapeLdapSearchFilter(_attributeValue));

            return expressionString;
        }

        /// <summary>
        /// Escapes the LDAP search filter to prevent LDAP injection attacks.
        /// </summary>
        /// <param name="searchFilter">The search filter.</param>
        /// <see cref="https://blogs.oracle.com/shankar/entry/what_is_ldap_injection" />
        /// <see cref="http://msdn.microsoft.com/en-us/library/aa746475.aspx" />
        /// <returns>The escaped search filter.</returns>
        private static string EscapeLdapSearchFilter(string searchFilter)
        {
            var escape = new StringBuilder(); // If using JDK >= 1.5 consider using StringBuilder
            foreach (var current in searchFilter)
            {
                switch (current)
                {
                    case '\\':
                        escape.Append(@"\5c");
                        break;
                    case '*':
                        escape.Append(@"\2a");
                        break;
                    case '(':
                        escape.Append(@"\28");
                        break;
                    case ')':
                        escape.Append(@"\29");
                        break;
                    case '\u0000':
                        escape.Append(@"\00");
                        break;
                    case '/':
                        escape.Append(@"\2f");
                        break;
                    default:
                        escape.Append(current);
                        break;
                }
            }

            return escape.ToString();
        }

        /// <summary>
        /// Negation
        /// </summary>
        /// <returns>Self</returns>
        public Expression Negative()
        {
            _negative = !_negative;
            return this;
        }

        /// <summary>
        /// Existence
        /// </summary>
        /// <param name="attrbuteName"></param>
        /// <returns>New Expression</returns>
        public static Expression Exists(string attrbuteName)
        {
            return new Expression(attrbuteName, Op.Exists);
        }

        /// <summary>
        /// Non-Existence
        /// </summary>
        /// <param name="attrbuteName"></param>
        /// <returns>New Expression</returns>
        public static Expression NotExists(string attrbuteName)
        {
            return new Expression(attrbuteName, Op.NotExists);
        }

        /// <summary>
        /// Equality
        /// </summary>
        /// <param name="attrbuteName"></param>
        /// <param name="attrbuteValue"></param>
        /// <returns>New Expression</returns>
        public static Expression Equal(string attrbuteName, string attrbuteValue)
        {
            return new Expression(attrbuteName, Op.Equal, attrbuteValue);
        }

        /// <summary>
        /// Not equality
        /// </summary>
        /// <param name="attrbuteName"></param>
        /// <param name="attrbuteValue"></param>
        /// <returns></returns>
        public static Expression NotEqual(string attrbuteName, string attrbuteValue)
        {
            return new Expression(attrbuteName, Op.NotEqual, attrbuteValue);
        }

        public static Expression Parse(string origin)
        {
            string spliter = null;
            var op = Op.Equal;

            var index = origin.IndexOf(EQUIAL, StringComparison.Ordinal);

            if (index > -1)
            {
                spliter = EQUIAL;
                op = Op.Equal;
            }
            else if ((index = origin.IndexOf(GREATER, StringComparison.Ordinal)) > -1)
            {
                spliter = GREATER;
                op = Op.Greater;
            }
            else if ((index = origin.IndexOf(GREATER_OR_EQUAL, StringComparison.Ordinal)) > -1)
            {
                spliter = GREATER_OR_EQUAL;
                op = Op.GreaterOrEqual;
            }
            else if ((index = origin.IndexOf(LESS, StringComparison.Ordinal)) > -1)
            {
                spliter = LESS;
                op = Op.Less;
            }
            else if ((index = origin.IndexOf(LESS_OR_EQUAL, StringComparison.Ordinal)) > -1)
            {
                spliter = LESS_OR_EQUAL;
                op = Op.LessOrEqual;
            }
            else if ((index = origin.IndexOf(APPROXIMATELY_EQUIAL, StringComparison.Ordinal)) > -1)
            {
                spliter = APPROXIMATELY_EQUIAL;
                op = Op.Exists;
            }

            if (string.IsNullOrEmpty(spliter))
                return null;

            var attributeName = origin.Substring(0, index);
            var attributeValue = origin.Substring(index + 1);

            if (string.IsNullOrEmpty(attributeName) || string.IsNullOrEmpty(attributeValue))
                return null;

            return new Expression(attributeName, op, attributeValue);
        }

        #region ICloneable Members
        /// <summary>
        /// ICloneable implemetation
        /// </summary>
        /// <returns>Clone object</returns>
        public object Clone()
        {
            return MemberwiseClone();
        }

        #endregion
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/js/editor.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


;
window.ASC.Files.Editor = (function () {
    var isInit = false;

    var docIsChanged = false;
    var docIsChangedTimeout = null;
    var canShowHistory = false;

    var docEditor = null;
    var docServiceParams = {};
    var configurationParams = null;

    var trackEditTimeout = null;
    var doStartEdit = true;

    var init = function () {
        if (isInit === false) {
            isInit = true;
        }

        jq("body").css("overflow-y", "hidden");

        window.onbeforeunload = ASC.Files.Editor.finishEdit;

        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.TrackEditFile, completeTrack);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.StartEdit, onStartEdit);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.GetEditHistory, completeGetEditHistory);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.GetDiffUrl, completeGetDiffUrl);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.RestoreVersion, completeGetEditHistory);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.GetMails, completeGetMails);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.StartMailMerge, completeStartMailMerge);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.FileRename, completeRename);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.GetUsers, completeGetUsers);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.SendEditorNotify, completeSendEditorNotify);
        ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.ToggleFavorite, completeToggleFavorite);
    };

    var createFrameEditor = function (configuration) {

        jq("#iframeEditor").parents().css("height", "100%");

        var eventsConfig = {
            "onAppReady": ASC.Files.Editor.readyEditor,
        };

        if (configuration) {
            var embedded = (configuration.type == "embedded");

            var documentConfig = configuration.document;

            var options = getOptions();
            if (options) {
                documentConfig.options = options;
            }

            var editorConfig = configuration.editorConfig;

            if (embedded) {
                var keyFullscreen = "fullscreen";
                if (location.hash.indexOf(keyFullscreen) < 0) {
                    editorConfig.embedded.fullscreenUrl = editorConfig.embedded.embedUrl + "#" + keyFullscreen;
                }
            } else {
                if (configuration.type != "embedded" && !editorConfig.recent) {
                    var listRecent = getRecentList();
                    if (listRecent && listRecent.length) {
                        editorConfig.recent = listRecent.toArray();
                    }
                }
            }

            var typeConfig = configuration.type;
            var documentTypeConfig = configuration.documentType;

            eventsConfig.onDocumentStateChange = ASC.Files.Editor.documentStateChangeEditor;
            if (ASC.Files.Editor.docServiceParams.linkToEdit) {
                eventsConfig.onRequestEditRights = ASC.Files.Editor.requestEditRightsEditor;
            }
            eventsConfig.onError = ASC.Files.Editor.errorEditor;
            eventsConfig.onDocumentReady = ASC.Files.Editor.readyDocument;
            eventsConfig.onOutdatedVersion = ASC.Files.Editor.reloadPage;
            eventsConfig.onInfo = ASC.Files.Editor.infoEditor;

            if (documentConfig.permissions.rename) {
                eventsConfig.onRequestRename = ASC.Files.Editor.rename;
            }

            eventsConfig.onMetaChange = ASC.Files.Editor.metaChange;
            eventsConfig.onRequestClose = ASC.Files.Editor.requestClose;
            eventsConfig.onMakeActionLink = ASC.Files.Editor.makeActionLink;

            if (ASC.Files.Constants.URL_MAIL_ACCOUNTS) {
                eventsConfig.onRequestEmailAddresses = ASC.Files.Editor.getMails;
                eventsConfig.onRequestStartMailMerge = ASC.Files.Editor.requestStartMailMerge;
            }

            if (!ASC.Files.Editor.docServiceParams.fileProviderKey
                && !ASC.Files.Editor.docServiceParams.editByUrl
                && !ASC.Files.Editor.docServiceParams.thirdPartyApp) {

                ASC.Files.Editor.canShowHistory = true;
                eventsConfig.onRequestHistory = ASC.Files.Editor.requestHistory;
                eventsConfig.onRequestHistoryData = ASC.Files.Editor.getDiffUrl;
                eventsConfig.onRequestHistoryClose = ASC.Files.Editor.historyClose;
                if (!!documentConfig.permissions.changeHistory) {
                    eventsConfig.onRequestRestore = ASC.Files.Editor.restoreVersion;
                }
            }

            if (ASC.Files.Editor.docServiceParams.canGetUsers) {
                eventsConfig.onRequestUsers = ASC.Files.Editor.requestUsers;
                eventsConfig.onRequestSendNotify = ASC.Files.Editor.requestSendNotify;
            }

            var token = configuration.token;
        }

        ASC.Files.Editor.docEditor = new DocsAPI.DocEditor("iframeEditor", {
            width: "100%",
            height: "100%",

            type: typeConfig || "desktop",
            documentType: documentTypeConfig,
            document: documentConfig,
            editorConfig: editorConfig,
            token: token,
            events: eventsConfig
        });
    };

    var getOptions = function () {
        try {
            var param = /(?:\?|\&)options=([^&]*)/g.exec(location.search);
            if (param && param[1]) {
                return jq.parseJSON(decodeURIComponent(param[1]));
            }
        } catch (e) {
        }
        return null;
    };

    var fixSize = function () {
        var wrapEl = document.getElementById("wrap");
        if (wrapEl) {
            wrapEl.style.height = screen.availHeight + "px";
            window.scrollTo(0, -1);
            wrapEl.style.height = window.innerHeight + "px";
        }
    };

    var readyEditor = function () {
        if (ASC.Files.Editor.docServiceParams.serverErrorMessage) {
            ASC.Files.Editor.docEditor.showMessage(ASC.Files.Editor.docServiceParams.serverErrorMessage);
            return;
        }

        if (checkMessageFromHash()) {
            location.hash = "";
            return;
        }

        if (ASC.Files.Editor.configurationParams && ASC.Files.Editor.configurationParams.editorConfig.mode === "edit") {
            ASC.Files.Editor.trackEdit();
        }
    };

    var readyDocument = function () {
        if (ASC.Files.Editor.canShowHistory
            && ASC.Files.Editor.docServiceParams.openHistory) {
            ASC.Files.Editor.requestHistory();
        }
    };

    var documentStateChangeEditor = function (event) {
        clearTimeout(docIsChangedTimeout);

        if (docIsChanged != event.data) {
            var titleChange = function () {
                updateDocumentTitle(event.data);
                docIsChanged = event.data;
            };

            if (event.data) {
                titleChange();
            } else {
                docIsChangedTimeout = setTimeout(titleChange, 500);
            }
        }

        if (event.data) {
            subscribeEdit(ASC.Files.ServiceManager.events.StartEdit);
        }
    };

    var updateDocumentTitle = function (changed) {
        document.title = (changed ? "*" : "")
            + ASC.Files.Editor.configurationParams.document.title
            + ASC.Files.Editor.docServiceParams.pageTitlePostfix;
    };

    var subscribeEdit = function (event) {
        if (!ASC.Files.Editor.configurationParams.editorConfig.callbackUrl
            && doStartEdit) {
            doStartEdit = false;

            ASC.Files.ServiceManager.startEdit(event, {
                fileID: ASC.Files.Editor.docServiceParams.fileId,
                shareLinkParam: ASC.Files.Editor.docServiceParams.shareLinkParam,
            });

            return true;
        }
        return false;
    };

    var errorEditor = function () {
        ASC.Files.Editor.finishEdit();
    };

    var requestEditRightsEditor = function () {
        location.href = ASC.Files.Editor.docServiceParams.linkToEdit + ASC.Files.Editor.docServiceParams.shareLinkParam;
    };

    var requestHistory = function () {
        if (!ASC.Files.Editor.canShowHistory) {
            return;
        }

        ASC.Files.Editor.finishEdit();

        ASC.Files.ServiceManager.getEditHistory(ASC.Files.ServiceManager.events.GetEditHistory,
            {
                fileID: ASC.Files.Editor.docServiceParams.fileId,
                shareLinkParam: ASC.Files.Editor.docServiceParams.shareLinkParam
            });
    };

    var historyClose = function () {
        if (location.search.indexOf("action=view") == -1) {
            ASC.Files.Editor.reloadPage();
            return;
        }

        var url = location.href;
        var indexAnchor = url.indexOf("#");
        if (indexAnchor != -1) {
            url = url.substring(0, indexAnchor);
        }

        if (/[\?\&]history=close/g.test(location.search)) {
            ASC.Files.Editor.reloadPage();
            return;
        }

        url += (url.indexOf("?") == -1) ? "?" : "&";
        url += "history=close";

        location.href = url;
    };

    var getDiffUrl = function (versionData) {
        if (!ASC.Files.Editor.canShowHistory) {
            return;
        }

        ASC.Files.ServiceManager.getDiffUrl(ASC.Files.ServiceManager.events.GetDiffUrl,
            {
                fileID: ASC.Files.Editor.docServiceParams.fileId,
                version: versionData.data | 0,
                shareLinkParam: ASC.Files.Editor.docServiceParams.shareLinkParam
            });
    };

    var restoreVersion = function (versionData) {
        ASC.Files.ServiceManager.restoreVersion(ASC.Files.ServiceManager.events.RestoreVersion,
            {
                fileID: ASC.Files.Editor.docServiceParams.fileId,
                version: versionData.data.version,
                shareLinkParam: ASC.Files.Editor.docServiceParams.shareLinkParam,
                setLast: true,
                url: versionData.data.url || "",
            });
    };

    var getMails = function () {
        ASC.Files.ServiceManager.getMailAccounts(ASC.Files.ServiceManager.events.GetMails);
    };

    var requestStartMailMerge = function () {
        if (!subscribeEdit(ASC.Files.ServiceManager.events.StartMailMerge)) {
            completeStartMailMerge();
        }
    };

    var infoEditor = function (event) {
        if (!!ASC.Files.Editor.configurationParams.editorConfig.callbackUrl
            || event && event.data && event.data.mode == "view") {
            clearTimeout(trackEditTimeout);
            trackEditTimeout = null;
        }
    };

    var requestUsers = function () {
        ASC.Files.ServiceManager.getUsers(ASC.Files.ServiceManager.events.GetUsers, {
            fileId: ASC.Files.Editor.docServiceParams.fileId
        });
    };

    var requestSendNotify = function (event) {
        var message = event.data;

        ASC.Files.ServiceManager.sendEditorNotify(ASC.Files.ServiceManager.events.SendEditorNotify,
            {
                ajaxcontentType: "application/json",
                fileId: ASC.Files.Editor.docServiceParams.fileId
            },
            message);
    };

    var rename = function (event) {
        ASC.Files.ServiceManager.renameFile(ASC.Files.ServiceManager.events.FileRename,
            {
                fileId: ASC.Files.Editor.docServiceParams.fileId,
                newname: event.data,
            });
    };

    var metaChange = function (event) {
        if (event && event.data) {
            if (event.data.title !== undefined) {
                ASC.Files.Editor.configurationParams.document.title = event.data.title;

                updateDocumentTitle(docIsChanged);
            } else if (event.data.favorite !== undefined) {
                toggleFavorite(!!event.data.favorite);
            }
        }
    };
    var toggleFavorite = function (favorite) {
        ASC.Files.ServiceManager.toggleFavorite(ASC.Files.ServiceManager.events.ToggleFavorite,
            {
                ajaxcontentType: "application/json",
                fileId: ASC.Files.Editor.docServiceParams.fileId,
                favorite: favorite
            });
    }

    var requestClose = function () {
        if (!window.opener
            && ASC.Files.Editor.configurationParams.editorConfig.customization.goback
            && ASC.Files.Editor.configurationParams.editorConfig.customization.goback.url) {
            location.href = ASC.Files.Editor.configurationParams.editorConfig.customization.goback.url;
            return;
        }
        window.close();
    };

    var makeActionLink = function (event) {
        var url = location.href;
        if (event && event.data) {
            var indexAnchor = url.indexOf("#");
            if (indexAnchor != -1) {
                url = url.substring(0, indexAnchor);
            }

            var data = JSON.stringify(event.data);
            data = "anchor=" + encodeURIComponent(data);

            var anchorRegex = /anchor=([^&]*)/g;
            if (anchorRegex.test(location.search)) {
                url = url.replace(anchorRegex, data);
            } else {
                url += (url.indexOf("?") == -1) ? "?" : "&";
                url += data;
            }
        }

        ASC.Files.Editor.docEditor.setActionLink(url);
    };

    var reloadPage = function () {
        location.reload(true);
    };

    var trackEdit = function () {
        clearTimeout(trackEditTimeout);
        trackEditTimeout = null;
        if (ASC.Files.Editor.docServiceParams.editByUrl || ASC.Files.Editor.docServiceParams.thirdPartyApp) {
            return;
        }
        if (!doStartEdit) {
            return;
        }
        if (!!ASC.Files.Editor.configurationParams.editorConfig.callbackUrl) {
            return;
        }

        ASC.Files.ServiceManager.trackEditFile(ASC.Files.ServiceManager.events.TrackEditFile,
            {
                fileID: ASC.Files.Editor.docServiceParams.fileId,
                tabId: ASC.Files.Editor.docServiceParams.tabId,
                docKeyForTrack: ASC.Files.Editor.docServiceParams.docKeyForTrack,
                shareLinkParam: ASC.Files.Editor.docServiceParams.shareLinkParam,
            });
    };

    var finishEdit = function () {
        if (trackEditTimeout !== null && doStartEdit) {
            clearTimeout(trackEditTimeout);
            trackEditTimeout = null;
            ASC.Files.ServiceManager.trackEditFile("FinishTrackEditFile",
                {
                    fileID: ASC.Files.Editor.docServiceParams.fileId,
                    tabId: ASC.Files.Editor.docServiceParams.tabId,
                    docKeyForTrack: ASC.Files.Editor.docServiceParams.docKeyForTrack,
                    shareLinkParam: ASC.Files.Editor.docServiceParams.shareLinkParam,
                    finish: true,
                    ajaxsync: true
                });
        }
    };

    var completeTrack = function (jsonData, params, errorMessage) {
        clearTimeout(trackEditTimeout);
        trackEditTimeout = null;
        if (typeof errorMessage != "undefined") {
            if (errorMessage == null || !errorMessage.length) {
                setTimeout(function () {
                    ASC.Files.Editor.docEditor.showMessage("Connection is lost");
                }, 500);
            } else {
                ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
            }
            return;
        }

        if (jsonData.key == true) {
            trackEditTimeout = setTimeout(ASC.Files.Editor.trackEdit, 5000);
        } else {
            errorMessage = jsonData.value;
            denyEditingRights(errorMessage);
        }
    };

    var onStartEdit = function (jsonData, params, errorMessage) {
        if (typeof errorMessage != "undefined") {
            denyEditingRights(errorMessage);
            return;
        }
    };

    var denyEditingRights = function (message) {
        ASC.Files.Editor.docEditor.denyEditingRights(message || "Connection is lost");
    };

    var checkMessageFromHash = function () {
        var regExpError = /^#error\/(\S+)?/;
        if (regExpError.test(location.hash)) {
            var errorMessage = regExpError.exec(location.hash)[1];
            errorMessage = decodeURIComponent(errorMessage).replace(/\+/g, " ");
            if (errorMessage.length) {
                ASC.Files.Editor.docEditor.showMessage(errorMessage);
                return true;
            }
        }
        var regExpMessage = /^#message\/(\S+)?/;
        if (regExpMessage.test(location.hash)) {
            errorMessage = regExpMessage.exec(location.hash)[1];
            errorMessage = decodeURIComponent(errorMessage).replace(/\+/g, " ");
            if (errorMessage.length) {
                ASC.Files.Editor.docEditor.showMessage(errorMessage);
                return true;
            }
        }
        return false;
    };

    var getRecentList = function () {
        if (!localStorageManager.isAvailable) {
            return null;
        }
        var localStorageKey = ASC.Files.Constants.storageKeyRecent;
        var localStorageCount = 50;
        var recentCount = 10;

        var result = new Array();

        try {
            var recordsFromStorage = localStorageManager.getItem(localStorageKey);
            if (!recordsFromStorage) {
                recordsFromStorage = new Array();
            }

            if (recordsFromStorage.length > localStorageCount) {
                recordsFromStorage.pop();
            }

            var currentRecord = {
                url: location.href,
                id: ASC.Files.Editor.docServiceParams.fileId,
                title: ASC.Files.Editor.configurationParams.document.title,
                folder: ASC.Files.Editor.configurationParams.document.info.folder,
                fileType: ASC.Files.Editor.configurationParams.documentType,
            };

            var containRecord = jq(recordsFromStorage).is(function () {
                return this.id == currentRecord.id;
            });

            if (!containRecord) {
                recordsFromStorage.unshift(currentRecord);

                localStorageManager.setItem(localStorageKey, recordsFromStorage);
            }

            result = jq(recordsFromStorage).filter(function () {
                return this.id != currentRecord.id &&
                    this.fileType === currentRecord.fileType;
            });
        } catch (e) {
        }

        return result.slice(0, recentCount);
    };

    var completeGetEditHistory = function (jsonData, params, errorMessage) {
        if (typeof ASC.Files.Editor.docEditor.refreshHistory != "function") {
            if (typeof errorMessage != "undefined") {
                ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
            } else {
                ASC.Files.Editor.docEditor.showMessage("Function is not available");
            }
            return;
        }

        if (typeof errorMessage != "undefined") {
            var data = {
                error: errorMessage || "Connection is lost"
            };
        } else {
            clearTimeout(trackEditTimeout);
            trackEditTimeout = null;

            var currentVersion = params.setLast
                ? jsonData.length
                : ASC.Files.Editor.docServiceParams.fileVersion;

            jq.each(jsonData, function (i, fileVersion) {
                if (fileVersion.version >= currentVersion) {
                    currentVersion = fileVersion.version;
                    return false;
                }
                return true;
            });

            data = {
                currentVersion: currentVersion,
                history: jsonData,
            };
        }

        ASC.Files.Editor.docEditor.refreshHistory(data);
    };

    var completeGetDiffUrl = function (jsonData, params, errorMessage) {
        if (typeof ASC.Files.Editor.docEditor.setHistoryData != "function") {
            if (typeof errorMessage != "undefined") {
                ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
            } else {
                ASC.Files.Editor.docEditor.showMessage("Function is not available");
            }
            return;
        }

        if (typeof errorMessage != "undefined") {
            jsonData = {
                error: errorMessage || "Connection is lost",
                version: params.version,
            };
        }

        ASC.Files.Editor.docEditor.setHistoryData(jsonData);
    };

    var completeGetMails = function (jsonData, params, errorMessage) {
        if (typeof ASC.Files.Editor.docEditor.setEmailAddresses != "function") {
            if (typeof errorMessage != "undefined") {
                ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
            } else {
                ASC.Files.Editor.docEditor.showMessage("Function is not available");
            }
            return;
        }

        if (typeof errorMessage != "undefined") {
            var data = {
                error: errorMessage || "Connection is lost",
            };
        } else {
            data = {
                emailAddresses: jsonData,
            };
        }

        if (ASC.Files.Constants.URL_MAIL_ACCOUNTS) {
            data.createEmailAccountUrl = ASC.Files.Constants.URL_MAIL_ACCOUNTS;
        }

        ASC.Files.Editor.docEditor.setEmailAddresses(data);
    };

    var completeStartMailMerge = function (jsonData, params, errorMessage) {
        if (typeof ASC.Files.Editor.docEditor.processMailMerge != "function") {
            if (typeof errorMessage != "undefined") {
                ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
            } else {
                ASC.Files.Editor.docEditor.showMessage("Function is not available");
            }
            return;
        }

        ASC.Files.Editor.docEditor.processMailMerge(typeof errorMessage == "undefined", errorMessage);
    };

    var completeRename = function (xmlData, params, errorMessage) {
        if (typeof errorMessage != "undefined") {
            ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
        }
        return;
    };

    var completeGetUsers = function (jsonData, params, errorMessage) {
        if (typeof errorMessage != "undefined") {
            ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
        }

        ASC.Files.Editor.docEditor.setUsers({users: jsonData});
    };

    var completeSendEditorNotify = function (jsonData, params, errorMessage) {
        if (typeof errorMessage != "undefined") {
            ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
        }

        if (jsonData) {
            ASC.Files.Editor.docEditor.setSharingSettings({sharingSettings: jsonData});

            ASC.Files.Editor.docEditor.showSharingSettings();
        }
    };

    var completeToggleFavorite = function (data, params, errorMessage) {
        if (typeof errorMessage != "undefined") {
            ASC.Files.Editor.docEditor.showMessage(errorMessage || "Connection is lost");
        }

        ASC.Files.Editor.docEditor.setFavorite(data);
    };

    return {
        init: init,
        createFrameEditor: createFrameEditor,
        fixSize: fixSize,

        docEditor: docEditor,

        //set in .cs
        docServiceParams: docServiceParams,
        configurationParams: configurationParams,

        trackEdit: trackEdit,
        finishEdit: finishEdit,

        //event
        readyEditor: readyEditor,
        readyDocument: readyDocument,
        documentStateChangeEditor: documentStateChangeEditor,
        requestEditRightsEditor: requestEditRightsEditor,
        errorEditor: errorEditor,
        reloadPage: reloadPage,
        requestHistory: requestHistory,
        historyClose: historyClose,
        getDiffUrl: getDiffUrl,
        restoreVersion: restoreVersion,
        getMails: getMails,
        requestStartMailMerge: requestStartMailMerge,
        infoEditor: infoEditor,
        rename: rename,
        metaChange: metaChange,
        requestClose: requestClose,
        makeActionLink: makeActionLink,
        requestUsers: requestUsers,
        requestSendNotify: requestSendNotify,

        canShowHistory: canShowHistory,updateDocumentTitle:updateDocumentTitle
    };
})();

(function ($) {

    if (jq("#iframeEditor").length == 0)
        return;

    ASC.Files.Editor.init();
    $(function () {
        if (typeof DocsAPI === "undefined") {
            alert(ASC.Files.Constants.DocsAPIundefined);
            ASC.Files.Editor.errorEditor();

            return;
        }

        var fixPageCaching = function (delta) {
            if (location.hash.indexOf("reload") == -1) {
                var openingDateParse = Date.parse(ASC.Files.Editor.docServiceParams.openinigDate);
                if (!openingDateParse) {
                    return;
                }
                var openinigDate = new Date();
                openinigDate.setTime(openingDateParse);

                var currentTime = new Date();
                var currentUTCTime = new Date(currentTime.getUTCFullYear(), currentTime.getUTCMonth(), currentTime.getUTCDate(), currentTime.getUTCHours(), currentTime.getUTCMinutes());
                if (Math.abs(currentUTCTime - openinigDate) > delta) {
                    location.hash = "reload";
                    location.reload(true);
                }
            } else {
                location.hash = "";
            }
        };
        fixPageCaching(10 * 60 * 1000);

        var $icon = jq("#docsEditorFavicon");
        if ($icon.attr('href').indexOf('logo_favicon_general.ico') !== -1) { //not default
            $icon.attr('href', $icon.attr('href'));
        }

        ASC.Files.Editor.createFrameEditor(ASC.Files.Editor.configurationParams);

        if (jq("body").hasClass("mobile") || ASC.Files.Editor.configurationParams && ASC.Files.Editor.configurationParams.type === "mobile") {
            if (window.addEventListener) {
                window.addEventListener("load", ASC.Files.Editor.fixSize);
                window.addEventListener("resize", ASC.Files.Editor.fixSize);
            } else if (window.attachEvent) {
                window.attachEvent("onload", ASC.Files.Editor.fixSize);
                window.attachEvent("onresize", ASC.Files.Editor.fixSize);
            }
        }
    });
})(jQuery);

String.prototype.format = function () {
    var txt = this,
        i = arguments.length;

    while (i--) {
        txt = txt.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
    }
    return txt;
};

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/DNS/Client/DNS_Client.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Dns.Client
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Net.Sockets;
    using System.Text;

    #endregion

    /// <summary>
    /// Dns client.
    /// </summary>
    /// <example>
    /// <code>
    /// // Set dns servers
    /// Dns_Client.DnsServers = new string[]{"192.168.3.11"};
    /// 
    /// Dns_Client dns = Dns_Client();
    /// 
    /// // Get MX records.
    /// DnsServerResponse resp = dns.Query("lumisoft.ee",QTYPE.MX);
    /// if(resp.ConnectionOk &amp;&amp; resp.ResponseCode == RCODE.NO_ERROR){
    ///		MX_Record[] mxRecords = resp.GetMXRecords();
    ///		
    ///		// Do your stuff
    ///	}
    ///	else{
    ///		// Handle error there, for more exact error info see RCODE 
    ///	}	 
    /// 
    /// </code>
    /// </example>
    public class Dns_Client
    {
        #region Members

        private static IPAddress[] m_DnsServers;
        private static int m_ID = 100;
        private static bool m_UseDnsCache = true;

        #endregion

        #region Constructor

        /// <summary>
        /// Static constructor.
        /// </summary>
        static Dns_Client()
        {
            // Try to get system dns servers
            try
            {
                List<IPAddress> dnsServers = new List<IPAddress>();
                foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
                {
                    if (nic.OperationalStatus == OperationalStatus.Up)
                    {
                        foreach (IPAddress ip in nic.GetIPProperties().DnsAddresses)
                        {
                            if (ip.AddressFamily == AddressFamily.InterNetwork)
                            {
                                if (!dnsServers.Contains(ip))
                                {
                                    dnsServers.Add(ip);
                                }
                            }
                        }
                    }
                }

                m_DnsServers = dnsServers.ToArray();
            }
            catch {}
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets dns servers.
        /// </summary>
        /// <exception cref="ArgumentNullException">Is raised when null value is passed.</exception>
        public static string[] DnsServers
        {
            get
            {
                string[] retVal = new string[m_DnsServers.Length];
                for (int i = 0; i < m_DnsServers.Length; i++)
                {
                    retVal[i] = m_DnsServers[i].ToString();
                }

                return retVal;
            }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException();
                }

                IPAddress[] retVal = new IPAddress[value.Length];
                for (int i = 0; i < value.Length; i++)
                {
                    retVal[i] = IPAddress.Parse(value[i]);
                }

                m_DnsServers = retVal;
            }
        }

        /// <summary>
        /// Gets or sets if to use dns caching.
        /// </summary>
        public static bool UseDnsCache
        {
            get { return m_UseDnsCache; }

            set { m_UseDnsCache = value; }
        }

        /// <summary>
        /// Get next query ID.
        /// </summary>
        internal static int ID
        {
            get
            {
                if (m_ID >= 65535)
                {
                    m_ID = 100;
                }
                return m_ID++;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Resolves host names to IP addresses.
        /// </summary>
        /// <param name="hosts">Host names to resolve.</param>
        /// <returns>Returns specified hosts IP addresses.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>hosts</b> is null.</exception>
        public static IPAddress[] Resolve(string[] hosts)
        {
            if (hosts == null)
            {
                throw new ArgumentNullException("hosts");
            }

            List<IPAddress> retVal = new List<IPAddress>();
            foreach (string host in hosts)
            {
                IPAddress[] addresses = Resolve(host);
                foreach (IPAddress ip in addresses)
                {
                    if (!retVal.Contains(ip))
                    {
                        retVal.Add(ip);
                    }
                }
            }

            return retVal.ToArray();
        }

        /// <summary>
        /// Resolves host name to IP addresses.
        /// </summary>
        /// <param name="host">Host name or IP address.</param>
        /// <returns>Return specified host IP addresses.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>host</b> is null.</exception>
        public static IPAddress[] Resolve(string host)
        {
            if (host == null)
            {
                throw new ArgumentNullException("host");
            }

            // If hostName_IP is IP
            try
            {
                return new[] {IPAddress.Parse(host)};
            }
            catch {}

            // This is probably NetBios name
            if (host.IndexOf(".") == -1)
            {
                return Dns.GetHostEntry(host).AddressList;
            }
            else
            {
                // hostName_IP must be host name, try to resolve it's IP
                Dns_Client dns = new Dns_Client();
                DnsServerResponse resp = dns.Query(host, QTYPE.A);
                if (resp.ResponseCode == RCODE.NO_ERROR)
                {
                    DNS_rr_A[] records = resp.GetARecords();
                    IPAddress[] retVal = new IPAddress[records.Length];
                    for (int i = 0; i < records.Length; i++)
                    {
                        retVal[i] = records[i].IP;
                    }

                    return retVal;
                }
                else
                {
                    throw new Exception(resp.ResponseCode.ToString());
                }
            }
        }

        /// <summary>
        /// Queries server with specified query.
        /// </summary>
        /// <param name="queryText">Query text. It depends on queryType.</param>
        /// <param name="queryType">Query type.</param>
        /// <returns></returns>
        public DnsServerResponse Query(string queryText, QTYPE queryType)
        {
            if (queryType == QTYPE.PTR)
            {
                string ip = queryText;

                // See if IP is ok.
                IPAddress ipA = IPAddress.Parse(ip);
                queryText = "";

                // IPv6
                if (ipA.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    // 4fc00:e968:6179::de52:7100
                    // would be
                    // b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.IP6.ARPA

                    char[] ipChars = ip.Replace(":", "").ToCharArray();
                    for (int i = ipChars.Length - 1; i > -1; i--)
                    {
                        queryText += ipChars[i] + ".";
                    }
                    queryText += "IP6.ARPA";
                }
                    // IPv4
                else
                {
                    // 172.16.31.10
                    // would be
                    // 172.16.58.3.in-addr.arpa

                    string[] ipParts = ip.Split('.');
                    //--- Reverse IP ----------
                    for (int i = 3; i > -1; i--)
                    {
                        queryText += ipParts[i] + ".";
                    }
                    queryText += "in-addr.arpa";
                }
            }

            return QueryServer(2000, queryText, queryType, 1);
        }

        /// <summary>
        /// Gets specified host IP addresses(A and AAAA).
        /// </summary>
        /// <param name="host">Host name.</param>
        /// <returns>Returns specified host IP addresses.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>host</b> is null reference.</exception>
        public IPAddress[] GetHostAddresses(string host)
        {
            if (host == null)
            {
                throw new ArgumentNullException("host");
            }

            List<IPAddress> retVal = new List<IPAddress>();

            // This is probably NetBios name
            if (host.IndexOf(".") == -1)
            {
                return Dns.GetHostEntry(host).AddressList;
            }
            else
            {
                DnsServerResponse response = Query(host, QTYPE.A);
                if (response.ResponseCode != RCODE.NO_ERROR)
                {
                    throw new DNS_ClientException(response.ResponseCode);
                }

                foreach (DNS_rr_A record in response.GetARecords())
                {
                    retVal.Add(record.IP);
                }

                response = Query(host, QTYPE.AAAA);
                if (response.ResponseCode != RCODE.NO_ERROR)
                {
                    throw new DNS_ClientException(response.ResponseCode);
                }

                foreach (DNS_rr_A record in response.GetARecords())
                {
                    retVal.Add(record.IP);
                }
            }

            return retVal.ToArray();
        }

        #endregion

        #region Internal methods

        internal static bool GetQName(byte[] reply, ref int offset, ref string name)
        {
            try
            {
                // Do while not terminator
                while (reply[offset] != 0)
                {
                    // Check if it's pointer(In pointer first two bits always 1)
                    bool isPointer = ((reply[offset] & 0xC0) == 0xC0);

                    // If pointer
                    if (isPointer)
                    {
                        // Pointer location number is 2 bytes long
                        // 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7  # byte 2 # 0 | 1 | 2 | | 3 | 4 | 5 | 6 | 7
                        // empty | < ---- pointer location number --------------------------------->
                        int pStart = ((reply[offset] & 0x3F) << 8) | (reply[++offset]);
                        offset++;
                        return GetQName(reply, ref pStart, ref name);
                    }
                    else
                    {
                        // label length (length = 8Bit and first 2 bits always 0)
                        // 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
                        // empty | lablel length in bytes 
                        int labelLength = (reply[offset] & 0x3F);
                        offset++;

                        // Copy label into name 
                        name += Encoding.ASCII.GetString(reply, offset, labelLength);
                        offset += labelLength;
                    }

                    // If the next char isn't terminator,
                    // label continues - add dot between two labels
                    if (reply[offset] != 0)
                    {
                        name += ".";
                    }
                }

                // Move offset by terminator length
                offset++;

                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Reads character-string from spefcified data and offset.
        /// </summary>
        /// <param name="data">Data from where to read.</param>
        /// <param name="offset">Offset from where to start reading.</param>
        /// <returns>Returns readed string.</returns>
        internal static string ReadCharacterString(byte[] data, ref int offset)
        {
            /* RFC 1035 3.3.
                <character-string> is a single length octet followed by that number of characters. 
                <character-string> is treated as binary information, and can be up to 256 characters 
                in length (including the length octet).
            */

            int dataLength = data[offset++];
            string retVal = Encoding.Default.GetString(data, offset, dataLength);
            offset += dataLength;

            return retVal;
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Sends query to server.
        /// </summary>
        /// <param name="timeout">Query timeout in milli seconds.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private DnsServerResponse QueryServer(int timeout, string qname, QTYPE qtype, int qclass)
        {
            if (m_DnsServers == null || m_DnsServers.Length == 0)
            {
                throw new Exception("Dns server isn't specified !");
            }

            // See if query is in cache
            if (m_UseDnsCache)
            {
                DnsServerResponse resopnse = DnsCache.GetFromCache(qname, (int) qtype);
                if (resopnse != null)
                {
                    return resopnse;
                }
            }

            int queryID = ID;
            byte[] query = CreateQuery(queryID, qname, qtype, qclass);

            // Create sending UDP socket.
            Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            udpClient.SendTimeout = 500;

            // Send parallel query to all dns servers and get first answer.
            DateTime startTime = DateTime.Now;
                List<DnsServerResponse> responses = new List<DnsServerResponse>();
            while (startTime.AddMilliseconds(timeout) > DateTime.Now)
            {
                foreach (IPAddress dnsServer in m_DnsServers)
                {
                    try
                    {
                        udpClient.SendTo(query, new IPEndPoint(dnsServer, 53));
                    }
                    catch {}
                }

                // Wait 10 ms response to arrive, if no response, retransmit query.
                if (udpClient.Poll(10, SelectMode.SelectRead))
                {
                    try
                    {
                        byte[] retVal = new byte[1024];
                        int countRecieved = udpClient.Receive(retVal);

                        // If reply is ok, return it
                        DnsServerResponse serverResponse = ParseQuery(retVal, queryID);

                        // Cache query
                        if (m_UseDnsCache && serverResponse.ResponseCode == RCODE.NO_ERROR)
                        {
                            DnsCache.AddToCache(qname, (int) qtype, serverResponse);
                        }
                        responses.Add(serverResponse);
                    }
                    catch {}
                }
            }

            udpClient.Close();

            // If we reach so far, we probably won't get connection to dsn server
            return responses.Count>0?responses[0]:new DnsServerResponse(false,
                                         RCODE.SERVER_FAILURE,
                                         new List<DNS_rr_base>(),
                                         new List<DNS_rr_base>(),
                                         new List<DNS_rr_base>());
        }

        /// <summary>
        /// Creates new query.
        /// </summary>
        /// <param name="ID">Query ID.</param>
        /// <param name="qname">Query text.</param>
        /// <param name="qtype">Query type.</param>
        /// <param name="qclass">Query class.</param>
        /// <returns></returns>
        private byte[] CreateQuery(int ID, string qname, QTYPE qtype, int qclass)
        {
            byte[] query = new byte[512];

            //---- Create header --------------------------------------------//
            // Header is first 12 bytes of query

            /* 4.1.1. Header section format
										  1  1  1  1  1  1
			0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                      ID                       |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                    QDCOUNT                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                    ANCOUNT                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                    NSCOUNT                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                    ARCOUNT                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			
			QR  A one bit field that specifies whether this message is a
                query (0), or a response (1).
				
			OPCODE          A four bit field that specifies kind of query in this
                message.  This value is set by the originator of a query
                and copied into the response.  The values are:

                0               a standard query (QUERY)

                1               an inverse query (IQUERY)

                2               a server status request (STATUS)
				
			*/

            //--------- Header part -----------------------------------//
            query[0] = (byte) (ID >> 8);
            query[1] = (byte) (ID & 0xFF);
            query[2] = 1;
            query[3] = 0;
            query[4] = 0;
            query[5] = 1;
            query[6] = 0;
            query[7] = 0;
            query[8] = 0;
            query[9] = 0;
            query[10] = 0;
            query[11] = 0;
            //---------------------------------------------------------//

            //---- End of header --------------------------------------------//

            //----Create query ------------------------------------//

            /* 	Rfc 1035 4.1.2. Question section format
											  1  1  1  1  1  1
			0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                                               |
			/                     QNAME                     /
			/                                               /
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                     QTYPE                     |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                     QCLASS                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			
			QNAME
				a domain name represented as a sequence of labels, where
				each label consists of a length octet followed by that
				number of octets.  The domain name terminates with the
				zero length octet for the null label of the root.  Note
				that this field may be an odd number of octets; no
				padding is used.
			*/
            string[] labels = qname.Split(new[] {'.'});
            int position = 12;

            // Copy all domain parts(labels) to query
            // eg. lumisoft.ee = 2 labels, lumisoft and ee.
            // format = label.length + label(bytes)
            foreach (string label in labels)
            {
                // add label lenght to query
                query[position++] = (byte) (label.Length);

                // convert label string to byte array
                byte[] b = Encoding.ASCII.GetBytes(label);
                b.CopyTo(query, position);

                // Move position by label length
                position += b.Length;
            }

            // Terminate domain (see note above)
            query[position++] = 0;

            // Set QTYPE 
            query[position++] = 0;
            query[position++] = (byte) qtype;

            // Set QCLASS
            query[position++] = 0;
            query[position++] = (byte) qclass;
            //-------------------------------------------------------//
            string queryStr = Encoding.ASCII.GetString(query);
            return query;
        }

        /// <summary>
        /// Parses query.
        /// </summary>
        /// <param name="reply">Dns server reply.</param>
        /// <param name="queryID">Query id of sent query.</param>
        /// <returns></returns>
        private DnsServerResponse ParseQuery(byte[] reply, int queryID)
        {
            //--- Parse headers ------------------------------------//

            /* RFC 1035 4.1.1. Header section format
			 
											1  1  1  1  1  1
			  0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
			 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			 |                      ID                       |
			 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			 |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
			 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			 |                    QDCOUNT                    |
			 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			 |                    ANCOUNT                    |
			 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			 |                    NSCOUNT                    |
			 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			 |                    ARCOUNT                    |
			 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			 
			QDCOUNT
				an unsigned 16 bit integer specifying the number of
				entries in the question section.

			ANCOUNT
				an unsigned 16 bit integer specifying the number of
				resource records in the answer section.
				
			NSCOUNT
			    an unsigned 16 bit integer specifying the number of name
                server resource records in the authority records section.

			ARCOUNT
			    an unsigned 16 bit integer specifying the number of
                resource records in the additional records section.
				
			*/

            // Get reply code
            int id = (reply[0] << 8 | reply[1]);
            OPCODE opcode = (OPCODE) ((reply[2] >> 3) & 15);
            RCODE replyCode = (RCODE) (reply[3] & 15);
            int queryCount = (reply[4] << 8 | reply[5]);
            int answerCount = (reply[6] << 8 | reply[7]);
            int authoritiveAnswerCount = (reply[8] << 8 | reply[9]);
            int additionalAnswerCount = (reply[10] << 8 | reply[11]);
            //---- End of headers ---------------------------------//

            // Check that it's query what we want
            if (queryID != id)
            {
                throw new Exception("This isn't query with ID what we expected");
            }

            int pos = 12;

            //----- Parse question part ------------//
            for (int q = 0; q < queryCount; q++)
            {
                string dummy = "";
                GetQName(reply, ref pos, ref dummy);
                //qtype + qclass
                pos += 4;
            }
            //--------------------------------------//

            // 1) parse answers
            // 2) parse authoritive answers
            // 3) parse additional answers
            List<DNS_rr_base> answers = ParseAnswers(reply, answerCount, ref pos);
            List<DNS_rr_base> authoritiveAnswers = ParseAnswers(reply, authoritiveAnswerCount, ref pos);
            List<DNS_rr_base> additionalAnswers = ParseAnswers(reply, additionalAnswerCount, ref pos);

            return new DnsServerResponse(true, replyCode, answers, authoritiveAnswers, additionalAnswers);
        }

        /// <summary>
        /// Parses specified count of answers from query.
        /// </summary>
        /// <param name="reply">Server returned query.</param>
        /// <param name="answerCount">Number of answers to parse.</param>
        /// <param name="offset">Position from where to start parsing answers.</param>
        /// <returns></returns>
        private List<DNS_rr_base> ParseAnswers(byte[] reply, int answerCount, ref int offset)
        {
            /* RFC 1035 4.1.3. Resource record format
			 
										   1  1  1  1  1  1
			 0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                                               |
			/                                               /
			/                      NAME                     /
			|                                               |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                      TYPE                     |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                     CLASS                     |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                      TTL                      |
			|                                               |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			|                   RDLENGTH                    |
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
			/                     RDATA                     /
			/                                               /
			+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
			*/

            List<DNS_rr_base> answers = new List<DNS_rr_base>();
            //---- Start parsing answers ------------------------------------------------------------------//
            for (int i = 0; i < answerCount; i++)
            {
                string name = "";
                if (!GetQName(reply, ref offset, ref name))
                {
                    throw new Exception("Error parsing anser");
                }

                int type = reply[offset++] << 8 | reply[offset++];
                int rdClass = reply[offset++] << 8 | reply[offset++];
                int ttl = reply[offset++] << 24 | reply[offset++] << 16 | reply[offset++] << 8 |
                          reply[offset++];
                int rdLength = reply[offset++] << 8 | reply[offset++];

                if ((QTYPE) type == QTYPE.A)
                {
                    answers.Add(DNS_rr_A.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.NS)
                {
                    answers.Add(DNS_rr_NS.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.CNAME)
                {
                    answers.Add(DNS_rr_CNAME.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.SOA)
                {
                    answers.Add(DNS_rr_SOA.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.PTR)
                {
                    answers.Add(DNS_rr_PTR.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.HINFO)
                {
                    answers.Add(DNS_rr_HINFO.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.MX)
                {
                    answers.Add(DNS_rr_MX.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.TXT)
                {
                    answers.Add(DNS_rr_TXT.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.AAAA)
                {
                    answers.Add(DNS_rr_AAAA.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.SRV)
                {
                    answers.Add(DNS_rr_SRV.Parse(reply, ref offset, rdLength, ttl));
                }
                else if ((QTYPE) type == QTYPE.NAPTR)
                {
                    answers.Add(DNS_rr_NAPTR.Parse(reply, ref offset, rdLength, ttl));
                }
                else
                {
                    // Unknown record, skip it.
                    offset += rdLength;
                }
            }

            return answers;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Utility/HtmlUtility/HtmlUtility.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Core.WhiteLabel;

using HtmlAgilityPack;

namespace ASC.Web.Studio.Utility.HtmlUtility
{
    public class HtmlUtility
    {
        private static readonly Regex htmlTags = new Regex(@"</?html[^>]*>", RegexOptions.Compiled | RegexOptions.IgnoreCase);
        private static readonly Regex rxNumeric = new Regex(@"^[0-9]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);


        public static string GetFull(string html, bool removeAsccut = true)
        {
            if (string.IsNullOrWhiteSpace(html))
            {
                return html ?? string.Empty;
            }

            try
            {
                var doc = new HtmlDocument();
                doc.LoadHtml(htmlTags.Replace(html, string.Empty));
                if (removeAsccut)
                {
                    var nodes = doc.DocumentNode.SelectNodes("//div[translate(@class,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='asccut']");
                    if (nodes != null)
                    {
                        foreach (var node in nodes)
                        {
                            node.Attributes.Remove("class");
                            var styleAttr = doc.CreateAttribute("style");
                            styleAttr.Value = "display:inline;";
                            node.Attributes.Append(styleAttr);
                        }
                    }
                }

                ProcessMaliciousTag(doc);
                ProcessMaliciousAttributes(doc);
                ProcessAscUserTag(doc);
                ProcessCodeTags(doc);
                ProcessExternalLinks(doc);
                ProcessZoomImages(doc);

                return doc.DocumentNode.InnerHtml;
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC.Web").Error(e);
                return string.Format("{0}<br/>Please contact us: <a href='mailto:{1}'>{1}</a>", e.Message, CompanyWhiteLabelSettings.Instance.Email);
            }
        }

        private static string GetLanguageAttrValue(HtmlNode node)
        {
            var attr = node.Attributes["lang"];
            if (attr != null && !string.IsNullOrEmpty(attr.Value))
            {
                return attr.Value;
            }
            return string.Empty;
        }

        private static LangType GetLanguage(HtmlNode node)
        {
            var result = LangType.Unknown;

            switch (GetLanguageAttrValue(node).ToLower())
            {
                case "c":
                    result = LangType.C;
                    break;
                case "cpp":
                case "c++":
                    result = LangType.CPP;
                    break;
                case "csharp":
                case "c#":
                case "cs":
                    result = LangType.CS;
                    break;
                case "asp":
                    result = LangType.Asp;
                    break;
                case "html":
                case "htm":
                    result = LangType.Html;
                    break;
                case "xml":
                    result = LangType.Xml;
                    break;
                case "js":
                case "jsript":
                case "javascript":
                    result = LangType.JS;
                    break;
                case "sql":
                case "tsql":
                    result = LangType.TSql;
                    break;
                case "vb":
                case "vbnet":
                    result = LangType.VB;
                    break;
            }

            return result;
        }

        private static void ProcessMaliciousAttributes(HtmlDocument doc)
        {
            var nodes = doc.DocumentNode.SelectNodes("//*");
            if (nodes == null || nodes.Count == 0)
            {
                return;
            }

            foreach (var node in nodes)
            {
                var toRemove = node.Attributes
                                   .Where(htmlAttribute =>
                                       {
                                           var name = htmlAttribute.Name;
                                           if (name.Contains("/")) name = name.Split('/').Last();
                                           var value = htmlAttribute.Value.Replace("&Tab;", "").TrimStart();
                                           return name.StartsWith("on", StringComparison.OrdinalIgnoreCase)
                                                  || value.StartsWith("javascript", StringComparison.OrdinalIgnoreCase)
                                                  || value.StartsWith("data", StringComparison.OrdinalIgnoreCase)
                                                  || value.StartsWith("vbscript", StringComparison.OrdinalIgnoreCase)
                                                  || value.StartsWith(">", StringComparison.OrdinalIgnoreCase);
                                       }
                    ).ToList();
                foreach (var htmlAttribute in toRemove)
                {
                    if (node.Name == "img" && htmlAttribute.Name == "src")
                        continue;

                    node.Attributes.Remove(htmlAttribute);
                }
            }
        }

        private static void ProcessZoomImages(HtmlDocument doc)
        {
            var nodes = doc.DocumentNode.SelectNodes("//img[@_zoom]");

            if (nodes == null) return;
            foreach (var node in nodes)
            {
                if (node.ParentNode != null && (node.ParentNode.Name ?? "").ToLower() == "a") continue;

                var srcAttribute = node.Attributes["src"];
                if (srcAttribute == null || string.IsNullOrEmpty(srcAttribute.Value)) continue;

                var zoomAttribute = node.Attributes["_zoom"];
                if (zoomAttribute == null || string.IsNullOrEmpty(zoomAttribute.Value)) continue;

                var borderAttribute = node.Attributes["border"];
                if (borderAttribute == null)
                {
                    borderAttribute = doc.CreateAttribute("border");
                    node.Attributes.Append(borderAttribute);
                }
                borderAttribute.Value = "0";

                var imgSrc = srcAttribute.Value;

                if (!rxNumeric.IsMatch(zoomAttribute.Value))
                {
                    imgSrc = zoomAttribute.Value;
                }

                if (node.ParentNode != null)
                {
                    var hrefNode = doc.CreateElement("a");

                    var hrefAttribute = doc.CreateAttribute("href");
                    hrefAttribute.Value = imgSrc;
                    hrefNode.Attributes.Append(hrefAttribute);

                    hrefAttribute = doc.CreateAttribute("class");
                    hrefAttribute.Value = "screenzoom";
                    hrefNode.Attributes.Append(hrefAttribute);

                    string title = null;
                    var titleAttribute = node.Attributes["title"];
                    if (titleAttribute != null)
                    {
                        title = titleAttribute.Value;
                    }
                    else
                    {
                        var altAttribute = node.Attributes["alt"];
                        if (altAttribute != null)
                        {
                            title = altAttribute.Value;
                        }
                    }
                    if (!string.IsNullOrEmpty(title))
                    {
                        hrefAttribute = doc.CreateAttribute("title");
                        hrefAttribute.Value = title;
                        hrefNode.Attributes.Append(hrefAttribute);
                    }

                    node.ParentNode.ReplaceChild(hrefNode, node);
                    hrefNode.AppendChild(node);
                }
            }
        }

        private static void ProcessMaliciousTag(HtmlDocument doc)
        {
            var nodes = doc.DocumentNode.SelectNodes("//*");
            if (nodes == null || nodes.Count == 0)
                return;

            foreach (var node in nodes.Where(node => Regex.IsMatch(node.Name, "\\W")))
            {
                node.ParentNode.RemoveChild(node);
            }

            nodes = doc.DocumentNode.SelectNodes("//script|//meta|//style");

            if (nodes == null || nodes.Count == 0)
                return;

            foreach (var node in nodes.Where(node => node.ParentNode != null))
            {
                node.ParentNode.RemoveChild(node);
            }
        }

        private static void ProcessAscUserTag(HtmlDocument doc)
        {
            var nodes = doc.DocumentNode.SelectNodes("//div[@__ascuser]");
            if (nodes == null || nodes.Count == 0) return;

            foreach (var node in nodes)
            {
                var userId = new Guid(node.Attributes["__ascuser"].Value);
                node.Attributes.RemoveAll();
                var styleAttr = doc.CreateAttribute("style");
                styleAttr.Value = "display:inline;";
                node.Attributes.Append(styleAttr);
                node.InnerHtml = CoreContext.UserManager.GetUsers(userId).RenderProfileLinkBase();
            }
        }

        private static void ProcessCodeTags(HtmlDocument doc)
        {
            var scripts = doc.DocumentNode.SelectNodes("//code");
            if (scripts != null)
            {
                foreach (var node in scripts)
                {
                    var textNode = doc.CreateTextNode(Highlight.HighlightToHTML(node.InnerHtml, GetLanguage(node), true).Replace(@"class=""codestyle""", string.Format(@"class=""codestyle"" _wikiCodeStyle=""{0}""", GetLanguageAttrValue(node))));
                    node.ParentNode.ReplaceChild(textNode, node);
                }
            }
        }

        private static void ProcessExternalLinks(HtmlDocument doc)
        {
            var links = doc.DocumentNode.SelectNodes("//a");

            if (links == null) return;

            var context = HttpContext.Current;

            if (context == null) return;

            var uri = context.Request.GetUrlRewriter();

            if (uri == null) return;

            var internalHost = uri.Host;

            if ((uri.Port != 80 && uri.Scheme.Equals("http", StringComparison.InvariantCultureIgnoreCase))
                || (uri.Port != 443 && uri.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase)))
            {
                internalHost = string.Format(@"^{2}:\/\/{0}:{1}", internalHost, uri.Port, uri.Scheme);
            }
            else
            {
                internalHost = string.Format(@"^{2}:\/\/{0}(:{1})?", internalHost, uri.Port, uri.Scheme);
            }

            var rxInternalHost = new Regex(internalHost, RegexOptions.Compiled | RegexOptions.CultureInvariant);

            foreach (var node in links)
            {
                ProcessExternalLink(node, rxInternalHost);
            }
        }

        private static void ProcessExternalLink(HtmlNode node, Regex rxIntLink)
        {
            var attrHref = node.Attributes["href"];
            if (attrHref == null) return;

            if (!rxIntLink.IsMatch(attrHref.Value))
            {
                var attrTarg = node.Attributes["target"];
                if (attrTarg == null)
                {
                    attrTarg = node.OwnerDocument.CreateAttribute("target");
                    node.Attributes.Append(attrTarg);
                }

                attrTarg.Value = "_blank";
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/HelpCenter/HelpCenter.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.UI;

using ASC.Web.Core;
using ASC.Web.Studio.Core.HelpCenter;
using ASC.Web.Studio.UserControls.Common.VideoGuides;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Common.HelpCenter
{
    public partial class HelpCenter : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Common/HelpCenter/HelpCenter.ascx"; }
        }

        public bool IsSideBar { get; set; }
        public Guid ModuleId { get; set; }

        protected List<HelpCenterItem> HelpCenterItems { get; set; }
        protected String HelpLink { get; set; }
        protected String HelpLinkBlock { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(CommonLinkUtility.GetHelpLink()))
            {
                return;
            }

            Page.RegisterStyle("~/UserControls/Common/HelpCenter/css/help-center.less");

            string module;
            string mainLink;

            if (Page is Studio.Management)
            {
                module = "configuration.aspx";
                mainLink = CommonLinkUtility.GetAdministration(ManagementType.HelpCenter);
            }
            else
            {
                var currentModule = GetProduct();
                if (currentModule == null || string.IsNullOrEmpty(currentModule.HelpURL)) return;

                module = currentModule.ProductClassName + ".aspx";
                mainLink = VirtualPathUtility.ToAbsolute(currentModule.HelpURL);
            }

            const string index = "#help";
            HelpLink = mainLink + index;
            HelpLinkBlock = mainLink + index + "=";

            HelpCenterItems = HelpCenterHelper.GetHelpCenter(module, HelpLinkBlock);

            if (IsSideBar)
            {
                var videoGuidesControl = (VideoGuidesControl)LoadControl(VideoGuidesControl.Location);
                if (HelpCenterItems == null)
                {
                    VideoGuides.Controls.Add(videoGuidesControl);
                }
                else
                {
                    videoGuidesControl.IsSubItem = true;
                    VideoGuidesSubItem.Controls.Add(videoGuidesControl);
                }
            }

            if (MediaViewersPlaceHolder != null)
            {
                MediaViewersPlaceHolder.Controls.Add(LoadControl(MediaPlayer.Location));
            }
        }

        private IWebItem GetProduct()
        {
            var currentModule = WebItemManager.Instance[ModuleId] ?? CommonLinkUtility.GetWebItemByUrl(Context.Request.Url.AbsoluteUri);

            if (currentModule is IAddon)
                return currentModule;

            var product = currentModule as IProduct;
            if (product != null)
                return product;

            if (currentModule == null) return null;

            IModule module;
            CommonLinkUtility.GetLocationByUrl(CommonLinkUtility.GetFullAbsolutePath(currentModule.StartURL), out product, out module);
            return product;
        }


        public static string RenderControlToString()
        {
            return RenderControlToString(null);
        }

        public static string RenderControlToString(Guid? moduleId)
        {
            var cntrl = new HelpCenter();
            cntrl = (HelpCenter)cntrl.LoadControl(Location);
            if (moduleId.HasValue)
            {
                cntrl.ModuleId = moduleId.Value;
            }

            var page = new Page();
            page.Controls.Add(cntrl);

            var writer = new StringWriter();
            HttpContext.Current.Server.Execute(page, writer, false);
            var renderedControl = writer.ToString();
            writer.Close();

            return renderedControl;
        }
    }
}

<|start_filename|>common/ASC.Common/Utils/TimeZoneConverter/TimeZoneConverter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;

using ASC.Common.Logging;

namespace ASC.Common.Utils
{
    public class TimeZoneConverter
    {
        private static readonly ILog Log = LogManager.GetLogger("ASC.TimeZone");

        private static IEnumerable<MapZone> _mapZones;

        private static bool _customMode;

        private static bool _isMono;

        private static Dictionary<string, string> _translations;

        static TimeZoneConverter()
        {
            InitMapZones();
            InitTranslations();
        }

        private static void InitMapZones()
        {
            try
            {
                var assembly = Assembly.GetExecutingAssembly();

                using (var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.windowsZones.xml"))
                {
                    var xml = XElement.Load(stream);
                    _mapZones = from row in xml.XPathSelectElements("*/mapTimezones/mapZone")
                                let olsonTimeZones = row.Attribute("type").Value.Split(' ')
                                from olsonTimeZone in olsonTimeZones
                                select new MapZone
                                {
                                    OlsonTimeZoneId = olsonTimeZone,
                                    WindowsTimeZoneId = row.Attribute("other").Value,
                                    Territory = row.Attribute("territory").Value
                                };
                }
            }
            catch (Exception error)
            {
                _mapZones = new MapZone[0];
                Log.Error(error);
            }
        }

        public static string OlsonTzId2WindowsTzId(string olsonTimeZoneId, bool defaultIfNoMatch = true)
        {
            var mapZone = GetMapZoneByWindowsTzId(olsonTimeZoneId);

            if (mapZone != null)
                return olsonTimeZoneId; //already Windows

            mapZone = GetMapZoneByOlsonTzId(olsonTimeZoneId);

            if (mapZone != null)
                return mapZone.WindowsTimeZoneId;

            Log.Error(string.Format("OlsonTimeZone {0} not found", olsonTimeZoneId));

            return defaultIfNoMatch ? "UTC" : null;
        }

        public static string WindowsTzId2OlsonTzId(string windowsTimeZoneId, bool defaultIfNoMatch = true)
        {
            var mapZone = GetMapZoneByOlsonTzId(windowsTimeZoneId);

            if (mapZone != null)
                return windowsTimeZoneId; //already Olson

            mapZone = GetMapZoneByWindowsTzId(windowsTimeZoneId);

            if (mapZone != null)
                return mapZone.OlsonTimeZoneId;

            Log.Error(string.Format("WindowsTimeZone {0} not found", windowsTimeZoneId));

            return defaultIfNoMatch ? "Etc/GMT" : null;
        }

        public static TimeZoneInfo GetTimeZone(string timeZoneId, bool defaultIfNoMatch = true)
        {
            try
            {
                return TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
            }
            catch (TimeZoneNotFoundException)
            {
                try
                {
                    var mapZone = GetMapZoneByOlsonTzId(timeZoneId);

                    if (mapZone != null)
                    {
                        return TimeZoneInfo.FindSystemTimeZoneById(mapZone.WindowsTimeZoneId);
                    }

                    mapZone = GetMapZoneByWindowsTzId(timeZoneId);

                    if (mapZone != null)
                    {
                        return TimeZoneInfo.FindSystemTimeZoneById(mapZone.OlsonTimeZoneId);
                    }

                    Log.InfoFormat("TimeZone {0} not found", timeZoneId);
                    return defaultIfNoMatch ? GetTimeZoneByOffset(timeZoneId) ?? TimeZoneInfo.Utc : null;
                }
                catch (Exception error)
                {
                    Log.Error(error);
                    return defaultIfNoMatch ? TimeZoneInfo.Utc : null;
                }
            }
            catch (Exception error)
            {
                Log.Error(error);
                return defaultIfNoMatch ? TimeZoneInfo.Utc : null;
            }
        }

        private static MapZone GetMapZoneByOlsonTzId(string olsonTimeZoneId)
        {
            return _mapZones.FirstOrDefault(x =>
                                            x.OlsonTimeZoneId.Equals(olsonTimeZoneId, StringComparison.CurrentCultureIgnoreCase));
        }

        private static MapZone GetMapZoneByWindowsTzId(string windowsTimeZoneId)
        {
            return _mapZones.FirstOrDefault(x =>
                                            x.WindowsTimeZoneId.Equals(windowsTimeZoneId, StringComparison.CurrentCultureIgnoreCase) &&
                                            x.Territory.Equals("001", StringComparison.CurrentCultureIgnoreCase));
        }

        private static TimeZoneInfo GetTimeZoneByOffset(string timeZoneId)
        {
            var systemTimeZones = TimeZoneInfo.GetSystemTimeZones();

            var timeZone = systemTimeZones.FirstOrDefault(tz =>
                                                          tz.DisplayName == timeZoneId ||
                                                          tz.StandardName == timeZoneId ||
                                                          tz.DaylightName == timeZoneId);

            if (timeZone != null) return timeZone;

            var regex = new Regex(@"[+-][0-9]{2}:[0-9]{2}\b");

            var offsetStr = regex.Match(timeZoneId).Value.TrimStart('+');

            if (string.IsNullOrEmpty(offsetStr)) return null;

            TimeSpan offset;

            if (!TimeSpan.TryParse(offsetStr, out offset))
                return null;

            return systemTimeZones.FirstOrDefault(tz => tz.BaseUtcOffset == offset);
        }

        private static void InitTranslations()
        {
            try
            {
                _customMode = ConfigurationManagerExtension.AppSettings["core.custom-mode"] == "true";

                _isMono = Type.GetType("Mono.Runtime") != null;

                if (!_customMode)
                {
                    _translations = new Dictionary<string, string>();
                    return;
                }

                var assembly = Assembly.GetExecutingAssembly();

                using (var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.timeZoneNames.xml"))
                {
                    var xml = XElement.Load(stream);
                    _translations = (from row in xml.XPathSelectElements("*/zone")
                                     select new KeyValuePair<string, string>(row.Attribute("type").Value, row.Value)
                                    ).ToDictionary(item => item.Key, item => item.Value);
                }
            }
            catch (Exception error)
            {
                _translations = new Dictionary<string, string>();
                Log.Error(error);
            }
        }

        public static string GetTimeZoneName(TimeZoneInfo timeZone)
        {
            if (!_customMode)
                return _isMono ? timeZone.Id : timeZone.DisplayName;

            return _translations.ContainsKey(timeZone.Id) ? _translations[timeZone.Id] : timeZone.DisplayName;
        }

        private class MapZone
        {
            public string OlsonTimeZoneId { get; set; }
            public string WindowsTimeZoneId { get; set; }
            public string Territory { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/Confirm/js/confirm.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


StudioConfirm = new function() {
    this.OpenDialog = function(additionalID, callback) {
        jq("#studio_confirmMessage").html('');
        StudioBlockUIManager.blockUI("#studio_confirmDialog" + additionalID, 400);
        PopupKeyUpActionProvider.ClearActions();
        PopupKeyUpActionProvider.EnterAction = StudioConfirm.Select.bind(null, additionalID, callback);
        if (callback) {
            var conf = jq("#studio_confirmOk");
            conf.removeAttr("onclick");
            conf.off("click");
            conf.on("click", function () {
                callback();
            });
        }
    };
    this.Cancel = function() {
        PopupKeyUpActionProvider.ClearActions();
        jq.unblockUI();
    };
    this.SelectCallback = function() {
        alert('empty callback');
    };
    this.Select = function(additionalID, callback) {
        callback(jq("#studio_confirmInput" + additionalID).val());
    };
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/Core/Pojo/Comment.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;

#endregion

namespace ASC.Bookmarking.Pojo
{
    public class Comment
    {
        public virtual Guid ID { get; set; }

        public virtual Guid UserID { get; set; }

        public virtual string Content { get; set; }

        public virtual DateTime Datetime { get; set; }

        public virtual string Parent { get; set; }

        public virtual long BookmarkID { get; set; }

        public virtual Bookmark Bookmark { get; set; }

        public Comment()
        {
        }

        public Comment(Bookmark bookmark)
        {
            Bookmark = bookmark;
        }

        public virtual bool Inactive { get; set; }

        // override object.Equals
        public override bool Equals(object obj)
        {
            //       
            // See the full list of guidelines at
            //   http://go.microsoft.com/fwlink/?LinkID=85237  
            // and also the guidance for operator== at
            //   http://go.microsoft.com/fwlink/?LinkId=85238
            //

            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            var c = obj as Comment;
            return c != null && ID.Equals(c.ID);
        }

        public override int GetHashCode()
        {
            return (GetType().FullName + "|" + ID).GetHashCode();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/js/auth.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


/*******************************************************************************
    Auth for Thirdparty
*******************************************************************************/

var OAuthCallback = function (token) {
};

var OAuthError = function (error) {
    ASC.Files.UI.displayInfoPanel(error, true);
};

var OAuthPopup = function (url, providerKey, providerId) {
    if (ASC.Desktop) {
        var redirect = ASC.Files.Anchor.modulePath
            + "#setting=thirdparty&"
            + (providerKey ? ("providerKey=" + encodeURIComponent(providerKey))
                : (providerId ? ("providerId=" + encodeURIComponent(providerId)) : ""));
        location.href = url + "?redirect=" + encodeURIComponent(redirect);
        return null;
    }

    var newwindow;
    try {
        var params = "height=600,width=1020,resizable=0,status=0,toolbar=0,menubar=0,location=1";
        newwindow = window.open(url, "Authorization", params);
    } catch (err) {
        newwindow = window.open(url, "Authorization");
    }
    return newwindow;
};

<|start_filename|>common/ASC.Common/DependencyInjection/ParameterElement.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Configuration;


namespace ASC.Common.DependencyInjection
{
    public class ParameterElement : ConfigurationElement
    {
        private const string NameAttributeName = "name";
        private const string ValueAttributeName = "value";
        private const string TypeAttributeName = "type";
        private const string ListElementName = "list";
        private const string DictionaryElementName = "dictionary";
        internal const string Key = "name";

        [ConfigurationProperty(NameAttributeName, IsRequired = true)]
        public string Name
        {
            get
            {
                return (string)this[NameAttributeName];
            }
        }

        [ConfigurationProperty(ValueAttributeName, IsRequired = false)]
        public string Value
        {
            get
            {
                return (string)this[ValueAttributeName];
            }
        }

        [ConfigurationProperty(TypeAttributeName, IsRequired = false)]
        public string Type
        {
            get
            {
                return (string)this[TypeAttributeName];
            }
        }

        [ConfigurationProperty(ListElementName, DefaultValue = null, IsRequired = false)]
        public ListElementCollection List
        {
            get
            {
                return this[ListElementName] as ListElementCollection;
            }
        }

        [ConfigurationProperty(DictionaryElementName, DefaultValue = null, IsRequired = false)]
        public DictionaryElementCollection Dictionary
        {
            get
            {
                return this[DictionaryElementName] as DictionaryElementCollection;
            }
        }

        public object CoerceValue()
        {
            if (List.ElementInformation.IsPresent)
                return List;
            if (Dictionary.ElementInformation.IsPresent)
                return Dictionary;
            return Value;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/skins/default/codestyle.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.codestyle,
.codestyle pre {
    font-size: small;
    color: black;
    font-family: Consolas, "Courier New", Courier, Monospace;
    background-color: #ffffff;
    margin: 8px 0;
}
.codestyle ul,
.codestyle pre {
    list-style-type: none;
    margin: 0;
}
.codestyle table {
    border: 1px none Black;
    width: 100%;
}
.codestyle table td {
    padding: 5px 3px;
}
.codestyle table td.lines {
    border-right: 1px none black;
    text-align: right;
}
.codestyle table td.tdcode pre {
    width: 670px;
    overflow-x: auto;
    overflow-y: hidden;
}
.codestyle .rem {
    color: #008000;
}
.codestyle .kwrd {
    color: #0000ff;
}
.codestyle .str {
    color: #006080;
}
.codestyle .op {
    color: #0000c0;
}
.codestyle .preproc {
    color: #cc6633;
}
.codestyle .asp {
    background-color: #ffff00;
}
.codestyle .html {
    color: #800000;
}
.codestyle .attr {
    color: #ff0000;
}
.codestyle .alt {
    background-color: #f4f4f4;
    width: 100%;
    margin: 0;
}
.codestyle .lnum {
    color: #606060;
}
.codestyle ol li,
.codestyle ul li {
    white-space: pre-wrap;
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/People/Resources/PeopleJSResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.People.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class PeopleJSResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal PeopleJSResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.People.Resources.PeopleJSResource", typeof(PeopleJSResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose user.
        /// </summary>
        public static string ChooseUser {
            get {
                return ResourceManager.GetString("ChooseUser", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Image format is not supported.
        /// </summary>
        public static string ErrorMessage_NotImageSupportFormat {
            get {
                return ResourceManager.GetString("ErrorMessage_NotImageSupportFormat", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to An error occurred while uploading the image to the server.
        /// </summary>
        public static string ErrorMessage_SaveImageError {
            get {
                return ResourceManager.GetString("ErrorMessage_SaveImageError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Active.
        /// </summary>
        public static string LblActive {
            get {
                return ResourceManager.GetString("LblActive", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Type.
        /// </summary>
        public static string LblByType {
            get {
                return ResourceManager.GetString("LblByType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other.
        /// </summary>
        public static string LblOther {
            get {
                return ResourceManager.GetString("LblOther", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Pending.
        /// </summary>
        public static string LblPending {
            get {
                return ResourceManager.GetString("LblPending", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Status.
        /// </summary>
        public static string LblStatus {
            get {
                return ResourceManager.GetString("LblStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Disabled.
        /// </summary>
        public static string LblTerminated {
            get {
                return ResourceManager.GetString("LblTerminated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to People.
        /// </summary>
        public static string People {
            get {
                return ResourceManager.GetString("People", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} selected.
        /// </summary>
        public static string SelectedCount {
            get {
                return ResourceManager.GetString("SelectedCount", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The user status was successfully changed.
        /// </summary>
        public static string SuccessChangeUserStatus {
            get {
                return ResourceManager.GetString("SuccessChangeUserStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The user type was successfully changed.
        /// </summary>
        public static string SuccessChangeUserType {
            get {
                return ResourceManager.GetString("SuccessChangeUserType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The invitation was successfully sent.
        /// </summary>
        public static string SuccessSendInvitation {
            get {
                return ResourceManager.GetString("SuccessSendInvitation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your current pricing plan allows you to add {0}{1} more active users{2}..
        /// </summary>
        public static string TariffActiveUserLimit {
            get {
                return ResourceManager.GetString("TariffActiveUserLimit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your current pricing plan allows you to add {0}{1} active users{2} (guests are not taken into consideration)..
        /// </summary>
        public static string TariffActiveUserLimitExcludingGuests {
            get {
                return ResourceManager.GetString("TariffActiveUserLimitExcludingGuests", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your current pricing plan allows you to add {0}{1} guests{2}..
        /// </summary>
        public static string TariffGuestLimit {
            get {
                return ResourceManager.GetString("TariffGuestLimit", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/core/ASC.Web.Core/WhiteLabel/TenantLogoManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Web;

using ASC.Common.Caching;
using ASC.Core;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Core.WhiteLabel
{
    public class TenantLogoManager
    {
        private static readonly ICache Cache = AscCache.Default;

        private static string CacheKey
        {
            get { return "letterlogodata" + TenantProvider.CurrentTenantID; }
        }

        public static bool WhiteLabelEnabled
        {
            get;
            private set;
        }


        static TenantLogoManager()
        {
            var hideSettings = (ConfigurationManagerExtension.AppSettings["web.hide-settings"] ?? "").Split(new[] { ',', ';', ' ' });
            WhiteLabelEnabled = !hideSettings.Contains("WhiteLabel", StringComparer.CurrentCultureIgnoreCase);
        }


        public static string GetFavicon(bool general, bool timeParam)
        {
            string faviconPath;
            if (WhiteLabelEnabled)
            {
                var tenantWhiteLabelSettings = TenantWhiteLabelSettings.Load();
                faviconPath = tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.Favicon, general);
                if (timeParam)
                {
                    var now = DateTime.Now;
                    faviconPath = String.Format("{0}?t={1}", faviconPath, now.Ticks);
                }
            }
            else
            {
                faviconPath = TenantWhiteLabelSettings.GetAbsoluteDefaultLogoPath(WhiteLabelLogoTypeEnum.Favicon, general);
            }

            return faviconPath;
        }

        public static string GetTopLogo(bool general)//LogoLightSmall
        {
            if (WhiteLabelEnabled)
            {
                var tenantWhiteLabelSettings = TenantWhiteLabelSettings.Load();

                return tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.LightSmall, general);
            }
            return TenantWhiteLabelSettings.GetAbsoluteDefaultLogoPath(WhiteLabelLogoTypeEnum.LightSmall, general);
        }

        public static string GetLogoDark(bool general)
        {
            if (WhiteLabelEnabled)
            {
                var tenantWhiteLabelSettings = TenantWhiteLabelSettings.Load();
                return tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.Dark, general);
            }

            /*** simple scheme ***/
            var tenantInfoSettings = TenantInfoSettings.Load();
            return tenantInfoSettings.GetAbsoluteCompanyLogoPath();
            /***/
        }

        public static string GetLogoDocsEditor(bool general)
        {
            if (WhiteLabelEnabled)
            {
                var tenantWhiteLabelSettings = TenantWhiteLabelSettings.Load();
                return tenantWhiteLabelSettings.GetAbsoluteLogoPath(WhiteLabelLogoTypeEnum.DocsEditor, general);
            }
            return TenantWhiteLabelSettings.GetAbsoluteDefaultLogoPath(WhiteLabelLogoTypeEnum.DocsEditor, general);
        }

        public static string GetLogoText()
        {
            if (WhiteLabelEnabled)
            {
                var tenantWhiteLabelSettings = TenantWhiteLabelSettings.Load();
                return tenantWhiteLabelSettings.LogoText ?? TenantWhiteLabelSettings.DefaultLogoText;
            }
            return TenantWhiteLabelSettings.DefaultLogoText;
        }

        public static bool IsRetina(HttpRequest request)
        {
            if (request != null)
            {
                var cookie = request.Cookies["is_retina"];
                if (cookie != null && !String.IsNullOrEmpty(cookie.Value))
                {
                    bool result;
                    if (Boolean.TryParse(cookie.Value, out result))
                    {
                        return result;
                    }
                }
            }

            return !SecurityContext.IsAuthenticated;
        }

        public static bool WhiteLabelPaid
        {
            get
            {
                return CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).WhiteLabel;
            }
        }

        /// <summary>
        /// Get logo stream or null in case of default logo
        /// </summary>
        public static Stream GetWhitelabelMailLogo()
        {
            if (WhiteLabelEnabled)
            {
                var tenantWhiteLabelSettings = TenantWhiteLabelSettings.Load();
                return tenantWhiteLabelSettings.GetWhitelabelLogoData(WhiteLabelLogoTypeEnum.Dark, true);
            }

            /*** simple scheme ***/
            var tenantInfoSettings = TenantInfoSettings.Load();
            return tenantInfoSettings.GetStorageLogoData();
            /***/
        }


        public static byte[] GetMailLogoDataFromCache()
        {
            return Cache.Get<byte[]>(CacheKey);
        }

        public static void InsertMailLogoDataToCache(byte[] data)
        {
            Cache.Insert(CacheKey, data, DateTime.UtcNow.Add(TimeSpan.FromDays(1)));
        }

        public static void RemoveMailLogoDataFromCache()
        {
            Cache.Remove(CacheKey);
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/Routing/ApiAccessControlRouteRegistrator.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Web;
using System.Web.Routing;

using ASC.Api.Impl.Constraints;
using ASC.Api.Interfaces;

namespace ASC.Api.Impl.Routing
{
    public class ApiAccessControlRouteRegistrator : IApiRouteRegistrator
    {
        public IApiConfiguration Config { get; set; }

        public void RegisterRoutes(RouteCollection routes)
        {
            //Register 1 route
            var basePath = Config.GetBasePath();
            var constrasints = new RouteValueDictionary { { "method", ApiHttpMethodConstraint.GetInstance("OPTIONS") } };
            routes.Add(new Route(basePath + "{*path}", null, constrasints, new ApiAccessRouteHandler()));
        }

        public class ApiAccessRouteHandler : IRouteHandler
        {
            public IHttpHandler GetHttpHandler(RequestContext requestContext)
            {
                return new ApiAccessHttpHandler();
            }

            public class ApiAccessHttpHandler : IHttpHandler
            {
                public void ProcessRequest(HttpContext context)
                {
                    //Set access headers
                    //Access-Control-Allow-Origin: http://foo.example  
                    //Access-Control-Allow-Methods: POST, GET, OPTIONS  
                    //Access-Control-Allow-Headers: X-PINGOTHER  
                    //Access-Control-Max-Age: 1728000  
                    //context.Response.Headers["Access-Control-Allow-Origin"] = "*";
                    context.Response.Headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE";
                    context.Response.Headers["Access-Control-Allow-Headers"] = "origin, authorization, accept, content-type";
                    context.Response.Headers["Access-Control-Max-Age"] = "1728000";

                }

                public bool IsReusable
                {
                    get { return false; }
                }
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTP_SourceState.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    /// <summary>
    /// This enum specifies <b>RTP_SyncSource</b> state.
    /// </summary>
    public enum RTP_SourceState
    {
        /// <summary>
        /// Source is passive, sending only RTCP packets.
        /// </summary>
        Passive = 1,

        /// <summary>
        /// Source is active, sending RTP packets.
        /// </summary>
        Active = 2,

        /// <summary>
        /// Source has disposed.
        /// </summary>
        Disposed = 3,
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/js/navsidepanel.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined") {
    ASC = {};
}
if (typeof ASC.CRM === "undefined") {
    ASC.CRM = (function() { return {} })();
}

ASC.CRM.NavSidePanel = (function() {
    var isInit = false,
        entityID = 0,
        action = null,
        companiesAnchor = "<KEY>
        personsAnchor = "<KEY>",
        pagesForHistory = ["Default.aspx", "Tasks.aspx", "Deals.aspx", "Invoices.aspx", "Cases.aspx"],
        pagesForExportToCSV = ["Default.aspx", "Tasks.aspx", "Deals.aspx", "Cases.aspx"];

    var init = function () {
        if (isInit) {
            return;
        }

        isInit = true;
        entityID = jq.getURLParam("id");
        entityID = (entityID != null && !isNaN(parseInt(entityID))) ? parseInt(entityID) : 0;
        action = jq.getURLParam("action");

        var currentPage = getCurrentPage();

        if (currentPage == "Default.aspx" && action != "manage" && entityID != 0) {
            ASC.CRM.TaskActionView.init(false);
        } else {
            ASC.CRM.TaskActionView.init(true);
        }

        if ((checkNeedExportCsvBtns(currentPage) || jq.inArray(currentPage, pagesForHistory) != -1) && entityID == 0 && action == null) {
            jq("#exportListToCSV").on("click", ASC.CRM.Common.exportCurrentListToCsv);
        } else {
            ASC.CRM.Common.hideExportButtons();
        }

        /***
        Bug Fix for Bug 23487
        ***/
        if (entityID == 0 && jq.inArray(currentPage, pagesForHistory) != -1 && checkInit("Default.aspx", 0)) {
            initMenuItem({ id: "#nav-menu-contacts .companies-menu-item:first", href: "Default.aspx", onclick: highlightMenu }, "Default.aspx#" + companiesAnchor);
            initMenuItem({ id: "#nav-menu-contacts .persons-menu-item:first", href: "Default.aspx", onclick: highlightMenu }, "Default.aspx#" + personsAnchor);
        }
        /***
        Difficult part
        ***/
        jq("#nav-menu-contacts .companies-menu-item:first").on("click", function () {
            if (!checkInit("Default.aspx", 0)) {
                location.href = "Default.aspx#" + companiesAnchor;
            } else {
                var p = getCurrentPage();
                if (checkInit(p, 0) && jq.getURLParam("action") == null && jq.getURLParam("id") == null) {
                    ASC.Controls.AnchorController.move(companiesAnchor);
                    ASC.CRM.ListContactView.filterSortersCorrection();
                } else {
                    if (p != "Default.aspx" || jq.getURLParam("action") != null || jq.getURLParam("id") != null) {
                        location.href = "Default.aspx#" + companiesAnchor;
                    } else {
                        ASC.Controls.AnchorController.move(companiesAnchor);
                        ASC.CRM.ListContactView.filterSortersCorrection();
                    }
                }
            }
        });

        jq("#nav-menu-contacts .persons-menu-item:first").on("click", function () {
            if (!checkInit("Default.aspx", 0)) {
                location.href = "Default.aspx#" + personsAnchor;
            } else {
                var p = getCurrentPage();
                if (checkInit(p, 0) && jq.getURLParam("action") == null && jq.getURLParam("id") == null) {
                    ASC.Controls.AnchorController.move(personsAnchor);
                    ASC.CRM.ListContactView.filterSortersCorrection();
                } else {
                    if (p != "Default.aspx" || jq.getURLParam("action") != null || jq.getURLParam("id") != null) {
                        location.href = "Default.aspx#" + personsAnchor;
                    } else {
                        ASC.Controls.AnchorController.move(personsAnchor);
                        ASC.CRM.ListContactView.filterSortersCorrection();
                    }
                }
            }
        });
        /*******/

        if (entityID != 0 || jq.inArray(currentPage, pagesForHistory) == -1) { return; }

        highlightMenu();
        initMenuItems([
            { id: '#nav-menu-contacts .category-wrapper a', href: 'Default.aspx', onclick: highlightMenu },
            { id: '#nav-menu-tasks a', href: 'Tasks.aspx', onclick: highlightMenu },
            { id: '#nav-menu-deals a', href: 'Deals.aspx', onclick: highlightMenu },
            { id: '#nav-menu-invoices .category-wrapper a', href: 'Invoices.aspx', onclick: highlightMenu },
            { id: '#nav-menu-cases a', href: 'Cases.aspx', onclick: highlightMenu }]);

        if (checkInit("Invoices.aspx", 0)) {

            initMenuItem({ id: "#nav-menu-invoices .drafts-menu-item:first", href: "Invoices.aspx", onclick: highlightMenu },
                "Invoices.aspx#<KEY>");
            initMenuItem({ id: "#nav-menu-invoices .sent-menu-item:first", href: "Invoices.aspx", onclick: highlightMenu },
                "Invoices.aspx#<KEY>");
            initMenuItem({ id: "#nav-menu-invoices .paid-menu-item:first", href: "Invoices.aspx", onclick: highlightMenu },
                "<KEY>");
            initMenuItem({ id: "#nav-menu-invoices .rejected-menu-item:first", href: "Invoices.aspx", onclick: highlightMenu },
                "Invoices.aspx#<KEY>);
        }
    };

    var getCurrentPage = function () {
        var parts = location.pathname.split('/'),
            currentPage = parts[parts.length - 1];
        if (currentPage == "") {
            currentPage = "Default.aspx";
        }
        return currentPage;
    };

    var checkNeedExportCsvBtns = function (currentPage) {
        return jq.inArray(currentPage, pagesForExportToCSV) != -1 || currentPage == "Settings.aspx" && jq.getURLParam("type") == "invoice_items";
    };

    var initCurrentPage = function (currentPage) {
        ASC.CRM.Common.hideExportButtons();

        if (currentPage == "Default.aspx") {
            jq("#nav-menu-contacts").addClass("active currentCategory");
            ASC.CRM.ListContactView.init(".main-list-contacts", ".filter-content", ".paging-content");
        }

        if (currentPage == "Tasks.aspx") {
            jq("#nav-menu-tasks").addClass("active currentCategory");
            ASC.CRM.ListTaskView.init(".main-list-tasks", ".filter-content", ".paging-content");
        }

        if (currentPage == "Deals.aspx") {
            jq("#nav-menu-deals").addClass("active currentCategory");
            ASC.CRM.ListDealView.init(".main-list-deals", ".filter-content", ".paging-content");
        }

        if (currentPage == "Invoices.aspx") {
            jq("#nav-menu-invoices").addClass("active currentCategory");
            ASC.CRM.ListInvoiceView.init(".main-list-invoices", ".filter-content", ".paging-content");
        }

        if (currentPage == "Cases.aspx") {
            jq("#nav-menu-cases").addClass("active currentCategory");
            ASC.CRM.ListCasesView.init(".main-list-cases", ".filter-content", ".paging-content");
        }

    };

    var highlightMenu = function () {
        jq(".menu-list li").removeClass("active currentCategory");
        var currentPage = getCurrentPage();
        
        initCurrentPage(currentPage);
    };

    var initMenuItems = function (items) {
        var currentPage = getCurrentPage(),
            entityId = jq.getURLParam('id');
        if (checkInit(currentPage, entityId)) {
            items.forEach(function (item) {
                initMenuItem(item);
            });
        }
    };

    var checkInit = function (currentPage, entityId) {
        return !!(window.history && window.history.replaceState) &&
            !entityId && !jq.getURLParam('action') &&
            (jq.inArray(currentPage, pagesForHistory) != -1);
    };

    var initMenuItem = function (item, extHref) {
        jq(item.id).on('click', function (event) {
            if (event.which == 1 && event.ctrlKey || event.which == 2) return true;
            event.stopPropagation();
            jq('#privatePanelWrapper').appendTo('#hiddenBlockForPrivatePanel');
            var activeList = jq(".main-list:not(.display-none)");
            activeList.addClass("display-none");
            activeList.html('');
            
            jq(".filter-content, .paging-content").html('');

            var historyHref = item.href;
            if (typeof (extHref) != "undefined" && extHref != null && extHref != "") {
                historyHref = extHref;
            }
            history.pushState({ href: historyHref }, { href: historyHref },  historyHref);
            item.onclick();
            return false;
        });
    };

    return {
        init: init,
        initMenuItems: initMenuItems
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Search/BundleSearch.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.CRM.Core;
using ASC.ElasticSearch;

namespace ASC.Web.CRM.Core.Search
{
    public class BundleSearch
    {
        public static bool Support(EntityType entityType)
        {
            switch (entityType)
            {
                case EntityType.Person:
                case EntityType.Contact:
                case EntityType.Company:
                    return FactoryIndexer<ContactsWrapper>.Support &&
                           FactoryIndexer<InfoWrapper>.Support &&
                           FactoryIndexer<FieldsWrapper>.Support &&
                           FactoryIndexer<EventsWrapper>.Support;
                case EntityType.Opportunity:
                    return FactoryIndexer<DealsWrapper>.Support &&
                           FactoryIndexer<FieldsWrapper>.Support &&
                           FactoryIndexer<EventsWrapper>.Support;
                case EntityType.RelationshipEvent:
                    return FactoryIndexer<EventsWrapper>.Support;
                case EntityType.Task:
                    return FactoryIndexer<TasksWrapper>.Support;
                case EntityType.Case:
                    return FactoryIndexer<CasesWrapper>.Support &&
                           FactoryIndexer<FieldsWrapper>.Support &&
                           FactoryIndexer<EventsWrapper>.Support;
                case EntityType.Invoice:
                    return FactoryIndexer<InvoicesWrapper>.Support;
            }

            return false;
        }

        public static bool TrySelectCase(string text, out List<int> result)
        {
            var success = false;
            result = new List<int>();

            List<int> casesId;
            if (FactoryIndexer<CasesWrapper>.TrySelectIds(s => s.MatchAll(text), out casesId))
            {
                result.AddRange(casesId);
                success = true;
            }

            IReadOnlyCollection<FieldsWrapper> casesCustom;
            if (FactoryIndexer<FieldsWrapper>.TrySelect(s => s.MatchAll(text).Where(r => r.EntityType, 7), out casesCustom))
            {
                result.AddRange(casesCustom.Select(r => r.EntityId).ToList());
                success = true;
            }

            IReadOnlyCollection<EventsWrapper> events;
            if (!FactoryIndexer<EventsWrapper>.TrySelect(s => s.MatchAll(text).Where(r => r.EntityType, 7).Gt(r => r.EntityId, 0), out events))
            {
                result.AddRange(events.Select(r => r.EntityId).ToList());
                success = true;
            }

            return success;
        }

        public static bool TrySelectContact(string text, out List<int> result)
        {
            var success = false;
            result = new List<int>();

            List<int> contactsId;
            if (FactoryIndexer<ContactsWrapper>.TrySelectIds(s => s.MatchAll(text), out contactsId))
            {
                result.AddRange(contactsId);
                success = true;
            }

            IReadOnlyCollection<InfoWrapper> infos;
            if (FactoryIndexer<InfoWrapper>.TrySelect(s => s.MatchAll(text), out infos))
            {
                result.AddRange(infos.Select(r => r.ContactId).ToList());
                success = true;
            }

            IReadOnlyCollection<FieldsWrapper> personCustom;
            if (FactoryIndexer<FieldsWrapper>.TrySelect(s => s.MatchAll(text).In(r => r.EntityType, new[] { 0, 4, 5 }), out personCustom))
            {
                result.AddRange(personCustom.Select(r => r.EntityId).ToList());
                success = true;
            }

            IReadOnlyCollection<EventsWrapper> events;
            if (FactoryIndexer<EventsWrapper>.TrySelect(s => s.MatchAll(text).Gt(r => r.ContactId, 0), out events))
            {
                result.AddRange(events.Select(r => r.ContactId).ToList());
                success = true;
            }

            return success;
        }

        public static bool TrySelectOpportunity(string text, out List<int> result)
        {
            var success = false;
            result = new List<int>();

            List<int> dealsId;
            if (FactoryIndexer<DealsWrapper>.TrySelectIds(s => s.MatchAll(text), out dealsId))
            {
                result.AddRange(dealsId);
                success = true;
            }

            IReadOnlyCollection<FieldsWrapper> casesCustom;
            if (FactoryIndexer<FieldsWrapper>.TrySelect(s => s.MatchAll(text).Where(r => r.EntityType, 1), out casesCustom))
            {
                result.AddRange(casesCustom.Select(r => r.EntityId).ToList());
                success = true;
            }

            IReadOnlyCollection<EventsWrapper> events;
            if (!FactoryIndexer<EventsWrapper>.TrySelect(s => s.MatchAll(text).Where(r => r.EntityType, 1).Gt(r => r.EntityId, 0), out events))
            {
                result.AddRange(events.Select(r => r.EntityId).ToList());
                success = true;
            }

            return success;
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Specific/AuthorizationApi/AuthenticationTokenData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

namespace ASC.Specific.AuthorizationApi
{
    [DataContract(Name = "token", Namespace = "")]
    public class AuthenticationTokenData
    {
        [DataMember(Order = 1)]
        public string Token { get; set; }

        [DataMember(Order = 2, EmitDefaultValue = false)]
        public ApiDateTime Expires { get; set; }

        [DataMember(Order = 3, EmitDefaultValue = false)]
        public bool Sms { get; set; }

        [DataMember(Order = 4, EmitDefaultValue = false)]
        public string PhoneNoise { get; set; }

        [DataMember(Order = 5, EmitDefaultValue = false)]
        public bool Tfa { get; set; }

        [DataMember(Order = 6, EmitDefaultValue = false)]
        public string TfaKey { get; set; }

        public static AuthenticationTokenData GetSample()
        {
            return new AuthenticationTokenData
            {
                Expires = ApiDateTime.GetSample(),
                Token = "<KEY>",
                Sms = false,
                PhoneNoise = null,
                Tfa = false,
                TfaKey = null
            };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/_Obsolete/MIME/HeaderField.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Mime
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Mime entity header field.
    /// </summary>
    [Obsolete("See LumiSoft.Net.MIME or LumiSoft.Net.Mail namepaces for replacement.")]
    public class HeaderField
    {
        #region Members

        private string m_Name = "";
        private string m_Value = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets header field name. Header field name must end with colon(:) and may contain US-ASCII character values between 33 and 126.
        /// </summary>
        public string Name
        {
            get { return m_Name; }

            set
            {
                /* RFC 2822 2.2 Header Fields
					Header fields are lines composed of a field name, followed by a colon
					(":"), followed by a field body, and terminated by CRLF.  A field
					name MUST be composed of printable US-ASCII characters (i.e.,
					characters that have values between 33 and 126, inclusive), except
					colon.  A field body may be composed of any US-ASCII characters,
					except for CR and LF.  However, a field body may contain CRLF when
					used in header "folding" and  "unfolding" as described in section
					2.2.3.  All field bodies MUST conform to the syntax described in
					sections 3 and 4 of this standard.
				*/

                if (value == "")
                {
                    throw new Exception("Header Field name can't be empty !");
                }

                // Colon is missing from name, just add it
                if (!value.EndsWith(":"))
                {
                    value += ":";
                }

                // Check if name is between ASCII 33 - 126 characters
                foreach (char c in value.Substring(0, value.Length - 1))
                {
                    if (c < 33 || c > 126)
                    {
                        throw new Exception("Invalid field name '" + value +
                                            "'. A field name MUST be composed of printable US-ASCII characters (i.e.,characters that have values between 33 and 126, inclusive),except	colon.");
                    }
                }

                m_Name = value;
            }
        }

        /// <summary>
        /// Gets or sets header field value.
        /// </summary>
        public string Value
        {
            get { return MimeUtils.DecodeWords(m_Value); }

            set { m_Value = Core.CanonicalEncode(value, "utf-8"); }
        }

        /// <summary>
        /// Gets header field encoded value.
        /// </summary>
        internal string EncodedValue
        {
            get { return m_Value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default construtor.
        /// </summary>
        public HeaderField() {}

        /// <summary>
        /// Creates new header field with specified name and value.
        /// </summary>
        /// <param name="name">Header field name. Header field name must end with colon(:) and may contain US-ASCII character values between 33 and 126.</param>
        /// <param name="value">Header field value.</param>
        public HeaderField(string name, string value)
        {
            Name = name;
            Value = value;
        }

        #endregion
    }
}

<|start_filename|>web/core/ASC.Web.Core/Utility/UrlSwitcher.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

namespace ASC.Web.Core.Utility
{
    public static class UrlSwitcher
    {
        public static string SelectCurrentUriScheme(string uri)
        {
            return HttpContext.Current != null ? SelectUriScheme(uri, HttpContext.Current.Request.GetUrlRewriter().Scheme) : uri;
        }

        public static string SelectUriScheme(string uri, string scheme)
        {
            return Uri.IsWellFormedUriString(uri, UriKind.Absolute) ? SelectUriScheme(new Uri(uri, UriKind.Absolute), scheme).ToString() : uri;
        }

        public static Uri SelectCurrentUriScheme(Uri uri)
        {
            if (HttpContext.Current != null)
            {
                return SelectUriScheme(uri, HttpContext.Current.Request.GetUrlRewriter().Scheme);
            }
            return uri;
        }

        public static Uri SelectUriScheme(Uri uri, string scheme)
        {
            if (!string.IsNullOrEmpty(scheme) && !scheme.Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase))
            {
                //Switch
                var builder = new UriBuilder(uri) { Scheme = scheme.ToLowerInvariant(), Port = scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? 443 : 80 };//Set proper port!
                return builder.Uri;
            }
            return uri;
        }

        public static Uri ToCurrentScheme(this Uri uri)
        {
            return SelectCurrentUriScheme(uri);
        }

        public static Uri ToScheme(this Uri uri, string scheme)
        {
            return SelectUriScheme(uri, scheme);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/LdapSettings/LdapSettings.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

using Newtonsoft.Json;

namespace ASC.Web.Studio.UserControls.Management
{
    [ManagementControl(ManagementType.LdapSettings, Location)]
    [AjaxNamespace("LdapSettingsController")]
    public partial class LdapSettings : UserControl
    {
        protected ActiveDirectory.Base.Settings.LdapSettings Settings;
        protected string LdapMapping;

        public const string Location = "~/UserControls/Management/LdapSettings/LdapSettings.ascx";

        protected bool isAvailable
        {
            get
            {
                return TenantExtra.GetTenantQuota().Ldap;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (CoreContext.Configuration.Standalone || !SetupInfo.IsVisibleSettings(ManagementType.LdapSettings.ToString()))
            {
                Response.Redirect(CommonLinkUtility.GetDefault(), true);
                return;
            }

            AjaxPro.Utility.RegisterTypeForAjax(typeof(LdapSettings), Page);
            Page.RegisterStyle(
                "~/UserControls/Management/LdapSettings/css/Default/ldapsettings.css",
                "~/UserControls/Management/LdapSettings/css/Default/jqCron.css");

            Page.RegisterBodyScripts(
                "~/js/third-party/moment.min.js", "~/js/third-party/moment-timezone.min.js",
                "~/js/third-party/jquery/jquery.cron.js",
                "~/UserControls/Management/LdapSettings/js/ldapsettings.js"
                );
            ldapSettingsConfirmContainerId.Options.IsPopup = true;
            ldapSettingsLimitPanelId.Options.IsPopup = true;
            ldapSettingsCronPanel.Options.IsPopup = true;
            ldapSettingsCronTurnOffContainer.Options.IsPopup = true;
            ldapSettingsTurnOffContainer.Options.IsPopup = true;
            ldapSettingsCertificateValidationContainer.Options.IsPopup = true;

            Settings = ActiveDirectory.Base.Settings.LdapSettings.Load();

            LdapMapping = JsonConvert.SerializeObject(Settings.LdapMapping, Formatting.Indented).ToString();
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Mail/MailApi.HelpCenter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Api.Attributes;
using ASC.Web.Studio.UserControls.Common.HelpCenter;

namespace ASC.Api.Mail
{
    public partial class MailApi
    {
        /// <summary>
        ///    Returns the string with html of help center page
        /// </summary>
        /// <returns>String with html of help center page</returns>
        /// <short>Get html of help center page</short> 
        /// <category>HelpCenter</category>
        [Read(@"helpcenter")]
        public string GetHelpCenterHtml()
        {
            return HelpCenter.RenderControlToString(new Guid("{2A923037-8B2D-487b-9A22-5AC0918ACF3F}"));
        }
    }
}


<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Classes/SmsSender.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.HealthCheck.Settings;
using log4net;
using System;
using System.Configuration;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using RestSharp.Extensions;


namespace ASC.HealthCheck.Classes
{
    public class SmsSender : ISmsSender
    {
        private readonly ILog log;
        private const string GetMethod = "GET";
        private const string PostMethod = "POST";
        private readonly string SMSUSAregex;
        private readonly string SMSCISregex;

        public SmsSender()
        {
            log = LogManager.GetLogger(typeof(SmsSender));
            SMSUSAregex = HealthCheckCfgSectionHandler.Instance.SMSUSAregex;
            SMSCISregex = HealthCheckCfgSectionHandler.Instance.SMSCISregex;
        }

        public void SendSMS(string number, string message, HealthCheckSettings healthCheckSettings)
        {
            if (string.IsNullOrWhiteSpace(number)) throw new ArgumentException("number");
            if (string.IsNullOrWhiteSpace(message)) throw new ArgumentException("message");
            if (healthCheckSettings == null) throw new ArgumentNullException("healthCheckSettings");

            log.DebugFormat("SendSMS: number = {0}, message = {1}", number, message);
            if ("log".Equals(ConfigurationManager.AppSettings["core.notify.postman"], StringComparison.InvariantCultureIgnoreCase))
            {
                log.InfoFormat("Send notify sms to phoneNumber: {0}\n Message: {1}", number, message);
                return;
            }

            number = new Regex("[^\\d+]").Replace(number, string.Empty);

            var url = healthCheckSettings.SmsOperatorUrlClickatel;
            var method = PostMethod;

            if (!string.IsNullOrEmpty(SMSUSAregex) &&
                Regex.IsMatch(number, SMSUSAregex))
            {
                url = healthCheckSettings.SmsOperatorUrlClickatelUSA;
            }

            if (!string.IsNullOrEmpty(SMSCISregex) &&
                Regex.IsMatch(number, SMSCISregex))
            {
                url = healthCheckSettings.SmsOperatorUrlSmsc;
                method = GetMethod;
            }

            try
            {
                var request = (HttpWebRequest)WebRequest.Create(url.Replace("{phone}", number).Replace("{text}", message.UrlEncode()));
                request.Method = method;
                request.ContentType = "application/x-www-form-urlencoded";
                request.Timeout = 1000;

                using (var stream = request.GetResponse().GetResponseStream())
                using (var reader = new StreamReader(stream))
                {
                    var result = reader.ReadToEnd();
                    log.InfoFormat("SMS was sent to {0}, service returned: {1}", number, result);
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("SendSMS: Failed to send sms message. {0} {1}",
                    ex.ToString(), ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/Common/ActionButton/js/actionbutton.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


function actionButtonClick(redirectFlag, btnContainer) {

	AjaxPro.onLoading = function(b) {
		if (b) {
		    showHideActionButtonPanel( btnContainer, true);
		}
		else {
			setTimeout(function() {
				if (!redirectFlag) {
				    showHideActionButtonPanel( btnContainer, false);
				}		
			}, 200);			
		}
	}
}

function showHideActionButtonPanel( btnContainer, showFlag) {
	if (showFlag) {
	    LoadingBanner.showLoaderBtn(btnContainer);
	} else {
	    LoadingBanner.hideLoaderBtn(btnContainer);
	}
}

function showPopupWindowWithActionButton(popupWindowID) {
	StudioBlockUIManager.blockUI('#' + popupWindowID, 400);
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Interfaces/IUserFolderXMailDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao.Interfaces
{
    public interface IUserFolderXMailDao
    {
        UserFolderXMail Get(int mailId);
        List<UserFolderXMail> GetList(uint? folderId = null, List<int> mailIds = null);
        List<int> GetMailIds(uint folderId);
        void SetMessagesFolder(IEnumerable<int> messageIds, uint folderId);
        int Save(UserFolderXMail item);
        int Remove(int? mailId = null, uint? folderId = null);
        int Remove(List<int> mailIds);
        int RemoveByMailbox(int mailboxId);
    }
}


<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/ProjectsModuleSpecifics.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text.RegularExpressions;

using ASC.Data.Backup.Tasks.Data;
using ASC.Data.Backup.Utils;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal class ProjectsModuleSpecifics : ModuleSpecificsBase
    {
        private readonly TableInfo[] _tables = new[]
            {
                new TableInfo("projects_comments", "tenant_id", "comment_id", IdType.Autoincrement) {UserIDColumns = new[] {"create_by"}},
                new TableInfo("projects_following_project_participant") {UserIDColumns = new[] {"participant_id"}},
                new TableInfo("projects_messages", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"create_by", "last_modified_by"},
                        DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"last_modified_on", false}}
                    },
                new TableInfo("projects_milestones", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
                        DateColumns = new Dictionary<string, bool> {{"deadline", true}, {"status_changed", false}, {"create_on", false}, {"last_modified_on", false}}
                    },
                new TableInfo("projects_projects", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
                        DateColumns = new Dictionary<string, bool> {{"status_changed", false}, {"create_on", false}, {"last_modified_on", false}}
                    },
                new TableInfo("projects_project_participant", "tenant") {UserIDColumns = new[] {"participant_id"}},
                new TableInfo("projects_project_tag"),
                new TableInfo("projects_report_template", "tenant_id", "id") {UserIDColumns = new[] {"create_by"}},
                new TableInfo("projects_subtasks", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
                        DateColumns = new Dictionary<string, bool> {{"status_changed", false}, {"create_on", false}, {"last_modified_on", false}}
                    },
                new TableInfo("projects_tags", "tenant_id", "id"),
                new TableInfo("projects_tasks", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"create_by", "last_modified_by", "responsible_id"},
                        DateColumns = new Dictionary<string, bool> {{"status_changed", true}, {"deadline", true}, {"create_on", false}, {"last_modified_on", true}, {"start_date", true}}
                    },
                new TableInfo("projects_tasks_responsible", "tenant_id") {UserIDColumns = new[] {"responsible_id"}},
                new TableInfo("projects_templates", "tenant_id", "id") {UserIDColumns = new[] {"create_by", "last_modified_by"}},
                new TableInfo("projects_time_tracking", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"create_by", "person_id"},
                        DateColumns = new Dictionary<string, bool> {{"date", true}, {"create_on", false}, {"status_changed", true}}
                    },
                new TableInfo("projects_tasks_links", "tenant_id"),
                new TableInfo("projects_tasks_order", "tenant_id")
            };

        private readonly RelationInfo[] _tableRelations = new[]
            {
                new RelationInfo("projects_comments", "id", "projects_comments", "parent_id"),
                new RelationInfo("projects_messages", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Message_", StringComparison.InvariantCultureIgnoreCase)),
                new RelationInfo("projects_tasks", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Task_", StringComparison.InvariantCultureIgnoreCase)),
                new RelationInfo("projects_milestones", "id", "projects_comments", "target_uniq_id", x => Convert.ToString(x["target_uniq_id"]).StartsWith("Milestone_", StringComparison.InvariantCultureIgnoreCase)),
                new RelationInfo("projects_projects", "id", "projects_following_project_participant", "project_id"),
                new RelationInfo("projects_projects", "id", "projects_messages", "project_id"),
                new RelationInfo("projects_projects", "id", "projects_milestones", "project_id"),
                new RelationInfo("projects_projects", "id", "projects_project_participant", "project_id"),
                new RelationInfo("projects_projects", "id", "projects_project_tag", "project_id"),
                new RelationInfo("projects_tags", "id", "projects_project_tag", "tag_id"),
                new RelationInfo("projects_tasks", "id", "projects_subtasks", "task_id"),
                new RelationInfo("projects_projects", "id", "projects_tasks", "project_id"),
                new RelationInfo("projects_milestones", "id", "projects_tasks", "milestone_id"),
                new RelationInfo("projects_tasks", "id", "projects_tasks_responsible", "task_id"),
                new RelationInfo("projects_projects", "id", "projects_time_tracking", "project_id"),
                new RelationInfo("projects_tasks", "id", "projects_time_tracking", "relative_task_id"),
                new RelationInfo("projects_tasks", "id", "projects_tasks_links", "task_id"),
                new RelationInfo("projects_tasks", "id", "projects_tasks_links", "parent_id"),
                new RelationInfo("projects_projects", "id", "projects_tasks_order", "project_id"),
                new RelationInfo("projects_tasks", "id", "projects_tasks_order", "task_order"),
                new RelationInfo("projects_milestones", "id", "projects_tasks_order", "task_order")
            };

        public override ModuleName ModuleName
        {
            get { return ModuleName.Projects; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return _tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return _tableRelations; }
        }

        public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
        {
            var match = Regex.Match(filePath, @"^thumbs/\d+/\d+/\d+/(?'fileId'\d+)\.jpg$");
            if (match.Success)
            {
                var fileId = columnMapper.GetMapping("files_file", "id", match.Groups["fileId"].Value);
                if (fileId == null)
                {
                    if (!dump) return false;

                    fileId = match.Groups["fileId"].Value;
                }

                var s = fileId.ToString().PadRight(6, '0');
                filePath = string.Format("thumbs/{0}/{1}/{2}/{3}.jpg", s.Substring(0, 2), s.Substring(2, 2), s.Substring(4), fileId);
                return true;
            }

            return false;
        }

        protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
        {
            if (table.Name == "projects_project_tag" || table.Name == "projects_following_project_participant")
                return "inner join projects_projects as t1 on t1.id = t.project_id where t1.tenant_id = " + tenantId;

            return base.GetSelectCommandConditionText(tenantId, table);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
        {

            if (table.Name == "projects_comments" && columnName == "content" ||
                table.Name == "projects_messages" && columnName == "content")
            {
                value = FCKEditorPathUtility.CorrectStoragePath(value as string, columnMapper.GetTenantMapping());
                return true;
            }
            return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
        {
            if (relation.ChildTable == "projects_comments" && relation.ChildColumn == "target_uniq_id")
            {
                var valParts = value.ToString().Split('_');

                var entityId = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, valParts[1]);
                if (entityId == null)
                    return false;

                value = string.Format("{0}_{1}", valParts[0], entityId);
                return true;
            }

            return base.TryPrepareValue(connection, columnMapper, relation, ref value);
        }

        protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
        {
            if (table.Name == "projects_tasks_order" && columnName == "task_order")
            {
                value = Regex.Replace(
                    Convert.ToString(value),
                    @"(?<=""tasks"":\[(\d+,)*)\d+,?",
                    match =>
                    {
                        var mappedId = Convert.ToString(columnMapper.GetMapping("projects_tasks", "id", match.Value.TrimEnd(',')));
                        return !string.IsNullOrEmpty(mappedId) && match.Value.EndsWith(",") ? mappedId + "," : mappedId;
                    },
                    RegexOptions.Compiled);

                value = Regex.Replace(
                    Convert.ToString(value),
                    @"(?<=""milestones"":\[(\d+,)*)\d+,?",
                    match =>
                    {
                        var mappedId = Convert.ToString(columnMapper.GetMapping("projects_milestones", "id", match.Value.TrimEnd(',')));
                        return !string.IsNullOrEmpty(mappedId) && match.Value.EndsWith(",") ? mappedId + "," : mappedId;
                    },
                    RegexOptions.Compiled);

                return true;
            }

            return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relations, ref value);
        }
    }
}


<|start_filename|>module/ASC.Thumbnails/config/index.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


const nconf = require('nconf');
const path = require('path');

nconf.argv()
    .env()
    .file({ file: path.join(__dirname, 'config.json') });

nconf.noThumb = nconf.get("noThumb");

const ext = nconf.get("fileExt");
let savePath = nconf.get("savePath");

if(!path.isAbsolute(savePath)){
    savePath = path.join(__dirname, "..", savePath);
}

nconf.pathToFile = (name) => path.join(savePath, name + ext);
module.exports = nconf;


<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Classes/HealthCheckRunner.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Notify.Senders;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.HealthCheck.Models;
using ASC.HealthCheck.Resources;
using ASC.HealthCheck.Settings;
using ASC.Notify.Config;
using ASC.Notify.Messages;
using log4net;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;

namespace ASC.HealthCheck.Classes
{
    public static class HealthCheckRunner
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(HealthCheckRunner));
        private static readonly IServiceRepository serviceRepository = new ServiceRepository();
        private static volatile bool alreadyNotifyAboutSmallDiskSpace;
        public static readonly ConcurrentDictionary<string, Timer> TimerDictionary = new ConcurrentDictionary<string, Timer>();
        public static IDictionary<string, INotifySender> NotifySenders = NotifyServiceCfg.Senders;

        private const string FakeTenantAlias = "fake-tenant-alias";
        public const string FakeUserId = "83A07DA6-EEA5-4DA3-B325-C2F4BCBA7DF2";
        public const int OneMb = 1048576;
        public const int OneGb = OneMb * 1024;
        public const string OneHundreedMb = "104857600";

        public static IServiceRepository ServiceRepository { get { return serviceRepository; } }

        public static void Run()
        {
            try
            {
                log.Debug("--Run HealthCheck--");

                if (GetFakeTenant() == 0)
                {
                    log.ErrorFormat("Error! Could not create tenant alias = {0}", FakeTenantAlias);
                    return;
                }

                GetFakeUserId();

               var mainLoopPeriod = HealthCheckCfgSectionHandler.Instance.MainLoopPeriod;

                foreach (var service in HealthCheckCfgSectionHandler.Instance.ServiceNames)
                {
                    log.DebugFormat("Add service {0} for checking.", service);
                    serviceRepository.Add(service);
                    TimerDictionary.TryAdd(service.ToString(), new Timer(IdleTimeout, service, TimeSpan.Zero, mainLoopPeriod));
                }

                IDriveSpaceChecker spaceChecker = new DriveSpaceChecker();
                TimerDictionary.TryAdd(spaceChecker.DriveName, new Timer(IdleTimeoutDriveSpace, spaceChecker.DriveName, TimeSpan.Zero, mainLoopPeriod));
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error on HealthCheckRunner.Run. {0} {1}", ex, ex.InnerException != null ? ex.InnerException.Message : string.Empty);
            }
        }

        public static void Stop()
        {
            try
            {
                log.Debug("--Stop HealthCheck--");
                foreach (var keyValue in TimerDictionary)
                {
                    keyValue.Value.Dispose();
                }
                TimerDictionary.Clear();
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error on HealthCheckRunner.Stop. {0} {1} {2}",
                    ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : string.Empty);
            }
        }

        public static bool ServerStatusIsOk()
        {
            foreach (var serviceObject in ServiceRepository.GetServicesSnapshot())
            {
                try
                {
                    if (serviceObject.Message != string.Empty)
                    {
                        log.DebugFormat("ServerStatusIsOk: serviceObject is not OK, ServiceName = {0}, Status = {1}",
                            serviceObject.ServiceName, serviceObject.Status);
                        return false; // "Error";
                    }
                }
                catch (InvalidOperationException)
                {
                    // serviceObject not found
                    log.DebugFormat("ServerStatusIsOk: serviceObject not found, ServiceName = {0}", serviceObject.ServiceName);
                }
            }
            log.Debug("ServerStatusIsOk: all is OK!");
            return true; // "Works";
        }

        private static int GetFakeTenant()
        {
            var fakeTenant = CoreContext.TenantManager.GetTenant(FakeTenantAlias);

            /*
var tenants = CoreContext.TenantManager.GetTenants();

if (fakeTenant != null)
{
    tenants = tenants.Where(t => t.TenantId != fakeTenant.TenantId).ToList();
}

if (tenants.Count() <= 0 || !CoreContext.TenantManager.GetTenantQuota(tenants.First().TenantId).HealthCheck)
{
    log.Debug("Service wasn't started. There is no correct license for HealthCheck.");
    return;
}*/

            if (fakeTenant == null)
            {
                fakeTenant = new Tenant
                {
                    TenantAlias = FakeTenantAlias
                };
                fakeTenant = CoreContext.TenantManager.SaveTenant(fakeTenant);
            }

            if (fakeTenant != null)
            {
                var healthcheckSettings = HealthCheckSettingsAccessor.GetHealthCheckSettings();
                healthcheckSettings.FakeTenantId = fakeTenant.TenantId;
                HealthCheckSettingsAccessor.SaveHealthCheckSettings(healthcheckSettings);

                CoreContext.TenantManager.SetCurrentTenant(fakeTenant.TenantId);

                return fakeTenant.TenantId;
            }

            return 0;
        }

        private static void GetFakeUserId()
        {
            var userGuid = new Guid(FakeUserId);
            var userInfo = CoreContext.UserManager.GetUsers(userGuid);
            if (userInfo == Constants.LostUser)
            {
                userInfo = new UserInfo
                {
                    ID = userGuid,
                    UserName = "fake-user",
                    Email = "<EMAIL>",
                    FirstName = "fake",
                    LastName = "user",
                    ActivationStatus = EmployeeActivationStatus.Activated
                };
                try
                {
                    SecurityContext.AuthenticateMe(Core.Configuration.Constants.CoreSystem);
                    CoreContext.UserManager.SaveUserInfo(userInfo);
                }
                finally
                {
                    SecurityContext.Logout();
                }
            }


            /*
            var ascAuthKey = SecurityContext.AuthenticateMe(userGuid);

            if (!MailBoxExists(tenant, userInfo, ascAuthKey))
            {
                CreateMailBox(tenant, userInfo, ascAuthKey);
            }
            */
        }

        private static void IdleTimeoutDriveSpace(object e)
        {
            try
            {
                var healthCheckSettings = HealthCheckSettingsAccessor.GetHealthCheckSettings();

                /*var tenants = CoreContext.TenantManager.GetTenants().Where(t => t.TenantId != healthCheckSettings.FakeTenantId).ToList();
                if (tenants.Count() <= 0 || !CoreContext.TenantManager.GetTenantQuota(tenants.First().TenantId).HealthCheck)
                {
                    log.Debug("Service wasn't started. There is no correct license for HealthCheck.");
                    return;
                }*/
                log.Debug("Begin IdleTimeoutDriveSpace");

                CoreContext.TenantManager.SetCurrentTenant(healthCheckSettings.FakeTenantId);
                Thread.CurrentThread.CurrentCulture = CoreContext.TenantManager.GetCurrentTenant().GetCulture();

                IDriveSpaceChecker spaceChecker = new DriveSpaceChecker();
                spaceChecker.GetTotalAndFreeSpace();
                var freeSpace = spaceChecker.TotalFreeSpace;
                if (freeSpace == -1)
                {
                    log.Error("Not found drive name.");
                    return;
                }
                var space = freeSpace / OneMb + " Mb";
                var driveSpaceThreashold = HealthCheckCfgSectionHandler.Instance.DriveSpaceThreashold;
                if (freeSpace >= driveSpaceThreashold)
                {
                    log.DebugFormat("It is enough free disk space, {0}.", space);
                    alreadyNotifyAboutSmallDiskSpace = false;
                    return;
                }

                // Send sms and e-mail about small free disk space
                log.WarnFormat("It isn't enough free disk space, {0}.", space);
                if (alreadyNotifyAboutSmallDiskSpace) return;

                if (!healthCheckSettings.SendNotify || (!healthCheckSettings.SendEmail && !healthCheckSettings.SendSms))
                {
                    log.Debug("Notification isn't sent. Notifications disabled.");
                    return;
                }

                alreadyNotifyAboutSmallDiskSpace = true;

                if (healthCheckSettings.SendEmail)
                {
                    log.Debug("Send email notification");
                    SendEmail("Onlyoffice:" + HealthCheckResource.SmallDriveSpace + ": " + space,
                        HealthCheckResource.SmallDriveSpace + ": " + space, healthCheckSettings);
                }
                else
                {
                    log.Debug("Email isn't sent. Email notification disabled.");
                }

                if (healthCheckSettings.SendSms)
                {
                    log.Debug("Send SMS notification");
                    SendSms(HealthCheckResource.SmallDriveSpace + ": " + space, healthCheckSettings);
                }
                else
                {
                    log.Debug("SMS isn't sent. SMS notifications disabled.");
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error on IdleTimeoutDriveSpace. {0} {1} {2}",
                    ex.Message, ex.StackTrace, ex.InnerException != null ? ex.InnerException.Message : string.Empty);
            }
            finally
            {
                log.Debug("End IdleTimeoutDriveSpace");
            }
        }

        private static void IdleTimeout(object e)
        {
            var healthCheckSettings = HealthCheckSettingsAccessor.GetHealthCheckSettings();
            /*
            var tenants = CoreContext.TenantManager.GetTenants().Where(t => t.TenantId != healthCheckSettings.FakeTenantId).ToList();
            if (tenants.Count() <= 0 || !CoreContext.TenantManager.GetTenantQuota(tenants.First().TenantId).HealthCheck)
            {
                log.Debug("Service wasn't started. There is no correct license for HealthCheck.");
                return;
            }*/
            log.Debug("Begin IdleTimeout");

            CoreContext.TenantManager.SetCurrentTenant(healthCheckSettings.FakeTenantId);
            Thread.CurrentThread.CurrentCulture = CoreContext.TenantManager.GetCurrentTenant().GetCulture();

            try
            {
                var serviceName = (ServiceEnum)e;

                ServiceStatus serviceStatus;
                using (var xplatServiceController = XplatServiceController.GetXplatServiceController(serviceName))
                {
                    serviceStatus = xplatServiceController.GetServiceStatus();
                }

                switch (serviceStatus)
                {
                    case ServiceStatus.StartPending:
                        // wait till started
                        break;
                    case ServiceStatus.Running:
                        var result = serviceRepository.GetService(serviceName).Check(healthCheckSettings.FakeTenantId);

                        if (result != null)
                        {
                            serviceRepository.SetStates(serviceName,
                                (result == string.Empty
                                    ? ServiceStatus.Running
                                    : ServiceStatus.NotFound).GetStringStatus(), result);
                            //if (result != string.Empty)
                            //{
                            //    HasAttempt(serviceName);
                            //}
                            //else
                            //{
                            //    serviceRepository.DropAttempt(serviceName);
                            //}
                        }
                        break;
                    case ServiceStatus.NotFound:
                        serviceRepository.SetStates(serviceName, ServiceStatus.NotFound.GetStringStatus(), ServiceStatus.NotFound.GetMessageStatus());
                        //HasAttempt(serviceName);
                        break;
                    default:
                        serviceRepository.SetStates(serviceName, ServiceStatus.Stopped.GetStringStatus(), ServiceStatus.Stopped.GetMessageStatus());
                        //HasAttempt(serviceName);
                        break;
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error on IdleTimeout. {0} {1}", ex.ToString(),
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
            }
            finally
            {
                log.Debug("End IdleTimeout");
            }
        }

        private static void HasAttempt(ServiceEnum serviceName)
        {
            log.DebugFormat("HasAttempt: service = {0}", serviceName);
            if (serviceRepository.ShouldRestart(serviceName))
            {
                log.DebugFormat("HasAttempt: ShouldRestart is true, service = {0}", serviceName);
                var healthCheckServiceManager = new HealthCheckServiceManager(ServiceRepository);
                healthCheckServiceManager.StopService(serviceName);
                Thread.Sleep(5);
                healthCheckServiceManager.StartService(serviceName);
                return;
            }
            if (!serviceRepository.HasAtempt(serviceName))
            {
                // Send sms and e-mail about service/site/zone
                var service = ServiceRepository.GetService(serviceName);
                log.ErrorFormat("There are some problem with serviceName = {0}, status = {1}, Message = {2}.",
                    serviceName, service.Status, service.Message);

                var healthCheckSettings = HealthCheckSettingsAccessor.GetHealthCheckSettings();

                if (healthCheckSettings.SendNotify)
                {
                    if (healthCheckSettings.SendEmail)
                    {
                        log.Debug("Send email notification.");
                        SendEmail(String.Format("Onlyoffice {0} problem.", serviceName),
                            String.Format(HealthCheckResource.ServiceProblem, serviceName, service.Status, service.Message),
                            healthCheckSettings);
                    }
                    else
                    {
                        log.Debug("Email isn't sent. Email notification disabled.");
                    }
                    if (healthCheckSettings.SendSms)
                    {
                        log.Debug("Send SMS notification.");
                        SendSms(String.Format(HealthCheckResource.ServiceProblem,
                            serviceName, service.Status, service.Message), healthCheckSettings);
                    }
                    else
                    {
                        log.Debug("SMS isn't sent. SMS notification disabled.");
                    }
                }
                else
                {
                    log.Debug("Notification isn't sent. Notification disabled.");
                }
            }
        }

        /*
        private static bool MailBoxExists(Tenant tenant, UserInfo userInfo, string ascAuthKey)
        {
            string portalUrl = ConfigurationManager.AppSettings["portalUrl"] ?? "http://localhost/";
            var client = new RestClient(portalUrl);
            var request = new RestRequest("/api/2.0/mail/accounts/" + HttpUtility.UrlEncode(userInfo.Email), Method.GET);
            request.AddCookie("asc_auth_key", ascAuthKey);
            var response = client.Execute(request);
            var jObject = JObject.Parse(response.Content);
            if (response.StatusCode == HttpStatusCode.InternalServerError)
            {
                if (jObject["error"]["type"].ToString() == "System.NullReferenceException")
                {
                    log.DebugFormat("MailBox account {0} does not exist", userInfo.Email);
                    return false;
                }
            }
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new Exception("Can't get mailBox using API. Response code = " + response.StatusCode, response.ErrorException);
            }
            return true;
        }
        
        private static void CreateMailBox(Tenant tenant, UserInfo userInfo, string ascAuthKey)
        {
            string portalUrl = ConfigurationManager.AppSettings["portalUrl"] ?? "http://localhost/";
            var client = new RestClient(portalUrl);
            var request = new RestRequest();
            request.AddCookie("asc_auth_key", ascAuthKey);
        }
        */

        private static void SendEmail(string subject, string message, HealthCheckSettings healthCheckSettings)
        {
            if (healthCheckSettings.Emails != null && healthCheckSettings.Emails.Count != 0)
            {
                log.DebugFormat("SendEmail: subject = {0}, message = {1}", subject, message);
                var sender = NotifySenders["email.sender"];
                sender.Send(new NotifyMessage
                {
                    Content = message,
                    Subject = subject,
                    CreationDate = DateTime.UtcNow,
                    Sender = Core.Configuration.Constants.NotifyEMailSenderSysName,
                    To = string.Join("|", healthCheckSettings.Emails),
                    From = MailAddressUtils.Create(CoreContext.Configuration.SmtpSettings.SenderAddress,
                        CoreContext.Configuration.SmtpSettings.SenderDisplayName).ToString()
                });
            }
            else
            {
                log.Debug("SendEmail: healthCheckSettings.Emails is empty, there are no recipients");
            }
        }

        private static void SendSms(string message, HealthCheckSettings healthCheckSettings)
        {
            if (healthCheckSettings.PhoneNumbers != null && healthCheckSettings.PhoneNumbers.Count != 0)
            {
                log.DebugFormat("SendSms: message = {0}", message);
                ISmsSender smsSender = new SmsSender();

                foreach (var t in healthCheckSettings.PhoneNumbers)
                {
                    smsSender.SendSMS(t, message, healthCheckSettings);
                }
            }
            else
            {
                log.Debug("SendSms: healthCheckSettings.PhoneNumbers is empty, there are no recipients");
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/_Obsolete/SmtpClientEx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SMTP.Client
{
    #region usings

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Security.Cryptography;
    using System.Text;
    using System.Threading;
    using Dns.Client;
    using Mime;

    #endregion

    /// <summary>
    /// Is called when asynchronous command had completed.
    /// </summary>
    public delegate void CommadCompleted(SocketCallBackResult result, Exception exception);

    /// <summary>
    /// SMTP client.
    /// </summary>
    [Obsolete("Use SMTP_Client instead !")]
    public class SmtpClientEx : IDisposable
    {
        #region Nested type: Auth_state_data

        /// <summary>
        /// Provides state date for BeginAuthenticate method.
        /// </summary>
        private class Auth_state_data
        {
            #region Members

            private readonly string m_Password = "";
            private readonly CommadCompleted m_pCallback;
            private readonly string m_UserName = "";

            #endregion

            #region Properties

            /// <summary>
            /// Gets user name.
            /// </summary>
            public string UserName
            {
                get { return m_UserName; }
            }

            /// <summary>
            /// Gets user password.
            /// </summary>
            public string Password
            {
                get { return m_Password; }
            }

            /// <summary>
            /// Gets callback what must be called when aynchrounous execution completes.
            /// </summary>
            public CommadCompleted Callback
            {
                get { return m_pCallback; }
            }

            /// <summary>
            /// Gets or sets user data.
            /// </summary>
            public object Tag { get; set; }

            #endregion

            #region Constructor

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="userName">User name.</param>
            /// <param name="password">Password.</param>
            /// <param name="callback">Callback what must be called when aynchrounous execution completes.</param>
            public Auth_state_data(string userName, string password, CommadCompleted callback)
            {
                m_UserName = userName;
                m_Password = password;
                m_pCallback = callback;
            }

            #endregion
        }

        #endregion

        #region Events

        /// <summary>
        /// Occurs when SMTP session has finished and session log is available.
        /// </summary>
        public event LogEventHandler SessionLog = null;

        #endregion

        #region Members

        private bool m_Authenticated;
        private bool m_Connected;
        private string[] m_pDnsServers;
        private SocketLogger m_pLogger;
        private SocketEx m_pSocket;
        private bool m_Supports_Bdat;
        private bool m_Supports_CramMd5;
        private bool m_Supports_Login;
        private bool m_Supports_Size;

        #endregion

        #region Properties

        /// <summary>
        /// Gets local endpoint. Returns null if smtp client isn't connected.
        /// </summary>
        public EndPoint LocalEndpoint
        {
            get
            {
                if (m_pSocket != null)
                {
                    return m_pSocket.LocalEndPoint;
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets remote endpoint. Returns null if smtp client isn't connected.
        /// </summary>
        public EndPoint RemoteEndPoint
        {
            get
            {
                if (m_pSocket != null)
                {
                    return m_pSocket.RemoteEndPoint;
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets or sets dns servers.
        /// </summary>
        public string[] DnsServers
        {
            get { return m_pDnsServers; }

            set { m_pDnsServers = value; }
        }

        /// <summary>
        /// Gets if smtp client is connected.
        /// </summary>
        public bool Connected
        {
            get { return m_Connected; }
        }

        /// <summary>
        /// Gets if pop3 client is authenticated.
        /// </summary>
        public bool Authenticated
        {
            get { return m_Authenticated; }
        }

        /// <summary>
        /// Gets when was last activity.
        /// </summary>
        public DateTime LastDataTime
        {
            get { return m_pSocket.LastActivity; }
        }

        /// <summary>
        /// Gets log entries that are currently in log buffer. Returns null if socket not connected or no logging enabled.
        /// </summary>
        public SocketLogger SessionActiveLog
        {
            get
            {
                if (m_pSocket == null)
                {
                    return null;
                }
                else
                {
                    return m_pSocket.Logger;
                }
            }
        }

        /// <summary>
        /// Gets how many bytes are readed through smtp client.
        /// </summary>
        public long ReadedCount
        {
            get
            {
                if (!m_Connected)
                {
                    throw new Exception("You must connect first");
                }

                return m_pSocket.ReadedCount;
            }
        }

        /// <summary>
        /// Gets how many bytes are written through smtp client.
        /// </summary>
        public long WrittenCount
        {
            get
            {
                if (!m_Connected)
                {
                    throw new Exception("You must connect first");
                }

                return m_pSocket.WrittenCount;
            }
        }

        /// <summary>
        /// Gets if the connection is an SSL connection.
        /// </summary>
        public bool IsSecureConnection
        {
            get
            {
                if (!m_Connected)
                {
                    throw new Exception("You must connect first");
                }

                return m_pSocket.SSL;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Sends specified message to specified smart host.
        /// </summary>
        /// <param name="smartHost">Smarthost name or IP.</param>
        /// <param name="port">SMTP port number. Normally this is 25.</param>
        /// <param name="hostName">Host name reported to SMTP server.</param>
        /// <param name="message">Mime message to send.</param>
        public static void QuickSendSmartHost(string smartHost, int port, string hostName, Mime message)
        {
            QuickSendSmartHost(smartHost, port, hostName, "", "", message);
        }

        /// <summary>
        /// Sends specified message to specified smart host.
        /// </summary>
        /// <param name="smartHost">Smarthost name or IP.</param>
        /// <param name="port">SMTP port number. Normally this is 25.</param>
        /// <param name="hostName">Host name reported to SMTP server.</param>
        /// <param name="userName">SMTP user name. Note: Pass empty string if no authentication wanted.</param>
        /// <param name="password">SMTP password.</param>
        /// <param name="message">Mime message to send.</param>
        public static void QuickSendSmartHost(string smartHost,
                                              int port,
                                              string hostName,
                                              string userName,
                                              string password,
                                              Mime message)
        {
            QuickSendSmartHost(smartHost, port, false, hostName, userName, password, message);
        }

        /// <summary>
        /// Sends specified message to specified smart host.
        /// </summary>
        /// <param name="smartHost">Smarthost name or IP.</param>
        /// <param name="port">SMTP port number. Default SMTP port is 25 and SSL port is 465.</param>
        /// <param name="ssl">Specifies if to connected via SSL.</param>
        /// <param name="hostName">Host name reported to SMTP server.</param>
        /// <param name="userName">SMTP user name. Note: Pass empty string if no authentication wanted.</param>
        /// <param name="password">SMTP password.</param>
        /// <param name="message">Mime message to send.</param>
        public static void QuickSendSmartHost(string smartHost,
                                              int port,
                                              bool ssl,
                                              string hostName,
                                              string userName,
                                              string password,
                                              Mime message)
        {
            string from = "";
            if (message.MainEntity.From != null)
            {
                MailboxAddress[] addresses = message.MainEntity.From.Mailboxes;
                if (addresses.Length > 0)
                {
                    from = addresses[0].EmailAddress;
                }
            }

            ArrayList recipients = new ArrayList();
            if (message.MainEntity.To != null)
            {
                MailboxAddress[] addresses = message.MainEntity.To.Mailboxes;
                foreach (MailboxAddress address in addresses)
                {
                    recipients.Add(address.EmailAddress);
                }
            }
            if (message.MainEntity.Cc != null)
            {
                MailboxAddress[] addresses = message.MainEntity.Cc.Mailboxes;
                foreach (MailboxAddress address in addresses)
                {
                    recipients.Add(address.EmailAddress);
                }
            }
            if (message.MainEntity.Bcc != null)
            {
                MailboxAddress[] addresses = message.MainEntity.Bcc.Mailboxes;
                foreach (MailboxAddress address in addresses)
                {
                    recipients.Add(address.EmailAddress);
                }
            }
            string[] to = new string[recipients.Count];
            recipients.CopyTo(to);

            MemoryStream messageStream = new MemoryStream();
            message.ToStream(messageStream);
            messageStream.Position = 0;

            // messageStream
            QuickSendSmartHost(smartHost, port, ssl, hostName, userName, password, from, to, messageStream);
        }

        /// <summary>
        /// Sends specified message to specified smart host. NOTE: Message sending starts from message stream current posision.
        /// </summary>
        /// <param name="smartHost">Smarthost name or IP.</param>
        /// <param name="port">SMTP port number. Normally this is 25.</param>
        /// <param name="hostName">Host name reported to SMTP server.</param>
        /// <param name="from">From address reported to SMTP server.</param>
        /// <param name="to">Message recipients.</param>
        /// <param name="messageStream">Message stream. NOTE: Message sending starts from message stream current posision.</param>
        public static void QuickSendSmartHost(string smartHost,
                                              int port,
                                              string hostName,
                                              string from,
                                              string[] to,
                                              Stream messageStream)
        {
            QuickSendSmartHost(smartHost, port, false, hostName, "", "", from, to, messageStream);
        }

        /// <summary>
        /// Sends specified message to specified smart host. NOTE: Message sending starts from message stream current posision.
        /// </summary>
        /// <param name="smartHost">Smarthost name or IP.</param>
        /// <param name="port">SMTP port number. Normally this is 25.</param>
        /// <param name="hostName">Host name reported to SMTP server.</param>
        /// <param name="userName">SMTP user name. Note: Pass empty string if no authentication wanted.</param>
        /// <param name="password">SMTP password.</param>
        /// <param name="from">From address reported to SMTP server.</param>
        /// <param name="to">Message recipients.</param>
        /// <param name="messageStream">Message stream. NOTE: Message sending starts from message stream current posision.</param>
        public static void QuickSendSmartHost(string smartHost,
                                              int port,
                                              string hostName,
                                              string userName,
                                              string password,
                                              string from,
                                              string[] to,
                                              Stream messageStream)
        {
            QuickSendSmartHost(smartHost, port, false, hostName, userName, password, from, to, messageStream);
        }

        /// <summary>
        /// Sends specified message to specified smart host. NOTE: Message sending starts from message stream current posision.
        /// </summary>
        /// <param name="smartHost">Smarthost name or IP.</param>
        /// <param name="port">SMTP port number. Default SMTP port is 25 and SSL port is 465.</param>
        /// <param name="ssl">Specifies if to connected via SSL.</param>
        /// <param name="hostName">Host name reported to SMTP server.</param>
        /// <param name="userName">SMTP user name. Note: Pass empty string if no authentication wanted.</param>
        /// <param name="password">SMTP password.</param>
        /// <param name="from">From address reported to SMTP server.</param>
        /// <param name="to">Message recipients.</param>
        /// <param name="messageStream">Message stream. NOTE: Message sending starts from message stream current posision.</param>
        public static void QuickSendSmartHost(string smartHost,
                                              int port,
                                              bool ssl,
                                              string hostName,
                                              string userName,
                                              string password,
                                              string from,
                                              string[] to,
                                              Stream messageStream)
        {
            using (SmtpClientEx smtp = new SmtpClientEx())
            {
                smtp.Connect(smartHost, port, ssl);
                smtp.Ehlo(hostName);
                if (userName.Length > 0)
                {
                    smtp.Authenticate(userName, password);
                }
                smtp.SetSender(MailboxAddress.Parse(from).EmailAddress,
                               messageStream.Length - messageStream.Position);
                foreach (string t in to)
                {
                    smtp.AddRecipient(MailboxAddress.Parse(t).EmailAddress);
                }

                smtp.SendMessage(messageStream);
            }
        }

        /// <summary>
        /// Cleasns up resources and disconnect smtp client if open.
        /// </summary>
        public void Dispose()
        {
            try
            {
                Disconnect();
            }
            catch {}
        }

        /// <summary>
        /// Connects to sepcified host.
        /// </summary>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect.</param>
        public void Connect(string host, int port)
        {
            Connect(null, host, port, false);
        }

        /// <summary>
        /// Connects to sepcified host.
        /// </summary>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect. Default SMTP port is 25 and SSL port is 465.</param>
        /// <param name="ssl">Specifies if to connected via SSL.</param>
        public void Connect(string host, int port, bool ssl)
        {
            Connect(null, host, port, ssl);
        }

        /// <summary>
        /// Connects to sepcified host.
        /// </summary>
        /// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect.</param>
        public void Connect(IPEndPoint localEndpoint, string host, int port)
        {
            Connect(localEndpoint, host, port, false);
        }

        /// <summary>
        /// Connects to sepcified host.
        /// </summary>
        /// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect.</param>
        /// <param name="ssl">Specifies if to connected via SSL. Default SMTP port is 25 and SSL port is 465.</param>
        public void Connect(IPEndPoint localEndpoint, string host, int port, bool ssl)
        {
            m_pSocket = new SocketEx();
            if (localEndpoint != null)
            {
                m_pSocket.Bind(localEndpoint);
            }

            // Create logger
            if (SessionLog != null)
            {
                m_pLogger = new SocketLogger(m_pSocket.RawSocket, SessionLog);
                m_pLogger.SessionID = Guid.NewGuid().ToString();
                m_pSocket.Logger = m_pLogger;
            }

            if (host.IndexOf("@") == -1)
            {
                m_pSocket.Connect(host, port, ssl);
            }
            else
            {
                //---- Parse e-domain -------------------------------//
                string domain = host;

                // eg. Ivx <<EMAIL>>
                if (domain.IndexOf("<") > -1 && domain.IndexOf(">") > -1)
                {
                    domain = domain.Substring(domain.IndexOf("<") + 1,
                                              domain.IndexOf(">") - domain.IndexOf("<") - 1);
                }

                if (domain.IndexOf("@") > -1)
                {
                    domain = domain.Substring(domain.LastIndexOf("@") + 1);
                }

                if (domain.Trim().Length == 0)
                {
                    if (m_pLogger != null)
                    {
                        m_pLogger.AddTextEntry("Destination address '" + host + "' is invalid, aborting !");
                    }
                    throw new Exception("Destination address '" + host + "' is invalid, aborting !");
                }

                //--- Get MX record -------------------------------------------//
                Dns_Client dns = new Dns_Client();
                Dns_Client.DnsServers = m_pDnsServers;
                DnsServerResponse dnsResponse = dns.Query(domain, QTYPE.MX);

                bool connected = false;
                switch (dnsResponse.ResponseCode)
                {
                    case RCODE.NO_ERROR:
                        DNS_rr_MX[] mxRecords = dnsResponse.GetMXRecords();

                        // Try all available hosts by MX preference order, if can't connect specified host.
                        foreach (DNS_rr_MX mx in mxRecords)
                        {
                            try
                            {
                                if (m_pLogger != null)
                                {
                                    m_pLogger.AddTextEntry("Connecting with mx record to: " + mx.Host);
                                }
                                m_pSocket.Connect(mx.Host, port, ssl);
                                connected = true;
                                break;
                            }
                            catch (Exception x)
                            {
                                // Just skip and let for to try next host.									
                                if (m_pLogger != null)
                                {
                                    m_pLogger.AddTextEntry("Failed connect to: " + mx.Host + " error:" +
                                                           x.Message);
                                }
                            }
                        }

                        // None of MX didn't connect
                        if (mxRecords.Length > 0 && !connected)
                        {
                            throw new Exception("Destination email server is down");
                        }

                        /* Rfc 2821 5
						 If no MX records are found, but an A RR is found, the A RR is treated as
						 if it was associated with an implicit MX RR, with a preference of 0,
						 pointing to that host.
						*/
                        if (!connected)
                        {
                            // Try to connect with A record
                            IPAddress[] ipEntry = null;
                            try
                            {
                                if (m_pLogger != null)
                                {
                                    m_pLogger.AddTextEntry("No mx record, trying to get A record for: " +
                                                           domain);
                                }
                                ipEntry = Dns_Client.Resolve(domain);
                            }
                            catch
                            {
                                if (m_pLogger != null)
                                {
                                    m_pLogger.AddTextEntry("Invalid domain,no MX or A record: " + domain);
                                }
                                throw new Exception("Invalid domain,no MX or A record: " + domain);
                            }

                            try
                            {
                                if (m_pLogger != null)
                                {
                                    m_pLogger.AddTextEntry("Connecting with A record to:" + domain);
                                }
                                m_pSocket.Connect(domain, port, ssl);
                            }
                            catch
                            {
                                if (m_pLogger != null)
                                {
                                    m_pLogger.AddTextEntry("Failed connect to:" + domain);
                                }
                                throw new Exception("Destination email server is down");
                            }
                        }
                        break;

                    case RCODE.NAME_ERROR:
                        if (m_pLogger != null)
                        {
                            m_pLogger.AddTextEntry("Invalid domain,no MX or A record: " + domain);
                        }
                        throw new Exception("Invalid domain,no MX or A record: " + domain);

                    case RCODE.SERVER_FAILURE:
                        if (m_pLogger != null)
                        {
                            m_pLogger.AddTextEntry("Dns server unvailable.");
                        }
                        throw new Exception("Dns server unvailable.");
                }
            }

            /*
			 * Notes: Greeting may be single or multiline response.
			 *		
			 * Examples:
			 *		220<SP>SMTP server ready<CRLF> 
			 * 
			 *		220-SMTP server ready<CRLF>
			 *		220-Addtitional text<CRLF>
			 *		220<SP>final row<CRLF>
			 * 
			*/

            // Read server response
            string responseLine = m_pSocket.ReadLine(1000);
            while (!responseLine.StartsWith("220 "))
            {
                // If lisne won't start with 220, then its error response
                if (!responseLine.StartsWith("220"))
                {
                    throw new Exception(responseLine);
                }

                responseLine = m_pSocket.ReadLine(1000);
            }

            m_Connected = true;
        }

        /// <summary>
        /// Starts connection to specified host.
        /// </summary>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect.</param>
        /// <param name="callback">Callback to be called if connect ends.</param>
        public void BeginConnect(string host, int port, CommadCompleted callback)
        {
            BeginConnect(null, host, port, false, callback);
        }

        /// <summary>
        /// Starts connection to specified host.
        /// </summary>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect.</param>
        /// <param name="ssl">Specifies if to connected via SSL.</param>
        /// <param name="callback">Callback to be called if connect ends.</param>
        public void BeginConnect(string host, int port, bool ssl, CommadCompleted callback)
        {
            BeginConnect(null, host, port, ssl, callback);
        }

        /// <summary>
        /// Starts connection to specified host.
        /// </summary>
        /// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect.</param>
        /// <param name="callback">Callback to be called if connect ends.</param>
        public void BeginConnect(IPEndPoint localEndpoint, string host, int port, CommadCompleted callback)
        {
            BeginConnect(localEndpoint, host, port, false, callback);
        }

        /// <summary>
        /// Starts connection to specified host.
        /// </summary>
        /// <param name="localEndpoint">Sets local endpoint. Pass null, to use default.</param>
        /// <param name="host">Host name or IP address.</param>
        /// <param name="port">Port where to connect.</param>
        /// <param name="ssl">Specifies if to connected via SSL.</param>
        /// <param name="callback">Callback to be called if connect ends.</param>
        public void BeginConnect(IPEndPoint localEndpoint,
                                 string host,
                                 int port,
                                 bool ssl,
                                 CommadCompleted callback)
        {
            ThreadPool.QueueUserWorkItem(BeginConnect_workerThread,
                                         new object[] {localEndpoint, host, port, ssl, callback});
        }

        /*		/// <summary>
		/// Starts disconnecting SMTP client.
		/// </summary>
		public void BeginDisconnect()
		{
			if(!m_Connected){
				throw new Exception("You must connect first");
			}
		}*/

        /// <summary>
        /// Disconnects smtp client from server.
        /// </summary>
        public void Disconnect()
        {
            try
            {
                if (m_pSocket != null && m_pSocket.Connected)
                {
                    m_pSocket.WriteLine("QUIT");

                    m_pSocket.Shutdown(SocketShutdown.Both);
                }
            }
            catch {}

            m_pSocket = null;
            m_Connected = false;
            m_Supports_Size = false;
            m_Supports_Bdat = false;
            m_Supports_Login = false;
            m_Supports_CramMd5 = false;

            if (m_pLogger != null)
            {
                m_pLogger.Flush();
                m_pLogger = null;
            }
        }

        /// <summary>
        /// Switches SMTP connection to SSL.
        /// </summary>
        public void StartTLS()
        {
            /* RFC 2487 STARTTLS 5. STARTTLS Command.
                STARTTLS with no parameters.
              
                After the client gives the STARTTLS command, the server responds with
                one of the following reply codes:

                220 Ready to start TLS
                501 Syntax error (no parameters allowed)
                454 TLS not available due to temporary reason
            */

            if (!m_Connected)
            {
                throw new Exception("You must connect first !");
            }
            if (m_Authenticated)
            {
                throw new Exception("The STLS command is only valid in non-authenticated state !");
            }
            if (m_pSocket.SSL)
            {
                throw new Exception("Connection is already secure !");
            }

            m_pSocket.WriteLine("STARTTLS");

            string reply = m_pSocket.ReadLine();
            if (!reply.ToUpper().StartsWith("220"))
            {
                throw new Exception("Server returned:" + reply);
            }

            m_pSocket.SwitchToSSL_AsClient();
        }

        /// <summary>
        /// Start TLS(SSL) negotiation asynchronously.
        /// </summary>
        /// <param name="callback">The method to be called when the asynchronous StartTLS operation is completed.</param>
        public void BeginStartTLS(CommadCompleted callback)
        {
            ThreadPool.QueueUserWorkItem(BeginStartTLS_workerThread, callback);
        }

        /// <summary>
        /// Does EHLO command. If server don't support EHLO, tries HELO.
        /// </summary>
        /// <param name="hostName">Host name which is reported to SMTP server.</param>
        public void Ehlo(string hostName)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* Rfc 2821 192.168.3.11 EHLO
			 * Syntax: "EHLO" SP Domain CRLF
			*/

            if (hostName.Length == 0)
            {
                hostName = Dns.GetHostName();
            }

            // Send EHLO command to server
            m_pSocket.WriteLine("EHLO " + hostName);

            string responseLine = m_pSocket.ReadLine();
            // Response line must start with 250 or otherwise it's error response,
            // try HELO
            if (!responseLine.StartsWith("250"))
            {
                // Send HELO command to server
                m_pSocket.WriteLine("HELO " + hostName);

                responseLine = m_pSocket.ReadLine();
                // HELO failed, return error
                if (!responseLine.StartsWith("250"))
                {
                    throw new Exception(responseLine);
                }
            }

            /* RFC 2821 4.1.1.1 EHLO
				*	Examples:
				*		250-domain<SP>free_text<CRLF>
				*       250-EHLO_keyword<CRLF>
				*		250<SP>EHLO_keyword<CRLF>
				* 
				*		250<SP> specifies that last EHLO response line.
			*/

            while (!responseLine.StartsWith("250 "))
            {
                //---- Store supported ESMTP features --------------------//
                if (responseLine.ToLower().IndexOf("size") > -1)
                {
                    m_Supports_Size = true;
                }
                else if (responseLine.ToLower().IndexOf("chunking") > -1)
                {
                    m_Supports_Bdat = true;
                }
                else if (responseLine.ToLower().IndexOf("cram-md5") > -1)
                {
                    m_Supports_CramMd5 = true;
                }
                else if (responseLine.ToLower().IndexOf("login") > -1)
                {
                    m_Supports_Login = true;
                }
                //--------------------------------------------------------//

                // Read next EHLO response line
                responseLine = m_pSocket.ReadLine();
            }
        }

        /// <summary>
        /// Begins EHLO command.
        /// </summary>
        /// <param name="hostName">Host name which is reported to SMTP server.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginEhlo(string hostName, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* Rfc 2821 4.1.1.1 EHLO
			 * Syntax: "EHLO" SP Domain CRLF
			*/

            if (hostName.Length == 0)
            {
                hostName = Dns.GetHostName();
            }

            // Start sending EHLO command to server
            m_pSocket.BeginWriteLine("EHLO " + hostName, new object[] {hostName, callback}, OnEhloSendFinished);
        }

        /// <summary>
        /// Does AUTH command.
        /// </summary>
        /// <param name="userName">Uesr name.</param>
        /// <param name="password">Password.</param>
        public void Authenticate(string userName, string password)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first !");
            }
            if (!(m_Supports_CramMd5 || m_Supports_Login))
            {
                throw new Exception("Authentication isn't supported.");
            }

            /* LOGIN
			 * Example:
			 *	C: AUTH<SP>LOGIN<CRLF>
			 *	S: 334<SP>base64(USERNAME)<CRLF>   // USERNAME is string constant
			 *	C: base64(username)<CRLF>
			 *  S: 334<SP>base64(PASSWORD)<CRLF>   // PASSWORD is string constant
			 *  C: base64(password)<CRLF>
			 *	S: 235 Ok<CRLF>
			*/

            /* Cram-M5
			   Example:
					C: AUTH<SP>CRAM-MD5<CRLF>
					S: 334<SP>base64(md5_calculation_hash)<CRLF>
					C: base64(username<SP>password_hash)<CRLF>
					S: 235 Ok<CRLF>
			*/

            if (m_Supports_CramMd5)
            {
                m_pSocket.WriteLine("AUTH CRAM-MD5");

                string responseLine = m_pSocket.ReadLine();
                // Response line must start with 334 or otherwise it's error response
                if (!responseLine.StartsWith("334"))
                {
                    throw new Exception(responseLine);
                }

                string md5HashKey =
                    Encoding.ASCII.GetString(Convert.FromBase64String(responseLine.Split(' ')[1]));

                HMACMD5 kMd5 = new HMACMD5(Encoding.ASCII.GetBytes(password));
                byte[] md5HashByte = kMd5.ComputeHash(Encoding.ASCII.GetBytes(md5HashKey));
                string hashedPwd = BitConverter.ToString(md5HashByte).ToLower().Replace("-", "");

                m_pSocket.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + " " + hashedPwd)));

                responseLine = m_pSocket.ReadLine();
                // Response line must start with 235 or otherwise it's error response
                if (!responseLine.StartsWith("235"))
                {
                    throw new Exception(responseLine);
                }

                m_Authenticated = true;
            }
            else if (m_Supports_Login)
            {
                m_pSocket.WriteLine("AUTH LOGIN");

                string responseLine = m_pSocket.ReadLine();
                // Response line must start with 334 or otherwise it's error response
                if (!responseLine.StartsWith("334"))
                {
                    throw new Exception(responseLine);
                }

                // Send user name to server
                m_pSocket.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(userName)));

                responseLine = m_pSocket.ReadLine();
                // Response line must start with 334 or otherwise it's error response
                if (!responseLine.StartsWith("334"))
                {
                    throw new Exception(responseLine);
                }

                // Send password to server
                m_pSocket.WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(password)));

                responseLine = m_pSocket.ReadLine();
                // Response line must start with 235 or otherwise it's error response
                if (!responseLine.StartsWith("235"))
                {
                    throw new Exception(responseLine);
                }

                m_Authenticated = true;
            }

            if (m_Authenticated && m_pSocket.Logger != null)
            {
                m_pSocket.Logger.UserName = userName;
            }
        }

        /// <summary>
        /// Begins authenticate.
        /// </summary>
        /// <param name="userName">Uesr name.</param>
        /// <param name="password">Password.</param> 
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginAuthenticate(string userName, string password, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first !");
            }
            if (!(m_Supports_CramMd5 || m_Supports_Login))
            {
                throw new Exception("Authentication isn't supported.");
            }

            /* LOGIN
			 * Example:
			 *	C: AUTH<SP>LOGIN<CRLF>
			 *	S: 334<SP>base64(USERNAME)<CRLF>   // USERNAME is string constant
			 *	C: base64(username)<CRLF>
			 *  S: 334<SP>base64(PASSWORD)<CRLF>   // PASSWORD is string constant
			 *  C: base64(password)<CRLF>
			 *	S: 235 Ok<CRLF>
			*/

            /* Cram-M5
			   Example:
					C: AUTH<SP>CRAM-MD5<CRLF>
					S: 334<SP>base64(md5_calculation_hash)<CRLF>
					C: base64(username<SP>password_hash)<CRLF>
					S: 235 Ok<CRLF>
			*/

            if (m_Supports_CramMd5)
            {
                m_pSocket.BeginWriteLine("AUTH CRAM-MD5",
                                         new Auth_state_data(userName, password, callback),
                                         OnAuthCramMd5SendFinished);
            }
            else if (m_Supports_Login)
            {
                m_pSocket.BeginWriteLine("AUTH LOGIN",
                                         new Auth_state_data(userName, password, callback),
                                         OnAuthLoginSendFinished);
            }
        }

        /// <summary>
        /// Does MAIL FROM: command.
        /// </summary>
        /// <param name="senderEmail">Sender email address what is reported to smtp server</param>
        /// <param name="messageSize">Message size in bytes or -1 if message size isn't known.</param>
        public void SetSender(string senderEmail, long messageSize)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.2 MAIL
			 *  Examples:
			 *		MAIL FROM:<<EMAIL>>
			 * 
			 * RFC 1870 adds optional SIZE keyword support.
			 * SIZE keyword may only be used if it's reported in EHLO command response.
			 *	Examples:
			 *		MAIL FROM:<<EMAIL>> SIZE=1000
			*/

            if (m_Supports_Size && messageSize > -1)
            {
                m_pSocket.WriteLine("MAIL FROM:<" + senderEmail + "> SIZE=" + messageSize);
            }
            else
            {
                m_pSocket.WriteLine("MAIL FROM:<" + senderEmail + ">");
            }

            string responseLine = m_pSocket.ReadLine();
            // Response line must start with 250 or otherwise it's error response
            if (!responseLine.StartsWith("250"))
            {
                throw new Exception(responseLine);
            }
        }

        /// <summary>
        /// Begin setting sender.
        /// </summary>
        /// <param name="senderEmail">Sender email address what is reported to smtp server.</param>
        /// <param name="messageSize">Message size in bytes or -1 if message size isn't known.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginSetSender(string senderEmail, long messageSize, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.2 MAIL
			 *  Examples:
			 *		MAIL FROM:<<EMAIL>>
			 * 
			 * RFC 1870 adds optional SIZE keyword support.
			 * SIZE keyword may only be used if it's reported in EHLO command response.
			 *	Examples:
			 *		MAIL FROM:<<EMAIL>> SIZE=1000
			*/

            if (m_Supports_Size && messageSize > -1)
            {
                m_pSocket.BeginWriteLine("MAIL FROM:<" + senderEmail + "> SIZE=" + messageSize,
                                         callback,
                                         OnMailSendFinished);
            }
            else
            {
                m_pSocket.BeginWriteLine("MAIL FROM:<" + senderEmail + ">", callback, OnMailSendFinished);
            }
        }

        /// <summary>
        /// Does RCPT TO: command.
        /// </summary>
        /// <param name="recipientEmail">Recipient email address.</param>
        public void AddRecipient(string recipientEmail)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.2 RCPT
			 *  Examples:
			 *		RCPT TO:<<EMAIL>>
			*/

            m_pSocket.WriteLine("RCPT TO:<" + recipientEmail + ">");

            string responseLine = m_pSocket.ReadLine();
            // Response line must start with 250 or otherwise it's error response
            if (!responseLine.StartsWith("250"))
            {
                throw new Exception(responseLine);
            }
        }

        /// <summary>
        /// Begin adding recipient.
        /// </summary>
        /// <param name="recipientEmail">Recipient email address.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginAddRecipient(string recipientEmail, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.2 RCPT
			 *  Examples:
			 *		RCPT TO:<<EMAIL>>
			*/

            m_pSocket.BeginWriteLine("RCPT TO:<" + recipientEmail + ">", callback, OnRcptSendFinished);
        }

        /// <summary>
        /// Sends message to server. NOTE: Message sending starts from message stream current posision.
        /// </summary>
        /// <param name="message">Message what will be sent to server. NOTE: Message sending starts from message stream current posision.</param>
        public void SendMessage(Stream message)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.4 DATA
			 * Notes:
			 *		Message must be period handled for DATA command. This meas if message line starts with .,
			 *		additional .(period) must be added.
			 *		Message send is ended with <CRLF>.<CRLF>.
			 *	Examples:
			 *		C: DATA<CRLF>
			 *		S: 354 Start sending message, end with <crlf>.<crlf><CRLF>
			 *		C: send_message
			 *		C: <CRLF>.<CRLF>
			*/

            /* RFC 3030 BDAT
			 *	Syntax:BDAT<SP>message_size_in_bytes<SP>LAST<CRLF>
			 *	
			 *	Exapmle:
			 *		C: BDAT 1000 LAST<CRLF>
			 *		C: send_1000_byte_message
			 *		S: 250 OK<CRLF>
			 * 
			*/

            if (m_Supports_Bdat)
            {
                m_pSocket.WriteLine("BDAT " + (message.Length - message.Position) + " LAST");

                m_pSocket.Write(message);

                string responseLine = m_pSocket.ReadLine();
                // Response line must start with 250 or otherwise it's error response
                if (!responseLine.StartsWith("250"))
                {
                    throw new Exception(responseLine);
                }
            }
            else
            {
                m_pSocket.WriteLine("DATA");

                string responseLine = m_pSocket.ReadLine();
                // Response line must start with 334 or otherwise it's error response
                if (!responseLine.StartsWith("354"))
                {
                    throw new Exception(responseLine);
                }

                m_pSocket.WritePeriodTerminated(message);

                responseLine = m_pSocket.ReadLine();
                // Response line must start with 250 or otherwise it's error response
                if (!responseLine.StartsWith("250"))
                {
                    throw new Exception(responseLine);
                }
            }
        }

        /// <summary>
        /// Starts sending message.
        /// </summary>
        /// <param name="message">Message what will be sent to server. NOTE: Message sending starts from message stream current posision.</param>
        /// <param name="callback">Callback to be called if command ends.</param>
        public void BeginSendMessage(Stream message, CommadCompleted callback)
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            /* RFC 2821 4.1.1.4 DATA
			 * Notes:
			 *		Message must be period handled for DATA command. This meas if message line starts with .,
			 *		additional .(period) must be added.
			 *		Message send is ended with <CRLF>.<CRLF>.
			 *	Examples:
			 *		C: DATA<CRLF>
			 *		S: 354 Start sending message, end with <crlf>.<crlf><CRLF>
			 *		C: send_message
			 *		C: <CRLF>.<CRLF>
			*/

            /* RFC 3030 BDAT
			 *	Syntax:BDAT<SP>message_size_in_bytes<SP>LAST<CRLF>
			 *	
			 *	Exapmle:
			 *		C: BDAT 1000 LAST<CRLF>
			 *		C: send_1000_byte_message
			 *		S: 250 OK<CRLF>
			 * 
			*/

            if (m_Supports_Bdat)
            {
                m_pSocket.BeginWriteLine("BDAT " + (message.Length - message.Position) + " LAST",
                                         new object[] {message, callback},
                                         OnBdatSendFinished);
            }
            else
            {
                m_pSocket.BeginWriteLine("DATA", new object[] {message, callback}, OnDataSendFinished);
            }
        }

        /// <summary>
        /// Send RSET command to SMTP server, resets SMTP session.
        /// </summary>
        public void Reset()
        {
            if (!m_Connected)
            {
                throw new Exception("You must connect first");
            }

            m_pSocket.WriteLine("RSET");

            string responseLine = m_pSocket.ReadLine();
            if (!responseLine.StartsWith("250"))
            {
                throw new Exception(responseLine);
            }
        }

        /// <summary>
        /// Gets specified email domain possible connect points. Values are in priority descending order.
        /// </summary>
        /// <param name="domain">Email address or domain name.</param>
        /// <returns>Returns possible email server connection points.</returns>
        public IPAddress[] GetDestinations(string domain)
        {
            /* 
                1) Add MX records
                2) Add A records
            */

            // We have email address, just get domain from it.
            if (domain.IndexOf('@') > -1)
            {
                domain = domain.Substring(domain.IndexOf('@') + 1);
            }

            List<IPAddress> retVal = new List<IPAddress>();
            Dns_Client dns = new Dns_Client();
            Dns_Client.DnsServers = DnsServers;
            DnsServerResponse response = dns.Query(domain, QTYPE.MX);
            // Add MX            
            foreach (DNS_rr_MX mx in response.GetMXRecords())
            {
                try
                {
                    IPAddress[] ips = Dns.GetHostAddresses(mx.Host);
                    foreach (IPAddress ip in ips)
                    {
                        if (!retVal.Contains(ip))
                        {
                            retVal.Add(ip);
                        }
                    }
                }
                catch
                {
                    // Probably wrong MX record, no A reocrd for it, so we don't get IP. Just skip it.
                }
            }
            // Add A records only if no MX records.
            if (retVal.Count == 0)
            {
                response = dns.Query(domain, QTYPE.A);
                foreach (DNS_rr_A a in response.GetARecords())
                {
                    IPAddress ip = a.IP;
                    if (!retVal.Contains(ip))
                    {
                        retVal.Add(ip);
                    }
                }
            }

            return retVal.ToArray();
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Is called from ThreadPool Thread. This method just call synchrounous Connect.
        /// </summary>
        /// <param name="tag"></param>
        private void BeginConnect_workerThread(object tag)
        {
            CommadCompleted callback = (CommadCompleted) ((object[]) tag)[4];

            try
            {
                IPEndPoint localEndpoint = (IPEndPoint) ((object[]) tag)[0];
                string host = (string) ((object[]) tag)[1];
                int port = (int) ((object[]) tag)[2];
                bool ssl = (bool) ((object[]) tag)[3];

                Connect(localEndpoint, host, port, ssl);

                // Connect completed susscessfully, call callback method.
                callback(SocketCallBackResult.Ok, null);
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called from ThreadPool Thread. This method just call synchrounous StartTLS.
        /// </summary>
        /// <param name="tag">User data.</param>
        private void BeginStartTLS_workerThread(object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                StartTLS();

                // Connect completed susscessfully, call callback method.
                callback(SocketCallBackResult.Ok, null);
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished EHLO command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnEhloSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // Begin reading server EHLO command response
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new[] {((object[]) tag)[0], callback, ms},
                                            OnEhloReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading EHLO command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnEhloReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[2])).ToArray());

                    /* RFC 2821 192.168.3.11 EHLO
					*	Examples:
					*		250-domain<SP>free_text<CRLF>
					*       250-EHLO_keyword<CRLF>
					*		250<SP>EHLO_keyword<CRLF>
					* 
					* 250<SP> specifies that last EHLO response line.
					*/

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        // Server isn't required to support EHLO, try HELO
                        string hostName = (string) (((object[]) tag)[0]);
                        m_pSocket.BeginWriteLine("HELO " + hostName, callback, OnHeloSendFinished);
                    }
                    else
                    {
                        //---- Store supported ESMTP features --------------------//
                        if (responseLine.ToLower().IndexOf("size") > -1)
                        {
                            m_Supports_Size = true;
                        }
                        else if (responseLine.ToLower().IndexOf("chunking") > -1)
                        {
                            m_Supports_Bdat = true;
                        }
                        else if (responseLine.ToLower().IndexOf("cram-md5") > -1)
                        {
                            m_Supports_CramMd5 = true;
                        }
                        else if (responseLine.ToLower().IndexOf("login") > -1)
                        {
                            m_Supports_Login = true;
                        }
                        //--------------------------------------------------------//

                        // This isn't last EHLO response line
                        if (!responseLine.StartsWith("250 "))
                        {
                            MemoryStream ms = new MemoryStream();
                            m_pSocket.BeginReadLine(ms,
                                                    1000,
                                                    new[] {(((object[]) tag)[0]), callback, ms},
                                                    OnEhloReadServerResponseFinished);
                        }
                        else
                        {
                            // EHLO completed susscessfully, call callback method.
                            callback(SocketCallBackResult.Ok, null);
                        }
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished HELO command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnHeloSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // Begin reading server HELO command response
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {callback, ms},
                                            OnHeloReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading EHLO command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnHeloReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray());

                    /* RFC 2821 192.168.3.11 HELO
					*	Examples:
					*		250<SP>domain<SP>free_text<CRLF>
					* 
					*/

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // EHLO completed susscessfully, call callback method.
                        callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished AUTH CRAM-MD5 command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnAuthCramMd5SendFinished(SocketCallBackResult result,
                                               long count,
                                               Exception exception,
                                               object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    stateData.Tag = ms;
                    m_pSocket.BeginReadLine(ms, 1000, stateData, OnAuthCramMd5ReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading AUTH CRAM-MD% server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthCramMd5ReadServerResponseFinished(SocketCallBackResult result,
                                                             long count,
                                                             Exception exception,
                                                             object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray());

                    // Response line must start with 334 or otherwise it's error response
                    if (!responseLine.StartsWith("334"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        string md5HashKey =
                            Encoding.ASCII.GetString(Convert.FromBase64String(responseLine.Split(' ')[1]));

                        HMACMD5 kMd5 = new HMACMD5(Encoding.ASCII.GetBytes(stateData.Password));
                        byte[] md5HashByte = kMd5.ComputeHash(Encoding.ASCII.GetBytes(md5HashKey));
                        string hashedPwd = BitConverter.ToString(md5HashByte).ToLower().Replace("-", "");

                        // Start sending user name to server
                        m_pSocket.BeginWriteLine(
                            Convert.ToBase64String(
                                Encoding.ASCII.GetBytes(stateData.UserName + " " + hashedPwd)),
                            stateData,
                            OnAuthCramMd5UserPwdSendFinished);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished sending username and password to smtp server.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnAuthCramMd5UserPwdSendFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    stateData.Tag = ms;
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            stateData,
                                            OnAuthCramMd5UserPwdReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading user name and password send server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthCramMd5UserPwdReadServerResponseFinished(SocketCallBackResult result,
                                                                    long count,
                                                                    Exception exception,
                                                                    object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray());

                    // Response line must start with 235 or otherwise it's error response
                    if (!responseLine.StartsWith("235"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        m_Authenticated = true;

                        if (m_Authenticated && m_pSocket.Logger != null)
                        {
                            m_pSocket.Logger.UserName = stateData.UserName;
                        }

                        // AUTH CRAM-MD5 completed susscessfully, call callback method.
                        stateData.Callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished AUTH LOGIN command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnAuthLoginSendFinished(SocketCallBackResult result,
                                             long count,
                                             Exception exception,
                                             object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    stateData.Tag = ms;
                    m_pSocket.BeginReadLine(ms, 1000, stateData, OnAuthLoginReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading MAIL FROM: command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthLoginReadServerResponseFinished(SocketCallBackResult result,
                                                           long count,
                                                           Exception exception,
                                                           object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) (stateData.Tag)).ToArray());

                    // Response line must start with 334 or otherwise it's error response
                    if (!responseLine.StartsWith("334"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // Start sending user name to server
                        m_pSocket.BeginWriteLine(
                            Convert.ToBase64String(Encoding.ASCII.GetBytes(stateData.UserName)),
                            stateData,
                            OnAuthLoginUserSendFinished);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished sending user name to SMTP server.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnAuthLoginUserSendFinished(SocketCallBackResult result,
                                                 long count,
                                                 Exception exception,
                                                 object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    stateData.Tag = ms;
                    m_pSocket.BeginReadLine(ms, 1000, stateData, OnAuthLoginUserReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading AUTH LOGIN user send server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthLoginUserReadServerResponseFinished(SocketCallBackResult result,
                                                               long count,
                                                               Exception exception,
                                                               object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray());

                    // Response line must start with 334 or otherwise it's error response
                    if (!responseLine.StartsWith("334"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // Start sending password to server
                        m_pSocket.BeginWriteLine(
                            Convert.ToBase64String(Encoding.ASCII.GetBytes(stateData.Password)),
                            stateData,
                            OnAuthLoginPasswordSendFinished);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished sending password to SMTP server.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnAuthLoginPasswordSendFinished(SocketCallBackResult result,
                                                     long count,
                                                     Exception exception,
                                                     object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    stateData.Tag = ms;
                    m_pSocket.BeginReadLine(ms, 1000, stateData, OnAuthLoginPwdReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading AUTH LOGIN password send server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnAuthLoginPwdReadServerResponseFinished(SocketCallBackResult result,
                                                              long count,
                                                              Exception exception,
                                                              object tag)
        {
            Auth_state_data stateData = (Auth_state_data) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine = Encoding.ASCII.GetString(((MemoryStream) stateData.Tag).ToArray());

                    // Response line must start with 235 or otherwise it's error response
                    if (!responseLine.StartsWith("235"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        m_Authenticated = true;

                        if (m_Authenticated && m_pSocket.Logger != null)
                        {
                            m_pSocket.Logger.UserName = stateData.UserName;
                        }

                        // AUTH LOGIN completed susscessfully, call callback method.
                        stateData.Callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                stateData.Callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished MAIL FROM: command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnMailSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {callback, ms},
                                            OnMailReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading MAIL FROM: command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param> 
        private void OnMailReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray());

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // MAIL FROM: completed susscessfully, call callback method.
                        callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished RCPT TO: command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnRcptSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {callback, ms},
                                            OnRcptReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading RCPT TO: command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnRcptReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray());

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // RCPT TO: completed susscessfully, call callback method.
                        callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished BDAT command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnBdatSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // BDAT command successfully sent to SMTP server, start sending DATA.
                    m_pSocket.BeginWrite((Stream) (((object[]) tag)[0]), callback, OnBdatDataSendFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished sending BDAT message data to smtp server.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnBdatDataSendFinished(SocketCallBackResult result,
                                            long count,
                                            Exception exception,
                                            object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // BDAT message data successfully sent to SMTP server, start reading server response
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {callback, ms},
                                            OnBdatReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading BDAT: command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnBdatReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray());

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // BDAT: completed susscessfully, call callback method.
                        callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished DATA command sending.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataSendFinished(SocketCallBackResult result,
                                        long count,
                                        Exception exception,
                                        object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // DATA command has sent to SMTP server, start reading server response.
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {(((object[]) tag)[0]), callback, ms},
                                            OnDataReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading DATA command server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataReadServerResponseFinished(SocketCallBackResult result,
                                                      long count,
                                                      Exception exception,
                                                      object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[1]);

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[2])).ToArray());

                    // Response line must start with 334 or otherwise it's error response
                    if (!responseLine.StartsWith("354"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        Stream message = (Stream) (((object[]) tag)[0]);

                        // Start sending message to smtp server
                        m_pSocket.BeginWritePeriodTerminated(message, callback, OnDataMessageSendFinished);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has sending MESSAGE to smtp server.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataMessageSendFinished(SocketCallBackResult result,
                                               long count,
                                               Exception exception,
                                               object tag)
        {
            CommadCompleted callback = (CommadCompleted) tag;

            try
            {
                if (result == SocketCallBackResult.Ok)
                {
                    // Message has successfully sent to smtp server, start reading server response
                    MemoryStream ms = new MemoryStream();
                    m_pSocket.BeginReadLine(ms,
                                            1000,
                                            new object[] {callback, ms},
                                            OnDataMessageSendReadServerResponseFinished);
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Is called when smtp client has finished reading MESSAGE send smtp server response line.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="count"></param>
        /// <param name="exception"></param>
        /// <param name="tag"></param>
        private void OnDataMessageSendReadServerResponseFinished(SocketCallBackResult result,
                                                                 long count,
                                                                 Exception exception,
                                                                 object tag)
        {
            CommadCompleted callback = (CommadCompleted) (((object[]) tag)[0]);

            try
            {
                // TODO: some servers close connection after DATA command, hanndle Socket closed.

                if (result == SocketCallBackResult.Ok)
                {
                    string responseLine =
                        Encoding.ASCII.GetString(((MemoryStream) (((object[]) tag)[1])).ToArray());

                    // Response line must start with 250 or otherwise it's error response
                    if (!responseLine.StartsWith("250"))
                    {
                        throw new Exception(responseLine);
                    }
                    else
                    {
                        // DATA: completed susscessfully, call callback method.
                        callback(SocketCallBackResult.Ok, null);
                    }
                }
                else
                {
                    HandleSocketError(result, exception);
                }
            }
            catch (Exception x)
            {
                // Pass exception to callback method
                callback(SocketCallBackResult.Exception, x);
            }
        }

        /// <summary>
        /// Handles socket errors.
        /// </summary>
        /// <param name="result"></param>
        /// <param name="x"></param>
        private void HandleSocketError(SocketCallBackResult result, Exception x)
        {
            // Log socket errors to log
            if (m_pSocket.Logger != null)
            {
                if (result == SocketCallBackResult.SocketClosed)
                {
                    m_pSocket.Logger.AddTextEntry("Server closed socket !");
                }
                else if (x != null && x is SocketException)
                {
                    SocketException socketException = (SocketException) x;
                    // Server disconnected or aborted connection
                    if (socketException.ErrorCode == 10054 || socketException.ErrorCode == 10053)
                    {
                        m_pSocket.Logger.AddTextEntry("Server closed socket or aborted connection !");
                    }
                }
                else
                {
                    m_pSocket.Logger.AddTextEntry("Unknown error !");
                }
            }

            if (result == SocketCallBackResult.Exception)
            {
                throw x;
            }
            else
            {
                throw new Exception(result.ToString());
            }
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Common/Security/Cryptography/Hasher.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Security.Cryptography;
using System.Text;

namespace ASC.Security.Cryptography
{
    public sealed class Hasher
    {
        private const HashAlg DefaultAlg = HashAlg.SHA256;


        public static byte[] Hash(string data, HashAlg hashAlg)
        {
            return ComputeHash(data, hashAlg);
        }

        public static byte[] Hash(string data)
        {
            return Hash(data, DefaultAlg);
        }

        public static byte[] Hash(byte[] data, HashAlg hashAlg)
        {
            return ComputeHash(data, hashAlg);
        }

        public static byte[] Hash(byte[] data)
        {
            return Hash(data, DefaultAlg);
        }

        public static string Base64Hash(string data, HashAlg hashAlg)
        {
            return ComputeHash64(data, hashAlg);
        }

        public static string Base64Hash(string data)
        {
            return Base64Hash(data, DefaultAlg);
        }

        public static string Base64Hash(byte[] data, HashAlg hashAlg)
        {
            return ComputeHash64(data, hashAlg);
        }

        public static string Base64Hash(byte[] data)
        {
            return Base64Hash(data, DefaultAlg);
        }

        public static bool EqualHash(byte[] dataToCompare, byte[] hash, HashAlg hashAlg)
        {
            return String.Equals(
                ComputeHash64(dataToCompare, hashAlg),
                B2S64(hash)
                );
        }

        public static bool EqualHash(byte[] dataToCompare, byte[] hash)
        {
            return EqualHash(dataToCompare, hash, DefaultAlg);
        }

        public static bool EqualHash(string dataToCompare, string hash, HashAlg hashAlg)
        {
            return EqualHash(S2B(dataToCompare), S642B(hash), hashAlg);
        }

        public static bool EqualHash(string dataToCompare, string hash)
        {
            return EqualHash(dataToCompare, hash, DefaultAlg);
        }


        private static HashAlgorithm GetAlg(HashAlg hashAlg)
        {
            switch (hashAlg)
            {
                case HashAlg.MD5:
                    return MD5.Create();
                case HashAlg.SHA1:
                    return SHA1.Create();
                case HashAlg.SHA256:
                    return SHA256.Create();
                case HashAlg.SHA512:
                    return SHA512.Create();
                default:
                    return SHA256.Create();
            }
        }

        private static byte[] S2B(string str)
        {
            if (str == null) throw new ArgumentNullException("str");
            return Encoding.UTF8.GetBytes(str);
        }

        private static string B2S(byte[] data)
        {
            if (data == null) throw new ArgumentNullException("data");
            return Encoding.UTF8.GetString(data);
        }

        private static byte[] S642B(string str)
        {
            if (str == null) throw new ArgumentNullException("str");
            return Convert.FromBase64String(str);
        }

        private static string B2S64(byte[] data)
        {
            if (data == null) throw new ArgumentNullException("data");
            return Convert.ToBase64String(data);
        }

        private static byte[] ComputeHash(byte[] data, HashAlg hashAlg)
        {
            return GetAlg(hashAlg).ComputeHash(data);
        }

        private static byte[] ComputeHash(string data, HashAlg hashAlg)
        {
            return ComputeHash(S2B(data), hashAlg);
        }

        private static string ComputeHash64(byte[] data, HashAlg hashAlg)
        {
            return B2S64(ComputeHash(data, hashAlg));
        }

        private static string ComputeHash64(string data, HashAlg hashAlg)
        {
            return ComputeHash64(S2B(data), hashAlg);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Common/ListBaseView.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Core;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.UserControls.EmptyScreens;

namespace ASC.Web.CRM.Controls.Common
{
    public partial class ListBaseView : BaseUserControl
    {
        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Common/ListBaseView.ascx"); }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            InitPage();

            var hasactivity = DaoFactory.ContactDao.HasActivity();
            if (!hasactivity)
            {
                RenderDashboardEmptyScreen();
            }
        }


        private void InitPage()
        {
            Page.RegisterClientScript(new Masters.ClientScripts.ListViewData());
            Page.RegisterClientScript(new Masters.ClientScripts.ExchangeRateViewData());

            var privatePanel = (PrivatePanel)LoadControl(PrivatePanel.Location);
            var usersWhoHasAccess = new List<string> { CustomNamingPeople.Substitute<CRMCommonResource>("CurrentUser") };
            privatePanel.UsersWhoHasAccess = usersWhoHasAccess;
            privatePanel.DisabledUsers = new List<Guid> { SecurityContext.CurrentAccount.ID };
            privatePanel.HideNotifyPanel = true;
            _phPrivatePanel.Controls.Add(privatePanel);
        }


        protected void RenderDashboardEmptyScreen()
        {
            var dashboardEmptyScreen = (CRMDashboardEmptyScreen)Page.LoadControl(CRMDashboardEmptyScreen.Location);
            _phDashboardEmptyScreen.Controls.Add(dashboardEmptyScreen);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/HttpHandlers/ThumbHandler.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Net;
using System.Web;

using ASC.Core;
using ASC.Web.UserControls.Bookmarking.Util;

namespace ASC.Web.Community.HttpHandlers
{
    public class ThumbHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            if (!SecurityContext.IsAuthenticated || !ThumbnailHelper.HasService
                || !context.Request.QueryString.AllKeys.Contains("url"))
            {

                ProccessFail(context);
                return;
            }

            var url = context.Request.QueryString["url"];
            url = url.Replace("&amp;", "&");
            url = System.Net.WebUtility.UrlEncode(url);

            try
            {
                using (var wc = new WebClient())
                {
                    var bytes = wc.DownloadData(string.Format(ThumbnailHelper.ServiceUrl, url));
                    context.Response.ContentType = wc.ResponseHeaders["Content-Type"] ?? "image/png";
                    context.Response.BinaryWrite(bytes);
                    context.Response.Flush();
                }
            }
            catch
            {
                ProccessFail(context);
            }
        }

        private void ProccessFail(HttpContext context)
        {
            context.Response.Redirect("~/Products/Community/Modules/Bookmarking/App_Themes/default/images/noimageavailable.jpg");
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Core/Dao/Interfaces/ITagDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

namespace ASC.Files.Core
{
    public interface ITagDao : IDisposable
    {
        IEnumerable<Tag> GetTags(Guid subject, TagType tagType, IEnumerable<FileEntry> fileEntries);

        IEnumerable<Tag> GetTags(TagType tagType, IEnumerable<FileEntry> fileEntries);

        IEnumerable<Tag> GetTags(Guid owner, TagType tagType);

        IEnumerable<Tag> GetTags(string name, TagType tagType);

        IEnumerable<Tag> GetTags(string[] names, TagType tagType);

        IEnumerable<Tag> GetNewTags(Guid subject, Folder parentFolder, bool deepSearch);

        IEnumerable<Tag> GetNewTags(Guid subject, IEnumerable<FileEntry> fileEntries);

        IEnumerable<Tag> GetNewTags(Guid subject, FileEntry fileEntry);

        IEnumerable<Tag> SaveTags(IEnumerable<Tag> tag);

        IEnumerable<Tag> SaveTags(Tag tag);

        void UpdateNewTags(IEnumerable<Tag> tag);

        void UpdateNewTags(Tag tag);

        void RemoveTags(IEnumerable<Tag> tag);

        void RemoveTags(Tag tag);

        IEnumerable<Tag> GetTags(object entryID, FileEntryType entryType, TagType tagType);
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/SingleBookmarkUserControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using AjaxPro;

using ASC.Bookmarking.Pojo;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;

namespace ASC.Web.UserControls.Bookmarking
{
    [AjaxNamespace("SingleBookmarkUserControl")]
    public partial class SingleBookmarkUserControl : BookmarkInfoBase
    {

        /// <summary>
        /// Init tags and added by list
        /// </summary>
        public override void InitUserControl()
        {
            if (Bookmark != null)
            {
                var tags = Bookmark.Tags;
                if (tags != null && tags.Count > 0)
                {
                    InitTagsRepeater(tags);
                }
            }
        }

        private void InitTagsRepeater(IList<Tag> tags)
        {
            if (tags != null && tags.Count > 0)
            {
                TagsRepeater.DataSource = tags;
                TagsRepeater.DataBind();

                UserTagsString = BookmarkingServiceHelper.ConvertTagsToString(tags);
            }
        }

    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Controls/Settings/VoipSettings/VoipCommon.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Core;
using ASC.CRM.Core;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Studio;

namespace ASC.Web.CRM.Controls.Settings
{
    public partial class VoipCommon : BaseUserControl
    {
        public static string Location
        {
            get { return PathProvider.GetFileStaticRelativePath("Settings/VoIPSettings/VoipCommon.ascx"); }
        }


        protected void Page_Load(object sender, EventArgs e)
        {
            if (!VoipNumberData.Allowed || !CRMSecurity.IsAdmin)
            {
                Response.Redirect(PathProvider.StartURL() + "Settings.aspx");
            }

            Page.RegisterBodyScripts("~/js/uploader/jquery.fileupload.js");
            Page.RegisterBodyScripts(PathProvider.GetFileStaticRelativePath("voip.common.js"));
            Page.RegisterClientScript(new VoipCommonData());
        }
    }

    public class VoipCommonData : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Resources.Master.Voip"; }
        }

        protected override string GetCacheHash()
        {
            return CoreContext.TenantManager.GetCurrentTenant().TenantId + VoipNumberData.Allowed.ToString();
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            yield return RegisterObject(new { enabled = VoipNumberData.Allowed });
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/js/tariffcustom.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var TariffSettings = new function () {
    var isInit = false;

    var _tariffsMaxUsers = [],
        _defaultTariff = 0,
        _maxTariff = 0,
        _minTariff = 0,
        _sliderVals = [],
        _sliderClasses = [],
        _monthPrice = 0,
        _yearPrice = 0;

    var init = function () {
        if (isInit === false) {
            isInit = true;
        }

        jq.switcherAction("#switcherPayments", "#paymentsContainer");

        jq.dropdownToggle({
            switcherSelector: "#currencySelector",
            dropdownID: "currencyList",
            rightPos: true,
        });

        jq("#currencyHelpSwitcher").click(function () { jq(this).helper({BlockHelperID: "currencyHelp"}) });

        var country = jq(".text-edit-phone").attr("data-country");
        PhoneController.Init(jq(".text-edit-phone"), CountriesManager.countriesList, [country, "US"]);

        initMainProperties();
        initSlider();

        updateSelectedTariff("year");
        updatePrices(_defaultTariff);
        jq(".tarrifs-button-year").click(function() { updateSelectedTariff("year"); }); 
        jq(".tarrifs-button-month").click(function() { updateSelectedTariff("month"); }); 
    };

    function updateSelectedTariff (t) {
        if (t == "year") {
            jq(".tarrifs-button-year").addClass('green');
            jq(".tarrifs-button-year").removeClass("gray");
            jq(".tarrifs-button-month").removeClass('green');
            jq(".tarrifs-button-month").addClass("gray");
            jq(".text-edit-message").val("Year tariff");
        } else {
            jq(".tarrifs-button-month").addClass('green');
            jq(".tarrifs-button-month").removeClass("gray");
            jq(".tarrifs-button-year").removeClass('green');
            jq(".tarrifs-button-year").addClass("gray");
            jq(".text-edit-message").val("Month tariff");
        }
    }

    var initMainProperties = function () {
        _tariffsMaxUsers = jq(".tariff-user-descr-item").map(function (i, item) {
            return parseInt(jq(item).attr("data-users"));
        }).toArray();


        _maxTariff = _tariffsMaxUsers[_tariffsMaxUsers.length - 1] || 0;
        jq(".tariff-header").toggle(_maxTariff != 0);
        _defaultTariff = jq(".tariff-slider-container").attr("data-default");
        _minTariff = jq(".tariff-slider-container").attr("data-min");

        for (var i = 1; i <= _maxTariff; i++) {
            _sliderVals.push(i);
            var curClass = '';

            _sliderClasses.push(curClass);
        }

        for (var i = 1; i <= 10; i++) { // 10 steps (100px) for max zone ">50" users
            _sliderVals.push(_maxTariff + i);
            _sliderClasses.push("darkGrey" + (i == 10 ? " rightRadius" : ""));
        }

        _monthPrice = parseInt(jq("#monthPrice").val());
        _yearPrice = parseInt(jq("#yearPrice").val());
    };

    var slideRefreshText = function (slideHandle, curUsrCount) {
        slideHandle.children(".ui-slider-handle-text")
            .text(_maxTariff < curUsrCount
                ? (">" + _maxTariff)
                : curUsrCount);
    };

    var slideExt = function (e, ui) {
        var $thisHandle = jq(ui.handle),
            liItems = $thisHandle.parent().children('ol.ui-slider-scale').children('li'),
            opts = $thisHandle.data("options");

        $thisHandle.attr('aria-valuenow', ui.value);

        for (var i = 0, n = liItems.length; i < n; i++) {
            if (i < ui.value) {
                jq(liItems[i]).addClass(opts.baseCssClass);
            } else {
                jq(liItems[i]).removeClass(opts.baseCssClass);
            }
        }

        if (e != null) {
            opts.value = ui.value;
            $thisHandle.data("options", opts);

            slideRefreshText($thisHandle, ui.value);
        } else {
            selectUserCount(jq(ui.handle), ui.curTariffMaxUsers);
        }
    };

    var onSliderCreate = function (event, ui) {
        var sliderHandle = jq("#pricingPlanSlider .ui-slider a.ui-slider-handle:first");
        var curTariffMaxUsers = getTariffMaxUsersByCurUsrCnt(_defaultTariff);

        sliderHandle.append("<div class=\"ui-slider-handle-text\">" + _defaultTariff + "</div><div class=\"ui-slider-handle-q\"></div>");
        sliderHandle.children(".ui-slider-handle-q").append(jq(".tariff-user-question:first"));
        if (_defaultTariff / _sliderVals.length < 0.3) {
            jq(".tariff-user-question").addClass("tariff-user-question-right");
        }

        selectUserCount(sliderHandle, curTariffMaxUsers);
    };

    function formatNumber(num) {
        return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1 ');
    }

    function updatePrices(value) {
        jq('.tariffs-body-month .price-string').html((_monthPrice) + '<span class="tariff-price-cur">&#x20BD;</span>');
        jq('.tariffs-body-month .tariffs-price').html(formatNumber((_monthPrice * value)) + '<span class="tariff-price-cur">&#x20BD;</span>');

        jq('.tariffs-body-year .price-string').html((_yearPrice) + '<span class="tariff-price-cur">&#x20BD;</span>');
        jq('.tariffs-body-year .tariffs-price').html(formatNumber((_yearPrice * 12 * value)) + '<span class="tariff-price-cur">&#x20BD;</span>');

        jq('.text-edit-csize').val(value>_maxTariff ? (">" + _maxTariff) : ("" + value));
    }

    var onSliderStop = function (event, ui) {
        var curTariffMaxUsers = getTariffMaxUsersByCurUsrCnt(ui.value);

        updatePrices(ui.value);

        slideExt(null,
            {
                handle: ui.handle,
                value: _maxTariff < ui.value ? _sliderVals[_sliderVals.length - 1] : ui.value,
                curTariffMaxUsers: curTariffMaxUsers
            });

    };

    var onSliderStart = function (event, ui) {
        jq(ui.handle).children(".ui-slider-handle-q").remove();
    };

    var initMainSliderOpts = function () {
        return {
            values: _sliderVals,
            defaultClasses: _sliderClasses,
            width: parseInt(jq("#pricingPlanSlider").css("width")) / (_maxTariff + 10),
            height: '6px',

            sliderOptions: {
                baseCssClass: 'blue',
                step: 1,
                animate: 0,
                min: 1,
                max: _sliderVals.length,
                orientation: 'horizontal',
                range: false,
                value: _defaultTariff,

                create: onSliderCreate,

                start: onSliderStart,
                slide: slideExt,
                stop: onSliderStop
            }
        };
    };

    var initSlider = function () {
        var $this = jq("#pricingPlanSlider"),
            options = initMainSliderOpts(),
            sliderComponent = jq('<div></div>');

        jq(['<a tabindex="0" class="ui-slider-handle" role="slider" aria-valuenow="',
                options.sliderOptions.value,
                '"></a>'
        ].join(''))
            .data("options", options.sliderOptions)
            .appendTo(sliderComponent);

        var scale = sliderComponent.append('<ol class="ui-slider-scale" role="presentation" style="width: 100%;' +
            ' height: ' + (options.height != null ? options.height : "100%") + ';"></ol>')
            .find('.ui-slider-scale:eq(0)'),
            liClass = '';

        for (var i = 0, n = options.values.length; i < n; i++) {
            liClass = (i < options.sliderOptions.value) ? options.sliderOptions.baseCssClass : '';

            if (i == 0) {
                liClass = "leftRadius " + options.sliderOptions.baseCssClass;
            }
            if (options.defaultClasses != null && typeof (options.defaultClasses[i]) !== "undefined" && options.defaultClasses[i] != "") {
                liClass += " " + options.defaultClasses[i];
            }


            scale.append(
                ['<li class="',
                liClass,
                '" style="left:',
                options.width * i, 'px;',
                ' height: ',
                (options.height != null ? options.height : "100%"),
                '; width:',
                options.width, "px",
                ';"></li>'
                ]
                .join(''));
        }

        //inject and return
        sliderComponent.appendTo($this).slider(options.sliderOptions).attr('role', 'application');

       jq(".tariff-request-panel").show();

    };

    var getTariffMaxUsersByCurUsrCnt = function (curUserCount) {
        for (var i = 0, n = _tariffsMaxUsers.length; i < n; i++) {
            if (curUserCount <= _tariffsMaxUsers[i]) {
                return _tariffsMaxUsers[i];
            }
        }
        return curUserCount;
    };

    var selectUserCount = function (handle, curTariffMaxUsers) {
        var userMinWarn = curTariffMaxUsers < _minTariff,
            userMaxWarn = _maxTariff < curTariffMaxUsers;

        jq(".tariff-user-descr-item, .tariff-item").hide();
        jq(".tariff-user-descr-item[data-users=\"" + curTariffMaxUsers + "\"], .tariff-item[data-users=\"" + curTariffMaxUsers + "\"]").show();


        jq("#pricingPlanSlider").toggleClass("warn-slider", userMinWarn);
        jq(".tariff-user-warn-min").toggle(userMinWarn);
        jq(".tariff-user-warn-max").toggle(userMaxWarn);
        jq(".tariffs-panel, .see-full-price, #currencyPanel").toggle(!userMaxWarn);
    };

    var requestTariff = function () {
        var fname = jq(".text-edit-fname").val().trim();
        var lname = jq(".text-edit-lname").val().trim();
        var title = (jq(".text-edit-title").val() || "").trim();
        var email = jq(".text-edit-email").val().trim();
        var phone = jq(".text-edit-phone").val().trim();
        var ctitle = jq(".text-edit-ctitle").val().trim();
        var csize = jq(".text-edit-csize").val().trim();
        var site = (jq(".text-edit-site").val() || "").trim();
        var message = (jq(".text-edit-message").val() || "").trim();
        if (!fname.length || !email.length || !phone.length || !ctitle.length || !csize.length) {
            toastr.error(ASC.Resources.Master.ResourceJS.ErrorEmptyField);
            return;
        }
        if (!site.length && jq(".text-edit-site").is(":visible")
            || !message.length && jq(".text-edit-message").is(":visible")) {
            toastr.error(ASC.Resources.Master.ResourceJS.ErrorEmptyField);
            return;
        }

        TariffUsageController.RequestTariff(fname, lname, title, email, phone, ctitle, csize + " / " + message, site, message,
            function (result) {
                if (result.error != null) {
                    toastr.error(result.error.Message);
                    return;
                }
                toastr.success(ASC.Resources.Master.ResourceJS.SendTariffRequest1);
            });
    };

    return {
        init: init,

        requestTariff: requestTariff,
    };
};

jq(function () {
    TariffSettings.init();

    jq(".tariff-request").click(TariffSettings.requestTariff);
});

<|start_filename|>common/Tests/ASC.Common.Tests/Utils/DnsLookupTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#if DEBUG
namespace ASC.Common.Tests.Utils
{
    using System;
    using System.Linq;
    using ASC.Common.Utils;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    
    [TestClass]
    public class DnsLookupTest
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException), "domainName")]
        public void DomainNameEmptyExists()
        {
            const string domain = "";

            var dnsLoopup = new DnsLookup();

            dnsLoopup.IsDomainExists(domain);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException), "Domain name could not be parsed")]
        public void DomainNameInvalidExists()
        {
            const string domain = "/.";

            var dnsLoopup = new DnsLookup();

            var exists = dnsLoopup.IsDomainExists(domain);

            Assert.IsTrue(exists);
        }

        [TestMethod]
        public void DomainExists()
        {
            const string domain = "onlyoffice.com";

            var dnsLoopup = new DnsLookup();

            var exists = dnsLoopup.IsDomainExists(domain);

            Assert.IsTrue(exists);
        }

        [TestMethod]
        public void DomainNotExists()
        {
            const string domain = "sdkjskytt111hdhdhwooo.ttt";

            var dnsLoopup = new DnsLookup();

            var exists = dnsLoopup.IsDomainExists(domain);

            Assert.IsFalse(exists);
        }

        [TestMethod]
        public void MxExists()
        {
            const string domain = "onlyoffice.com";
            const string mx_record = "mx1.onlyoffice.com";

            var dnsLoopup = new DnsLookup();

            var exists = dnsLoopup.IsDomainMxRecordExists(domain, mx_record);

            Assert.IsTrue(exists);
        }

        [TestMethod]
        public void DkimExists()
        {
            const string domain = "onlyoffice.com";
            const string dkim_record = "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiblqlVejxACSfc3Y0OzRzyFFtnUHgkw65k+QGjG4WvjmJJQNcfdJNaaLo9xKPIfw9vTRVigZa78KgeYFymGlqXtR0z323EwiHaNh82Qo1oBICOZT2AVjWpPjBUGwD6qTorulmLnY9+YKn1bV8B7mt964ewpPHDDsqaHddhV7hqQIDAQAB";

            var dnsLoopup = new DnsLookup();

            var exists = dnsLoopup.IsDomainDkimRecordExists(domain, "dkim", dkim_record);

            Assert.IsTrue(exists);
        }

        [TestMethod]
        public void TxtSpfExists()
        {
            const string domain = "onlyoffice.com";
            const string txt_record = "v=spf1 a mx mx:avsmedia.net a:smtp1.uservoice.com a:qamail.teamlab.info include:amazonses.com -all";

            var dnsLoopup = new DnsLookup();

            var exists = dnsLoopup.IsDomainTxtRecordExists(domain, txt_record);

            Assert.IsTrue(exists);
        }

        [TestMethod]
        public void GetMxRecords()
        {
            const string domain = "onlyoffice.com";

            var dnsLoopup = new DnsLookup();

            var mxRecords = dnsLoopup.GetDomainMxRecords(domain);

            Assert.IsTrue(mxRecords.Any());
        }

        [TestMethod]
        public void GetARecords()
        {
            const string domain = "onlyoffice.com";

            var dnsLoopup = new DnsLookup();

            var aRecords = dnsLoopup.GetDomainARecords(domain);

            Assert.IsTrue(aRecords.Any());
        }

        [TestMethod]
        public void GetIPs()
        {
            const string domain = "onlyoffice.com";

            var dnsLoopup = new DnsLookup();

            var ips = dnsLoopup.GetDomainIPs(domain);

            Assert.IsTrue(ips.Any());
        }

        [TestMethod]
        public void GetPtr()
        {
            const string domain = "mx1.onlyoffice.com";
            const string ip = "172.16.31.10";

            var dnsLoopup = new DnsLookup();

            var exists = dnsLoopup.IsDomainPtrRecordExists(ip, domain);

            Assert.IsTrue(exists);
        }


        [TestMethod]
        public void GetNoexistedDomainMx()
        {
            const string domain = "taramparam.tk";

            var dnsLoopup = new DnsLookup();

            var mxRecords = dnsLoopup.GetDomainMxRecords(domain);

            Assert.IsTrue(!mxRecords.Any());
        }
    }
}
#endif

<|start_filename|>module/ASC.Mail/ASC.Mail/Extensions/RestClientExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Net;

using ASC.Mail.Exceptions;

using Newtonsoft.Json.Linq;

using RestSharp;

namespace ASC.Mail.Extensions
{
    static class RestClientExtensions
    {
        public static IRestResponse ExecuteSafe(this RestClient client, RestRequest request)
        {
            IRestResponse response;
            try
            {
                response = client.Execute(request);

                if (response.StatusCode == HttpStatusCode.InternalServerError &&
                    response.ErrorException == null &&
                    !string.IsNullOrEmpty(response.Content))
                {
                    try
                    {
                        var json = JObject.Parse(response.Content);
                        if (json == null || json["error"] == null || json["error"]["message"] == null)
                            return response;

                        response.ErrorException = new ApiHelperException(json["error"]["message"].ToString(), response.StatusCode, response.Content);
                    }
                    catch
                    {
                        // ignored
                    }
                }
            }
            catch (Exception ex)
            {
                response = new RestResponse { ErrorException = ex };
            }

            return response;
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Billing/BillingClient.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using System.Web;

using Newtonsoft.Json;

namespace ASC.Core.Billing
{
    public class BillingClient
    {
        public readonly static bool Configured = false;
        private readonly static string _billingDomain;
        private readonly static string _billingKey;
        private readonly static string _billingSecret;
        private readonly bool _test;

        private const int AvangatePaymentSystemId = 1;

        static BillingClient()
        {
            var billingDomain = ConfigurationManagerExtension.AppSettings["core.payment-url"];

            _billingDomain = (billingDomain ?? "").Trim().TrimEnd('/');
            if (!string.IsNullOrEmpty(_billingDomain))
            {
                _billingDomain += "/billing/";

                _billingKey = ConfigurationManager.AppSettings["core.payment-key"];
                _billingSecret = ConfigurationManager.AppSettings["core.payment-secret"];

                Configured = true;
            }
        }

        public BillingClient(bool test)
        {
            _test = test;
        }


        public PaymentLast GetLastPayment(string portalId)
        {
            var result = Request("GetActiveResource", portalId);
            var paymentLast = JsonConvert.DeserializeObject<PaymentLast>(result);

            if (!_test && paymentLast.PaymentStatus == 4)
            {
                throw new BillingException("Can not accept test payment.", new { PortalId = portalId });
            }

            return paymentLast;
        }

        public IEnumerable<PaymentInfo> GetPayments(string portalId)
        {
            string result = Request("GetPayments", portalId);
            var payments = JsonConvert.DeserializeObject<List<PaymentInfo>>(result);

            return payments;
        }

        public IDictionary<string, Tuple<Uri, Uri>> GetPaymentUrls(string portalId, string[] products, string affiliateId = null, string campaign = null, string currency = null, string language = null, string customerId = null, string quantity = null)
        {
            var urls = new Dictionary<string, Tuple<Uri, Uri>>();

            var additionalParameters = new List<Tuple<string, string>>() { Tuple.Create("PaymentSystemId", AvangatePaymentSystemId.ToString()) };
            if (!string.IsNullOrEmpty(affiliateId))
            {
                additionalParameters.Add(Tuple.Create("AffiliateId", affiliateId));
            }
            if (!string.IsNullOrEmpty(campaign))
            {
                additionalParameters.Add(Tuple.Create("campaign", campaign));
            }
            if (!string.IsNullOrEmpty(currency))
            {
                additionalParameters.Add(Tuple.Create("Currency", currency));
            }
            if (!string.IsNullOrEmpty(language))
            {
                additionalParameters.Add(Tuple.Create("Language", language));
            }
            if (!string.IsNullOrEmpty(customerId))
            {
                additionalParameters.Add(Tuple.Create("CustomerID", customerId));
            }
            if (!string.IsNullOrEmpty(quantity))
            {
                additionalParameters.Add(Tuple.Create("Quantity", quantity));
            }

            var parameters = products
                .Distinct()
                .Select(p => Tuple.Create("ProductId", p))
                .Concat(additionalParameters)
                .ToArray();

            //max 100 products
            var result = Request("GetPaymentUrl", portalId, parameters);
            var paymentUrls = JsonConvert.DeserializeObject<Dictionary<string, string>>(result);

            var upgradeUrls = new Dictionary<string, string>();
            if (!string.IsNullOrEmpty(portalId)
                //TODO: remove
                && false)
            {
                try
                {
                    //max 100 products
                    result = Request("GetPaymentUpgradeUrl", portalId, parameters);
                    upgradeUrls = JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
                }
                catch (BillingNotFoundException)
                {
                }
            }

            foreach (var p in products)
            {
                string url;
                var paymentUrl = (Uri)null;
                var upgradeUrl = (Uri)null;
                if (paymentUrls.TryGetValue(p, out url) && !string.IsNullOrEmpty(url = ToUrl(url)))
                {
                    paymentUrl = new Uri(url);
                }
                if (upgradeUrls.TryGetValue(p, out url) && !string.IsNullOrEmpty(url = ToUrl(url)))
                {
                    upgradeUrl = new Uri(url);
                }
                urls[p] = Tuple.Create(paymentUrl, upgradeUrl);
            }
            return urls;
        }

        public IDictionary<string, Dictionary<string, decimal>> GetProductPriceInfo(params string[] productIds)
        {
            if (productIds == null)
            {
                throw new ArgumentNullException("productIds");
            }

            var parameters = productIds.Select(pid => Tuple.Create("ProductId", pid)).ToList();
            parameters.Add(Tuple.Create("PaymentSystemId", AvangatePaymentSystemId.ToString()));

            var result = Request("GetProductsPrices", null, parameters.ToArray());
            var prices = JsonConvert.DeserializeObject<Dictionary<int, Dictionary<string, Dictionary<string, decimal>>>>(result);

            if (prices.ContainsKey(AvangatePaymentSystemId))
            {
                var pricesPaymentSystem = prices[AvangatePaymentSystemId];

                return productIds.Select(productId =>
                    {
                        if (pricesPaymentSystem.ContainsKey(productId))
                        {
                            return new { ProductId = productId, Prices = pricesPaymentSystem[productId] };
                        }
                        return new { ProductId = productId, Prices = new Dictionary<string, decimal>() };
                    })
                    .ToDictionary(e => e.ProductId, e => e.Prices);
            }

            return new Dictionary<string, Dictionary<string, decimal>>();
        }


        private string CreateAuthToken(string pkey, string machinekey)
        {
            using (var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(machinekey)))
            {
                var now = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
                var hash = HttpServerUtility.UrlTokenEncode(hasher.ComputeHash(Encoding.UTF8.GetBytes(string.Join("\n", now, pkey))));
                return string.Format("ASC {0}:{1}:{2}", pkey, now, hash);
            }
        }

        private string Request(string method, string portalId, params Tuple<string, string>[] parameters)
        {
            var url = _billingDomain + method;

            var request = WebRequest.Create(url);
            request.Method = "POST";
            request.Timeout = 60000;
            request.ContentType = "application/json";

            if (!string.IsNullOrEmpty(_billingKey))
            {
                request.Headers.Add("Authorization", CreateAuthToken(_billingKey, _billingSecret));
            }

            var data = new Dictionary<string, List<string>>();
            if (!string.IsNullOrEmpty(portalId))
            {
                data.Add("PortalId", new List<string>() { portalId });
            }
            foreach (var parameter in parameters)
            {
                if (!data.ContainsKey(parameter.Item1))
                {
                    data.Add(parameter.Item1, new List<string>() { parameter.Item2 });
                }
                else
                {
                    data[parameter.Item1].Add(parameter.Item2);
                }
            }
            var body = JsonConvert.SerializeObject(data);

            var bytes = Encoding.UTF8.GetBytes(body ?? "");
            request.ContentLength = bytes.Length;
            using (var stream = request.GetRequestStream())
            {
                stream.Write(bytes, 0, bytes.Length);
            }

            string result;
            try
            {
                using (var response = request.GetResponse())
                using (var stream = response.GetResponseStream())
                {
                    if (stream == null)
                    {
                        throw new BillingNotConfiguredException("Billing response is null");
                    }
                    using (var readStream = new StreamReader(stream))
                    {
                        result = readStream.ReadToEnd();
                    }
                }
            }
            catch (WebException)
            {
                request.Abort();
                throw;
            }

            if (string.IsNullOrEmpty(result))
            {
                throw new BillingNotConfiguredException("Billing response is null");
            }
            if (!result.StartsWith("{\"Message\":\"error"))
            {
                return result;
            }

            var @params = (parameters ?? Enumerable.Empty<Tuple<string, string>>()).Select(p => string.Format("{0}: {1}", p.Item1, p.Item2));
            var info = new { Method = method, PortalId = portalId, Params = string.Join(", ", @params) };
            if (result.Contains("{\"Message\":\"error: cannot find "))
            {
                throw new BillingNotFoundException(result, info);
            }
            throw new BillingException(result, info);
        }

        private string ToUrl(string s)
        {
            s = s.Trim();
            if (s.StartsWith("error", StringComparison.InvariantCultureIgnoreCase))
            {
                return string.Empty;
            }
            if (_test && !s.Contains("&DOTEST = 1"))
            {
                s += "&DOTEST=1";
            }
            return s;
        }
    }

    [Serializable]
    public class BillingException : Exception
    {
        public BillingException(string message, object debugInfo = null) : base(message + (debugInfo != null ? " Debug info: " + debugInfo : string.Empty))
        {
        }

        public BillingException(string message, Exception inner) : base(message, inner)
        {
        }

        protected BillingException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }
    }

    [Serializable]
    public class BillingNotFoundException : BillingException
    {
        public BillingNotFoundException(string message, object debugInfo = null) : base(message, debugInfo)
        {
        }

        protected BillingNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }
    }

    [Serializable]
    public class BillingNotConfiguredException : BillingException
    {
        public BillingNotConfiguredException(string message, object debugInfo = null) : base(message, debugInfo)
        {
        }

        public BillingNotConfiguredException(string message, Exception inner) : base(message, inner)
        {
        }

        protected BillingNotConfiguredException(SerializationInfo info, StreamingContext context) : base(info, context)
        {
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/PortalRename/js/portalrename.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


jq(function () {
    PortalRename.init();
});

var PortalRename = new function () {

    this.init = function () {
        jq.tmpl("template-blockUIPanel", {
            id: "portalRenameConfirmation",
            headerTest: ASC.Resources.Master.ResourceJS.PortalRenameConfirmationTitle,
            questionText: '',
            innerHtmlText: jq.format(ASC.Resources.Master.ResourceJS.PortalRenameConfirmationPopup, "<p>", "</p>"),
            OKBtn: ASC.Resources.Master.ResourceJS.ContinueButton,
            CancelBtn: ASC.Resources.Master.ResourceJS.CancelButton
        }).insertAfter("#studio_portalRename");

        jq("#portalRenameConfirmation").find(".button.blue").on("click", function () {
            PopupKeyUpActionProvider.CloseDialog();
            PortalRename.saveNewTenantAlias();
        });

        jq("#studio_portalRename .button.blue").on("click", function (event) {
            if (jq("#studio_portalRename .button.blue").hasClass("disable")) return;

            var alias = jq.trim(jq("#studio_tenantAlias").val());
            if (alias === "") {
                jq("#studio_tenantAlias").addClass("with-error");
                return;
            } else if (alias == jq("#studio_tenantAlias").attr("data-actualvalue")) {
                jq("#studio_tenantAlias").addClass("with-error");
                LoadingBanner.showMesInfoBtn("#studio_portalRename", ASC.Resources.Master.ResourceJS.ErrorPortalNameWasNotChanged, "error");
                return;
            }  else {
                jq("#studio_tenantAlias").removeClass("with-error");
            }

            StudioBlockUIManager.blockUI("#portalRenameConfirmation", 420);
        });
    };

    this.saveNewTenantAlias = function () {

        var alias = jq.trim(jq("#studio_tenantAlias").val());

        Teamlab.updatePortalName({}, alias, {

            before: function () {
                jq("#studio_tenantAlias").prop("disabled", true);
                LoadingBanner.showLoaderBtn("#studio_portalRename");
            },
            after: function () {
                LoadingBanner.hideLoaderBtn("#studio_portalRename");
            },
            success: function (params, response) {
                LoadingBanner.showMesInfoBtn("#studio_portalRename", response.message, "success");
                window.location.replace(response.reference);
            },
            error: function (params, errors) {
                var errTest = errors[0];
                try {
                    var error = jq.parseJSON(Encoder.htmlDecode(errTest)).errors[0];

                    switch (error) {
                        case "portalNameExist": errTest = ASC.Resources.Master.ResourceJS.ErrorPortalNameExist; break;
                        case "tooShortError": errTest = ASC.Resources.Master.ResourceJS.ErrorPortalNameTooShort; break;
                        case "portalNameIncorrect": errTest = ASC.Resources.Master.ResourceJS.ErrorPortalNameIncorrect; break;
                    }
                }
                catch (e) { }
                LoadingBanner.showMesInfoBtn("#studio_portalRename", errTest, "error");
                jq("#studio_tenantAlias").prop("disabled", false);
            }

        });
    };
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Services/NotifyService/NotifySource.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Notify.Model;
using ASC.Notify.Patterns;
using ASC.Web.Projects.Core.Model.Resources;

using NotifySourceBase = ASC.Core.Notify.NotifySource;

namespace ASC.Projects.Core.Services.NotifyService
{
    public class NotifySource : NotifySourceBase
    {
        public static NotifySource Instance
        {
            get;
            private set;
        }


        static NotifySource()
        {
            Instance = new NotifySource();
        }

        private NotifySource()
            : base(new Guid("{6045B68C-2C2E-42db-9E53-C272E814C4AD}"))
        {
        }


        protected override IActionProvider CreateActionProvider()
        {
            return new ConstActionProvider(
                NotifyConstants.Event_NewCommentForMessage,
                NotifyConstants.Event_NewCommentForTask,
                NotifyConstants.Event_NewFileForDiscussion,
                NotifyConstants.Event_NewFileForTask,
                NotifyConstants.Event_ResponsibleForProject,
                NotifyConstants.Event_ResponsibleForTask,
                NotifyConstants.Event_RemoveResponsibleForTask,
                NotifyConstants.Event_ReminderAboutTask,
                NotifyConstants.Event_ReminderAboutTaskDeadline,
                NotifyConstants.Event_TaskEdited,
                NotifyConstants.Event_TaskClosed,
                NotifyConstants.Event_TaskCreated,
                NotifyConstants.Event_TaskResumed,
                NotifyConstants.Event_TaskDeleted,
                NotifyConstants.Event_TaskMovedToMilestone,
                NotifyConstants.Event_TaskMovedFromMilestone,
                NotifyConstants.Event_InviteToProject,
                NotifyConstants.Event_RemoveFromProject,
                NotifyConstants.Event_MilestoneDeadline,
                NotifyConstants.Event_MilestoneEdited,
                NotifyConstants.Event_MilestoneClosed,
                NotifyConstants.Event_MilestoneCreated,
                NotifyConstants.Event_MilestoneDeleted,
                NotifyConstants.Event_MilestoneResumed,
                NotifyConstants.Event_ResponsibleForMilestone,
                NotifyConstants.Event_MessageCreated,
                NotifyConstants.Event_MessageEdited,
                NotifyConstants.Event_MessageDeleted,
                NotifyConstants.Event_ImportData,
                NotifyConstants.Event_ResponsibleForSubTask,
                NotifyConstants.Event_SubTaskDeleted,
                NotifyConstants.Event_SubTaskCreated,
                NotifyConstants.Event_SubTaskEdited,
                NotifyConstants.Event_SubTaskClosed,
                NotifyConstants.Event_SubTaskResumed,
                NotifyConstants.Event_ProjectDeleted,
                NotifyConstants.Event_EditedCommentForMessage,
                NotifyConstants.Event_EditedCommentForTask);
        }

        protected override IPatternProvider CreatePatternsProvider()
        {
            return new XmlPatternProvider2(ProjectsPatternResource.patterns) { GetPatternMethod = ChoosePattern };
        }

        private IPattern ChoosePattern(INotifyAction action, string senderName, Notify.Engine.NotifyRequest request)
        {
            if (action == NotifyConstants.Event_NewCommentForMessage)
            {
                var tag = request.Arguments.Find(tv => tv.Tag == "EventType");
                if (tag != null)
                {
                    return PatternProvider.GetPattern(new NotifyAction(Convert.ToString(tag.Value)), senderName);
                }
            }
            return null;
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiRouteConfigurator.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web.Routing;

using ASC.Api.Attributes;
using ASC.Api.Exceptions;
using ASC.Api.Impl.Constraints;
using ASC.Api.Interfaces;
using ASC.Common.Logging;
using ASC.Common.Web;

using Autofac;
using Autofac.Core;

namespace ASC.Api.Impl
{
    class ApiRouteConfigurator : IApiRouteConfigurator
    {
        public IComponentContext Container { get; set; }

        public IApiConfiguration Config { get; set; }

        public ILog Log { get; set; }

        public IEnumerable<IApiMethodCall> RegisterEntryPoints()
        {
            Log.Debug("configuring entry points");
            var routeMap = new List<IApiMethodCall>();
            var registrations = Container.ComponentRegistry.Registrations
                .Where(x => typeof(IApiEntryPoint).IsAssignableFrom(x.Activator.LimitType)).ToList();
            //Register instances
            foreach (var apiMethodCall in registrations.Select(RouteEntryPoint).SelectMany(routePaths => routePaths.Cast<ApiMethodCall>()))
            {
                apiMethodCall.FullPath = GetFullPath(apiMethodCall);
                if (routeMap.Contains(apiMethodCall))
                {
                    throw new ApiDuplicateRouteException(apiMethodCall, routeMap.Find(x => x.Equals(apiMethodCall)));
                }
                Log.DebugFormat("configured {0}", apiMethodCall);
                routeMap.Add(apiMethodCall);
            }

            return routeMap;
        }


        private IEnumerable<IApiMethodCall> RouteEntryPoint(IComponentRegistration apiEntryPoint)
        {
            try
            {
                //Get all methods
                var methods = apiEntryPoint.Activator.LimitType.GetMethods(BindingFlags.Instance | BindingFlags.Public);

                var gloabalFilters = apiEntryPoint.Activator.LimitType.GetCustomAttributes(typeof(ApiCallFilter), true).Cast<ApiCallFilter>().ToList();
                gloabalFilters.AddRange(apiEntryPoint.Activator.LimitType.Assembly.GetCustomAttributes(typeof(ApiCallFilter), true).Cast<ApiCallFilter>());
                gloabalFilters.AddRange(Container.Resolve<IEnumerable<ApiCallFilter>>()); //Add gloably registered filters

                return (from methodInfo in methods.Where(x => !x.IsConstructor)
                        let attr = methodInfo.GetCustomAttributes(typeof(ApiAttribute), true).Cast<ApiAttribute>().FirstOrDefault()
                        let cache = methodInfo.GetCustomAttributes(typeof(CacheAttribute), true).Cast<CacheAttribute>().FirstOrDefault()
                        let filters = methodInfo.GetCustomAttributes(typeof(ApiCallFilter), true).Cast<ApiCallFilter>()
                        where attr != null
                        select ToApiMethodCall(methodInfo, apiEntryPoint, attr, cache, filters, gloabalFilters)).ToList();
            }
            catch (Exception err)
            {
                Log.Error(string.Format("Could not load apiEntryPoint {0}", apiEntryPoint.Activator.LimitType), err);
                return Enumerable.Empty<IApiMethodCall>();
            }
        }

        private IApiMethodCall ToApiMethodCall(MethodInfo methodInfo, IComponentRegistration apiEntryPointType, ApiAttribute attr, CacheAttribute cache, IEnumerable<ApiCallFilter> filters, List<ApiCallFilter> gloabalFilters)
        {
            var methodCall = Container.Resolve<IApiMethodCall>();
            methodCall.MethodCall = methodInfo;
            methodCall.Name = apiEntryPointType.Services.OfType<KeyedService>().First().ServiceKey.ToString();
            methodCall.ApiClassType = apiEntryPointType.Activator.LimitType;
            methodCall.HttpMethod = attr.Method;
            methodCall.RoutingUrl = ExtractPath(attr.Path);
            methodCall.CacheTime = cache != null ? cache.CacheTime : 0;
            methodCall.Constraints = ExtractConstraints(attr.Path, attr.Method);
            methodCall.RequiresAuthorization = attr.RequiresAuthorization;
            methodCall.CheckPayment = attr.CheckPayment;

            //Add filters
            gloabalFilters.AddRange(filters);
            methodCall.Filters = gloabalFilters;

            return methodCall;
        }

        private static readonly Regex RouteParser = new Regex(@"\{(?'route'[^\}:]+)(?'constraint'\:[^\}]+)}", RegexOptions.Compiled);
        private static readonly Regex RouteReplacer = new Regex(@"\{(?'route'[^\}]+)}", RegexOptions.Compiled);

        private RouteValueDictionary ExtractConstraints(string path, string method)
        {
            var rwDict = new RouteValueDictionary();
            var dictionary = RouteParser.Matches(path).Cast<Match>()
                                        .Where(match => match.Success && match.Groups["constraint"].Success && match.Groups["route"].Success)
                                        .ToDictionary(match => match.Groups["route"].Value,
                                                      match => match.Groups["constraint"].Value.TrimStart(':'));
            if (dictionary.Count > 0)
            {
                foreach (var constraint in dictionary)
                {
                    rwDict.Add(constraint.Key, constraint.Value);
                }
            }

            rwDict.Add("method", ApiHttpMethodConstraint.GetInstance(method)); //Adding method Constraint
            return rwDict;
        }

        private static string ExtractPath(string path)
        {
            return RouteParser.Replace(path, EvaluteRoute);
        }

        private static string EvaluteRoute(Match match)
        {
            if (match.Success && match.Groups["constraint"].Success)
            {
                return match.Value.Replace(match.Groups["constraint"].Value, "");
            }
            return match.Value;
        }

        public RouteCallInfo ResolveRoute(MethodInfo apiCall, Dictionary<string, object> arguments)
        {
            //Iterate throug all points and find needed one
            var entryPoint = Container.Resolve<IEnumerable<IApiMethodCall>>().SingleOrDefault(x => x.MethodCall.Equals(apiCall));
            if (entryPoint != null)
            {
                //Yahoo
                var url = RouteReplacer.Replace(GetFullPath(entryPoint),
                                                x =>
                                                    {
                                                        if (x.Success && x.Groups["route"].Success && arguments.ContainsKey(x.Groups["route"].Value))
                                                        {
                                                            var args = arguments[x.Groups["route"].Value];
                                                            arguments.Remove(x.Groups["route"].Value);
                                                            return x.Value.Replace("{" + x.Groups["route"].Value + "}",
                                                                                   Convert.ToString(args, CultureInfo.InvariantCulture));
                                                        }
                                                        return x.Value;
                                                    });
                return new RouteCallInfo
                {
                    Url = url,
                    Method = entryPoint.HttpMethod,
                    Params = arguments
                };
            }
            throw new ArgumentException("Api method not found or not registered");
        }

        private string GetFullPath(IApiMethodCall apiMethodCall)
        {
            return (Config.GetBasePath() + apiMethodCall.Name + Config.ApiSeparator +
                    apiMethodCall.RoutingUrl.TrimStart(Config.ApiSeparator)).TrimEnd('/');
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SDP/SDP_MediaDescription.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SDP
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// A SDP_MediaDescription represents an <B>m=</B> SDP message field. Defined in RFC 4566 5.14. Media Descriptions.
    /// </summary>
    public class SDP_MediaDescription
    {
        #region Members

        private string m_MediaFormat = "";
        private string m_MediaType = "";
        private int m_NumberOfPorts = 1;
        private int m_Port;
        private string m_Protocol = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets meadia type. Currently defined media are "audio", "video", "text", 
        /// "application", and "message", although this list may be extended in the future.
        /// </summary>
        public string MediaType
        {
            get { return m_MediaType; }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("Property Protocol can't be null or empty !");
                }

                m_MediaType = value;
            }
        }

        /// <summary>
        /// Gets or sets the transport port to which the media stream is sent.
        /// </summary>
        public int Port
        {
            get { return m_Port; }

            set { m_Port = value; }
        }

        /// <summary>
        /// Gets or sets number of continuos media ports.
        /// </summary>
        public int NumberOfPorts
        {
            get { return m_NumberOfPorts; }

            set
            {
                if (value < 1)
                {
                    throw new ArgumentException("Property NumberOfPorts must be >= 1 !");
                }

                m_NumberOfPorts = value;
            }
        }

        /// <summary>
        /// Gets or sets transport protocol. Currently known protocols: UDP;RTP/AVP;RTP/SAVP.
        /// </summary>
        public string Protocol
        {
            get { return m_Protocol; }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("Property Protocol cant be null or empty !");
                }

                m_Protocol = value;
            }
        }

        /// <summary>
        /// Gets or sets media format description. The interpretation of the media 
        /// format depends on the value of the "proto" sub-field.
        /// </summary>
        public string MediaFormatDescription
        {
            get { return m_MediaFormat; }

            set
            {
                if (value == null)
                {
                    throw new ArgumentException("Property Protocol cant be null !");
                }

                m_MediaFormat = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses media from "m" SDP message field.
        /// </summary>
        /// <param name="mValue">"m" SDP message field.</param>
        /// <returns></returns>
        public static SDP_MediaDescription Parse(string mValue)
        {
            SDP_MediaDescription media = new SDP_MediaDescription();

            // m=<media> <port>/<number of ports> <proto> <fmt> ...
            StringReader r = new StringReader(mValue);
            r.QuotedReadToDelimiter('=');

            //--- <media> ------------------------------------------------------------
            string word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("SDP message \"m\" field <media> value is missing !");
            }
            media.m_MediaType = word;

            //--- <port>/<number of ports> -------------------------------------------
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("SDP message \"m\" field <port> value is missing !");
            }
            if (word.IndexOf('/') > -1)
            {
                string[] port_nPorts = word.Split('/');
                media.m_Port = Convert.ToInt32(port_nPorts[0]);
                media.m_NumberOfPorts = Convert.ToInt32(port_nPorts[1]);
            }
            else
            {
                media.m_Port = Convert.ToInt32(word);
                media.m_NumberOfPorts = 1;
            }

            //--- <proto> --------------------------------------------------------------
            word = r.ReadWord();
            if (word == null)
            {
                throw new Exception("SDP message \"m\" field <proto> value is missing !");
            }
            media.m_Protocol = word;

            //--- <fmt> ----------------------------------------------------------------
            word = r.ReadWord();
            if (word == null)
            {
                media.m_MediaFormat = "";
            }
            else
            {
                media.m_MediaFormat = word;
            }

            return media;
        }

        /// <summary>
        /// Converts this to valid media string.
        /// </summary>
        /// <returns></returns>
        public string ToValue()
        {
            // m=<media> <port>/<number of ports> <proto> <fmt> ...

            return "m=" + MediaType + " " + Port + "/" + NumberOfPorts + " " + Protocol + " " +
                   MediaFormatDescription + "\r\n";
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/Backup/js/backup.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.BackupManager = new function() {
    var $ = jq;

    var backupStorageFolderId = null;
    var autoBackupSettingsStorageFolderId = null;

    var autoBackupInitOff = null;

    var $view = $('#backup-manager-view');

    var $maxStoredCopiesCount = $view.find('#maxStoredCopiesCount');
    var thirdPartyStorageSelectorHelpers = $view.find('.thirdPartyStorageSelectorHelper');

    var $backupBox = $view.find('#backupBox');

    var $backupStoragesBox = $backupBox.find('#backupStoragesBox');
    var $backupTeamlabStorageFolderSelector = $backupBox.find('#backupTeamlabStorageFolderSelector');
    var $backupTeamlabStorageFolderSelectorBtn = $backupBox.find('#backupTeamlabStorageFolderSelectorBtn');

    var $backupThirdPartyStorageSelectorBox = $backupBox.find('#backupThirdPartyStorageSelectorBox');
    var $backupThirdPartyStorage = $backupBox.find('#backupThirdPartyStorage');
    var $backupWithMailCheck = $backupBox.find('#backupWithMailCheck');

    var $startBackupBtn = $backupBox.find('#startBackupBtn');

    var $backupProgressBox = $backupBox.find('#backupProgressBox');
    var $backupProgressValue = $backupBox.find('#backupProgressValue');
    var $backupProgressText = $backupBox.find('#backupProgressText');

    var $backupResultLinkBox = $backupBox.find('#backupResultLinkBox');
    var $backupResultLink = $backupBox.find('#backupResultLink');

    var $autoBackupSettingsBox = $view.find('#autoBackupSettingsBox');

    var $autoBackupOn = $autoBackupSettingsBox.find('#autoBackupOn');
    var $autoBackupOff = $autoBackupSettingsBox.find('#autoBackupOff');

    var $autoBackuSettingsBlock = $autoBackupSettingsBox.find('#autoBackuSettingsBlock');
    var $autoBackupSettingsStoragesBox = $autoBackuSettingsBlock.find('#autoBackupSettingsStoragesBox');

    var $autoBackupSettingsTeamlabStorageFolderSelectorBox = $autoBackuSettingsBlock.find('#autoBackupSettingsTeamlabStorageFolderSelectorBox');
    var $autoBackupSettingsTeamlabStorageFolderSelector = $autoBackuSettingsBlock.find('#autoBackupSettingsTeamlabStorageFolderSelector');
    var $autoBackupSettingsTeamlabStorageFolderSelectorBtn = $autoBackuSettingsBlock.find('#autoBackupSettingsTeamlabStorageFolderSelectorBtn');

    var $autoBackupSettingsThirdPartyStorage = $autoBackuSettingsBlock.find('#autoBackupSettingsThirdPartyStorage');
    var $autobackupConsumerStorageSettingsBox = $autoBackuSettingsBlock.find('#backupConsumerStorageScheduleSettingsBox');
    var $autoBackupSettingsTeamlabStorage = $autoBackuSettingsBlock.find('#autoBackupSettingsTeamlabStorage');

    var $autoBackupSettingsWithMailCheck = $autoBackuSettingsBlock.find('#autoBackupSettingsWithMailCheck');

    var $saveSettingsBtn = $view.find('#saveSettingsBtn');

    var storageTypes = {
        Temp: "4",
        Docs: "0",
        ThirdPartyDocs: "1",
        Consumers: "5"
    }

    var displayNoneClass = "display-none", withErrorClass = "withError", disable = "disable";
    var ResourceJS = ASC.Resources.Master.ResourceJS;

    function init() {

        showLoader();

        initFolderSelector();
        initMaxStoredCopiesCount();

        Teamlab.getBackupSchedule({},
        {
            success: function (params, response) {
                initAutoBackupSchedule(response);
                bind$Events();

                hideLoader();
                Teamlab.getBackupProgress({},
                {
                    success: function (params, data) {
                        processBackupResponseContinue(data);
                    }
                });
            },
            error: function (params, errors) {
                toastr.error(errors[0]);
            }
        });

        Teamlab.getBackupStorages({},
        {
            success: function (params, response) {
                initConsumerStorages(response);
            },
            error: function (params, errors) {
                toastr.error(errors[0]);
            }
        });
    }

    function initFolderSelector() {
        $('#fileSelectorTree > ul > li.tree-node:not([data-id=\'' + ASC.Files.Constants.FOLDER_ID_COMMON_FILES + '\'])').remove();

        ASC.Files.FileSelector.onInit = function() {
            ASC.Files.FileSelector.toggleThirdParty(true);

            ASC.Files.FileSelector.onThirdPartyTreeCreated = function() {
                $('*:not(.disabled) > .settings-block .thirdPartyStorageSelectorBox')
                    .removeAttr('title')
                    .removeClass('disabled')
                    .find(':radio')
                    .attr('disabled', false);
            };
            ASC.Files.FileSelector.createThirdPartyTree();
        };
    }

    function initMaxStoredCopiesCount() {
        for (var i = 1; i < 31; i++) {
            if (i == 10) {
                $maxStoredCopiesCount.append('<option selected="selected" val=' + i + '>' + i + '</option>');
            } else {
                $maxStoredCopiesCount.append('<option val=' + i + '>' + i + '</option>');
            }
        }
    }

    function initAutoBackupSchedule(response) {
        if (typeof (response.storageType) !== "undefined") {
            var value = response;
            var storage = {
                name: value.storageType,
                params: value.storageParams
            };
            var withMail = value.backupMail;
            var scheduleTime = value.cronParams;
            var maxStoredCopiesCount = value.backupsStored;
            var storageType = storage.name.toString();

            switch (storageType) {
                case storageTypes.Docs:
                case storageTypes.ThirdPartyDocs:
                    $autoBackupSettingsTeamlabStorageFolderSelector.attr('data-folderid', storage.params["folderId"]);
                    autoBackupSettingsStorageFolderId = storage.params["folderId"];
                    displayFolderPath($autoBackupSettingsBox, autoBackupSettingsStorageFolderId);
                    getAutoBackupTeamlabFolderStorage(autoBackupSettingsStorageFolderId);
                    break;
                case storageTypes.Consumers:
                    $autobackupConsumerStorageSettingsBox.removeClass(displayNoneClass);
                    break;
            }

            var $time = $('.select-time-period');
            var $period = $time.find('#generatedTimePeriod');
            var $week = $time.find('#week');
            var $month = $time.find('#month');
            var $hours = $time.find('#hours');

            switch (scheduleTime.period) {
                case 0:
                    $period.val('day');
                    break;
                case 1:
                    $period.val('week');
                    $week.val(scheduleTime.day).removeClass('display-none');
                    break;
                case 2:
                    $period.val('month');
                    $month.val(scheduleTime.day).removeClass('display-none');
                    break;
            }
            $hours.val(scheduleTime.hour);

            
            $autoBackupSettingsStoragesBox.find('input[value="' + storage.name + '"]').prop('checked', true);

            $autoBackupSettingsWithMailCheck.prop('checked', withMail);
            $maxStoredCopiesCount.val(maxStoredCopiesCount);

            if (!jq("#autoBackupSettingsBox").hasClass("disable")) {
                $autoBackuSettingsBlock.show();
                $autoBackupOn.prop('checked', true);
            } else {
                $autoBackupOff.prop('checked', true);
            }
            $view.show();
        } else {
            autoBackupInitOff = true;
            $autoBackupOff.prop('checked', true);
            $view.show();
        }
    }

    function getAutoBackupTeamlabFolderStorage(folderId) {
        Teamlab.getFolderPath(folderId, {
            success: function(e, data) {
                var path = $(data).map(function(i, folder) {
                    return folder.title;
                });
                var pathTitle = path.toArray().join(' > ');
                $autoBackupSettingsTeamlabStorageFolderSelector.val(pathTitle).attr('data-folderId', folderId);
                $autoBackupSettingsTeamlabStorageFolderSelectorBox.show();
            },
            error: function(params, errors) {
                toastr.error(errors);
            }
        });
    }

    function bind$Events() {
        $backupTeamlabStorageFolderSelectorBtn.on('click', showTeamlabStorageFolderPop);
        $autoBackupSettingsTeamlabStorageFolderSelectorBtn.on('click', showTeamlabStorageFolderPop);

        thirdPartyStorageSelectorHelpers.on('click', showThirdPartyStorageSelectorHelpBox);

        $autoBackupOn.on('change', toggleAutoBackupSettingsBlock);
        $autoBackupOff.on('change', toggleAutoBackupSettingsBlock);

        $backupStoragesBox.find('input[name=backupStorageSelector]').on('change', selectStorage);
        $autoBackupSettingsStoragesBox.find('input[name=autoBackupSettingsStorageSelector]').on('change', selectStorage);

        $startBackupBtn.on('click', startBackup);
        $saveSettingsBtn.on('click', saveSettings);
    }

    function showTeamlabStorageFolderPop() {
        var $this = $(this);
        if ($this.is('.disable')) {
            return;
        }

        var $box = $(this).closest('.backupBox');
        ASC.Files.FileSelector.onSubmit = function(folderId) {
            displayFolderPath($box, folderId);
        };

        if ($(this).is($backupTeamlabStorageFolderSelectorBtn)) {
            ASC.Files.FileSelector.openDialog(backupStorageFolderId, true, $backupThirdPartyStorage.is(':checked'));
            ASC.Files.FileSelector.setTitle(ResourceJS.SelectFolder);
        } else {
            ASC.Files.FileSelector.openDialog(autoBackupSettingsStorageFolderId, true, $autoBackupSettingsThirdPartyStorage.is(':checked'));
            ASC.Files.FileSelector.setTitle(ResourceJS.SelectFolder);
        }
    }

    function initConsumerStorages(storages) {
        if (!storages.length) return;

        var $input = $view.find("#backupConsumerStorage,#scheduleConsumerStorage");
        $input.removeAttr("disabled");
        $input.parent("li").removeClass("disabled");

        var $backupConsumerStorageSettingsBox = $view.find("#backupConsumerStorageSettingsBox");
        var selectedConsumer = storages.find(function (item) { return item.isSet }) || storages[1];
        initConsumerStorage($backupConsumerStorageSettingsBox, selectedConsumer, storages);

        var $backupConsumerStorageScheduleSettingsBox = $view.find("#backupConsumerStorageScheduleSettingsBox");
        selectedConsumer = storages.find(function (item) { return item.current }) || selectedConsumer;
        initConsumerStorage($backupConsumerStorageScheduleSettingsBox, selectedConsumer, storages);
        for (var i = 0; i < selectedConsumer.properties.length; i++) {
            var prop = selectedConsumer.properties[i];
            $backupConsumerStorageScheduleSettingsBox.find("[data-id='" + prop.title + "']").val(prop.value);
        }
    }

    function initConsumerStorage($box, selectedConsumer, storages) {
        var textBoxClass = ".textBox";
        var textEditClass = ".textEdit";

        $box.html(jq.tmpl("consumerSettingsTmpl", { storages: storages, selectedConsumer: selectedConsumer }));
        $box.off("change" + textEditClass).on("change" + textEditClass, textEditClass, function () {
            $box.find(textBoxClass).val('');

            var newVal = jq(this).find(":selected").val();
            $box.find(textBoxClass).removeClass(withErrorClass);
            $box.find("div[data-id]").addClass(displayNoneClass);
            $box.find("[data-id='" + newVal + "']").removeClass(displayNoneClass);
            $startBackupBtn.addClass(disable);
        });
        $box.find("select option[value='" + selectedConsumer.id + "']").attr("selected", "selected");
        $box.find("select");
        $box.off("input" + textBoxClass).on("input" + textBoxClass, textBoxClass, function () {
            var $self = $(this);
            var $siblings = Array.from($self.siblings());
            $siblings.push(this);

            $self.removeClass(withErrorClass);

            function notEmpty(item) {
                return item.value.length > 0;
            }

            if ($siblings.every(notEmpty)) {
                $startBackupBtn.removeClass(disable);
            } else {
                $startBackupBtn.addClass(disable);
            }
        });
    }

    function toggleAutoBackupSettingsBlock() {
        var on = $autoBackupOn.is(':checked');
        if (on) {
            $autoBackuSettingsBlock.show();
            
            if (autoBackupInitOff) {
                autoBackupInitOff = false;
                $autoBackupSettingsTeamlabStorage.click();
            }
        } else {
            $autoBackuSettingsBlock.hide();
        }
    }

    function showThirdPartyStorageSelectorHelpBox() {
        $(this).helper({
            BlockHelperID: $(this).attr('data-helpboxselector')
        });
    }

    function selectStorage() {
        var $box = $(this).closest('.backupBox');

        var $storagesBox = $box.find('.backupStoragesBox');
        var storage = $storagesBox.find(':checked').val();

        var $teamlabStorageFolderSelectorBox = $box.find('.teamlabStorageFolderSelectorBox');
        var $teamlabStorageFolderSelector = $teamlabStorageFolderSelectorBox.find('.teamlabStorageFolderSelector');

        var $backupConsumerStorageSettingsBox = $box.find('.consumerStorageSettingsBox');
        $teamlabStorageFolderSelectorBox.addClass(displayNoneClass);
        $backupConsumerStorageSettingsBox.addClass(displayNoneClass);
        $startBackupBtn.removeClass(disable);

        switch (storage) {
            case storageTypes.Docs:
                if ($box.is('#backupBox')) {
                    backupStorageFolderId = ASC.Files.Constants.FOLDER_ID_COMMON_FILES;
                    $teamlabStorageFolderSelector.attr('data-folderid', backupStorageFolderId);
                    displayFolderPath($box, backupStorageFolderId);
                } else {
                    autoBackupSettingsStorageFolderId = ASC.Files.Constants.FOLDER_ID_COMMON_FILES;
                    $teamlabStorageFolderSelector.attr('data-folderid', autoBackupSettingsStorageFolderId);
                    displayFolderPath($box, autoBackupSettingsStorageFolderId);
                }

                $teamlabStorageFolderSelectorBox.removeClass(displayNoneClass);
                break;
            case storageTypes.ThirdPartyDocs:
                $teamlabStorageFolderSelector.val('').attr('data-folderId', '');
                $teamlabStorageFolderSelectorBox.removeClass(displayNoneClass);
                break;
            case storageTypes.Consumers:
                if (!$view.find("#backupConsumerStorage").parent("li").hasClass("disabled")) {
                    $backupConsumerStorageSettingsBox.find("select").trigger("change");
                    $backupConsumerStorageSettingsBox.removeClass(displayNoneClass);
                }
                break;
        }
    }

    function displayFolderPath($box, folderId) {
        var folderTitle = ASC.Files.FileSelector.fileSelectorTree.getFolderTitle(folderId);

        var path = ASC.Files.FileSelector.fileSelectorTree.getPath(folderId);
        var pathId = $(path).map(function(i, fId) {
            return ASC.Files.FileSelector.fileSelectorTree.getFolderTitle(fId);
        });

        pathId.push(folderTitle);
        var pathTitle = pathId.toArray().join(' > ');

        var $teamlabStorageFolderSelector = $box.find('.teamlabStorageFolderSelector');
        $teamlabStorageFolderSelector.val(pathTitle).attr('data-folderId', folderId);
    }

    function getStorage($box) {
        var $storage = $box.find('.backupStoragesBox :checked');
        var storage = {
            storageType: $storage.val(),
            storageParams: []
        };

        $box.find('.teamlabStorageFolderSelector').removeClass('with-error');

        switch (storage.storageType) {
            case storageTypes.Docs:
            case storageTypes.ThirdPartyDocs:
                var $path = $box.find('.teamlabStorageFolderSelector');
                var val = $path.attr('data-folderid');
                storage.storageParams.push({ key: "folderId", value: val });
                if (!val) {
                    $path.addClass('with-error');
                    return false;
                }

                break;
            case storageTypes.Consumers:
                var isError;
                var $selectedConsumer = $box.find('.consumerStorageSettingsBox');
                var selectedConsumer = $selectedConsumer.find('.textEdit :selected').val();
                var $settings = $selectedConsumer.find('div[data-id="' + selectedConsumer + '"] .textBox');
                storage.storageParams.push({ key: "module", value: selectedConsumer });
                var settingsLength = $settings.length;
                for (var i = 0; i < settingsLength; i++) {
                    var $item = $($settings[i]);
                    if (!$item.val()) {
                        $item.addClass(withErrorClass);
                        isError = true;
                    }
                    else {
                        storage.storageParams.push({ key: $item.attr("data-id"), value: $item.val() });
                    }
                }

                if (isError) {
                    return false;
                }
                break;
        }

        return storage;
    }

    function startBackup() {
        if ($startBackupBtn.is('.disable')) {
            return;
        }

        $backupProgressBox.hide();
        $backupResultLinkBox.hide();

        var storage = getStorage($backupBox);
        storage.backupMail = $backupWithMailCheck.is(':checked');

        if (!storage) {
            return;
        }

        LoadingBanner.showLoaderBtn($backupBox);
        lockBackupBox(true);
        showBackupProgress(0);

        Teamlab.startbackup({}, storage,
        {
            success: function(params, data) {
                processBackupResponse(data);
            },
            error: function(params, errors) {
                showAmazonServerError($backupBox, errors[0]);
                $backupProgressBox.hide();
                LoadingBanner.hideLoaderBtn($backupBox);
                lockBackupBox(false);
            }
        });
    }

    function processBackupResponse(response) {
        if (response && response.isCompleted) {
            $backupProgressBox.hide();
            LoadingBanner.hideLoaderBtn($backupBox);
            lockBackupBox(false);

            if (response.link) {
                $backupResultLink.attr('href', response.link);
                $backupResultLinkBox.show();
            }
            toastr.success(ResourceJS.BackupMakeCopySuccess);
            return;
        }

        processBackupResponseContinue(response);
    }

    function processBackupResponseContinue(response) {
        if (typeof(response.isCompleted) === "undefined" || response.isCompleted) {
            return;
        }

        showBackupProgress(response.progress);
        setTimeout(function () {
            Teamlab.getBackupProgress({},
            {
                success: function (params, data) {
                    processBackupResponse(data);
                },
                error: function (params, errors) {
                    $backupProgressBox.hide();
                    LoadingBanner.hideLoaderBtn($backupBox);
                    lockBackupBox(false);
                    toastr.error(ResourceJS.CommonJSErrorMsg);
                },
                max_request_attempts: 1
            });
        }, 1000);
    }

    function lockBackupBox(locked) {
        $backupBox.find('input[name="backupStorageSelector"]:not(#backupThirdPartyStorage)').prop('disabled', locked);
        $backupTeamlabStorageFolderSelector.prop('disabled', locked);
        $backupWithMailCheck.prop('disabled', locked);

        $backupTeamlabStorageFolderSelectorBtn.toggleClass(disable, locked);
        $startBackupBtn.data('locked', locked);
        $startBackupBtn.toggleClass(disable, locked);
        jq("#saveSettingsBtn").toggleClass(disable, locked);

        if (!$backupThirdPartyStorageSelectorBox.is('.disabled')) {
            $backupThirdPartyStorage.prop('disabled', locked);
        }
    }

    function showBackupProgress(progress) {
        $backupProgressValue.animate({ 'width': progress + '%' });
        $backupProgressText.text(progress + '% ');
        $backupProgressBox.show();
    }

    function saveSettings() {
        if ($saveSettingsBtn.hasClass(disable)) {
            return;
        }

        var autoOn = $autoBackupOn.is(':checked');
        if (autoOn) {
            var storage = getStorage($autoBackupSettingsBox);
            var $period = $('.select-time-period');
            var periodTime = {};
            var countCopy = $maxStoredCopiesCount.val();
            var withMail = $autoBackupSettingsWithMailCheck.is(':checked');

            if (!storage) {
                return;
            }

            switch ($period.find('#generatedTimePeriod').val()) {
                case 'day':
                    periodTime.Period = 0;
                    break;
                case 'week':
                    periodTime.Period = 1;
                    break;
                case 'month':
                    periodTime.Period = 2;
                    break;
            }
            periodTime.Hour = $period.find('#hours').val();

            if ($period.find('#week').is(':visible')) {
                periodTime.Day = $period.find('#week').val();
            }
            if ($period.find('#month').is(':visible')) {
                periodTime.Day = $period.find('#month').val();
            }
            LoadingBanner.showLoaderBtn($autoBackupSettingsBox);

            storage.backupsStored = countCopy;
            storage.cronParams = periodTime;
            storage.backupMail = withMail;

            Teamlab.createBackupSchedule({}, storage,
            {
                success: function(params, data) {
                    onCompleteCreateShedule(data);
                },
                error: function(params, data) {
                    oErrorCreateShedule(data);
                }
            });
        } else {
            LoadingBanner.showLoaderBtn($autoBackupSettingsBox);

            Teamlab.deleteBackupSchedule({},
            {
                success: function (params, data) {
                    onCompleteCreateShedule(data);
                },
                error: function (params, data) {
                    oErrorCreateShedule(data);
                }
            });
        }
    }

    function onCompleteCreateShedule() {
        $autoBackupSettingsBox.find('.with-error').removeClass('with-error');
        toastr.success(ResourceJS.SuccessfullySaveSettingsMessage);
        LoadingBanner.hideLoaderBtn($autoBackupSettingsBox);
    }

    function oErrorCreateShedule(errors) {
        showAmazonServerError($autoBackupSettingsBox, errors[0]);
    }


    function showAmazonServerError($box, error) {
        switch (error) {
            default:
                toastr.error(error);
                break;
        }
    }

    function showLoader() {
        LoadingBanner.displayLoading();
    }

    function hideLoader() {
        LoadingBanner.hideLoading();
    }

    return {
        init: init
    };
};

jq(function() {
    window.BackupManager.init();
});

<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Core/DbSchema/Tables/DomainTable.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Server.Core.DbSchema.Interfaces;

namespace ASC.Mail.Server.Core.DbSchema.Tables
{
    public class DomainTable : ITable
    {
        public const string TABLE_NAME = "domain";

        public static class Columns
        {
            public const string DOMAIN = "domain";
            public const string DESCRIPTION = "description";
            public const string ALIASES = "aliases";
            public const string MAILBOXES = "mailboxes";
            public const string MAXQUOTA = "maxquota";
            public const string QUOTA = "quota";
            public const string TRANSPORT = "transport";
            public const string BACKUPMX = "backupmx";
            public const string CREATED = "created";
            public const string MODIFIED = "modified";
            public const string ACTIVE = "active";
        }

        public string Name { get { return TABLE_NAME; } }

        public IEnumerable<string> OrderedColumnCollection { get; private set; }

        public DomainTable()
        {
            OrderedColumnCollection = new List<string>
            {
                Columns.DOMAIN,
                Columns.DESCRIPTION,
                Columns.ALIASES,
                Columns.MAILBOXES,
                Columns.MAXQUOTA,
                Columns.QUOTA,
                Columns.TRANSPORT,
                Columns.BACKUPMX,
                Columns.CREATED,
                Columns.MODIFIED,
                Columns.ACTIVE
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileOperations/FileOperationResult.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

namespace ASC.Web.Files.Services.WCFService.FileOperations
{
    [DataContract(Name = "operation_result", Namespace = "")]
    public class FileOperationResult
    {
        [DataMember(Name = "id")]
        public string Id { get; set; }

        [DataMember(Name = "operation")]
        public FileOperationType OperationType { get; set; }

        [DataMember(Name = "progress")]
        public int Progress { get; set; }

        [DataMember(Name = "source")]
        public string Source { get; set; }

        [DataMember(Name = "result")]
        public string Result { get; set; }

        [DataMember(Name = "error")]
        public string Error { get; set; }

        [DataMember(Name = "processed")]
        public string Processed { get; set; }

        [DataMember(Name = "finished")]
        public bool Finished { get; set; }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Sample/Masters/BasicTemplate.Master.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web.UI;

using ASC.Core;
using ASC.Web.Core;
using ASC.Web.Core.Client.Bundling;
using ASC.Web.Sample.Classes;
using ASC.Web.Sample.Configuration;
using ASC.Web.Sample.Controls;

namespace ASC.Web.Sample.Masters
{
    public partial class BasicTemplate : MasterPage, IStaticBundle
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            SampleDao.CheckTable();

            InitControls();

            Page.EnableViewState = false;

            Master
                .AddClientScript(((Product)WebItemManager.Instance[ProductEntryPoint.Id]).ClientScriptLocalization);
        }

        protected void InitControls()
        {
            CreateButtonContent.Controls.Add(LoadControl(ButtonsSidePanel.Location));
            SideNavigation.Controls.Add(LoadControl(NavigationSidePanel.Location));

            Master
                .AddStaticStyles(GetStaticStyleSheet())
                .AddStaticBodyScripts(GetStaticJavaScript())
                .RegisterInlineScript(string.Format("ASC.Sample.PageScript.init('{0}');", SecurityContext.CurrentAccount.ID));
        }


        public ScriptBundleData GetStaticJavaScript()
        {
            return (ScriptBundleData)
                   new ScriptBundleData("sample", "sample")
                       .AddSource(PathProvider.GetFileStaticRelativePath,
                                  "script.js")
                       .AddSource(ResolveUrl,
                                  "~/js/uploader/ajaxupload.js");
        }

        public StyleBundleData GetStaticStyleSheet()
        {
            return (StyleBundleData)
                   new StyleBundleData("sample", "sample")
                       .AddSource(PathProvider.GetFileStaticRelativePath,
                                  "style.less");
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Caching/CachedQuotaService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Caching;
using ASC.Core.Tenants;

namespace ASC.Core.Caching
{
    public class CachedQuotaService : IQuotaService
    {
        private const string KEY_QUOTA = "quota";
        private const string KEY_QUOTA_ROWS = "quotarows";
        private readonly IQuotaService service;
        private readonly ICache cache;
        private readonly ICacheNotify cacheNotify;


        public TimeSpan CacheExpiration
        {
            get;
            set;
        }


        public CachedQuotaService(IQuotaService service)
        {
            if (service == null) throw new ArgumentNullException("service");

            this.service = service;
            cache = AscCache.Memory;
            CacheExpiration = TimeSpan.FromMinutes(10);

            cacheNotify = AscCache.Notify;
            cacheNotify.Subscribe<QuotaCacheItem>((i, a) =>
            {
                if (i.Key == KEY_QUOTA)
                {
                    cache.Remove(KEY_QUOTA);
                }
                else
                {
                    cache.Remove(i.Key);
                }
            });
        }


        public IEnumerable<TenantQuota> GetTenantQuotas()
        {
            var quotas = cache.Get<IEnumerable<TenantQuota>>(KEY_QUOTA);
            if (quotas == null)
            {
                cache.Insert(KEY_QUOTA, quotas = service.GetTenantQuotas(), DateTime.UtcNow.Add(CacheExpiration));
            }
            return quotas;
        }

        public TenantQuota GetTenantQuota(int tenant)
        {
            return GetTenantQuotas().SingleOrDefault(q => q.Id == tenant);
        }

        public TenantQuota SaveTenantQuota(TenantQuota quota)
        {
            var q = service.SaveTenantQuota(quota);
            cacheNotify.Publish(new QuotaCacheItem { Key = KEY_QUOTA }, CacheNotifyAction.Remove);
            return q;
        }

        public void RemoveTenantQuota(int tenant)
        {
            throw new NotImplementedException();
        }


        public void SetTenantQuotaRow(TenantQuotaRow row, bool exchange)
        {
            service.SetTenantQuotaRow(row, exchange);
            cacheNotify.Publish(new QuotaCacheItem { Key = GetKey(row.Tenant) }, CacheNotifyAction.InsertOrUpdate);
        }

        public IEnumerable<TenantQuotaRow> FindTenantQuotaRows(int tenantId)
        {
            var key = GetKey(tenantId);
            var result = cache.Get<IEnumerable<TenantQuotaRow>>(key);

            if (result == null)
            {
                result = service.FindTenantQuotaRows(tenantId);
                cache.Insert(key, result, DateTime.UtcNow.Add(CacheExpiration));
            }

            return result;
        }

        public string GetKey(int tenant)
        {
            return KEY_QUOTA_ROWS + tenant;
        }


        [Serializable]
        class QuotaCacheItem
        {
            public string Key { get; set; }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/AUTH/AUTH_e_UserInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.AUTH
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class provides data for server authentication mechanisms <b>GetUserInfo</b> event.
    /// </summary>
    public class AUTH_e_UserInfo : EventArgs
    {
        #region Members

        private readonly string m_UserName = "";
        private string m_Password = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets if specified user exists.
        /// </summary>
        public bool UserExists { get; set; }

        /// <summary>
        /// Gets user name.
        /// </summary>
        public string UserName
        {
            get { return m_UserName; }
        }

        /// <summary>
        /// Gets or sets user password.
        /// </summary>
        public string Password
        {
            get { return m_Password; }

            set { m_Password = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="userName">User name.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>userName</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public AUTH_e_UserInfo(string userName)
        {
            if (userName == null)
            {
                throw new ArgumentNullException("userName");
            }
            if (userName == string.Empty)
            {
                throw new ArgumentException("Argument 'userName' value must be specified.", "userName");
            }

            m_UserName = userName;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/News/App_Themes/default/newsstylesheet.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.ContentView {

}
#left-section
{
	min-width: 160px;
	width:15%;
	padding:15px;
}
#right-section
{
	width:85%;
	padding:15px;
	max-width:400px;
}

.section
{
	padding:0 0.25em;
	vertical-align:top;
}
.divMenu
{
	float:left;
	width:100%;
	height:100%;
}

.divContent
{
	float:left;
	padding:10px;
	padding-right: 50px;
	width:95%;
}

.menuLink
{
	color:#ffffff;
	text-align:center;
	vertical-align:middle;
	font-size:12px;       
}

.infoLink
{   
	display:inline-block;
	padding:3px;
	color:#ffffff; 
	text-decoration:none;   
    cursor:pointer;
	position:relative;
	background-color:#367caf;
	width:100px;
	text-align:center;
	vertical-align:middle;
	font-size:12px;       
    border-color:#ffffff #ffffff #ffffff #ffffff;
    border-width:1px 1px 0px 1px;
    border-style: solid solid solid solid;
    margin-right:10px;
}

.newsDiv
{
	margin-bottom: 10px;
	padding: 5px;
	width: 100%;
	-moz-border-radius-bottomleft:5px;
	-moz-border-radius-bottomright:5px;
	-moz-border-radius-topleft:5px;
	-moz-border-radius-topright:5px;
	overflow:hidden;
}

.newsRepeater
{
	width: 100%;
}

.newsLink
{
	font-size:20px;
	text-decoration:none;
}


.newsHeader
{
	float:left;
	overflow: hidden;
	margin-bottom: 10px;
	width:100%;
	
}


.newsFullText img 
{
	max-width:800px;
	overflow:scroll;
}
.newsFullText
{
	overflow-y:hidden;
	overflow-x:auto;
	width:100%;
}

.newsText
{
	width: 100%;
	max-height:80px;
	overflow:hidden;
}

.newsContextMenu
{
	padding: 20px 0 5px 9px;
	width: 100%;
	overflow: hidden;
}


/*---------------------News module------------------*/
.news-row:hover
{
    background-color: #E6E6E6;
}
.news-row:hover .linkMedium
{
    text-decoration: underline;
}
.news-link-container {
    overflow: hidden;
    text-overflow: ellipsis;
}
.feedPrevDescription
{
	border-bottom: solid 1px #C7CCD2;
	border-top: solid 1px #C7CCD2;
	font-size:16px;
	font-weight:bold;
	padding:11px 0px;
	color:#111;
}

.feedPrevCaption {
    border: 0 none;
    color: #111;
    font-size: 24px;
    padding: 0;
    width: 100%;
}

.feedPrevBody
{
	padding:32px 24px 36px 32px;	
}

.feedPrevCredits
{
	border-bottom: solid 1px #C7CCD2;
	color:#D1D1D1;
	padding:10px 0;
}

.feedPrevEditButton
{
	color:#36393E !important;
}

/*--------------------------------------------------*/

#feedPrevDiv_Body
{   
    border-bottom: 1px solid #D1D1D1;
    margin-bottom: 20px; 
    padding: 15px 10px;
}

#tableForNavigation {
    height: 24px;
    width: 100%;
}
.navigationLinkBox .tl-combobox .combobox-container {
    padding: 8px;
    width: 50px;
}
.navigationLinkBox .tl-combobox .combobox-container .combobox-options {
    line-height: 22px;
}
.navigationLinkBox .tl-combobox .combobox-title .inner-text {
    border-bottom: 1px dotted #666666;
    color: #666666;
}
.navigationLinkBox .tl-combobox {
    background: url("images/comboarrow_bottom.png") no-repeat scroll right center transparent;
    margin-bottom: 1px;
    vertical-align: middle;
}


/*--------------Events list------------*/

.news-row .events_date {
}
.news-row .events_type {
}
.news-row .events_name {
    max-width:250px;
}
.news-row .events_autor {    
    max-width: 600px;
    overflow: hidden;
    text-align: right;
    text-overflow: ellipsis;
    white-space: nowrap;
}


body.media-width-0-1300 .news-row .events_name {
    max-width: 150px;
}
body.media-width-0-1300 .news-row .events_autor {
    max-width: 330px;
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/filters/modal.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.filterModal = (function($) {
    var isInit = false,
        wnd;

    function init() {
        if (isInit === true) return;

        isInit = true;

        wnd = $('#filterWnd');
    }

    function blockUi(width, message) {
        window.StudioBlockUIManager.blockUI(message, width, { bindEvents: false });

        $('#manageWindow .cancelButton').css('cursor', 'pointer');
        $('.containerBodyBlock .buttons .cancel').unbind('click').bind('click', function () {
            $.unblockUI();
            return false;
        });
    }

    function show(filter, type) {
        wnd.find('.buttons .button').hide();
        wnd.find('.mail-confirmationAction').hide();
        wnd.find('.buttons .cancel').show();

        var headerText;

        switch (type) {
        case 'apply':
            wnd.find('.save').show();

            var actionsContainer = wnd.find('.mail-confirmationAction p.actions');

            actionsContainer.empty();

            var i, n = filter.actions.length;
            for (i = 0; i < n; i++) {
                var a = filter.actions[i],
                    actionEl = $('<span class="actionText"></span>');

                var actionText = "&mdash; " + filtersPage.translateAction(a.action);
                if (a.data && a.data !== '') {
                    actionText += "&nbsp;<span class=\"actionValue\">\"{0}\"</span>".format(TMMail
                        .htmlEncode(filtersPage.translateActionData(a.action, a.data)));
                }
                actionEl.html(actionText);

                actionsContainer.append(actionEl).append("<br>");
            }

            headerText = wnd.attr('apply_header');
            break;
        case 'delete':
            wnd.find('.del').show();
            headerText = wnd.attr('delete_header');
            break;
        case 'confirm':
            wnd.find('.confirm').show();
            wnd.find('.change').show();
            headerText = wnd.attr('confirm_header');
            break;
        default:
            console.error("Modal window type is not accepted");
            return;
        }

        wnd.find('div.containerHeaderBlock:first td:first').html(headerText);

        blockUi(523, wnd);

        window.PopupKeyUpActionProvider.EnterAction = "jq('#filterWnd .containerBodyBlock .buttons .button.blue:visible').click();";

        wnd.find('.buttons .cancel')
            .unbind('click')
            .bind('click',
                function () {
                    hide();
                    return false;
                });
    }

    function showApply(filter, options) {
        if (!filter) return;

        init();

        show(filter, 'apply');

        wnd.find('.buttons .save')
            .unbind('click')
            .bind('click',
                function () {
                    hide();
                    options.onSuccess(filter);
                });
    }

    function showDelete(filter, options) {
        if (!filter || !filter.id) return;

        init();

        show(filter, 'delete');

        wnd.find('.buttons .del')
            .unbind('click')
            .bind('click',
                function () {
                    hide();
                    options.onSuccess(filter);
                });
    }

    function showDeleteActionConfirm(filter, options) {
        init();

        show(filter, 'confirm');

        wnd.find('.buttons .confirm')
            .unbind('click')
            .bind('click',
                function () {
                    hide();
                    options.onConfirm(filter);
                });

        wnd.find('.buttons .change')
            .unbind('click')
            .bind('click',
                function() {
                    hide();
                    options.onChange(filter);
                });
    }

    function hide() {
        window.PopupKeyUpActionProvider.ClearActions();
        $.unblockUI();
    }

    return {
        init: init,
        showApply: showApply,
        showDelete: showDelete,
        showDeleteActionConfirm: showDeleteActionConfirm,
        hide: hide
    };
})(jQuery);

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SMTP/Server/old/ValidateSender_EventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace LumiSoft.Net.SMTP.Server
{
	/// <summary>
	/// Provides data for the ValidateMailFrom event.
	/// </summary>
	public class ValidateSender_EventArgs
	{
		private SMTP_Session m_pSession  = null;
		private string       m_MailFrom  = "";
		private string       m_ErrorText = "";
		private bool         m_Validated = true;

		/// <summary>
		/// Default constructor.
		/// </summary>
		/// <param name="session">Reference to smtp session.</param>
		/// <param name="mailFrom">Sender email address.</param>
		public ValidateSender_EventArgs(SMTP_Session session,string mailFrom)
		{
			m_pSession = session;
			m_MailFrom = mailFrom;
		}


		#region Properties Implementation

		/// <summary>
		/// Gets reference to smtp session.
		/// </summary>
		public SMTP_Session Session
		{
			get{ return m_pSession; }
		}

		/// <summary>
		/// Sender's email address.
		/// </summary>
		public string MailFrom
		{
			get{ return m_MailFrom; }
		}

		/// <summary>
		/// Gets or sets error text reported to connected client.
		/// </summary>
		public string ErrorText
		{
			get{ return m_ErrorText; }

			set{
				value = value.Replace("\r\n"," ");
				if(value.Length > 200){
					m_ErrorText = value.Substring(0,200);
				}
				else{
					m_ErrorText = value;
				}
			}
		}

		/// <summary>
		/// Gets or sets if sender is ok.
		/// </summary>
		public bool Validated
		{
			get{ return m_Validated; }

			set{ m_Validated = value; }
		}

		#endregion

	}
}


<|start_filename|>common/ASC.Data.Backup/ActionInvoker.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Threading;

namespace ASC.Data.Backup
{
    public static class ActionInvoker
    {
        public static void Try(
            Action action,
            int maxAttempts,
            Action<Exception> onFailure = null,
            Action<Exception> onAttemptFailure = null,
            int sleepMs = 1000,
            bool isSleepExponential = true)
        {
            Try(state => action(), null, maxAttempts, onFailure, onAttemptFailure, sleepMs, isSleepExponential);
        }

        public static void Try(
            Action<object> action,
            object state,
            int maxAttempts,
            Action<Exception> onFailure = null,
            Action<Exception> onAttemptFailure = null,
            int sleepMs = 1000,
            bool isSleepExponential = true)
        {
            if (action == null)
                throw new ArgumentNullException("action");

            int countAttempts = 0;
            while (countAttempts++ < maxAttempts)
            {
                try
                {
                    action(state);
                    return;
                }
                catch (Exception error)
                {
                    if (countAttempts < maxAttempts)
                    {
                        if (onAttemptFailure != null)
                            onAttemptFailure(error);

                        if (sleepMs > 0)
                            Thread.Sleep(isSleepExponential ? sleepMs * countAttempts : sleepMs);
                    }
                    else if (onFailure != null)
                    {
                        onFailure(error);
                    }
                }
            }
        }
    }
}


<|start_filename|>common/ASC.ActiveDirectory/Base/LdapHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ASC.ActiveDirectory.Base.Data;
using ASC.ActiveDirectory.Base.Expressions;
using ASC.ActiveDirectory.Base.Settings;
using ASC.Common.Logging;
using ASC.Security.Cryptography;

namespace ASC.ActiveDirectory.Base
{
    public abstract class LdapHelper : IDisposable
    {
        public LdapSettings Settings { get; private set; }

        public abstract bool IsConnected { get; }

        protected readonly ILog Log;

        protected LdapHelper(LdapSettings settings)
        {
            Settings = settings;
            Log = LogManager.GetLogger("ASC");
        }

        public abstract void Connect();

        public abstract Dictionary<string, string[]> GetCapabilities();

        public abstract string SearchDomain();

        public abstract void CheckCredentials(string login, string password, string server, int portNumber,
            bool startTls, bool ssl, bool acceptCertificate, string acceptCertificateHash);

        public abstract bool CheckUserDn(string userDn);

        public abstract List<LdapObject> GetUsers(string filter = null, int limit = -1);

        public abstract LdapObject GetUserBySid(string sid);

        public abstract bool CheckGroupDn(string groupDn);

        public abstract List<LdapObject> GetGroups(Criteria criteria = null);

        public bool UserExistsInGroup(LdapObject domainGroup, LdapObject domainUser, LdapSettings settings) // string memberString, string groupAttribute, string primaryGroupId)
        {
            try
            {
                if (domainGroup == null || domainUser == null)
                    return false;

                var memberString = domainUser.GetValue(Settings.UserAttribute) as string;
                if (string.IsNullOrEmpty(memberString))
                    return false;

                var groupAttribute = settings.GroupAttribute;
                if (string.IsNullOrEmpty(groupAttribute))
                    return false;

                var userPrimaryGroupId = domainUser.GetValue(LdapConstants.ADSchemaAttributes.PRIMARY_GROUP_ID) as string;

                if (!string.IsNullOrEmpty(userPrimaryGroupId) && domainGroup.Sid.EndsWith("-" + userPrimaryGroupId))
                {
                    // Domain Users found
                    return true;
                }
                else
                {
                    var members = domainGroup.GetValues(groupAttribute);

                    if (!members.Any())
                        return false;

                    if (members.Any(member => memberString.Equals(member, StringComparison.InvariantCultureIgnoreCase)
                        || member.Equals(domainUser.DistinguishedName, StringComparison.InvariantCultureIgnoreCase)))
                        return true;
                }
            }
            catch (Exception e)
            {
                Log.ErrorFormat("UserExistsInGroup() failed. Error: {0}", e);
            }

            return false;
        }

        public static string GetPassword(byte[] passwordBytes)
        {
            if (passwordBytes == null || passwordBytes.Length == 0)
                return string.Empty;

            string password;
            try
            {
                password = new UnicodeEncoding().GetString(InstanceCrypto.Decrypt(passwordBytes));
            }
            catch (Exception)
            {
                password = string.Empty;
            }
            return password;
        }

        public static byte[] GetPasswordBytes(string password)
        {
            byte[] passwordBytes;

            try
            {
                passwordBytes = InstanceCrypto.Encrypt(new UnicodeEncoding().GetBytes(password));
            }
            catch (Exception)
            {
                passwordBytes = null;
            }

            return passwordBytes;
        }

        public abstract void Dispose();
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/vCard/ItemCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Mime.vCard
{
    #region usings

    using System.Collections;
    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// vCard item collection.
    /// </summary>
    public class ItemCollection : IEnumerable
    {
        #region Members

        private readonly List<Item> m_pItems;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        internal ItemCollection()
        {
            m_pItems = new List<Item>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets number of vCard items in the collection.
        /// </summary>
        public int Count
        {
            get { return m_pItems.Count; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Adds new vCard item to the collection.
        /// </summary>
        /// <param name="name">Item name.</param>
        /// <param name="parametes">Item parameters.</param>
        /// <param name="value">Item value.</param>
        public Item Add(string name, string parametes, string value)
        {
            Item item = new Item(name, parametes, value);
            m_pItems.Add(item);

            return item;
        }

        /// <summary>
        /// Removes all items with the specified name.
        /// </summary>
        /// <param name="name">Item name.</param>
        public void Remove(string name)
        {
            for (int i = 0; i < m_pItems.Count; i++)
            {
                if (m_pItems[i].Name.ToLower() == name.ToLower())
                {
                    m_pItems.RemoveAt(i);
                    i--;
                }
            }
        }

        /// <summary>
        /// Removes specified item from the collection.
        /// </summary>
        /// <param name="item">Item to remove.</param>
        public void Remove(Item item)
        {
            m_pItems.Remove(item);
        }

        /// <summary>
        /// Clears all items in the collection.
        /// </summary>
        public void Clear()
        {
            m_pItems.Clear();
        }

        /// <summary>
        /// Gets first item with specified name. Returns null if specified item doesn't exists.
        /// </summary>
        /// <param name="name">Item name. Name compare is case-insensitive.</param>
        /// <returns>Returns first item with specified name or null if specified item doesn't exists.</returns>
        public Item GetFirst(string name)
        {
            foreach (Item item in m_pItems)
            {
                if (item.Name.ToLower() == name.ToLower())
                {
                    return item;
                }
            }

            return null;
        }

        /// <summary>
        /// Gets items with specified name.
        /// </summary>
        /// <param name="name">Item name.</param>
        /// <returns></returns>
        public Item[] Get(string name)
        {
            List<Item> retVal = new List<Item>();
            foreach (Item item in m_pItems)
            {
                if (item.Name.ToLower() == name.ToLower())
                {
                    retVal.Add(item);
                }
            }

            return retVal.ToArray();
        }

        /// <summary>
        /// Sets first item with specified value.  If item doesn't exist, item will be appended to the end.
        /// If value is null, all items with specified name will be removed.
        /// Value is encoed as needed and specified item.ParametersString will be updated accordingly.
        /// </summary>
        /// <param name="name">Item name.</param>
        /// <param name="value">Item value.</param>
        public void SetDecodedValue(string name, string value)
        {
            if (value == null)
            {
                Remove(name);
                return;
            }

            Item item = GetFirst(name);
            if (item != null)
            {
                item.SetDecodedValue(value);
            }
            else
            {
                item = new Item(name, "", "");
                m_pItems.Add(item);
                item.SetDecodedValue(value);
            }
        }

        /// <summary>
        /// Sets first item with specified encoded value.  If item doesn't exist, item will be appended to the end.
        /// If value is null, all items with specified name will be removed.
        /// </summary>
        /// <param name="name">Item name.</param>
        /// <param name="value">Item encoded value.</param>
        public void SetValue(string name, string value)
        {
            SetValue(name, "", value);
        }

        /// <summary>
        /// Sets first item with specified name encoded value.  If item doesn't exist, item will be appended to the end.
        /// If value is null, all items with specified name will be removed.
        /// </summary>
        /// <param name="name">Item name.</param>
        /// <param name="parametes">Item parameters.</param>
        /// <param name="value">Item encoded value.</param>
        public void SetValue(string name, string parametes, string value)
        {
            if (value == null)
            {
                Remove(name);
                return;
            }

            Item item = GetFirst(name);
            if (item != null)
            {
                item.Value = value;
            }
            else
            {
                m_pItems.Add(new Item(name, parametes, value));
            }
        }

        /// <summary>
        /// Gets enumerator.
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            return m_pItems.GetEnumerator();
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Services/NotifyService/PatternResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Projects.Core.Model.Services.NotifyService {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class PatternResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal PatternResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Projects.Core.Model.Services.NotifyService.PatternResource", typeof(PatternResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Comment edited for discussion: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has edited a comment to the discussion: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$AdditionalData 
        ///
        ///&quot;Read more&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID#comment_$CommentID&quot; 
        ///
        ///^You receive this email because you are a registered us [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_EditedCommentForMessage {
            get {
                return ResourceManager.GetString("pattern_EditedCommentForMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Comment edited for task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has edited a comment to the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task: 
        ///
        ///$AdditionalData
        ///
        ///&quot;Read more&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID#comment_$CommentID&quot; 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__Virtual [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_EditedCommentForTask {
            get {
                return ResourceManager.GetString("pattern_EditedCommentForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Discussion edited: &quot;${EntityTitle}&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has edited the discussion: &quot;${EntityTitle}&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot;&quot;: 
        ///
        ///$AdditionalData.get_item(&quot;MessagePreview&quot;) 
        ///
        ///#foreach($fileInfo in $AdditionalData.get_item(&quot;Files&quot;).Keys) 
        ///
        ///#beforeall 
        ///
        ///---------------------------------------- 
        ///
        ///#each 
        ///
        ///&quot;$fileInfo&quot;:&quot;$AdditionalData.get_item [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_EditMessage {
            get {
                return ResourceManager.GetString("pattern_EditMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Projects. Import of the data from Basecamp
        ///
        ///The new data has been successfully imported.
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;:&quot;$RecipientSubscriptionConfigURL&quot;.^.
        /// </summary>
        public static string pattern_ImportData {
            get {
                return ResourceManager.GetString("pattern_ImportData", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.You have been added to the project team: &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added you to the team of the project:[&quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot;] 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;:&quot;$Recip [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_InviteToProject {
            get {
                return ResourceManager.GetString("pattern_InviteToProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Overdue milestone notification: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#sortBy=deadline&amp;sortOrder=ascending&quot; 
        ///
        ///The &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID&quot; milestone of the project &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; is overdue. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change t [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_LateMilestone {
            get {
                return ResourceManager.GetString("pattern_LateMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Discussion deleted: &quot;$EntityTitle&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has deleted the discussion &quot;$EntityTitle&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project.
        ///
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;:&quot;$RecipientSubscriptionConfigURL&quot;.^.
        /// </summary>
        public static string pattern_MessageDeleted {
            get {
                return ResourceManager.GetString("pattern_MessageDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Milestone closed: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#status=closed&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has closed the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#status=closed&quot; milestone in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project.
        ///
        /// ^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath} [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_MilestoneClosed {
            get {
                return ResourceManager.GetString("pattern_MilestoneClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Milestone created: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new milestone: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#sortBy=create_on&amp;sortOrder=descending&quot; to the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPa [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_MilestoneCreated {
            get {
                return ResourceManager.GetString("pattern_MilestoneCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Milestone due date notification: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; 
        ///
        ///Less than 48 hours is left till the due date of the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; milestone in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project.
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; po [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_MilestoneDeadline {
            get {
                return ResourceManager.GetString("pattern_MilestoneDeadline", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Milestone deleted: &quot;$EntityTitle&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has deleted the milestone &quot;$EntityTitle&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project:
        ///
        ///$AdditionalData 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;:&quot;$RecipientSubscriptionConfigURL&quot;.^.
        /// </summary>
        public static string pattern_MilestoneDeleted {
            get {
                return ResourceManager.GetString("pattern_MilestoneDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Milestone edited: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has edited the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; milestone in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_MilestoneEdited {
            get {
                return ResourceManager.GetString("pattern_MilestoneEdited", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Milestone resumed:  &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has resumed the milestone &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project: 
        ///
        ///$AdditionalData
        ///
        /// ^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; porta [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_MilestoneResumed {
            get {
                return ResourceManager.GetString("pattern_MilestoneResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.New comment to discussion: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new comment to the discussion: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$AdditionalData 
        ///
        ///&quot;Read more&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID#comment_$CommentID&quot; 
        ///
        ///^You receive this email because you are a registered use [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_NewCommentForMessage {
            get {
                return ResourceManager.GetString("pattern_NewCommentForMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.New comment to task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new comment to the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task: 
        ///
        ///$AdditionalData
        ///
        ///&quot;Read more&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID#comment_$CommentID&quot; 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualR [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_NewCommentForTask {
            get {
                return ResourceManager.GetString("pattern_NewCommentForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.New file to discussion: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new file to the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; discussion: 
        ///
        ///$AdditionalData
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you don&apos;t want to receive the notifications about this disc [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_NewFileForDiscussion {
            get {
                return ResourceManager.GetString("pattern_NewFileForDiscussion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.New file to task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new file to the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task.
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you don&apos;t want to receive the notifications about this task, please &quot;unsubscribe&quot;:&quot;${__VirtualR [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_NewFileForTask {
            get {
                return ResourceManager.GetString("pattern_NewFileForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.New discussion created: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has started a new discussion: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Messages.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot;: 
        ///
        ///$AdditionalData.get_item(&quot;MessagePreview&quot;) 
        ///
        ///#foreach($fileInfo in $AdditionalData.get_item(&quot;Files&quot;).Keys)
        ///
        ///#beforeall
        ///
        ///---------------------------------------- 
        ///
        ///#each 
        ///
        ///&quot;$fileInfo&quot;:&quot;$AdditionalData.get_ite [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_NewMessage {
            get {
                return ResourceManager.GetString("pattern_NewMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Project deleted: &quot;$EntityTitle&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has deleted the project &quot;$EntityTitle&quot; 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;:&quot;$RecipientSubscriptionConfigURL&quot;.^.
        /// </summary>
        public static string pattern_ProjectDeleted {
            get {
                return ResourceManager.GetString("pattern_ProjectDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. You have been added to the project team.
        /// </summary>
        public static string pattern_push_InviteToProject {
            get {
                return ResourceManager.GetString("pattern_push_InviteToProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Discussion deleted: $EntityTitle.
        /// </summary>
        public static string pattern_push_MessageDeleted {
            get {
                return ResourceManager.GetString("pattern_push_MessageDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone closed: $EntityTitle.
        /// </summary>
        public static string pattern_push_MilestoneClosed {
            get {
                return ResourceManager.GetString("pattern_push_MilestoneClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone created: $EntityTitle.
        /// </summary>
        public static string pattern_push_MilestoneCreated {
            get {
                return ResourceManager.GetString("pattern_push_MilestoneCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone deleted: $EntityTitle.
        /// </summary>
        public static string pattern_push_MilestoneDeleted {
            get {
                return ResourceManager.GetString("pattern_push_MilestoneDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone resumed: $EntityTitle.
        /// </summary>
        public static string pattern_push_MilestoneResumed {
            get {
                return ResourceManager.GetString("pattern_push_MilestoneResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. New discussion: $EntityTitle.
        /// </summary>
        public static string pattern_push_NewMessage {
            get {
                return ResourceManager.GetString("pattern_push_NewMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects. Project deleted: $EntityTitle.
        /// </summary>
        public static string pattern_push_ProjectDeleted {
            get {
                return ResourceManager.GetString("pattern_push_ProjectDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone assigned to you: $EntityTitle.
        /// </summary>
        public static string pattern_push_ResponsibleForMilestone {
            get {
                return ResourceManager.GetString("pattern_push_ResponsibleForMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. You were appointed project manager.
        /// </summary>
        public static string pattern_push_ResponsibleForProject {
            get {
                return ResourceManager.GetString("pattern_push_ResponsibleForProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask assigned to you: $SubEntityTitle.
        /// </summary>
        public static string pattern_push_ResponsibleForSubTask {
            get {
                return ResourceManager.GetString("pattern_push_ResponsibleForSubTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task assigned to you: $EntityTitle.
        /// </summary>
        public static string pattern_push_ResponsibleForTask {
            get {
                return ResourceManager.GetString("pattern_push_ResponsibleForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask closed: $SubEntityTitle.
        /// </summary>
        public static string pattern_push_SubTaskClosed {
            get {
                return ResourceManager.GetString("pattern_push_SubTaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask created: $SubEntityTitle.
        /// </summary>
        public static string pattern_push_SubTaskCreated {
            get {
                return ResourceManager.GetString("pattern_push_SubTaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask deleted: $SubEntityTitle.
        /// </summary>
        public static string pattern_push_SubTaskDeleted {
            get {
                return ResourceManager.GetString("pattern_push_SubTaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask resumed: $SubEntityTitle.
        /// </summary>
        public static string pattern_push_SubTaskResumed {
            get {
                return ResourceManager.GetString("pattern_push_SubTaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task closed: $EntityTitle.
        /// </summary>
        public static string pattern_push_TaskClosed {
            get {
                return ResourceManager.GetString("pattern_push_TaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task created: $EntityTitle.
        /// </summary>
        public static string pattern_push_TaskCreated {
            get {
                return ResourceManager.GetString("pattern_push_TaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task deleted: $EntityTitle.
        /// </summary>
        public static string pattern_push_TaskDeleted {
            get {
                return ResourceManager.GetString("pattern_push_TaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task resumed: $EntityTitle.
        /// </summary>
        public static string pattern_push_TaskResumed {
            get {
                return ResourceManager.GetString("pattern_push_TaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Reminder about the task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; reminds you about the task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot;: $AdditionalData.get_item(&quot;TaskDescription&quot;) 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_ReminderAboutTask {
            get {
                return ResourceManager.GetString("pattern_ReminderAboutTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Reminder about the task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///Today is the deadline for the task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot;: $AdditionalData.get_item(&quot;TaskDescription&quot;) 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;:&quot;$Recipien [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_ReminderAboutTaskDeadline {
            get {
                return ResourceManager.GetString("pattern_ReminderAboutTaskDeadline", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.You have been removed from the project team: &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot;
        ///
        /// $__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has removed you from the team of the project: &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot;
        ///
        /// ^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;: [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_RemoveFromProject {
            get {
                return ResourceManager.GetString("pattern_RemoveFromProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task no longer assigned to you: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime you are no longer responsible for the task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project: 
        ///
        ///$AdditionalData.get_item(&quot;TaskDescription&quot;)
        ///
        /// ^You receive this email because you are a registered user of the &quot;${__Vir [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_RemoveResponsibleForTask {
            get {
                return ResourceManager.GetString("pattern_RemoveResponsibleForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Milestone assigned to you: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has appointed you responsible for the milestone: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;: [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_ResponsibleForMilestone {
            get {
                return ResourceManager.GetString("pattern_ResponsibleForMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.You were appointed project manager: &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has appointed you manager of the project &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot;: 
        ///
        ///$AdditionalData 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription setti [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_ResponsibleForProject {
            get {
                return ResourceManager.GetString("pattern_ResponsibleForProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Subtask assigned to you: &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has appointed you responsible for the subtask: &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; added to the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task.
        ///
        ///$AdditionalData.get_item(&quot;TaskDescription&quot;) 
        ///
        ///^You receive this email becau [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_ResponsibleForSubTask {
            get {
                return ResourceManager.GetString("pattern_ResponsibleForSubTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task assigned to you: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has appointed you responsible for the task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; project.
        ///
        ///$AdditionalData.get_item(&quot;TaskDescription&quot;) 
        ///
        ///^You receive this email because you are  [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_ResponsibleForTask {
            get {
                return ResourceManager.GetString("pattern_ResponsibleForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Subtask closed: &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has closed the subtask added to the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you don&apos;t want to receive the notifications about this task, please &quot;unsubscribe&quot;:&quot;${ [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_SubTaskClosed {
            get {
                return ResourceManager.GetString("pattern_SubTaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Subtask created: &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new subtask: &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; to the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task. 
        ///
        ///The subtask is assigned to &quot;$Responsible&quot;. 
        ///
        ///^You receive this email because you are a registered user of the  [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_SubTaskCreated {
            get {
                return ResourceManager.GetString("pattern_SubTaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Subtask deleted: &quot;$SubEntityTitle&quot;
        ///
        /// $__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has deleted the subtask: &quot;$SubEntityTitle&quot; of the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you don&apos;t want to receive the notifications about this task, please &quot;unsubscribe&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_SubTaskDeleted {
            get {
                return ResourceManager.GetString("pattern_SubTaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Subtask edited: &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has edited the &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; subtask of the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task. 
        ///
        ///The subtask is assigned to &quot;$Responsible&quot;. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${ [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_SubTaskEdited {
            get {
                return ResourceManager.GetString("pattern_SubTaskEdited", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Subtask resumed: &quot;$SubEntityTitle&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has resumed the subtask: &quot;$SubEntityTitle&quot; of the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task. 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you don&apos;t want to receive the notifications about this task, please &quot;unsubscribe&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_SubTaskResumed {
            get {
                return ResourceManager.GetString("pattern_SubTaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task closed: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has closed the task &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project: 
        ///
        ///$AdditionalData 
        ///
        /// ^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; p [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_TaskClosed {
            get {
                return ResourceManager.GetString("pattern_TaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task created: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has added a new task: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; to the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project:
        ///
        /// $AdditionalData.get_item(&quot;TaskDescription&quot;) 
        ///
        ///The task is assigned to &quot;$Responsible&quot;
        ///
        /// ^You receive this email because you are a [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_TaskCreated {
            get {
                return ResourceManager.GetString("pattern_TaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task deleted: &quot;$EntityTitle&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has deleted the task &quot;$EntityTitle&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project:
        ///
        ///$AdditionalData 
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change the notification type, please manage your &quot;subscription settings&quot;:&quot;$RecipientSubscriptionConfigURL&quot;.^.
        /// </summary>
        public static string pattern_TaskDeleted {
            get {
                return ResourceManager.GetString("pattern_TaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task edited: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot;  
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has edited the  &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project.
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. To change t [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_TaskEdited {
            get {
                return ResourceManager.GetString("pattern_TaskEdited", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task moved: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot;  
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has removed the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task from the &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; milestone in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project.
        ///
        ///The &quot;$Entity [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_TaskMovedFromMilestone {
            get {
                return ResourceManager.GetString("pattern_TaskMovedFromMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task moved: &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has moved the &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; task to the &quot;$SubEntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Milestones.aspx?prjID=$ProjectID#my=true&quot; milestone in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project. 
        ///
        ///^You receive thi [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_TaskMovedToMilestone {
            get {
                return ResourceManager.GetString("pattern_TaskMovedToMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.Task resumed:  &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; 
        ///
        ///$__DateTime &quot;$__AuthorName&quot;:&quot;$__AuthorUrl&quot; has resumed the task &quot;$EntityTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID&quot; in the &quot;$ProjectTitle&quot;:&quot;${__VirtualRootPath}/Products/Projects/Projects.aspx?prjID=$ProjectID&quot; project: 
        ///
        ///$AdditionalData
        ///
        /// ^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_TaskResumed {
            get {
                return ResourceManager.GetString("pattern_TaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Edited comment to discussion: $EntityTitle.
        /// </summary>
        public static string subject_EditedCommentForMessage {
            get {
                return ResourceManager.GetString("subject_EditedCommentForMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Edited comment to discussion: [$EntityTitle](${__VirtualRootPath}/products/projects/messages.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_EditedCommentForMessage_tg {
            get {
                return ResourceManager.GetString("subject_EditedCommentForMessage_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Edited comment to task: $EntityTitle.
        /// </summary>
        public static string subject_EditedCommentForTask {
            get {
                return ResourceManager.GetString("subject_EditedCommentForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Edited comment to task: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_EditedCommentForTask_tg {
            get {
                return ResourceManager.GetString("subject_EditedCommentForTask_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Discussion edited: $EntityTitle.
        /// </summary>
        public static string subject_EditMessage {
            get {
                return ResourceManager.GetString("subject_EditMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Discussion edited: [$EntityTitle](${__VirtualRootPath}/products/projects/messages.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_EditMessage_tg {
            get {
                return ResourceManager.GetString("subject_EditMessage_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects. Import of the data from Basecamp.
        /// </summary>
        public static string subject_ImportData {
            get {
                return ResourceManager.GetString("subject_ImportData", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. You have been added to the project team.
        /// </summary>
        public static string subject_InviteToProject {
            get {
                return ResourceManager.GetString("subject_InviteToProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). You have been added to the project team.
        /// </summary>
        public static string subject_InviteToProject_tg {
            get {
                return ResourceManager.GetString("subject_InviteToProject_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Overdue milestone notification: $EntityTitle.
        /// </summary>
        public static string subject_LateMilestone {
            get {
                return ResourceManager.GetString("subject_LateMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Discussion deleted: $EntityTitle.
        /// </summary>
        public static string subject_MessageDeleted {
            get {
                return ResourceManager.GetString("subject_MessageDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Discussion deleted: [$EntityTitle](${__VirtualRootPath}/products/projects/messages.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_MessageDeleted_tg {
            get {
                return ResourceManager.GetString("subject_MessageDeleted_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone closed: $EntityTitle.
        /// </summary>
        public static string subject_MilestoneClosed {
            get {
                return ResourceManager.GetString("subject_MilestoneClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Milestone closed: [$EntityTitle](${__VirtualRootPath}/products/projects/milestones.aspx?prjID=$ProjectID#status=closed).
        /// </summary>
        public static string subject_MilestoneClosed_tg {
            get {
                return ResourceManager.GetString("subject_MilestoneClosed_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone created: $EntityTitle.
        /// </summary>
        public static string subject_MilestoneCreated {
            get {
                return ResourceManager.GetString("subject_MilestoneCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Milestone created: [$EntityTitle](${__VirtualRootPath}/products/projects/milestones.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_MilestoneCreated_tg {
            get {
                return ResourceManager.GetString("subject_MilestoneCreated_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone due date notification: $EntityTitle.
        /// </summary>
        public static string subject_MilestoneDeadline {
            get {
                return ResourceManager.GetString("subject_MilestoneDeadline", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone deleted: $EntityTitle.
        /// </summary>
        public static string subject_MilestoneDeleted {
            get {
                return ResourceManager.GetString("subject_MilestoneDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Milestone deleted: [$EntityTitle](${__VirtualRootPath}/products/projects/milestones.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_MilestoneDeleted_tg {
            get {
                return ResourceManager.GetString("subject_MilestoneDeleted_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone edited: $EntityTitle.
        /// </summary>
        public static string subject_MilestoneEdited {
            get {
                return ResourceManager.GetString("subject_MilestoneEdited", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Milestone edited: [$EntityTitle](${__VirtualRootPath}/products/projects/milestones.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_MilestoneEdited_tg {
            get {
                return ResourceManager.GetString("subject_MilestoneEdited_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone resumed: $EntityTitle.
        /// </summary>
        public static string subject_MilestoneResumed {
            get {
                return ResourceManager.GetString("subject_MilestoneResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Milestone resumed: [$EntityTitle](${__VirtualRootPath}/products/projects/milestones.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_MilestoneResumed_tg {
            get {
                return ResourceManager.GetString("subject_MilestoneResumed_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. New comment to discussion: $EntityTitle.
        /// </summary>
        public static string subject_NewCommentForMessage {
            get {
                return ResourceManager.GetString("subject_NewCommentForMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). New comment to discussion: [$EntityTitle](${__VirtualRootPath}/products/projects/messages.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_NewCommentForMessage_tg {
            get {
                return ResourceManager.GetString("subject_NewCommentForMessage_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. New comment to task: $EntityTitle.
        /// </summary>
        public static string subject_NewCommentForTask {
            get {
                return ResourceManager.GetString("subject_NewCommentForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). New comment to task: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_NewCommentForTask_tg {
            get {
                return ResourceManager.GetString("subject_NewCommentForTask_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. New file to discussion: $EntityTitle.
        /// </summary>
        public static string subject_NewFileForDiscussion {
            get {
                return ResourceManager.GetString("subject_NewFileForDiscussion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). New file to discussion: [$EntityTitle](${__VirtualRootPath}/products/projects/messages.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_NewFileForDiscussion_tg {
            get {
                return ResourceManager.GetString("subject_NewFileForDiscussion_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. New file to task: $EntityTitle.
        /// </summary>
        public static string subject_NewFileForTask {
            get {
                return ResourceManager.GetString("subject_NewFileForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). New file to task: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_NewFileForTask_tg {
            get {
                return ResourceManager.GetString("subject_NewFileForTask_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. New discussion: $EntityTitle.
        /// </summary>
        public static string subject_NewMessage {
            get {
                return ResourceManager.GetString("subject_NewMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). New discussion: [$EntityTitle](${__VirtualRootPath}/products/projects/messages.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_NewMessage_tg {
            get {
                return ResourceManager.GetString("subject_NewMessage_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects. Project deleted: $EntityTitle.
        /// </summary>
        public static string subject_ProjectDeleted {
            get {
                return ResourceManager.GetString("subject_ProjectDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have been added to the project team.
        /// </summary>
        public static string subject_push_InviteToProject {
            get {
                return ResourceManager.GetString("subject_push_InviteToProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Discussion has been deleted.
        /// </summary>
        public static string subject_push_MessageDeleted {
            get {
                return ResourceManager.GetString("subject_push_MessageDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone has been closed.
        /// </summary>
        public static string subject_push_MilestoneClosed {
            get {
                return ResourceManager.GetString("subject_push_MilestoneClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to A new milestone has been created.
        /// </summary>
        public static string subject_push_MilestoneCreated {
            get {
                return ResourceManager.GetString("subject_push_MilestoneCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone has been deleted.
        /// </summary>
        public static string subject_push_MilestoneDeleted {
            get {
                return ResourceManager.GetString("subject_push_MilestoneDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone has been resumed.
        /// </summary>
        public static string subject_push_MilestoneResumed {
            get {
                return ResourceManager.GetString("subject_push_MilestoneResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to A new discussion has been created.
        /// </summary>
        public static string subject_push_NewMessage {
            get {
                return ResourceManager.GetString("subject_push_NewMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects. Project deleted.
        /// </summary>
        public static string subject_push_ProjectDeleted {
            get {
                return ResourceManager.GetString("subject_push_ProjectDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone has been assigned to you.
        /// </summary>
        public static string subject_push_ResponsibleForMilestone {
            get {
                return ResourceManager.GetString("subject_push_ResponsibleForMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You were appointed project manager.
        /// </summary>
        public static string subject_push_ResponsibleForProject {
            get {
                return ResourceManager.GetString("subject_push_ResponsibleForProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subtask has been assigned to you.
        /// </summary>
        public static string subject_push_ResponsibleForSubTask {
            get {
                return ResourceManager.GetString("subject_push_ResponsibleForSubTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task has been assigned to you.
        /// </summary>
        public static string subject_push_ResponsibleForTask {
            get {
                return ResourceManager.GetString("subject_push_ResponsibleForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subtask has been closed.
        /// </summary>
        public static string subject_push_SubTaskClosed {
            get {
                return ResourceManager.GetString("subject_push_SubTaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to A new subtask has been created.
        /// </summary>
        public static string subject_push_SubTaskCreated {
            get {
                return ResourceManager.GetString("subject_push_SubTaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subtask has been deleted.
        /// </summary>
        public static string subject_push_SubTaskDeleted {
            get {
                return ResourceManager.GetString("subject_push_SubTaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subtask has been resumed.
        /// </summary>
        public static string subject_push_SubTaskResumed {
            get {
                return ResourceManager.GetString("subject_push_SubTaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task has been closed.
        /// </summary>
        public static string subject_push_TaskClosed {
            get {
                return ResourceManager.GetString("subject_push_TaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to A new task has been created.
        /// </summary>
        public static string subject_push_TaskCreated {
            get {
                return ResourceManager.GetString("subject_push_TaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task has been deleted.
        /// </summary>
        public static string subject_push_TaskDeleted {
            get {
                return ResourceManager.GetString("subject_push_TaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task has been resumed.
        /// </summary>
        public static string subject_push_TaskResumed {
            get {
                return ResourceManager.GetString("subject_push_TaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task reminder: $EntityTitle.
        /// </summary>
        public static string subject_ReminderAboutTask {
            get {
                return ResourceManager.GetString("subject_ReminderAboutTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Remind about the task: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_ReminderAboutTask_tg {
            get {
                return ResourceManager.GetString("subject_ReminderAboutTask_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task reminder: $EntityTitle.
        /// </summary>
        public static string subject_ReminderAboutTaskDeadline {
            get {
                return ResourceManager.GetString("subject_ReminderAboutTaskDeadline", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Remind about the task: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_ReminderAboutTaskDeadline_tg {
            get {
                return ResourceManager.GetString("subject_ReminderAboutTaskDeadline_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. You have been removed from the project team.
        /// </summary>
        public static string subject_RemoveFromProject {
            get {
                return ResourceManager.GetString("subject_RemoveFromProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). You have been removed from the project team.
        /// </summary>
        public static string subject_RemoveFromProject_tg {
            get {
                return ResourceManager.GetString("subject_RemoveFromProject_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task no longer assigned to you: $EntityTitle.
        /// </summary>
        public static string subject_RemoveResponsibleForTask {
            get {
                return ResourceManager.GetString("subject_RemoveResponsibleForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task no longer assigned to you: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_RemoveResponsibleForTask_tg {
            get {
                return ResourceManager.GetString("subject_RemoveResponsibleForTask_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Milestone assigned to you: $EntityTitle.
        /// </summary>
        public static string subject_ResponsibleForMilestone {
            get {
                return ResourceManager.GetString("subject_ResponsibleForMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Milestone assigned to you: [$EntityTitle](${__VirtualRootPath}/products/projects/milestones.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_ResponsibleForMilestone_tg {
            get {
                return ResourceManager.GetString("subject_ResponsibleForMilestone_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. You were appointed project manager.
        /// </summary>
        public static string subject_ResponsibleForProject {
            get {
                return ResourceManager.GetString("subject_ResponsibleForProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). You were appointed project manager.
        /// </summary>
        public static string subject_ResponsibleForProject_tg {
            get {
                return ResourceManager.GetString("subject_ResponsibleForProject_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask assigned to you: $SubEntityTitle.
        /// </summary>
        public static string subject_ResponsibleForSubTask {
            get {
                return ResourceManager.GetString("subject_ResponsibleForSubTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Subtask assigned to you: [$SubEntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_ResponsibleForSubTask_tg {
            get {
                return ResourceManager.GetString("subject_ResponsibleForSubTask_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task assigned to you: $EntityTitle.
        /// </summary>
        public static string subject_ResponsibleForTask {
            get {
                return ResourceManager.GetString("subject_ResponsibleForTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task assigned to you: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_ResponsibleForTask_tg {
            get {
                return ResourceManager.GetString("subject_ResponsibleForTask_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask closed: $SubEntityTitle.
        /// </summary>
        public static string subject_SubTaskClosed {
            get {
                return ResourceManager.GetString("subject_SubTaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Subtask closed: [$SubEntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_SubTaskClosed_tg {
            get {
                return ResourceManager.GetString("subject_SubTaskClosed_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask created: $SubEntityTitle.
        /// </summary>
        public static string subject_SubTaskCreated {
            get {
                return ResourceManager.GetString("subject_SubTaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Subtask created: [$SubEntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_SubTaskCreated_tg {
            get {
                return ResourceManager.GetString("subject_SubTaskCreated_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask deleted: $SubEntityTitle.
        /// </summary>
        public static string subject_SubTaskDeleted {
            get {
                return ResourceManager.GetString("subject_SubTaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Subtask deleted: [$SubEntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_SubTaskDeleted_tg {
            get {
                return ResourceManager.GetString("subject_SubTaskDeleted_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask edited: $EntityTitle.
        /// </summary>
        public static string subject_SubTaskEdited {
            get {
                return ResourceManager.GetString("subject_SubTaskEdited", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Subtask edited: [$SubEntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_SubTaskEdited_tg {
            get {
                return ResourceManager.GetString("subject_SubTaskEdited_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Subtask resumed: $SubEntityTitle.
        /// </summary>
        public static string subject_SubTaskResumed {
            get {
                return ResourceManager.GetString("subject_SubTaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Subtask resumed: [$SubEntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_SubTaskResumed_tg {
            get {
                return ResourceManager.GetString("subject_SubTaskResumed_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task closed: $EntityTitle.
        /// </summary>
        public static string subject_TaskClosed {
            get {
                return ResourceManager.GetString("subject_TaskClosed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task closed: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_TaskClosed_tg {
            get {
                return ResourceManager.GetString("subject_TaskClosed_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task created: $EntityTitle.
        /// </summary>
        public static string subject_TaskCreated {
            get {
                return ResourceManager.GetString("subject_TaskCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task created: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_TaskCreated_tg {
            get {
                return ResourceManager.GetString("subject_TaskCreated_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task deleted: $EntityTitle.
        /// </summary>
        public static string subject_TaskDeleted {
            get {
                return ResourceManager.GetString("subject_TaskDeleted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task deleted: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_TaskDeleted_tg {
            get {
                return ResourceManager.GetString("subject_TaskDeleted_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task edited: $EntityTitle.
        /// </summary>
        public static string subject_TaskEdited {
            get {
                return ResourceManager.GetString("subject_TaskEdited", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task edited: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_TaskEdited_tg {
            get {
                return ResourceManager.GetString("subject_TaskEdited_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task removed: $EntityTitle.
        /// </summary>
        public static string subject_TaskMovedFromMilestone {
            get {
                return ResourceManager.GetString("subject_TaskMovedFromMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task removed: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_TaskMovedFromMilestone_tg {
            get {
                return ResourceManager.GetString("subject_TaskMovedFromMilestone_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task moved: $EntityTitle.
        /// </summary>
        public static string subject_TaskMovedToMilestone {
            get {
                return ResourceManager.GetString("subject_TaskMovedToMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task moved: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID&amp;ID=$EntityID).
        /// </summary>
        public static string subject_TaskMovedToMilestone_tg {
            get {
                return ResourceManager.GetString("subject_TaskMovedToMilestone_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle]. Task resumed: $EntityTitle.
        /// </summary>
        public static string subject_TaskResumed {
            get {
                return ResourceManager.GetString("subject_TaskResumed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects [$ProjectTitle](${__VirtualRootPath}/products/projects/projects.aspx?prjID=$ProjectID). Task resumed: [$EntityTitle](${__VirtualRootPath}/products/projects/tasks.aspx?prjID=$ProjectID).
        /// </summary>
        public static string subject_TaskResumed_tg {
            get {
                return ResourceManager.GetString("subject_TaskResumed_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Nobody.
        /// </summary>
        public static string subtaskWithoutResponsible {
            get {
                return ResourceManager.GetString("subtaskWithoutResponsible", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Configuration/ProductEntryPoint.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Core;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Services.NotifyService;
using ASC.Projects.Engine;
using ASC.Web.Core;
using ASC.Web.Core.Utility;
using ASC.Web.Projects.Classes;
using ASC.Web.Projects.Core;
using ASC.Web.Projects.Core.Search;
using ASC.Web.Projects.Masters.ClientScripts;
using ASC.Web.Projects.Resources;

using AutoMapper;


namespace ASC.Web.Projects.Configuration
{
    public class ProductEntryPoint : Product
    {
        private ProductContext context;
        internal static IMapper Mapper { get; set; }

        public static readonly Guid ID = EngineFactory.ProductId;
        public static readonly Guid MilestoneModuleID = new Guid("{AF4AFD50-5553-47f3-8F91-651057BC930B}");
        public static readonly Guid TasksModuleID = new Guid("{04339423-70E6-4b81-A2DF-3C31C723BD90}");
        public static readonly Guid GanttChartModuleID = new Guid("{23CD2123-3C4C-4868-B927-A26BB49CA458}");
        public static readonly Guid MessagesModuleID = new Guid("{9FF0FADE-6CFA-44ee-901F-6185593E4594}");
        public static readonly Guid DocumentsModuleID = new Guid("{81402440-557D-401d-9EE1-D570748F426D}");
        public static readonly Guid TimeTrackingModuleID = new Guid("{57E87DA0-D59B-443d-99D1-D9ABCAB31084}");
        public static readonly Guid ProjectTeamModuleID = new Guid("{C42F993E-5D22-497e-AC26-1E9592515898}");
        public static readonly Guid ContactsModuleID = new Guid("{ec12f0ba-14cb-413c-b5e5-65f6ddd5fc19}");


        public override Guid ProductID
        {
            get { return ID; }
        }

        public override string Name
        {
            get { return ProjectsCommonResource.ProductName; }
        }

        public override string Description
        {
            get
            {
                var id = SecurityContext.CurrentAccount.ID;

                if (CoreContext.UserManager.IsUserInGroup(id, ASC.Core.Users.Constants.GroupVisitor.ID))
                    return ProjectsCommonResource.ProductDescriptionShort;

                if (CoreContext.UserManager.IsUserInGroup(id, ASC.Core.Users.Constants.GroupAdmin.ID) || CoreContext.UserManager.IsUserInGroup(id, ID))
                    return ProjectsCommonResource.ProductDescriptionEx;

                return ProjectsCommonResource.ProductDescription;
            }
        }

        public override string StartURL
        {
            get { return PathProvider.BaseVirtualPath; }
        }

        public override string HelpURL
        {
            get { return string.Concat(PathProvider.BaseVirtualPath, "Help.aspx"); }
        }

        public override string ProductClassName
        {
            get { return "projects"; }
        }

        public override bool Visible { get { return true; } }

        public override ProductContext Context
        {
            get { return context; }
        }

        public override void Init()
        {
            context = new ProductContext
            {
                MasterPageFile = String.Concat(PathProvider.BaseVirtualPath, "Masters/BasicTemplate.Master"),
                DisabledIconFileName = "product_disabled_logo.png",
                IconFileName = "product_logo.png",
                LargeIconFileName = "product_logolarge.svg",
                SubscriptionManager = new ProductSubscriptionManager(),
                DefaultSortOrder = 20,
                SpaceUsageStatManager = new ProjectsSpaceUsageStatManager(),
                AdminOpportunities = () => ProjectsCommonResource.ProductAdminOpportunities.Split('|').ToList(),
                UserOpportunities = () => ProjectsCommonResource.ProductUserOpportunities.Split('|').ToList(),
                HasComplexHierarchyOfAccessRights = true,
            };

            FileEngine.RegisterFileSecurityProvider();
            SearchHandlerManager.Registry(new SearchHandler());
            NotifyClient.RegisterSecurityInterceptor();
            ClientScriptLocalization = new ClientLocalizationResources();
            DIHelper.Register();

            var configuration = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Task, TasksWrapper>().ForMember(r => r.TenantId, opt => opt.MapFrom(r => GetCurrentTenant()));
                cfg.CreateMap<Message, DiscussionsWrapper>().ForMember(r => r.TenantId, opt => opt.MapFrom(r => GetCurrentTenant()));
                cfg.CreateMap<Milestone, MilestonesWrapper>().ForMember(r => r.TenantId, opt => opt.MapFrom(r => GetCurrentTenant()));
                cfg.CreateMap<Project, ProjectsWrapper>().ForMember(r => r.TenantId, opt => opt.MapFrom(r => GetCurrentTenant()));
                cfg.CreateMap<Subtask, SubtasksWrapper>().ForMember(r => r.TenantId, opt => opt.MapFrom(r => GetCurrentTenant()));
                cfg.CreateMap<Comment, CommentsWrapper>().ForMember(r => r.TenantId, opt => opt.MapFrom(r => GetCurrentTenant())).ForMember(r => r.LastModifiedOn, opt => opt.Ignore());
            });
            configuration.AssertConfigurationIsValid();
            Mapper = configuration.CreateMapper();
        }

        private int GetCurrentTenant()
        {
            return CoreContext.TenantManager.GetCurrentTenant().TenantId;
        }
        public override void Shutdown()
        {
            NotifyClient.UnregisterSendMethods();
        }

        public static void RegisterSendMethods()
        {
            NotifyClient.RegisterSendMethods();
        }
    }
}

<|start_filename|>common/ASC.Core.Common/Tenants/TenantRegistrationInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;

using ASC.Core.Users;

namespace ASC.Core.Tenants
{
    public class TenantRegistrationInfo
    {
        public string Name { get; set; }

        public string Address { get; set; }

        public CultureInfo Culture { get; set; }

        public TimeZoneInfo TimeZoneInfo { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public string Email { get; set; }

        public string MobilePhone { get; set; }

        public string PasswordHash { get; set; }

        public EmployeeActivationStatus ActivationStatus { get; set; }

        public string HostedRegion { get; set; }

        public string PartnerId { get; set; }

        public string AffiliateId { get; set; }

        public TenantIndustry Industry { get; set; }

        public bool Spam { get; set; }

        public bool Calls { get; set; }

        public string Campaign { get; set; }

        public bool LimitedControlPanel { get; set; }


        public TenantRegistrationInfo()
        {
            Culture = CultureInfo.CurrentCulture;
            TimeZoneInfo = TimeZoneInfo.Local;
        }
    }
}


<|start_filename|>module/ASC.Data.Reassigns/RemoveProgressItem.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;

using ASC.Common.Threading.Progress;
using ASC.Core;
using ASC.Core.Users;
using ASC.Data.Storage;
using ASC.Mail.Core.Engine;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.CRM.Core;
using ASC.Web.Files.Services.WCFService;
using ASC.Web.Studio.Core.Notify;

using Autofac;

using CrmDaoFactory = ASC.CRM.Core.Dao.DaoFactory;

namespace ASC.Data.Reassigns
{
    public class RemoveProgressItem : IProgressItem
    {
        private readonly HttpContext _context;
        private readonly Dictionary<string, string> _httpHeaders;

        private readonly int _tenantId;
        private readonly Guid _userId;
        private readonly string _userName;
        private readonly Guid _currentUserId;
        private readonly bool _notify;

        private readonly IFileStorageService _docService;
        private readonly MailGarbageEngine _mailEraser;

        public object Id { get; set; }
        public object Status { get; set; }
        public object Error { get; set; }
        public double Percentage { get; set; }
        public bool IsCompleted { get; set; }
        public Guid FromUser { get { return _userId; } }

        public RemoveProgressItem(HttpContext context, int tenantId, UserInfo user, Guid currentUserId, bool notify)
        {
            _context = context;
            _httpHeaders = QueueWorker.GetHttpHeaders(context.Request);

            _tenantId = tenantId;
            _userId = user.ID;
            _userName = UserFormatter.GetUserName(user, DisplayUserNameFormat.Default);
            _currentUserId = currentUserId;
            _notify = notify;

            _docService = Web.Files.Classes.Global.FileStorageService;
            _mailEraser = new MailGarbageEngine();

            Id = QueueWorker.GetProgressItemId(tenantId, _userId, typeof(RemoveProgressItem));
            Status = ProgressStatus.Queued;
            Error = null;
            Percentage = 0;
            IsCompleted = false;
        }

        public void RunJob()
        {
            var logger = log4net.LogManager.GetLogger("ASC.Web");

            try
            {
                Percentage = 0;
                Status = ProgressStatus.Started;

                CoreContext.TenantManager.SetCurrentTenant(_tenantId);
                SecurityContext.AuthenticateMe(Core.Configuration.Constants.CoreSystem);

                long docsSpace, crmSpace, mailSpace, talkSpace;
                GetUsageSpace(out docsSpace, out mailSpace, out talkSpace);

                logger.InfoFormat("deleting user data for {0} ", _userId);

                logger.Info("deleting of data from documents");

                Percentage = 25;
                _docService.DeleteStorage(_userId);

                logger.Info("deleting of data from crm");

                Percentage = 50;
                using (var scope = DIHelper.Resolve(_tenantId))
                {
                    var crmDaoFactory = scope.Resolve<CrmDaoFactory>();
                    crmSpace = crmDaoFactory.ReportDao.GetFiles(_userId).Sum(file => file.ContentLength);
                    crmDaoFactory.ReportDao.DeleteFiles(_userId);
                }

                logger.Info("deleting of data from mail");

                Percentage = 75;
                _mailEraser.ClearUserMail(_userId);

                logger.Info("deleting of data from talk");

                Percentage = 99;
                DeleteTalkStorage();

                SendSuccessNotify(docsSpace, crmSpace, mailSpace, talkSpace);

                Percentage = 100;
                Status = ProgressStatus.Done;
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                Status = ProgressStatus.Failed;
                Error = ex.Message;
                SendErrorNotify(ex.Message);
            }
            finally
            {
                logger.Info("data deletion is complete");
                IsCompleted = true;
                SecurityContext.AuthenticateMe(_currentUserId);
            }
        }

        public object Clone()
        {
            return MemberwiseClone();
        }

        private void GetUsageSpace(out long docsSpace, out long mailSpace, out long talkSpace)
        {
            docsSpace = mailSpace = talkSpace = 0;

            var webItems = WebItemManager.Instance.GetItems(Web.Core.WebZones.WebZoneType.All, ItemAvailableState.All);

            foreach (var item in webItems)
            {
                IUserSpaceUsage manager;

                if (item.ID == WebItemManager.DocumentsProductID)
                {
                    manager = item.Context.SpaceUsageStatManager as IUserSpaceUsage;
                    if (manager == null) continue;
                    docsSpace = manager.GetUserSpaceUsage(_userId);
                }

                if (item.ID == WebItemManager.MailProductID)
                {
                    manager = item.Context.SpaceUsageStatManager as IUserSpaceUsage;
                    if (manager == null) continue;
                    mailSpace = manager.GetUserSpaceUsage(_userId);
                }

                if (item.ID == WebItemManager.TalkProductID)
                {
                    manager = item.Context.SpaceUsageStatManager as IUserSpaceUsage;
                    if (manager == null) continue;
                    talkSpace = manager.GetUserSpaceUsage(_userId);
                }
            }
        }

        private void DeleteTalkStorage()
        {
            var data = MD5.Create().ComputeHash(Encoding.Default.GetBytes(_userId.ToString()));

            var sBuilder = new StringBuilder();

            for (int i = 0, n = data.Length; i < n; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            var md5Hash = sBuilder.ToString();

            var storage = StorageFactory.GetStorage(_tenantId.ToString(CultureInfo.InvariantCulture), "talk");

            if (storage != null && storage.IsDirectory(md5Hash))
            {
                storage.DeleteDirectory(md5Hash);
            }
        }

        private void SendSuccessNotify(long docsSpace, long crmSpace, long mailSpace, long talkSpace)
        {
            if (_notify)
                StudioNotifyService.Instance.SendMsgRemoveUserDataCompleted(_currentUserId, _userId, _userName,
                                                                            docsSpace, crmSpace, mailSpace, talkSpace);

            if (_httpHeaders != null)
                MessageService.Send(_httpHeaders, MessageAction.UserDataRemoving, MessageTarget.Create(_userId),
                                    new[] { _userName });
            else
                MessageService.Send(_context.Request, MessageAction.UserDataRemoving, MessageTarget.Create(_userId),
                                    _userName);
        }

        private void SendErrorNotify(string errorMessage)
        {
            if (!_notify) return;

            StudioNotifyService.Instance.SendMsgRemoveUserDataFailed(_currentUserId, _userId, _userName,
                                                                     errorMessage);
        }
    }
}


<|start_filename|>web/core/ASC.Web.Core/Client/Bundling/ClientScriptRouteHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Routing;

using ASC.Common.Logging;

namespace ASC.Web.Core.Client.Bundling
{
    class ClientScriptRouteHandler : IRouteHandler
    {
        public IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new ClientScriptHandler();
        }


        class ClientScriptHandler : HttpTaskAsyncHandler
        {
            public override async Task ProcessRequestAsync(HttpContext context)
            {
                try
                {
                    HttpContext.Current = context;
                    var clientScriptReference = new ClientScriptReference();
                    var version = clientScriptReference.GetContentHash(context.Request.Url.AbsolutePath);
                    if (string.Equals(context.Request.Headers["If-None-Match"], version))
                    {
                        context.Response.StatusCode = (int)HttpStatusCode.NotModified;
                    }
                    else
                    {
                        context.Response.Charset = Encoding.UTF8.WebName;
                        context.Response.ContentType = new ContentType("application/x-javascript") { CharSet = Encoding.UTF8.WebName }.ToString();

                        // cache
                        context.Response.Cache.SetVaryByCustom("*");
                        context.Response.Cache.SetAllowResponseInBrowserHistory(true);
                        context.Response.Cache.SetETag(version);
                        context.Response.Cache.SetCacheability(HttpCacheability.Public);

                        // body
                        var content = Encoding.UTF8.GetBytes(await clientScriptReference.GetContentAsync(context));

                        using (var inputStream = new MemoryStream())
                        {
                            if (ClientSettings.GZipEnabled)
                            {
                                using (var zip = new GZipStream(inputStream, CompressionMode.Compress, true))
                                {
                                    await zip.WriteAsync(content, 0, content.Length);
                                    zip.Flush();
                                }
                                context.Response.Headers["Content-Encoding"] = "gzip";
                            }
                            else
                            {
                                await inputStream.WriteAsync(content, 0, content.Length);
                            }
                            inputStream.Position = 0;
                            inputStream.CopyTo(context.Response.OutputStream);
                        }
                    }
                }
                catch (Exception e)
                {
                    LogManager.GetLogger("ASC").Error("ClientScriptHandler", e);
                }
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/NewPost.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Web.Community.Modules.Forum.Resources;
using ASC.Web.Studio;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Forum;
using ASC.Web.UserControls.Forum.Common;

namespace ASC.Web.Community.Forum
{
    public partial class NewPost : MainPage
    {
        protected string PageTitle { get; private set; }

        private NewPostControl newPostControl;

        protected void Page_Load(object sender, EventArgs e)
        {
            ForumManager.Instance.SetCurrentPage(ForumPage.NewPost);

            newPostControl = LoadControl(ForumManager.Settings.UserControlsVirtualPath + "/NewPostControl.ascx") as NewPostControl;
            newPostControl.SettingsID = ForumManager.Settings.ID;
            _newPostHolder.Controls.Add(newPostControl);
        }

        protected override void OnLoadComplete(EventArgs e)
        {
            base.OnLoadComplete(e);

            PageTitle = newPostControl.PostType == NewPostType.Post
                    ? ForumResource.NewPostButton
                    : newPostControl.PostType == NewPostType.Topic
                          ? ForumResource.NewTopicButton :
                          ForumResource.NewPollButton;

            Title = HeaderStringHelper.GetPageTitle(PageTitle);
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Expressions/Attachment/ConcreteContentAttachmentExp.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao.Expressions.Attachment
{
    public class ConcreteContentAttachmentExp : SimpleAttachmentExp
    {
        private readonly int _mailId;
        private readonly string _contentId;

        public ConcreteContentAttachmentExp(int mailId, string contentId, bool? isRemoved = false)
            : base(isRemoved)
        {
            _mailId = mailId;
            _contentId = contentId;
        }

        public override Exp GetExpression()
        {
            var exp = base.GetExpression();

            return exp
                & Exp.Eq(AttachmentTable.Columns.MailId.Prefix(AttachmentTable.TABLE_NAME), _mailId)
                & Exp.Eq(AttachmentTable.Columns.ContentId.Prefix(AttachmentTable.TABLE_NAME), _contentId);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/filters/edit.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.editFilterPage = (function($) {
    var isInit = false,
        container,
        header,
        page = 0,
        pageSize = 10,
        total = 0,
        needApply = false;

    function init() {
        if (isInit === true) return;

        container = $('#itemContainer').find('#editFilterPage');
        header = $('#pageActionContainer');

        ASC.Controls.AnchorController.bind(TMMail.anchors.createfilter, onEdit);
        ASC.Controls.AnchorController.bind(TMMail.anchors.editfilter, onEdit);

        window.filtersManager.bind(window.filtersManager.events.OnCreate, onSave);
        window.filtersManager.bind(window.filtersManager.events.OnUpdate, onSave);
    }

    function getNewPosition() {
        var array = filtersManager.getList().map(function (x) { return x.position; });
        if (array.length === 0) return 0;

        var max = Math.max.apply(Math, array);
        return max + 1;
    }

    function getFilter(id) {
        function isChecked(id) {
            var i, n = filter.options.applyTo.mailboxes.length;
            for (i = 0; i < n; i++) {
                var item = filter.options.applyTo.mailboxes[i];
                if (item === id)
                    return true;
            }

            return false;
        }

        var filter = id > 0
            ? TMMail.copy(filtersManager.get(id))
            : new ASC.Mail.Filter(0,
                "",
                getNewPosition(),
                true,
                [
                    new ASC.Mail.Filter.Condition(ASC.Mail.Filter.Constants.Condition.KeyType.From,
                        ASC.Mail.Filter.Constants.Condition.OperationType.Matches,
                        "")
                ],
                [],
                new ASC.Mail.Filter.Options([TMMail.sysfolders.inbox.id]));

        if (!filter) {
            return null;
        }

        var actions = {
            deleteAction: {
                checked: false
            },
            markAsReadAction: {
                checked: false
            },
            moveToAction: {
                checked: false,
                type: 1,
                id: null,
                name: null
            },
            tagAsAction: {
                checked: false,
                id: null,
                name: null
            },
            markAsImportantAction: {
                checked: false
            }
        };

        var i, n = filter.actions.length;
        var userFolder;
        for (i = 0; i < n; i++) {
            try {
                var item = filter.actions[i];

                switch (item.action) {
                case ASC.Mail.Filter.Constants.ActionType.DeleteForever:
                    actions.deleteAction.checked = true;
                    break;
                case ASC.Mail.Filter.Constants.ActionType.MoveTo:
                    actions.moveToAction.checked = true;

                    var data = JSON.parse(item.data);

                    if (data.type === TMMail.sysfolders.userfolder.id) {
                        userFolder = userFoldersManager.get(data.userFolderId);

                        actions.moveToAction.id = userFolder ? userFolder.id : null;
                        actions.moveToAction.name = userFolder ? userFolder.name : null;
                        actions.moveToAction.type = userFolder ? TMMail.sysfolders.userfolder.id : null;

                    } else {
                        actions.moveToAction.type = data.type;
                        actions.moveToAction.id = null;
                        actions.moveToAction.name = TMMail.getSysFolderDisplayNameById(data.type, '');
                    }

                    break;
                case ASC.Mail.Filter.Constants.ActionType.MarkTag:
                    actions.tagAsAction.checked = true;

                    var tag = tagsManager.getTag(item.data);

                    actions.tagAsAction.name = tag ? tag.name : null;
                    actions.tagAsAction.id = tag ? tag.id : null;

                    break;
                case ASC.Mail.Filter.Constants.ActionType.MarkAsImportant:
                    actions.markAsImportantAction.checked = true;
                    break;
                case ASC.Mail.Filter.Constants.ActionType.MarkAsRead:
                    actions.markAsReadAction.checked = true;
                    break;
                default:
                    continue;
                };
            } catch (e) {
                console.error(e);
            }
        }

        filter.acts = actions;

        filter.options.applyTo.mbxs = filter.options.applyTo.mailboxes || [];
 
        if (filter.options.applyTo.mailboxes.length === 0) {
            filter.options.applyTo.allMailboxes = true;

            filter.options.applyTo.mbxs = $.map(accountsManager.getAccountList(),
                function (a) {
                    if (a.is_alias || a.is_group)
                        return null;

                    return {
                        id: a.mailbox_id,
                        address: a.email,
                        checked: false
                    }
                });
        } else {
            filter.options.applyTo.allMailboxes = false;
            filter.options.applyTo.mbxs = $.map(accountsManager.getAccountList(),
                function (a) {
                    if (a.is_alias || a.is_group)
                        return null;

                    var id = parseInt(a.mailbox_id);
                    return {
                        id: id,
                        address: a.email,
                        checked: isChecked(id)
                    }
                });
        }

        filter.options.applyTo.flds = {
            inbox: filter.options.applyTo.folders.indexOf(TMMail.sysfolders.inbox.id) !== -1,
            sent: filter.options.applyTo.folders.indexOf(TMMail.sysfolders.sent.id) !== -1,
            spam: filter.options.applyTo.folders.indexOf(TMMail.sysfolders.spam.id) !== -1
        };

        return filter;
    }

    function onEdit(filterId) {
        mailBox.hidePages();
        var itemContainer = $('#itemContainer');

        itemContainer.height('auto');

        mailBox.hideContentDivs();
        mailBox.hideLoadingMask();

        needApply = false;

        filterId = filterId || 0;

        var filter = getFilter(filterId);

        if (!filter) {
            filtersManager.refresh()
                .then(function(params, filters) {
                        if (!filters.length || !getFilter(filterId)) {
                            window.toastr.error(window.MailScriptResource.UserFilterNotFound);
                            ASC.Controls.AnchorController.move('#filtersettings');
                            return;
                        }

                        onEdit(filterId);
                    },
                    function() {
                        window.toastr.error(window.MailScriptResource.UserFilterNotFound);
                        ASC.Controls.AnchorController.move('#filtersettings');
                    });

            return;
        }

        var editFilterActionHtml = $.tmpl('editFilterActionTmpl', filter);
        header.html(editFilterActionHtml);

        var writeMessageHtml = $.tmpl('editFilterTmpl', filter);
        container = itemContainer.find('#editFilterPage');

        if (container.length > 0) {
            container.replaceWith(writeMessageHtml);
        } else {
            itemContainer.append(writeMessageHtml);
        }

        container = itemContainer.find('#editFilterPage');

        mailBox.stickActionMenuToTheTop();

        container.find("select").tlcombobox({ align: 'left' });

        container.on("click",
            ".delete-field",
            function() {
                $(this).closest(".field-condition").remove();
                toggleMultiConditions();
                setFocus();
            });

        container.find("#conditionsContainer .add-new-field")
            .bind("click",
                function() {
                    addNewField(this);
                    toggleMultiConditions();
                    setFocus();
                });

        container.find(".applyToAttachments")
            .on("change",
                function() {
                    var self = $(this);

                    if (self.hasClass("disable")) return;

                    self.parent().find("input[type='checkbox']").prop("checked", true);
                });

        container.find("#selectMoveToFolderFilter")
            .on("click",
                function() {
                    var self = $(this);

                    if (self.hasClass("disable")) return;

                    var options = {
                        btnCaption: window.MailResource.Select,
                        hideDefaults: false,
                        hideRoot: true,
                        callback: function(folder) {
                            console.log("#selectMoveToFolderFilter .menuActionMoveTo -> callback", folder);

                            self.text(folder.name);
                            self.attr("selectedType", folder.folderType);
                            self.attr("selectedId", folder.userFolderId);
                            self.toggleClass("error", false);

                            self.parent().find("input[type='checkbox']").prop("checked", true);
                        }
                    };

                    userFoldersDropdown.show($(this), options);
                });

        container.find("#selectAddTagFilter")
            .on("click",
                function() {
                    var self = $(this);

                    if (self.hasClass("disable")) return;

                    var options = {
                        hideMarkRecipients: true,
                        onSelect: function(tag) {
                            console.log(tag);

                            self.text(tag.name);
                            self.attr("selectedId", tag.id);
                            self.toggleClass("error", false);

                            self.parent().find("input[type='checkbox']").prop("checked", true);
                        },
                        onDeselect: function(tag) {
                            console.log(tag);
                        },
                        getUsedTagsIds: function() {
                            var id = self.attr("selectedId");
                            return !id ? [] : [parseInt(id)];
                        }
                    }

                    tagsDropdown.show($(this), options);
                });

        container.find("#filterActionDelete")
            .on("click",
                function(e) {
                    var siblings = $(this)
                        .closest("li")
                        .siblings();

                    siblings
                        .find("label, input, a")
                        .toggleClass("disable", e.target.checked)
                        .attr("disabled", e.target.checked);

                    if (e.target.checked) {
                        siblings
                            .find("input")
                            .prop("checked", false);
                    }
                });

        header.find(".btnSaveFilter")
            .on("click", function() { saveFilter(filterId); });

        header.find(".btnCheckFilter")
            .on("click", checkFilter);

        header.find(".btnApplyFilter")
            .on("click",
                function() {
                    saveFilter(filterId);
                    needApply = true;
                });

        header.find(".btnDeleteFilter")
            .on("click",
                function() {
                    window.filtersManager.remove(filterId);
                    closeEdit();
                });

        container.find("#filterApplyToMailiboxes")
            .on("click",
                function(e) {
                    var otherMailboxesEl = $(this)
                        .closest(".field-with-actions")
                        .find(".applyToMailboxes.menu-list");

                    if (!e.target.checked) {
                        otherMailboxesEl.show();
                    } else {
                        otherMailboxesEl.hide();
                    }
                });

        container.find("#selectApplyToFolderFilter")
            .on("click",
                function() {
                    var self = $(this);

                    if (self.hasClass("disable")) return;

                    var options = {
                        hideDefaults: false,
                        hideRoot: true,
                        callback: function(folder) {
                            console.log("#selectApplyToFolderFilter .menuActionMoveTo -> callback", folder);

                            self.text(folder.name);
                            self.attr("selectedType", folder.folderType);
                            self.attr("selectedId", folder.userFolderId);
                            self.toggleClass("error", false);

                            self.parent().find("input[type='checkbox']").prop("checked", true);
                        }
                    };

                    userFoldersDropdown.show($(this), options);
                });

        var enterlinkText = container.find("#filterNameContainer .enterlinkText"),
            linkDeleteFilterName = container.find("#filterNameContainer .clear-field"),
            filterNameEnterContainer = container.find("#filterNameContainer .field-condition"),
            filterNameInput = filterNameEnterContainer.find(".filterNameInput");

        container.find("#filterNameContainer .filterName")
            .on("click",
                function() {
                    enterlinkText.hide();
                    filterNameEnterContainer.show();
                    filterNameInput.focus();
                });

        linkDeleteFilterName
            .on("click",
                function() {
                    filterNameInput.val("");
                    filterNameEnterContainer.hide();
                    enterlinkText.show();
                });

        container.find("#checkFilterResultsMoreBtn").on("click", checkFilterNext);

        container.find("select.key").on("change", onConditionKeyChange);

        var i, n = filter.conditions.length;
        for (i = 0; i < n; i++) {
            var id = filter.conditions[i].id;

            container.find('#' + id)
                .EmailsSelector("init",
                {
                    isInPopup: false,
                    items: []
                });
        }

        var foldersCbxs = container.find("#advancedContainer .applyToFolders input");
        foldersCbxs.change(function() {
            if (this.checked) {
                var labels = container.find("#advancedContainer .applyToFolders label");
                if (labels.hasClass("error")) {
                    labels.toggleClass("error", false);
                }
            }
        });

        var mailboxesCbxs = container.find("#advancedContainer #filterApplyToMailiboxesContainer input");
        mailboxesCbxs.change(function () {
            if (this.checked) {
                var labels = container.find("#advancedContainer #filterApplyToMailiboxesContainer label");
                if (labels.hasClass("error")) {
                    labels.toggleClass("error", false);
                }
            }
        });

        var actionsCbxs = container.find("#actionsContainer input");
        actionsCbxs.change(function () {
            if (this.checked) {
                var labels = container.find("#actionsContainer label");
                if (labels.hasClass("error")) {
                    labels.toggleClass("error", false);
                }
            }
        });

        if (!filter.options.applyTo.allMailboxes) {
            var allCheckedMbs = filter.options.applyTo.mbxs.filter(function (f) { return f.checked });
            if (!allCheckedMbs.length) {
                getFilterMailboxes(); // display no mailboxes selected error
            }
        }

        if (filter.id === 0) {
            setFocus();
        }

        TMMail.scrollTop();
    }

    function onConditionKeyChange() {
        var self = $(this);
        var key = +self.parent().attr("data-value");

        self.closest('.field-condition')
            .find('input.conditionInput')
            .EmailsSelector(key === ASC.Mail.Filter.Constants.Condition.KeyType.Subject
                ? "turnOff"
                : "turnOn");
    }

    function getApplyToAttachments() {
        var checked = container.find("#filterApplyToAttachments").prop('checked');
        if (!checked)
            return ASC.Mail.Filter.Constants.ApplyTo.AttachmentsType.WithAndWithoutAttachments;

        var value = container.find("#advancedContainer .filterApplyToAttachmentsCnt .tl-combobox").attr("data-value");
        return value ? parseInt(value) : ASC.Mail.Filter.Constants.ApplyTo.AttachmentsType.WithAndWithoutAttachments;
    }

    function getMatchConditions() {
        var value = container.find("#applyMultiConditionsContainer:visible .tl-combobox").attr("data-value");
        return value ? parseInt(value) : 0;
    }

    function getConditions() {
        var conditions = [];

        var list = container.find("#conditionsContainer .field-condition");

        var i, n = list.length;
        for (i = 0; i < n; i++) {
            var el = $(list[i]);

            var key = el.find("select.key").parent().attr("data-value"),
                operation = el.find("select.operation").parent().attr("data-value"),
                conditionInput = el.find(".conditionInput"),
                value = conditionInput.val().trim();

            if (!value) {
                conditionInput.toggleClass("invalidField", true);
                throw MailScriptResource.FilterErrorEmptyCondition;
            }

            conditionInput.toggleClass("invalidField", false);

            var condition = new ASC.Mail.Filter.Condition(key, operation, value);

            conditions.push(condition);
        }

        return conditions;
    }

    function getActions() {
        var actions = [];

        var deleteChecked = container.find("#actionsContainer #filterActionDelete").prop('checked');
        if (deleteChecked) {
            actions.push(new ASC.Mail.Filter.Action(ASC.Mail.Filter.Constants.ActionType.DeleteForever));
            // Skip other checkboxes
            return actions;
        }

        var data, elm;

        elm = container.find("#actionsContainer #selectMoveToFolderFilter");
        var moveToChecked = container.find("#actionsContainer #filterActionMoveTo").prop('checked');
        if (moveToChecked) {
            data = elm.attr('selectedid') || elm.attr('selectedtype');

            if (!data) {
                elm.toggleClass("error", true);
                throw MailScriptResource.FilterErrorEmptyMoveToFolderValue;
            }

            var selectedtype = +elm.attr('selectedtype');
            var selectedid = elm.attr('selectedid');

            if (selectedtype === TMMail.sysfolders.userfolder.id) {
                data = { type: TMMail.sysfolders.userfolder.id, userFolderId: selectedid };
            } else {
                data = { type: selectedtype };
            }

            data = JSON.stringify(data);

            elm.toggleClass("error", false);

            actions.push(new ASC.Mail.Filter.Action(ASC.Mail.Filter.Constants.ActionType.MoveTo, data));
        } else {
            elm.toggleClass("error", false);
        }

        elm = container.find("#actionsContainer #selectAddTagFilter");
        var tagAsChecked = container.find("#actionsContainer #filterActionMarkWithTag").prop('checked');
        if (tagAsChecked) {

            data = elm.attr('selectedid');

            if (!data) {
                elm.toggleClass("error", true);
                throw MailScriptResource.FilterErrorEmptyTagValue;
            }
            elm.toggleClass("error", false);

            actions.push(new ASC.Mail.Filter.Action(ASC.Mail.Filter.Constants.ActionType.MarkTag, data));
        } else {
            elm.toggleClass("error", false);
        }

        var markAsImportantChecked = container.find("#actionsContainer #filterActionMarkAsImportant").prop('checked');
        if (markAsImportantChecked) {
            actions.push(new ASC.Mail.Filter.Action(ASC.Mail.Filter.Constants.ActionType.MarkAsImportant));
        }

        var markAsReadChecked = container.find("#actionsContainer #filterActionMarkAsRead").prop('checked');
        if (markAsReadChecked) {
            actions.push(new ASC.Mail.Filter.Action(ASC.Mail.Filter.Constants.ActionType.MarkAsRead));
        }

        var labels = container.find("#actionsContainer label");

        if (!actions.length) {
            labels.toggleClass("error", true);
            throw MailScriptResource.FilterErrorNoActionSelected;
        }

        labels.toggleClass("error", false);

        return actions;
    }

    function getFilterName() {
        var elm = container.find("#filterNameContainer .field-condition:visible .filterNameInput");
        return elm ? elm.val() : null;
    }

    function getIgnoreOther() {
        var checked = container.find("#filterIgnoreOther").prop('checked');
        return checked;
    }

    function getFilterMailboxes() {
        var checkboxes = container.find("#advancedContainer .applyToMailboxes.menu-list:visible input:checked");
        var mailboxes = $.map(checkboxes, function(cbx) {
            return +$(cbx).attr("data_id");
        });

        var label = container.find("#advancedContainer #filterApplyToMailiboxesContainer label");

        if (!mailboxes.length && !container.find("#advancedContainer #filterApplyToMailiboxes").is(":checked")) {
            label.toggleClass("error", true);
            throw MailScriptResource.FilterErrorNoApplyToMailboxSelected;
        }

        label.toggleClass("error", false);

        return mailboxes;
    }

    function getApplyToFolders() {
        var checkboxes = container.find("#advancedContainer .applyToFolders.menu-list:visible input:checked");
        var folders = $.map(checkboxes, function (cbx) {
            return +$(cbx).attr("data_id");
        });

        var labels = container.find("#advancedContainer .applyToFolders label");

        if (!folders.length) {
            labels.toggleClass("error", true);
            throw MailScriptResource.FilterErrorNoApplyToFolderSelected;
        }

        labels.toggleClass("error", false);

        return folders;
    }

    function getFilterData(id, skipActions) {
        try {
            var matchMultiConditions = getMatchConditions(),
                conditions = getConditions(),
                actions = skipActions ? [] : getActions(),
                name = getFilterName(),
                position = id > 0 ? filtersManager.get(id).position : getNewPosition(),
                folders = getApplyToFolders(),
                mailboxes = getFilterMailboxes(),
                applyToAttachments = getApplyToAttachments(),
                ignoreOther = getIgnoreOther();

            var options = new ASC.Mail.Filter.Options();
            options.matchMultiConditions = matchMultiConditions;
            options.applyTo.folders = folders ? folders : [TMMail.sysfolders.inbox.id];
            options.applyTo.mailboxes = mailboxes;
            options.applyTo.withAttachments = applyToAttachments;
            options.ignoreOther = ignoreOther;

            var filter = new ASC.Mail.Filter(id, name, position, true, conditions, actions, options);

            return filter.ToData();

        } catch (e) {
            window.toastr.error(e);
        }

        return null;
    }

    function setFocus() {
        var conditions = container.find("#conditionsContainer .conditionInput");
        for (var i = 0; i < conditions.length; i++) {
            var condition = $(conditions[i]);

            if (condition.val() === '') {
                condition.focus();
                return;
            }
        }
    }

    function toggleMultiConditions() {
        var applyMultiConditionsContainer = container.find("#applyMultiConditionsContainer");
        var conditions = container.find("#conditionsContainer .field-condition");

        if (conditions.length > 1) {
            applyMultiConditionsContainer.show();
        } else {
            applyMultiConditionsContainer.hide();
        }
    }

    function addNewField(item) {
        var elm = $(item);
        if (elm.hasClass("disabled")) return;

        var filterCondition = new ASC.Mail.Filter.Condition(ASC.Mail.Filter.Constants.Condition.KeyType.From,
            ASC.Mail.Filter.Constants.Condition.OperationType.Matches,
            "");

        var newCondition = $($.tmpl('filterConditionTmpl', filterCondition));

        var conditionsContainer = $('#itemContainer').find('#editFilterPage #conditionsContainer');
        var list = conditionsContainer.find(".field-condition:last");

        if (list.length > 0) {
            list.after(newCondition);
        } else {
            elm.before(newCondition);
        }

        var selects = conditionsContainer.find("select");
        $(selects).tlcombobox({ align: 'left' });

        newCondition.find("select.key").on("change", onConditionKeyChange);

        newCondition.find('#' + filterCondition.id).EmailsSelector("init", {
            isInPopup: false,
            items: []
        });
    }

    function saveFilter(filterId) {
        var newFilter = getFilterData(filterId);
        if (!newFilter) return;

        var needConfirm = newFilter.actions.filter(function(a) {
            return a.action === ASC.Mail.Filter.Constants.ActionType.DeleteForever;
        }).length > 0;

        function save(data) {
            if (data.id === 0) {
                window.filtersManager.create(data);
            } else {
                window.filtersManager.update(data);
            }
        }

        if (needConfirm) {
            filterModal.showDeleteActionConfirm(newFilter,
            {
                onConfirm: function(filter) {
                    save(filter);
                },
                onChange: function (filter) {
                    var data = { type: TMMail.sysfolders.trash.id };
                    data = JSON.stringify(data);

                    filter.actions = [new ASC.Mail.Filter.Action(ASC.Mail.Filter.Constants.ActionType.MoveTo, data)];
                    save(filter);
                }
            });
        } else {
            save(newFilter);
        }
    }

    function checkFilter() {
        var filter = getFilterData(0, true);

        if (!filter) return;

        LoadingBanner.displayMailLoading();

        page = 0;
        pageSize = 10;

        window.Teamlab.checkMailFilter({}, filter, page, pageSize,
        {
            success: function (params, messages) {
                console.log("Check filter", filter, messages);
                LoadingBanner.hideLoading();

                container.find("#checkFilterResultsTitle").show();

                if (!messages || messages.length === 0) {
                    container.find("#checkFilterResults").empty().show();
                    var el = $("<p style='height: 20px; width=100%' />").text(MailScriptResource.NoLettersFilterHeader);
                    container.find("#checkFilterResults").append(el);
                    container.find("#checkFilterResultsMoreBtn").hide();
                    return;
                }

                page = 1;
                total = params.__total;

                var options = {
                    hasNext: false, 
                    hasPrev: false,
                    targetBlank: true,
                    hideCheckboxes: true,
                    showFolders: true
                };

                var html = mailBox.convertMessagesToHtml(messages, options);
                container.find("#checkFilterResults").html(html).show();

                var loadedCount = container.find("#checkFilterResults .row").length;

                if (loadedCount < total) {
                    container.find("#checkFilterResultsMoreBtn").show();
                } else {
                    container.find("#checkFilterResultsMoreBtn").hide();
                }
            },
            error: function (params, errors) {
                window.toastr.error(errors[0]);
                LoadingBanner.hideLoading();
            }
        });
    }

    function checkFilterNext() {
        var filter = getFilterData(0, true);

        if (!filter) return;

        LoadingBanner.displayMailLoading();

        window.Teamlab.checkMailFilter({}, filter, page, pageSize,
        {
            success: function (params, messages) {
                console.log("Check filter next", filter, messages);
                LoadingBanner.hideLoading();

                container.find("#checkFilterResultsTitle").show();

                if (!messages || messages.length === 0) {
                    container.find("#checkFilterResultsMoreBtn").hide();
                    return;
                }

                page +=1;
                total = params.__total;

                var options = {
                    hasNext: false,
                    hasPrev: false,
                    targetBlank: true,
                    hideCheckboxes: true,
                    showFolders: true
                };

                var html = mailBox.convertMessagesToHtml(messages, options);
                container.find("#checkFilterResults").append(html);

                var loadedCount = container.find("#checkFilterResults .row").length;

                if (loadedCount < total) {
                    container.find("#checkFilterResultsMoreBtn").show();
                } else {
                    container.find("#checkFilterResultsMoreBtn").hide();
                }
            },
            error: function (params, errors) {
                window.toastr.error(errors[0]);
                LoadingBanner.hideLoading();
            }
        });
    }

    function onSave(e, filter) {
        if (needApply) {
            window.filtersManager.applyFilter(filter.id);
            needApply = false;
        }

        closeEdit();
    }

    function closeEdit() {
        if (!TMMail.pageIs('editfilter') && !TMMail.pageIs('createfilter')) return;

        ASC.Controls.AnchorController.move('#filtersettings');

        container.remove();

        header.empty();
    }

    return {
        init: init,

        getFilterData: getFilterData,

        close: closeEdit
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/InvitePanel/js/invitepanel.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined") {
    ASC = {};
}

ASC.InvitePanel = (function () {
    var isInit = false;
    var isShortenSelected = false;
    var clip = null;

    var init = function () {
        if (isInit) return;
        isInit = true;

        jq("#invitePanelContainer").replaceWith(
            jq.tmpl("template-blockUIPanel", {
                id: "inviteLinkContainer",
                headerTest: jq("#invitePanelContainer").attr("data-header"),
                innerHtmlText: jq("#invitePanelContainer").html(),

                OKBtn: jq("#invitePanelContainer").attr("data-ok")
            })
        );

        jq("#inviteLinkContainer").on("click", ".button.blue.middle, .cancelButton", function () {
            var $target = jq(this),
                defaultLink = "";

            clip = ASC.Clipboard.destroy(clip);

            if ($target.is(".button.blue")) { PopupKeyUpActionProvider.CloseDialog(); }

            jq("#getShortenInviteLink").show();
            isShortenSelected = false;

            if (jq("#hiddenUserLink").length != 0) {
                jq("#chkVisitor").prop("checked", false);
                defaultLink = jq("#hiddenUserLink").val();
            } else {
                jq("#chkVisitor").prop("checked", true);
                defaultLink = jq("#hiddenVisitorLink").val();
            }

            jq("#shareInviteUserLink").val(defaultLink);

            ASC.InvitePanel.bindClipboardEvent();

            updateSocialLink(defaultLink);
            if ($target.is(".button.blue")) { return false; }
        });

        if (jq("#hiddenUserLink").length != 0 && jq("#hiddenVisitorLink").length != 0) {
            jq("#chkVisitor").on("click", function() {
                changeEmployeeType(this);
            });
        }

        if (jq("#getShortenInviteLink").length != 0) {
            jq("#getShortenInviteLink").on("click", function () {
                getShortenLink(jq("#shareInviteUserLink").val());
            });
        }

        updateSocialLink(jq("#shareInviteUserLink").val());

        jq("#shareInviteLinkViaSocPanel").on("click", "a", function () {
            window.open(jq(this).attr("href"), "new", "height=600,width=1020,fullscreen=0,resizable=0,status=0,toolbar=0,menubar=0,location=1");
            return false;
        });
    };

    var bindClipboardEvent = function () {
        if (!isInit) return;

        if (!ASC.Clipboard.enable) {
            jq("#shareInviteUserLinkCopy").remove();
        } else {

            clip = ASC.Clipboard.destroy(clip);

            var url = jq("#shareInviteUserLink").val();
            clip = ASC.Clipboard.create(url, "shareInviteUserLinkCopy", {
                onComplete: function () {
                    if (typeof(window.toastr) !== "undefined") {
                        toastr.success(ASC.Resources.Master.ResourceJS.LinkCopySuccess);
                    } else {
                        jq("#shareInviteUserLink, #shareInviteUserLinkCopy").yellowFade();
                    }
                }
            });
        }
    };

    function changeEmployeeType(obj) {
        var newLink = jq(obj).is(":checked") ? jq("#hiddenVisitorLink").val() : jq("#hiddenUserLink").val();

        if (isShortenSelected) {
            getShortenLink(newLink);
        } else {
            jq("#shareInviteUserLink").val(newLink);

            ASC.InvitePanel.bindClipboardEvent();

            updateSocialLink(newLink);
        }
    };

    function getShortenLink(link) {

        Teamlab.getShortenLink({}, link,
             {
                 before: function () {
                     LoadingBanner.showLoaderBtn("#inviteLinkContainer");
                 },
                 after: function () {
                     LoadingBanner.hideLoaderBtn("#inviteLinkContainer");
                 },
                 error: function (params, errors) {
                     toastr.error(errors[0]);
                     jq("#getShortenInviteLink").remove();
                 },
                 success: function (params, response) {
                    jq("#getShortenInviteLink").hide();
                    jq("#shareInviteUserLink").val(response);

                    ASC.InvitePanel.bindClipboardEvent();

                    updateSocialLink(jq("#shareInviteUserLink").val());
                    isShortenSelected = true;
                 }
             });
    };

    function updateSocialLink(url) {


        var linkPanel = jq("#shareInviteLinkViaSocPanel"),
            link = encodeURIComponent(url),
            text = encodeURIComponent(jq.format(ASC.Resources.Master.ResourceJS.ShareInviteLinkDscr, url));

        if (!!ASC.Resources.Master.UrlShareFacebook) {
            linkPanel.find(".facebook").attr("href", ASC.Resources.Master.UrlShareFacebook.format(link, "", "", ""));
        } else {
            linkPanel.find(".facebook").remove();
        }
        if (!!ASC.Resources.Master.UrlShareTwitter) {
            linkPanel.find(".twitter").attr("href", ASC.Resources.Master.UrlShareTwitter.format(text));
        } else {
            linkPanel.find(".twitter").remove();
        }
    };


    return {
        init: init,
        bindClipboardEvent: bindClipboardEvent
    };
})();

jq(document).ready(function () {
    try {
        ASC.InvitePanel.init();
    } catch (e) { }
});

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/FileEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;

using ASC.Files.Core;
using ASC.Web.Files.Api;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Services.WCFService;

using File = ASC.Files.Core.File;
using FileShare = ASC.Files.Core.Security.FileShare;
using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Projects.Engine
{
    public class FileEngine
    {
        private const string Module = "projects";
        private const string Bunch = "project";
        private readonly SecurityAdapterProvider securityAdapterProvider = new SecurityAdapterProvider();

        public object GetRoot(int projectId)
        {
            return FilesIntegration.RegisterBunch(Module, Bunch, projectId.ToString(CultureInfo.InvariantCulture));
        }

        public IEnumerable<object> GetRoots(IEnumerable<int> projectIds)
        {
            return FilesIntegration.RegisterBunchFolders(Module, Bunch, projectIds.Select(id => id.ToString(CultureInfo.InvariantCulture)));
        }

        public File GetFile(object id, int version = 1)
        {
            using (var dao = FilesIntegration.GetFileDao())
            {
                var file = 0 < version ? dao.GetFile(id, version) : dao.GetFile(id);
                return file;
            }
        }

        public IEnumerable<File> GetFiles(object[] id)
        {
            using (var dao = FilesIntegration.GetFileDao())
            {
                return dao.GetFiles(id);
            }
        }

        public File SaveFile(File file, Stream stream)
        {
            using (var dao = FilesIntegration.GetFileDao())
            {
                return dao.SaveFile(file, stream);
            }
        }

        public void RemoveRoot(int projectId)
        {
            var folderId = GetRoot(projectId);

            //requet long operation
            try
            {
                Global.FileStorageService.DeleteItems("delete", new ItemList<string> { "folder_" + folderId }, true);
            }
            catch (Exception)
            {

            }
        }

        public void MoveToTrash(object id)
        {
            using (var dao = FilesIntegration.GetFileDao())
            {
                dao.MoveFile(id, Global.FolderTrash);
            }
        }

        public static void RegisterFileSecurityProvider()
        {
            FilesIntegration.RegisterFileSecurityProvider(Module, Bunch, new SecurityAdapterProvider());
        }

        internal static List<Tuple<string, string>> GetFileListInfoHashtable(IEnumerable<File> uploadedFiles)
        {
            if (uploadedFiles == null) return new List<Tuple<string, string>>();

            var fileListInfoHashtable = new List<Tuple<string, string>>();

            foreach (var file in uploadedFiles)
            {
                var fileInfo = string.Format("{0} ({1})", file.Title, Path.GetExtension(file.Title).ToUpper());
                fileListInfoHashtable.Add(new Tuple<string, string>(fileInfo, file.DownloadUrl));
            }

            return fileListInfoHashtable;
        }

        internal FileShare GetFileShare(FileEntry file, int projectId)
        {
            var fileSecurity = securityAdapterProvider.GetFileSecurity(projectId);
            var currentUserId = SecurityContext.CurrentAccount.ID;
            if (!fileSecurity.CanRead(file, currentUserId)) return FileShare.Restrict;
            if (!fileSecurity.CanCreate(file, currentUserId) || !fileSecurity.CanEdit(file, currentUserId)) return FileShare.Read;
            if (!fileSecurity.CanDelete(file, currentUserId)) return FileShare.ReadWrite;

            return FileShare.None;
        }
    }
}

<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/WordpressLoginProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.Profile;

namespace ASC.FederatedLogin.LoginProviders
{
    public class WordpressLoginProvider : BaseLoginProvider<WordpressLoginProvider>
    {
        public const string WordpressMeInfoUrl = "https://public-api.wordpress.com/rest/v1/me";
        public const string WordpressSites = "https://public-api.wordpress.com/rest/v1.2/sites/";

        public WordpressLoginProvider()
        {
        }

        public WordpressLoginProvider(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null) : base(name, order, props, additional)
        {
        }

        public static string GetWordpressMeInfo(string token)
        {
            var headers = new Dictionary<string, string>
                {
                    { "Authorization", "bearer " + token }
                };
            return RequestHelper.PerformRequest(WordpressMeInfoUrl, "", "GET", "", headers);
        }

        public static bool CreateWordpressPost(string title, string content, string status, string blogId, OAuth20Token token)
        {
            try
            {
                var uri = WordpressSites + blogId + "/posts/new";
                const string contentType = "application/x-www-form-urlencoded";
                const string method = "POST";
                var body = "title=" + HttpUtility.UrlEncode(title) + "&content=" + HttpUtility.UrlEncode(content) + "&status=" + status + "&format=standard";
                var headers = new Dictionary<string, string>
                    {
                        { "Authorization", "bearer " + token.AccessToken }
                    };

                RequestHelper.PerformRequest(uri, contentType, method, body, headers);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public override string CodeUrl
        {
            get { return "https://public-api.wordpress.com/oauth2/authorize"; }
        }

        public override string AccessTokenUrl
        {
            get { return "https://public-api.wordpress.com/oauth2/token"; }
        }

        public override string RedirectUri
        {
            get { return this["wpRedirectUrl"]; }
        }

        public override string ClientID
        {
            get { return this["wpClientId"]; }
        }

        public override string ClientSecret
        {
            get { return this["wpClientSecret"]; }
        }

        public override LoginProfile GetLoginProfile(string accessToken)
        {
            throw new NotImplementedException();
        }
    }
}

<|start_filename|>common/TMResourceManager/ASC.Resource.Data/JsonManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;

using ASC.Common.Logging;

using Ionic.Zip;

using Newtonsoft.Json;

using TMResourceData.Model;

using Formatting = Newtonsoft.Json.Formatting;

namespace TMResourceData
{
    public static class JsonManager
    {
        public static void UploadJson(string fileName, Stream fileStream, string projectName, string moduleName)
        {
            var culture = GetCultureFromFileName(fileName);

            string jsonString;
            using (var reader = new StreamReader(fileStream))
            {
                jsonString = reader.ReadToEnd();
            }

            var jsonObj = new Dictionary<string, string>();

            if (Path.GetExtension(fileName) == ".xml")
            {
                var doc = new XmlDocument();
                doc.LoadXml(jsonString);
                var list = doc.SelectNodes("//resources//string");
                if (list != null)
                {
                    try
                    {
                        var nodes = list.Cast<XmlNode>().ToList();
                        jsonObj = nodes.ToDictionary(r => r.Attributes["name"].Value, r => r.InnerText);
                    }
                    catch (Exception e)
                    {
                        LogManager.GetLogger("ASC").ErrorFormat("parse xml " + fileName, e);
                    }
                }
            }
            else
            {
                jsonObj = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonString);
            }

            var fileID = ResourceData.AddFile(fileName, projectName, moduleName);
            const string resourceType = "text";
            foreach (var key in jsonObj.Keys)
            {
                var word = new ResWord
                {
                    Title = key,
                    ValueFrom = jsonObj[key],
                    ResFile = new ResFile { FileID = fileID }
                };
                if (culture != "Neutral")
                {
                    var neutralKey = new ResWord
                    {
                        Title = key,
                        ValueFrom = jsonObj[key],
                        ResFile = new ResFile { FileID = fileID }
                    };

                    ResourceData.GetValueByKey(neutralKey, "Neutral");
                    if (string.IsNullOrEmpty(neutralKey.ValueTo)) continue;
                }

                ResourceData.AddResource(culture, resourceType, DateTime.UtcNow, word, true, "Console");
            }
        }

        public static string ExportJson(string project, string module, List<string> languages, string exportPath,
            bool withDefaultValue = true)
        {
            using (var fastZip = new ZipFile())
            {
                var filter = new ResCurrent
                {
                    Project = new ResProject { Name = project },
                    Module = new ResModule { Name = module }
                };

                var zipDirectory = Directory.CreateDirectory(exportPath + module);
                foreach (var language in languages)
                {
                    filter.Language = new ResCulture { Title = language };

                    var words =
                        ResourceData.GetListResWords(filter, string.Empty).GroupBy(x => x.ResFile.FileID).ToList();
                    if (!words.Any())
                    {
                        Console.WriteLine("Error!!! Can't find appropriate project and module. Possibly wrong names!");
                        return null;
                    }

                    foreach (var fileWords in words)
                    {
                        var wordsDictionary = new Dictionary<string, string>();
                        foreach (
                            var word in
                                fileWords.OrderBy(x => x.Title).Where(word => !wordsDictionary.ContainsKey(word.Title)))
                        {
                            if (string.IsNullOrEmpty(word.ValueTo) && !withDefaultValue) continue;

                            wordsDictionary[word.Title] = word.ValueTo ?? word.ValueFrom;
                            if (!string.IsNullOrEmpty(wordsDictionary[word.Title]))
                            {
                                wordsDictionary[word.Title] = wordsDictionary[word.Title].TrimEnd('\n').TrimEnd('\r');
                            }
                        }

                        var firstWord = fileWords.FirstOrDefault();
                        var fileName = firstWord == null
                            ? module
                            : Path.GetFileNameWithoutExtension(firstWord.ResFile.FileName);
                        var ext = Path.GetExtension(firstWord.ResFile.FileName);

                        var zipFileName = zipDirectory.FullName + "\\" + fileName +
                                          (language == "Neutral" ? string.Empty : "." + language) + ext;
                        using (TextWriter writer = new StreamWriter(zipFileName))
                        {
                            if (ext == ".json")
                            {
                                var obj = JsonConvert.SerializeObject(wordsDictionary, Formatting.Indented);
                                writer.Write(obj);
                            }
                            else
                            {
                                var data = new XmlDocument();
                                var resources = data.CreateElement("resources");

                                foreach (var ind in wordsDictionary)
                                {
                                    var stringAttr = data.CreateAttribute("name");
                                    stringAttr.Value = ind.Key;

                                    var child = data.CreateElement("string");
                                    child.Attributes.Append(stringAttr);
                                    child.InnerText = ind.Value;

                                    resources.AppendChild(child);
                                }

                                data.AppendChild(resources);

                                var settings = new XmlWriterSettings
                                {
                                    Indent = true,
                                    IndentChars = "  ",
                                    NewLineChars = Environment.NewLine,
                                    NewLineHandling = NewLineHandling.Replace,
                                    OmitXmlDeclaration = false,
                                    ConformanceLevel = ConformanceLevel.Fragment
                                };

                                using (var xmlTextWriter = XmlWriter.Create(writer, settings))
                                {
                                    data.WriteTo(xmlTextWriter);
                                    xmlTextWriter.Flush();
                                }
                            }
                        }
                    }
                }

                var zipPath = exportPath + "\\" + module + ".zip";
                fastZip.AddDirectory(zipDirectory.FullName);
                fastZip.Save(zipPath);

                zipDirectory.Delete(true);
                return zipPath;
            }
        }

        private static string GetCultureFromFileName(string fileName)
        {
            var culture = "Neutral";
            var nameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);

            if (nameWithoutExtension != null && nameWithoutExtension.Split('.').Length > 1)
            {
                culture = nameWithoutExtension.Split('.')[1];
            }

            return culture;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/js/settings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined") {
    ASC = {};
}
if (typeof ASC.CRM === "undefined") {
    ASC.CRM = function() { return {} };
}

ASC.CRM.SettingsPage = (function() {

    var _initSortableFields = function (entityType) {

        jq("#customFieldList").sortable({
            cursor: "move",
            handle: '.sort_drag_handle',
            items: 'li',
            start: function(event, ui) {
                jq("#customFieldActionMenu").hide();
                jq("#customFieldList .entity-menu.active").removeClass("active");
            },
            beforeStop: function(event, ui) {
                jq(ui.item[0]).attr("style", "");
            },
            update: function(event, ui) {
                var fieldID = [];

                jq("#customFieldList li").find("[id^=custom_field_]").each(function() {
                    fieldID.push(jq(this).attr("id").split('_')[2]);
                });

                Teamlab.reorderCrmCustomFields({}, entityType, fieldID, {});
            }
        });
    };

    var _initFieldsActionMenu = function() {
        if (jq("#customFieldActionMenu").length != 1) return;

        jq.dropdownToggle({
            dropdownID: "customFieldActionMenu",
            switcherSelector: "#customFieldList .entity-menu",
            addTop: 0,
            addLeft: 10,
            rightPos: true,
            beforeShowFunction: function (switcherObj, dropdownItem) {
                var fieldId = switcherObj.attr("fieldid");
                if (!fieldId) return;
            },
            showFunction: function(switcherObj, dropdownItem) {
                jq("#customFieldList .entity-menu.active").removeClass("active");
                if (dropdownItem.is(":hidden")) {
                    switcherObj.addClass("active");
                    if (switcherObj.attr("fieldid") != dropdownItem.attr("fieldid")) {
                        dropdownItem.attr("fieldid", switcherObj.attr("fieldid"));
                    }
                }
            },
            hideFunction: function() {
                jq("#customFieldList .entity-menu.active").removeClass("active");
            }
        });
    };

    var _showAddFieldPanel = function() {
        jq('#manageField div.containerHeaderBlock td:first').text(ASC.CRM.Resources.CRMSettingResource.CreateNewField);
        jq('#manageField .middle-button-container a.button.blue.middle').text(ASC.CRM.Resources.CRMSettingResource.AddThisField);

        LoadingBanner.strLoading = ASC.CRM.Resources.CRMSettingResource.CreateFieldInProgressing;

        _resetManageFieldPanel();
        RemoveRequiredErrorClass(jq("#manageField dl input:first"));
        jq('#manageField .middle-button-container a.button.blue.middle').unbind('click').click(function () {
            if (jq(this).hasClass("disable"))
                return;

            _createField();
        });
        PopupKeyUpActionProvider.EnableEsc = false;
        StudioBlockUIManager.blockUI("#manageField", 400);
    };

    var _initOtherActionMenu = function() {
        jq("#menuCreateNewTask").bind("click", function() { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    };

    var _initNumericFieldsLimitation = function() {
        var maxCountRows = ASC.CRM.Data.MaxCustomFieldRows,
            maxCountCols = ASC.CRM.Data.MaxCustomFieldCols,
            maxCountSize = ASC.CRM.Data.MaxCustomFieldSize;

        jq.forceNumber({
            parent: "#manageField",
            input: "#text_field_size, #textarea_field_rows, #textarea_field_cols",
            integerOnly: true,
            positiveOnly: true
        });

        jq("#text_field_size").focusout(function (e) {
            var fieldSize = jq.trim(jq("#text_field_size").val());
            if (fieldSize != "" && fieldSize * 1 > maxCountSize) {
                jq("#text_field_size").val(maxCountSize);
            }
        });

        jq("#textarea_field_rows").focusout(function(e) {
            var fieldSize = jq.trim(jq("#textarea_field_rows").val());
            if (fieldSize != "" && fieldSize * 1 > maxCountRows) {
                jq("#textarea_field_rows").val(maxCountRows);
            }
        });

        jq("#textarea_field_cols").focusout(function(e) {
            var fieldSize = jq.trim(jq("#textarea_field_cols").val());
            if (fieldSize != "" && fieldSize * 1 > maxCountCols) {
                jq("#textarea_field_cols").val(maxCountCols);
            }
        });
    };

    var _findIndexOfFieldByID = function(fieldID) {
        for (var i = 0, n = ASC.CRM.SettingsPage.customFieldList.length; i < n; i++) {
            if (ASC.CRM.SettingsPage.customFieldList[i].id == fieldID) {
                return i;
            }
        }
        return -1;
    };

    var _resetManageFieldPanel = function() {
        var $p = jq("#manageField");
        $p.find("dl input:first").val("");
        $p.find("dl dd:last ul li:not(:first)").remove();
        $p.find("select").prop('value', '0');
        $p.find("dl .field_mask").hide();
        $p.find("dl .text_field").show();
        jq("#manageField input, #manageField select, #manageField textarea").removeAttr("readonly").removeAttr("disabled").removeClass('disabled');
        jq("#addOptionButton.display-none").removeClass("display-none");
        $p.find(".select_options .deleteBtn.display-none").removeClass("display-none");

        jq("#text_field_size").val(ASC.CRM.Data.DefaultCustomFieldSize);
        jq("#textarea_field_rows").val(ASC.CRM.Data.DefaultCustomFieldRows);
        jq("#textarea_field_cols").val(ASC.CRM.Data.DefaultCustomFieldCols);
    };


    var _fieldFactory = function(field) {
        if (jQuery.trim(field.mask) == "") {
            field.maskObj = "";
        } else {
            field.maskObj = jq.evalJSON(field.mask);
        }

        field.relativeItemsString = ASC.CRM.Common.getRelativeItemsLinkString(field.relativeItemsCount, jq.getURLParam("type"), _getCurEntityType());
    };

    var _validateDataField = function() {
        if (jq("#manageField dl input:first").val().trim() == "") {
            ShowRequiredError(jq("#manageField dl input:first"), true);
            return false;
        } else {
            RemoveRequiredErrorClass(jq("#manageField dl input:first"));
            return true;
        }
    };

    var _readFieldData = function(sortOrder) {
        var view = _getCurEntityType(),
            field = {
                label: jq("#manageField dl input:first").val().trim(),
                fieldType: parseInt(jq("#manageField dl select:first").val()),
                entityType: view != null && view != "" ? view : "contact",
                position: sortOrder
            };

        switch (field.fieldType) {
            case 0:
                field.mask = jq.toJSON({ "size": jq("#text_field_size").val() });
                break;
            case 1:
                field.mask = jq.toJSON({
                    "rows": jq("#textarea_field_rows").val(),
                    "cols": jq("#textarea_field_cols").val()
                });
                break;
            case 2:
                var selectedItem = new Array();
                jq("#manageField dd.select_options :input").each(function() {
                    var value = jq(this).val().trim();
                    if (value == "" || selectedItem.indexOf(value) != -1) { return; }
                    selectedItem.push(value);
                });

                if (selectedItem.length == 0) {
                    toastr.error(ASC.CRM.Resources.CRMJSResource.EmptyItemList);
                    return;
                }
                field.mask = jq.toJSON(selectedItem);
                break;
            default:
                field.mask = "";
                break;
        }
        return field;
    };

    var _createField = function() {
        if (!_validateDataField()) { return; }

        var $listCustomFields = jq("#customFieldList li"),
            field = _readFieldData($listCustomFields.length),
            index = 0;

        for (var i = 0, len = $listCustomFields.length; i < len; i++) {
            if (jq($listCustomFields[i]).find(".customFieldTitle").text().trim() == field.label) {
                index = i + 1;
                break;
            }
        }
        if (index == 0) {
            Teamlab.addCrmCustomField({}, field.entityType, field, {
                before: function (params) {
                    LoadingBanner.showLoaderBtn("#manageField");
                },
                after: function (params) {
                    LoadingBanner.hideLoaderBtn("#manageField");
                },
                success: ASC.CRM.SettingsPage.CallbackMethods.add_customField
            });
        } else {
            ASC.CRM.Common.animateElement({
                element: jq($listCustomFields[index - 1]),
                afterScrollFunc: jq.unblockUI()
            });
        }
    };

    var _editField = function (liObj, oldField, indexOfField) {
        var $listCustomFields = jq("#customFieldList li"),
            index = 0,
            field = null;
        if (!_validateDataField()) { return; }

        if (oldField.relativeItemsCount != 0) {
            var tmpField = _readFieldData(indexOfField);
            field = oldField;
            field.label = tmpField.label;
            field.entityType = tmpField.entityType;
            field.mask = tmpField.mask;
        } else {
            field = _readFieldData(indexOfField);
            field.id = oldField.id;
        }

   
        for (var i = 0, n = $listCustomFields.length; i < n; i++) {
            if (jq($listCustomFields[i]).find(".customFieldTitle").text().trim() == field.label && jq($listCustomFields[i]).not(jq(liObj)).length != 0) {
                index = i + 1;
                break;
            }
        }
        if (index == 0) {
            Teamlab.updateCrmCustomField({ liObj: liObj, indexOfField: indexOfField }, field.entityType, field.id, field, {
                before: function() {
                    LoadingBanner.showLoaderBtn("#manageField");
                },
                after: function() {
                    LoadingBanner.hideLoaderBtn("#manageField");
                },
                success: ASC.CRM.SettingsPage.CallbackMethods.edit_customField
            });
        } else {
            ASC.CRM.Common.animateElement({
                element: jq($listCustomFields[index - 1]),
                afterScrollFunc: jq.unblockUI()
            });
        }
    };

    var _initEmptyScreen = function () {
        jq.tmpl("template-emptyScreen",
            {
                ID: "emptyCustomFieldContent",
                ImgSrc: ASC.CRM.Data.EmptyScrImgs["empty_screen_userfields"],
                Header: ASC.CRM.Resources.CRMSettingResource.EmptyContentCustomFields,
                Describe: ASC.CRM.Resources.CRMSettingResource.EmptyContentCustomFieldsDescript,
                ButtonHTML: ['<a class="link dotline plus">', ASC.CRM.Resources.CRMSettingResource.CreateCustomField, '</a>'].join(''),
                CssClass: "display-none"
            }).insertAfter("#customFieldList");

        jq("#emptyCustomFieldContent .emptyScrBttnPnl > a").on("click", function () { _showAddFieldPanel(); });
    };

    var _initTabs = function (type) {

        jq("<div class='fakeTabContainer' id='contFake'></div>\
            <div class='fakeTabContainer' id='persFake'></div>\
            <div class='fakeTabContainer' id='compFake'></div>\
            <div class='fakeTabContainer' id='dealFake'></div>\
            <div class='fakeTabContainer' id='caseFake'></div>").insertAfter("#CustomFieldsTabs");
        window.ASC.Controls.ClientTabsNavigator.init("CustomFieldsTabs", {
            tabs: [
            {
                title: ASC.CRM.Resources.CRMSettingResource.BothPersonAndCompany,
                selected: type === "contact",
                anchor: "contact",
                divID: "contFake",
                onclick: "ASC.CRM.SettingsPage.initData('contact');"
            },
            {
                title: ASC.CRM.Resources.CRMSettingResource.JustForPerson,
                selected: type === "person",
                anchor: "person",
                divID: "persFake",
                onclick: "ASC.CRM.SettingsPage.initData('person');"
            },
            {
                title: ASC.CRM.Resources.CRMSettingResource.JustForCompany,
                selected: type === "company",
                anchor: "company",
                divID: "compFake",
                onclick: "ASC.CRM.SettingsPage.initData('company');"
            },
            {
                title: ASC.CRM.Resources.CRMCommonResource.DealModuleName,
                selected: type === "opportunity",
                anchor: "opportunity",
                divID: "dealFake",
                onclick: "ASC.CRM.SettingsPage.initData('opportunity');"
            },
            {
                title: ASC.CRM.Resources.CRMCommonResource.CasesModuleName,
                selected: type === "case",
                anchor: "case",
                divID: "caseFake",
                onclick: "ASC.CRM.SettingsPage.initData('case');"
            }]
        });
    };

    var _getCurEntityType = function () {
        var available = ["contact", "person", "company", "opportunity", "case"],
            type = ASC.Controls.AnchorController.getAnchor();
        if (type == null || type == "" || jq.inArray(type, available) == -1) { type = "contact"; }
        return type;
    };

    var _initManagePanel = function () {

        jq.tmpl("template-blockUIPanel", {
            id: "manageField",
            headerTest: ASC.CRM.Resources.CRMCommonResource.Confirmation,
            questionText: "",
            innerHtmlText: jq.tmpl("customFieldActionPanelBodyTmpl", {}).html(),
            OKBtn: ASC.CRM.Resources.CRMSettingResource.AddThisField,
            CancelBtn: ASC.CRM.Resources.CRMCommonResource.Cancel,
            progressText: ""
        }).insertAfter("#customFieldList");

        jq("#manageField .button.gray").on("click", function(){PopupKeyUpActionProvider.EnableEsc = true;jq.unblockUI();});
    };

    var _iniDeleteFieldConfirmationPanel = function () {
        jq.tmpl("template-blockUIPanel", {
            id: "deleteFieldConfirmation",
            headerTest: ASC.CRM.Resources.CRMCommonResource.Confirmation,
            questionText: '',
            innerHtmlText: ["<div>", ASC.CRM.Resources.CRMSettingResource.DeleteCustomFieldConfirmationText, "</div>"].join(''),
            OKBtn: ASC.CRM.Resources.CRMCommonResource.OK,
            OKBtnClass: "OKDeleteField",
            CancelBtn: ASC.CRM.Resources.CRMCommonResource.Cancel
        }).insertAfter("#customFieldList");

        jq("#deleteFieldConfirmation").on("click", ".OKDeleteField", function () {
            var fieldid = jq("#customFieldActionMenu").attr('fieldid'),
                $menu = null,
                liObj = null;

            if (typeof (fieldid) === "undefined" || fieldid == "" || jq("#fieldMenu_" + fieldid).length == 0)
            { return; }

            $menu = jq("#fieldMenu_" + fieldid);
            if ($menu.length != 1) { return; }
            liObj = jq($menu.parents('li').get(0));

            _deleteFieldComplete(fieldid, liObj);
        });
    };

    var _deleteFieldComplete = function (fieldid, liObj) {
        var entityType = _getCurEntityType();

        Teamlab.removeCrmCustomField({ liObj: liObj }, entityType, fieldid, {
            before: function (params) {
                params.liObj.find(".entity-menu").hide();
                params.liObj.find("div.ajax_loader").show();
            },
            success: ASC.CRM.SettingsPage.CallbackMethods.delete_customField
        });
    };

    var timeoutId = null;

    return {
        CallbackMethods: {
            add_customField: function(params, field) {
                _fieldFactory(field);
                ASC.CRM.SettingsPage.customFieldList.push(field);

                var $itemHTML = jq.tmpl("customFieldSettingsRowTmpl", field);
                if (jq("#customFieldList li").length == 0) {
                    jq("#emptyCustomFieldContent").addClass("display-none");
                    jq("#customFieldList").show();
                    jq("#createNewField.display-none").removeClass("display-none");
                }
                $itemHTML.appendTo("#customFieldList");

                ASC.CRM.Common.animateElement({
                    element: $itemHTML,
                    afterScrollFunc: jq.unblockUI()
                });
            },

            edit_customField: function(params, field) {
                _fieldFactory(field);
                ASC.CRM.SettingsPage.customFieldList[params.indexOfField] = field;

                var $itemHTML = jq.tmpl("customFieldSettingsRowTmpl", field);

                params.liObj.hide();
                $itemHTML.insertAfter(params.liObj);
                params.liObj.remove();

                ASC.CRM.Common.animateElement({
                    element: $itemHTML,
                    afterScrollFunc: jq.unblockUI()
                });
            },

            delete_customField: function (params, field) {
                jq.unblockUI();
                params.liObj.remove();

                var index = _findIndexOfFieldByID(field.id);
                if (index != -1) { ASC.CRM.SettingsPage.customFieldList.splice(index, 1); }

                if (jq("#customFieldList li").length == 0) {
                    jq("#customFieldList").hide();
                    jq("#createNewField:not(.display-none)").addClass("display-none");
                    jq("#emptyCustomFieldContent").removeClass("display-none");
                }
            }
        },

        initData: function (type) {
            ASC.CRM.SettingsPage.customFieldList = [];
            jq("#customFieldList").html("").hide();
            jq("#emptyCustomFieldContent:not(.display-none)").addClass("display-none");
            LoadingBanner.displayLoading();

            Teamlab.getCrmCustomFields({}, type, function (params, fields) {
                for (var i = 0, len = fields.length; i < len; i++) {
                    _fieldFactory(fields[i]);
                    ASC.CRM.SettingsPage.customFieldList.push(fields[i]);
                }

                if (ASC.CRM.SettingsPage.customFieldList.length != 0) {
                    jq("#customFieldList").show();
                    jq("#createNewField.display-none").removeClass("display-none");
                    jq.tmpl("customFieldSettingsRowTmpl", ASC.CRM.SettingsPage.customFieldList).appendTo("#customFieldList");
                } else {
                    jq("#createNewField:not(.display-none)").addClass("display-none");
                    jq("#emptyCustomFieldContent").removeClass("display-none");
                }
                _initSortableFields(type);
                LoadingBanner.hideLoading();
            });

        },

        init: function () {
            var type = _getCurEntityType();
            _initTabs(type);
            _initEmptyScreen();
            _initManagePanel();
            _iniDeleteFieldConfirmationPanel();
            //jq("#customFieldList").disableSelection();

            jq("#createNewField").on("click", function () { _showAddFieldPanel(); });

            _initFieldsActionMenu();
            _initOtherActionMenu();
            _initNumericFieldsLimitation();
            ASC.CRM.SettingsPage.initData(type);
        },

        initExportView: function() {
            _initOtherActionMenu();
            ASC.CRM.SettingsPage.checkExportStatus(true);
        },

        startExportData: function () {
            jq("#exportDataContent a.button.blue.middle").hide();
            jq("#exportDataContent p.header-base-small").show();

            Teamlab.startCrmExportToCSV({},
                {
                    success: function (params, response) {
                        ASC.CRM.SettingsPage.checkExportStatus(true);
                    },
                    error: function (params, errors) {
                        var err = errors[0];
                        if (err != null) {
                            toastr.error(err);
                        }
                    }
                });
        },

        deleteField: function() {
            jq("#customFieldActionMenu").hide();
            jq("#customFieldList .entity-menu.active").removeClass("active");

            var index = -1,
                fieldid = jq("#customFieldActionMenu").attr('fieldid'),
                field = null,
                liObj = null,
                $menu = null;


            if (typeof (fieldid) === "undefined" || fieldid == "" || jq("#fieldMenu_" + fieldid).length == 0)
            { return; }

            $menu = jq("#fieldMenu_" + fieldid);
            if ($menu.length != 1) { return; }
            liObj = jq($menu.parents('li').get(0));

            index = _findIndexOfFieldByID(fieldid);
            if (index === -1) { return; }

            field = ASC.CRM.SettingsPage.customFieldList[index];

            if (field.relativeItemsCount == 0) {
                _deleteFieldComplete(fieldid, liObj);
            } else {
                StudioBlockUIManager.blockUI("#deleteFieldConfirmation", 500);
            }

        },

        showEditFieldPanel: function() {
            jq("#customFieldActionMenu").hide();
            jq("#customFieldList .entity-menu.active").removeClass("active");
            var fieldid = jq("#customFieldActionMenu").attr("fieldid"),
                $menu = null,
                liObj = null,
                index = -1,
                field = null;

            if (typeof (fieldid) === "undefined" || fieldid == "") { return; }

            $menu = jq("#fieldMenu_" + fieldid);
            if ($menu.length != 1) { return; }

            liObj = jq($menu.parents('li:first'));

            index = _findIndexOfFieldByID(fieldid);
            if (index === -1) { return; }

            field = ASC.CRM.SettingsPage.customFieldList[index];
            _resetManageFieldPanel();
            if (field.relativeItemsCount != 0) {
                jq("#manageField input, #manageField select, #manageField textarea")
                    .not("#manageField dl input:first")
                    .not("#text_field_size")
                    .not("#textarea_field_rows")
                    .not("#textarea_field_cols")
                    .prop("readonly", "readonly").prop("disabled", "disabled").addClass('disabled');
                if (field.fieldType == 2) {//select box
                    jq("#manageField .select_options .deleteBtn:not(.display-none)").addClass("display-none");
                }
            }

            jq('#manageField div.containerHeaderBlock td:first').text(ASC.CRM.Resources.CRMJSResource.EditSelectedCustomField.replace('{0}', field.label));
            jq('#manageField .middle-button-container a.button.blue.middle').text(ASC.CRM.Resources.CRMJSResource.SaveChanges);
            LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.SaveChangesProggress;


            jq("#manageField dl input:first").val(field.label);
            jq("#manageField dl select:first").val(field.fieldType);
            jq("#manageField dl .field_mask").hide();

            switch (field.fieldType) {
                case 0:
                    jq("#text_field_size").val(field.maskObj.size);
                    jq("#manageField dl .text_field").show();
                    break;
                case 1:
                    jq("#textarea_field_rows").val(field.maskObj.rows);
                    jq("#textarea_field_cols").val(field.maskObj.cols);
                    jq("#manageField dl .textarea_field").show();
                    break;
                case 2:
                    for (var i = 0, n = field.maskObj.length; i < n; i++) {
                        ASC.CRM.SettingsPage.toSelectBox(jq("#addOptionButton"));
                        jq("#manageField dd.select_options ul li:last input").val(field.maskObj[i])
                    }
                    jq("#manageField .select_options .deleteBtn:first").removeClass("display-none");
                    jq("#manageField .select_options input:first").removeAttr("readonly").removeAttr("disabled", "disabled").removeClass('disabled');
                    jq("#manageField dl .select_options").show();
                    break;
                default:
                    break;
            }

            RemoveRequiredErrorClass(jq("#manageField dl input:first"));
            jq('#manageField .middle-button-container a.button.blue.middle').unbind('click').click(function() {
                _editField(liObj, field, index);
            });
            PopupKeyUpActionProvider.EnableEsc = false;
            StudioBlockUIManager.blockUI("#manageField", 400);
        },

        selectTypeEvent: function(selectObj) {
            var idx = selectObj.selectedIndex,
                which = parseInt(selectObj.options[idx].value);
            jq("#manageField dl .field_mask").hide();

            switch (which) {
                case 0:
                    jq("#manageField dl .text_field").show();
                    break;
                case 1:
                    jq("#manageField dl .textarea_field").show();
                    break;
                case 2:
                    jq("#manageField dl .select_options").show();
                    break;
            }
        },

        toSelectBox: function(buttonObj) {
            var ulObj = jq(buttonObj).prev();
            var optionObj = ulObj.children(":first").clone().show();
            optionObj.appendTo(ulObj);
            optionObj.find("input.textEdit").focus();
        },

        toggleCollapceExpand: function(elem) {
            $Obj = jq(elem);
            var isCollapse = $Obj.hasClass("headerCollapse");
            if (isCollapse) {
                $Obj.parents('li').nextUntil('#customFieldList li.expand_collapce_element').show();
            } else {
                $Obj.parents('li').nextUntil('#customFieldList li.expand_collapce_element').hide();
            }
            $Obj.toggleClass('headerExpand');
            $Obj.toggleClass('headerCollapse');
        },

        checkExportStatus: function(isFirstVisit) {
            if (isFirstVisit) {
                ASC.CRM.SettingsPage.closeExportProgressPanel();
            }

            Teamlab.getStatusExportToCSV({},
                {
                    success: function (params, response) {
                        if (response == null || response == "" || jQuery.isEmptyObject(response)) {
                            ASC.CRM.SettingsPage.closeExportProgressPanel();
                            return false;
                        }

                        var $edt = jq("#exportDataContent");
                        $edt.find("div.progress").css("width", parseInt(response.percentage) + "%");
                        $edt.find("div.percent").text(parseInt(response.percentage) + "%");
                        $edt.find("a.button.blue.middle").hide();
                        $edt.find("div.progress-container,div.middle-button-container,p.header-base-small,#abortButton").show();
                        $edt.find("#okButton").hide();

                        if (response.error != null && response.error != "") {
                            ASC.CRM.SettingsPage.buildErrorList(response);
                        } else {
                            if (response.isCompleted) {
                                $edt.find("#exportLinkBox span").html(
                                    jq("<a></a>").attr("href", response.fileUrl).attr("download", response.fileName).text(response.fileName)
                                );
                                $edt.find("p.header-base-small").hide();
                                $edt.find("#exportLinkBox").show();
                                $edt.find("#abortButton").hide();
                                $edt.find("#okButton").show();
                            } else {
                                timeoutId = setTimeout(ASC.CRM.SettingsPage.checkExportStatus, 3000);
                            }
                        }
                    },
                    error: function (params, errors) {
                        var err = errors[0];
                        if (err != null) {
                            toastr.error(err);
                        }
                    }
                });
        },

        abortExport: function () {
            Teamlab.cancelExportToCSV({},
                {
                    success: function (params, response) {
                        clearTimeout(timeoutId);
                        ASC.CRM.SettingsPage.closeExportProgressPanel();
                    },
                    error: function (params, errors) {
                        var err = errors[0];
                        if (err != null) {
                            toastr.error(err);
                        }
                    }
                });
        },

        closeExportProgressPanel: function () {
            var $edt = jq("#exportDataContent");
            $edt.find("div.progress").css("width", "0%");
            $edt.find("div.percent").text("0%");
            $edt.find("#abortButton").show();

            $edt.find("#okButton,div.progress-container,div.middle-button-container").hide();
            $edt.find("a.button.blue.middle").show();
            $edt.find("#exportErrorBox,#exportLinkBox,p.header-base-small").hide();

            $edt.find("div.progressErrorBox,#exportLinkBox span").html("");
        },

        buildErrorList: function(res) {
            var mess = "error";
            switch (typeof res.error) {
                case "object":
                    mess = res.error.Message + "<br/>";
                    break;
                case "string":
                    mess = res.error;
                    break;
            }

            jq("#exportDataContent div.progressErrorBox").html(
                jq("<div></div>").addClass("red-text").html(mess)
            );
            jq("#exportDataContent #exportErrorBox").show();
        }
    };
})();


ASC.CRM.ListItemView = (function() {

    var _initSortableElements = function() {
        jq("#listView").sortable({
            cursor: "move",
            handle: '.sort_drag_handle',
            items: 'li',
            start: function(event, ui) {
                if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
                    jq(".iconsPanelSettings").hide();
                }
                if (ASC.CRM.ListItemView.CurrentType === 1) {
                    jq("#colorsPanel").hide();
                    jq("#popup_colorsPanel").hide();
                }
                jq("#listItemActionMenu").hide();
                jq("#listView .entity-menu.active").removeClass("active");
            },
            stop: function(event, ui) {
                if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
                    var $activeImg = jq(ui.item).find("label.currentIcon");
                    if ($activeImg.length != 0) {
                        $activeImg.removeClass('active').removeClass('hover');
                    }
                }
            },

            beforeStop: function(event, ui) {
                jq(ui.item[0]).attr("style", "");
            },
            update: function(event, ui) {
                var itemsName = [];

                jq("#listView li[id*='list_item_id_']").each(function() {
                    var index = _findIndexOfItemByID(parseInt(jq(this).attr("id").replace("list_item_id_", "")));
                    if (index === -1) { return; }
                    itemsName.push(ASC.CRM.ListItemView.itemList[index].title);
                });
                Teamlab.reorderCrmListItems({}, ASC.CRM.ListItemView.CurrentType, itemsName, {});
            }
        });
    };

    var _initElementsActionMenu = function() {
        if (jq("#listItemActionMenu").length != 1) return;

        jq.dropdownToggle({
            dropdownID: "listItemActionMenu",
            switcherSelector: "#listView .entity-menu",
            addTop: 0,
            addLeft: 10,
            rightPos: true,
            showFunction: function(switcherObj, dropdownItem) {
                jq("#listView .entity-menu.active").removeClass("active");
                if (dropdownItem.is(":hidden")) {
                    switcherObj.addClass("active");
                    var listitemid = switcherObj.attr("data-listitemid"),
                        relativeCount = switcherObj.attr("data-relativecount");

                    if (relativeCount == "0") {
                        dropdownItem.find(".editItem.display-none").removeClass("display-none");
                    } else {
                        dropdownItem.find(".editItem").addClass("display-none");
                    }
                    
                    dropdownItem.attr("data-listitemid", listitemid);
                    dropdownItem.attr("data-relativecount", relativeCount);
                }
            },
            hideFunction: function() {
                jq("#listView .entity-menu.active").removeClass("active");
            }
        });
    };

    var _initOtherActionMenu = function() {
        jq("#menuCreateNewTask").bind("click", function() { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    };

    var _findIndexOfItemByID = function(id) {
        for (var i = 0, n = ASC.CRM.ListItemView.itemList.length; i < n; i++) {
            if (ASC.CRM.ListItemView.itemList[i].id == id) {
                return i;
            }
        }
        return -1;
    };

    var _resetManageItemPanel = function() {
        jq("#manageItem input").val("");
        jq("#manageItem textarea").val("");

        if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
            var $iconsPanel = jq("#iconsPanel_" + ASC.CRM.ListItemView.CurrentType);
            if ($iconsPanel.length == 1) {
                var $first_icon = $iconsPanel.children('label:first');
                if ($first_icon.length == 1) {
                    var $selectedIcinObj = jq("#manageItem label.selectedIcon"),
                        cssClass = $first_icon.attr('data-imgName').split('.')[0];

                    $selectedIcinObj.attr('data-imgName', $first_icon.attr('data-imgName'));
                    $selectedIcinObj.attr('title', $first_icon.attr('title'));
                    $selectedIcinObj.attr("class", ["selectedIcon ", ASC.CRM.ListItemView.CurrentType == 2 ? "task_category" : "event_category", " ", cssClass].join(''));
                }
            }
        }
        if (ASC.CRM.ListItemView.CurrentType === 1) {
            var $divColors = jq("#colorsPanel > span"),
                ind = Math.floor(Math.random() * $divColors.length);
            jq("#manageItem .selectedColor").css("background-color", ASC.CRM.Common.getHexRGBColor(jq($divColors.get(ind)).css("background-color")));
        }
    };

    var _showAddItemPanel = function() {
        jq('#manageItem div.containerHeaderBlock td:first').text(ASC.CRM.ListItemView.AddItemHeaderText);
        jq('#manageItem .middle-button-container a.button.blue.middle').text(ASC.CRM.ListItemView.AddItemButtonText);

        _resetManageItemPanel();

        jq('#manageItem .middle-button-container a.button.blue.middle').unbind('click').click(function () {
            if (jq(this).hasClass("disable"))
                return;
            
            _createItem();
        });
        RemoveRequiredErrorClass(jq("#manageItem input:first"));
        PopupKeyUpActionProvider.CloseDialogAction = "javascript:jq('.iconsPanelSettings').hide();jq('#colorsPanel').hide();jq('#popup_colorsPanel').hide();";
        PopupKeyUpActionProvider.EnableEsc = false;
        StudioBlockUIManager.blockUI("#manageItem", 400);

        if (!ASC.CRM.ListItemView.IsDropdownToggleRegistered) {
            ASC.CRM.ListItemView.IsDropdownToggleRegistered = true;
            if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
                jq.dropdownToggle({
                    dropdownID: "popup_iconsPanel_" + ASC.CRM.ListItemView.CurrentType,
                    switcherSelector: "#manageItem .change_icon",
                    noActiveSwitcherSelector: "#listView label.currentIcon",
                    addTop: 1,
                    addLeft: jq("#manageItem .change_icon").width() - 12,
                    position: "fixed"
                });
            }
            if (ASC.CRM.ListItemView.CurrentType === 1) {
                jq.dropdownToggle({
                    dropdownID: "popup_colorsPanel",
                    switcherSelector: "#manageItem .change_color",
                    noActiveSwitcherSelector: "#listView .currentColor",
                    addTop: 2,
                    addLeft: jq("#manageItem .change_color").width() - 12,
                    position: "fixed"
                });
            }
        }
    };

    var _changeColor = function(Obj, listItemId, color) {
        var data = {
            id: listItemId,
            color: color
        };
        Teamlab.updateCrmContactStatusColor({ Obj: Obj }, listItemId, data,
            function(params, contactStatus) {
                var index = _findIndexOfItemByID(contactStatus.id);
                if (index === -1) { return; }
                ASC.CRM.ListItemView.itemList[index] = contactStatus;

                jq(params.Obj).css("background-color", contactStatus.color);
                jq("#colorsPanel").hide();
            }
        );
    };

    var _changeIcon = function(Obj, listItemId, $imgObj) {
        var imgName = $imgObj.attr("data-imgName"),
            data = {
                id: listItemId,
                imageName: imgName
            };

        Teamlab.updateCrmListItemIcon({ Obj: jq(Obj) }, ASC.CRM.ListItemView.CurrentType, listItemId, data, {
            before: function(params) {
                params.Obj.hide();
                params.Obj.parent().find("div.ajax_change_icon").show();
            },
            success: function(params, listItem) {
                var index = _findIndexOfItemByID(listItem.id);
                if (index === -1) { return; }

                _itemFactory(listItem);
                ASC.CRM.ListItemView.itemList[index] = listItem;

                params.Obj
                    .attr("class", ["currentIcon ", ASC.CRM.ListItemView.CurrentType == 2 ? "task_category" : "event_category", " ", listItem.cssClass].join(''))
                    .attr("data-imgName", listItem.imageName)
                    .attr("title", listItem.imageTitle);

                params.Obj.parent().find("div.ajax_change_icon").hide();

                jq(params.Obj).show();
                jq(".iconsPanelSettings").hide();
            }
        });
    };

    var _getIconByCssClass = function (cssClass) {
        if (typeof (cssClass) === "undefined" || cssClass == "") return null;

        var $icon = jq('#iconsPanel_' + ASC.CRM.ListItemView.CurrentType + ' label.' + cssClass);
        if ($icon.length != 1)  return null;

        return $icon;
    };

    var _itemFactory = function(item) {
        if (typeof (item.relativeItemsCount) === "undefined") {
            item.relativeItemsCount = 0;
        }
        item.relativeItemsString = ASC.CRM.Common.getRelativeItemsLinkString(item.relativeItemsCount, jq.getURLParam("type"), null);
        if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
            if (item.hasOwnProperty("imagePath") && item.imagePath != "") {
                item.cssClass = jq.trim(item.imagePath.split('/')[item.imagePath.split('/').length - 1].split('.')[0]);
                var $icon = _getIconByCssClass(item.cssClass);

                if ($icon != null) {
                    item.imageTitle = $icon.attr('title');
                    item.imageName = $icon.attr('data-imgName');
                } else {
                    item.imageTitle = "";
                    item.imageName = "";
                }
                
            } else {
                item.imageTitle = "";
                item.imageName = "";
                item.cssClass= "";
            }
        }

        var hash = [],
            filtervaluehash = {},
            anchor = "";

        if (ASC.CRM.ListItemView.CurrentType == 1) { //Contact types
            //hash.push('{"id":"sorter","type":"sorter","params":"<KEY>}');

            filtervaluehash = {
                id: "contactStage",
                type: "combobox",
                params: jq.base64.encode(jq.toJSON({
                    value: item.id,
                    title: item.title
                }))
            };

            hash.push(jq.toJSON(filtervaluehash));
            anchor = jq.base64.encode(hash.join(';'));
            item.relativeItemsUrl = "Default.aspx#" + anchor;
        }
        if (ASC.CRM.ListItemView.CurrentType == 2) { //Task category
            //hash.push('{"id":"sorter","type":"sorter","params":"<KEY>}');

            filtervaluehash = {
                id: "categoryID",
                type: "combobox",
                params: jq.base64.encode(jq.toJSON({
                    value: item.id,
                    title: item.title
                }))
            };

            hash.push(jq.toJSON(filtervaluehash));
            anchor = jq.base64.encode(hash.join(';'));
            item.relativeItemsUrl = "Tasks.aspx#" + anchor;
        }

        if (ASC.CRM.ListItemView.CurrentType == 4) { //Contact type
            //hash.push('{"id":"sorter","type":"sorter","params":"eyJpZCI6ImNhdGVnb3J5IiwiZGVmIjpmYWxzZSwiZHNjIjpmYWxzZSwic29ydE9yZGVyIjoiYXNjZW5kaW5nIn0="}');

            filtervaluehash = {
                id: "contactType",
                type: "combobox",
                params: jq.base64.encode(jq.toJSON({
                    value: item.id,
                    title: item.title
                }))
            };

            hash.push(jq.toJSON(filtervaluehash));
            anchor = jq.base64.encode(hash.join(';'));
            item.relativeItemsUrl = "Default.aspx#" + anchor;
        }
    };

    var _validateDataItem = function() {
        if (jq("#manageItem input:first").val().trim() == "") {
            ShowRequiredError(jq("#manageItem input:first"), true);
            return false;
        } else {
            RemoveRequiredErrorClass(jq("#manageItem input:first"));
            return true;
        }
    };

    var _readItemData = function(sortOrder) {
        var item = {
            title: jq("#manageItem input:first").val().trim(),
            sortOrder: sortOrder
        };
        if (ASC.CRM.ListItemView.CurrentType !== 4) {
            item.description = jq("#manageItem textarea").val().trim();
        }

        if (ASC.CRM.ListItemView.CurrentType === 1) {
            item.color = ASC.CRM.Common.getHexRGBColor(jq("#manageItem .selectedColor").css("background-color"));
        }
        if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
            item.imageName = jq("#manageItem label.selectedIcon").attr('data-imgName');
        }

        return item;
    };

    var _createItem = function() {
        if (!_validateDataItem()) { return; }

        var $listItems = jq("#listView li"),
            item = _readItemData($listItems.length),
            index = 0;

        for (var i = 0, len = $listItems.length; i < len; i++) {
            if (jq($listItems[i]).find("td.item_title").text().trim() == item.title) {
                index = i + 1;
                break;
            }
        }
        if (index == 0) {
            Teamlab.addCrmListItem({}, ASC.CRM.ListItemView.CurrentType, item, {
                before: function (params) {
                    LoadingBanner.strLoading = ASC.CRM.ListItemView.AddItemProcessText;
                    LoadingBanner.showLoaderBtn("#manageItem");
                },
                after: function(params) {
                    LoadingBanner.hideLoaderBtn("#manageItem");
                },
                success: ASC.CRM.ListItemView.CallbackMethods.add_item
            });
        } else {
            ASC.CRM.Common.animateElement({
                element: jq($listItems[index - 1]),
                afterScrollFunc: jq.unblockUI()
            });
        }
    };

    var _editItem = function(liObj, id, indexOfItem) {
        if (!_validateDataItem()) return;

        var $listItems = jq("#listView li"),
            item = _readItemData(indexOfItem),
            index = 0;

        item.id = id;
        for (var i = 0, len = $listItems.length; i < len; i++) {
            if (jq($listItems[i]).find("td.item_title").text().trim() == item.title && jq($listItems[i]).not(jq(liObj)).length != 0) {
                index = i + 1;
                break;
            }
        }
        if (index == 0) {
            Teamlab.updateCrmListItem({ liObj: liObj, indexOfItem: indexOfItem }, ASC.CRM.ListItemView.CurrentType, item.id, item, {
                before: function (params) {
                    LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.SaveChangesProggress;
                    LoadingBanner.showLoaderBtn("#manageItem");
                },
                after: function(params) {
                    LoadingBanner.hideLoaderBtn("#manageItem");
                },
                success: ASC.CRM.ListItemView.CallbackMethods.edit_item
            });
        } else {
            ASC.CRM.Common.animateElement({
                element: jq($listItems[index - 1]),
                afterScrollFunc: jq.unblockUI()
            });
        }
    };

    var _initManagePanel = function () {
        jq.tmpl("template-blockUIPanel", {
            id: "manageItem",
            headerTest: ASC.CRM.ListItemView.AddItemHeaderText,
            questionText: "",
            innerHtmlText: jq.tmpl("listViewActionPanelBodyTmpl", { currentType: ASC.CRM.ListItemView.CurrentType }).html(),
            OKBtn: ASC.CRM.ListItemView.AddItemButtonText,
            CancelBtn: ASC.CRM.Resources.CRMCommonResource.Cancel,
            progressText: ""
        }).insertAfter("#listView");

        jq("#manageItem .button.gray").on("click", function () { PopupKeyUpActionProvider.EnableEsc = true; jq.unblockUI(); });
    };

    var _getAndRenderPageData = function (firstTime) {
        LoadingBanner.displayLoading();

        ASC.CRM.ListItemView.itemList = [];

        Teamlab.getCrmListItem({}, ASC.CRM.ListItemView.CurrentType, function (params, items) {
            for (var i = 0, len = items.length; i < len; i++) {
                _itemFactory(items[i]);
                ASC.CRM.ListItemView.itemList.push(items[i]);
            }

            jq.tmpl("listItemsTmpl", ASC.CRM.ListItemView.itemList).appendTo(jq("#listView").html(""));
            if (ASC.CRM.ListItemView.itemList.length == 1) {
                var $menuSwitcher = jq("#listView li [id^=list_item_menu_]:first");
                if ($menuSwitcher.attr("data-relativecount") != "0") {
                    $menuSwitcher.hide();
                } else {
                    jq("#listItemActionMenu .deleteItem").hide();
                }
            }

            if (firstTime === true) {
                _initSortableElements();
            }

            LoadingBanner.hideLoading();
        });

    };

    return {
        CallbackMethods: {
            delete_item: function(params, item) {
                params.liObj.remove();

                var index = _findIndexOfItemByID(item.id);
                if (index != -1) {
                    ASC.CRM.ListItemView.itemList.splice(index, 1);
                }

                if (jq("#listView li").length == 1) {
                    var $menuSwitcher = jq("#listView li [id^=list_item_menu_]:first");
                    if ($menuSwitcher.attr("data-relativecount") != "0") {
                        $menuSwitcher.hide();
                    } else {
                        jq("#listItemActionMenu .deleteItem").hide();
                    }
                }
            },

            add_item: function(params, item) {
                _itemFactory(item);
                ASC.CRM.ListItemView.itemList.push(item);

                var $itemHTML = jq.tmpl("listItemsTmpl", item);

                if (jq("#listView li").length == 1) {
                    jq("#listView li [id^=list_item_menu_]:first").show();
                    jq("#listItemActionMenu .deleteItem").show();
                }

                $itemHTML.appendTo("#listView");

                ASC.CRM.Common.animateElement({
                    element: $itemHTML,
                    afterScrollFunc: jq.unblockUI()
                });
            },

            edit_item: function(params, item) {
                _itemFactory(item);
                ASC.CRM.ListItemView.itemList[params.indexOfItem] = item;

                var $itemHTML = jq.tmpl("listItemsTmpl", item);
                jq(params.liObj).hide();
                $itemHTML.insertAfter(params.liObj);
                jq(params.liObj).remove();

                ASC.CRM.Common.animateElement({
                    element: $itemHTML,
                    afterScrollFunc: jq.unblockUI()
                });
            }
        },

        init: function (currentType, addItemHeaderText, addItemButtonText) {
            ASC.CRM.ListItemView.CurrentType = currentType;
            ASC.CRM.ListItemView.AddItemHeaderText = addItemHeaderText;
            ASC.CRM.ListItemView.AddItemButtonText = addItemButtonText;

            _getAndRenderPageData(true);

            _initManagePanel();
            _initElementsActionMenu();
            _initOtherActionMenu();

            if (jq("#cbx_ChangeContactStatusWithoutAsking").length == 1) {
                jq("#cbx_ChangeContactStatusWithoutAsking").bind("change", function () {
                    var changeContactStatusWithoutAsking = jq(this).is(":checked") ? true : null;
                    Teamlab.updateCRMContactStatusSettings({}, changeContactStatusWithoutAsking,
                        function () {
                        });
                });
            }

            jq("#createNewItem").bind("click", function() { _showAddItemPanel(); });

            ASC.CRM.ListItemView.IsDropdownToggleRegistered = false;
            if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
                jq.dropdownToggle({
                    dropdownID: "iconsPanel_" + ASC.CRM.ListItemView.CurrentType,
                    switcherSelector: "#listView label.currentIcon",
                    noActiveSwitcherSelector: "#manageItem .change_icon",
                    addTop: 1,
                    addLeft: -4,
                    showFunction: function(switcherObj, dropdownItem) {
                        if (dropdownItem.is(":hidden")) {
                            switcherObj.addClass("active");
                        } else {
                            switcherObj.removeClass("active");
                        }
                    },
                    hideFunction: function() {
                        var $activeImg = jq("#listView label.currentIcon.active");
                        if ($activeImg.length != 0) {
                            $activeImg.removeClass("active");
                        }
                    }
                });
            }
            if (ASC.CRM.ListItemView.CurrentType === 1) {
                jq.dropdownToggle({
                    dropdownID: "colorsPanel",
                    switcherSelector: "#listView .currentColor",
                    noActiveSwitcherSelector: "#manageItem .change_color",
                    addTop: 2,
                    addLeft: -12
                });
            }

            if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
                ASC.CRM.Common.registerChangeHoverStateByParent("label.currentIcon", "#listView .with-entity-menu");
                ASC.CRM.Common.registerChangeHoverStateByParent(".iconsPanelSettings>label", "");
            }
        },

        showEditItemPanel: function() {
            jq("#listItemActionMenu").hide();
            jq("#listView .entity-menu.active").removeClass("active");

            var index = 0,
                item = null,
                liObj = null,
                currIcon = null,
                listitemid = jq("#listItemActionMenu").attr("data-listitemid");
            if (typeof (listitemid) === "undefined" || listitemid == "") { return; }

            index = _findIndexOfItemByID(listitemid);
            if (index === -1) { return; }
            item = ASC.CRM.ListItemView.itemList[index];

            liObj = jq("#list_item_id_" + listitemid);
            if (liObj.length != 1) { return; }

            jq('#manageItem div.containerHeaderBlock td:first').text(ASC.CRM.ListItemView.EditItemHeaderText.replace('{0}', item.title));
            jq('#manageItem .middle-button-container a.button.blue.middle').text(ASC.CRM.Resources.CRMJSResource.SaveChanges);

            LoadingBanner.strLoading = ASC.CRM.ListItemView.AddItemProcessText;

            jq('#manageItem input:first').val(item.title);
            jq('#manageItem textarea').val(item.description);
            jq('#manageItem div.add_params input').val(item.additionalParams);

            currIcon = jq(liObj).find("label.currentIcon");
            if (currIcon.length == 1) {
                var $selectedIcinObj = jq("#manageItem label.selectedIcon");

                $selectedIcinObj.attr('data-imgName', item.imageName);
                $selectedIcinObj.attr('title', item.imageTitle);

                $selectedIcinObj.attr("class", ["selectedIcon ", ASC.CRM.ListItemView.CurrentType == 2 ? "task_category" : "event_category", " ", item.cssClass].join(''));
            } else {
                var currentColor = jq(liObj).find("div.currentColor").css("background-color");
                jq("#manageItem .selectedColor").css("background-color", currentColor);
            }

            jq('#manageItem .middle-button-container a.button.blue.middle').unbind('click').click(function () {
                _editItem(liObj, item.id, index);
            });
            RemoveRequiredErrorClass(jq("#manageItem input:first"));
            PopupKeyUpActionProvider.CloseDialogAction = "javascript:jq('.iconsPanelSettings').hide();jq('#colorsPanel').hide();jq('#popup_colorsPanel').hide();";
            PopupKeyUpActionProvider.EnableEsc = false;
            StudioBlockUIManager.blockUI("#manageItem", 400);

            if (!ASC.CRM.ListItemView.IsDropdownToggleRegistered) {
                ASC.CRM.ListItemView.IsDropdownToggleRegistered = true;
                if (ASC.CRM.ListItemView.CurrentType === 2 || ASC.CRM.ListItemView.CurrentType === 3) {
                    jq.dropdownToggle({
                        dropdownID: "popup_iconsPanel_" + ASC.CRM.ListItemView.CurrentType,
                        switcherSelector: "#manageItem .change_icon",
                        noActiveSwitcherSelector: "#listView label.currentIcon",
                        addTop: 1,
                        addLeft: jq("#manageItem .change_icon").width() - 12,
                        position: "fixed"
                    });
                }
                if (ASC.CRM.ListItemView.CurrentType === 1) {
                    jq.dropdownToggle({
                        dropdownID: "popup_colorsPanel",
                        switcherSelector: "#manageItem .change_color",
                        noActiveSwitcherSelector: "#listView .currentColor",
                        addTop: 2,
                        addLeft: jq("#manageItem .change_color").width() - 12,
                        position: "fixed"
                    });
                }
            }
        },

        deleteItem: function() {
            jq("#listItemActionMenu").hide();
            jq("#listView .entity-menu.active").removeClass("active");

            var listitemid = jq("#listItemActionMenu").attr("data-listitemid"),
                relativecount = jq("#listItemActionMenu").attr("data-relativecount");
            if (typeof (listitemid) === "undefined" || listitemid == "") { return; }

            var liObj = jq("#list_item_id_" + listitemid);
            if (liObj.length != 1) { return; }

            if (jq("#listView li").length == 1) {
                if (ASC.CRM.ListItemView.CurrentType == 1) {
                    toastr.error(jq.format(ASC.CRM.Resources.CRMJSResource.ErrorTheLastContactStage,
                        jq.trim(jq(liObj).find(".item_title").text())) + "\n" + ASC.CRM.Resources.CRMJSResource.PleaseRefreshThePage);
                    jq("#listView").find(".entity-menu").hide();
                    return;
                }
                if (ASC.CRM.ListItemView.CurrentType == 2) {
                    toastr.error(jq.format(ASC.CRM.Resources.CRMJSResource.ErrorTheLastTaskCategory,
                        jq.trim(jq(liObj).find(".item_title").text())) + "\n" + ASC.CRM.Resources.CRMJSResource.PleaseRefreshThePage);
                    jq("#listView").find(".entity-menu").hide();
                    return;
                }
                if (ASC.CRM.ListItemView.CurrentType == 3) {//HistoryCategory
                    toastr.error(jq.format(ASC.CRM.Resources.CRMJSResource.ErrorTheLastHistoryCategory,
                        jq.trim(jq(liObj).find(".item_title").text())) + "\n" + ASC.CRM.Resources.CRMJSResource.PleaseRefreshThePage);
                    jq("#listView").find(".entity-menu").hide();
                    return;
                }
                if (ASC.CRM.ListItemView.CurrentType == 4) {
                    toastr.error(jq.format(ASC.CRM.Resources.CRMJSResource.ErrorTheLastContactType,
                        jq.trim(jq(liObj).find(".item_title").text())) + "\n" + ASC.CRM.Resources.CRMJSResource.PleaseRefreshThePage);
                    jq("#listView").find(".entity-menu").hide();
                    return;
                }
                return;
            }

            if (ASC.CRM.ListItemView.CurrentType === 2 && relativecount != "0") {//For task categories with linked task

                if (jq("#selectItemForReplacePopUp").length == 0) {
                    jq.tmpl("template-blockUIPanel", {
                        id: "selectItemForReplacePopUp",
                        headerTest: ASC.CRM.Resources.CRMSettingResource.DeleteTaskCategoryConfirmation,
                        questionText: "",
                        innerHtmlText: "<div class=\"selectItemForReplaceContainer\"></div>",
                        progressText: ""
                    }).appendTo("#studioPageContent .mainPageContent .containerBodyBlock:first");

                    jq("#selectItemForReplacePopUp .selectItemForReplaceContainer").replaceWith(jq("#selectItemForReplacePopUpBody").removeClass("display-none"));
                }


                var selectedItem = { id: 0, title: "", cssClass: "" },
                    itemsForSelector = [];

                jq("#itemForReplaceSelector").remove();

                if (ASC.CRM.ListItemView.itemList.length > 0) {
                    for (var i = 0, n = ASC.CRM.ListItemView.itemList.length; i < n; i++) {
                        if (ASC.CRM.ListItemView.itemList[i].id != listitemid) {
                            itemsForSelector.push({
                                id: ASC.CRM.ListItemView.itemList[i].id,
                                title: ASC.CRM.ListItemView.itemList[i].title,
                                cssClass: "task_category " + ASC.CRM.ListItemView.itemList[i].cssClass
                            });
                        }
                    }
                    selectedItem = itemsForSelector[0];
                } else {
                    itemsForSelector.push(selectedItem);
                }

                window.itemForReplaceSelector = new ASC.CRM.CategorySelector("itemForReplaceSelector", selectedItem);
                window.itemForReplaceSelector.renderControl(itemsForSelector, selectedItem, "#itemForReplaceSelectorContainer", 0, "");

                jq("#deleteItemPopupOK").off("click").on("click", function () {
                    Teamlab.removeCrmListItem({ liObj: liObj }, ASC.CRM.ListItemView.CurrentType, listitemid, window.itemForReplaceSelector.CategoryID, {
                        before: function (params) {
                            params.liObj.find(".entity-menu").hide();
                            params.liObj.find("div.ajax_loader").show();

                            LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.LoadingWait;
                            LoadingBanner.showLoaderBtn("#selectItemForReplacePopUp");
                        },
                        success: function (params, response) {
                            LoadingBanner.hideLoaderBtn("#selectItemForReplacePopUp");
                            jq.unblockUI();
                            _getAndRenderPageData(false);
                        }
                    });
                });

                StudioBlockUIManager.blockUI("#selectItemForReplacePopUp", 500);

            } else {
                Teamlab.removeCrmListItem({ liObj: liObj }, ASC.CRM.ListItemView.CurrentType, listitemid, 0, {
                    before: function (params) {
                        params.liObj.find(".entity-menu").hide();
                        params.liObj.find("div.ajax_loader").show();
                    },
                    success: ASC.CRM.ListItemView.CallbackMethods.delete_item
                });
            }
        },

        showColorsPanel: function(switcherUI) {
            jq("#colorsPanel > span").unbind("click").click(function() {
                _changeColor(switcherUI, jq(switcherUI).parents("li").get(0).id.replace("list_item_id_", "") * 1, ASC.CRM.Common.getHexRGBColor(jq(this).css("background-color")));
            });
        },

        showColorsPanelToSelect: function() {
            jq("#popup_colorsPanel > span").unbind("click").click(function() {
                jq("#manageItem .selectedColor").css("background", ASC.CRM.Common.getHexRGBColor(jq(this).css("background-color")));
                jq("#popup_colorsPanel").hide();
            });
        },

        showIconsPanel: function(switcherUI) {
            var $iconsPanel = jq("#iconsPanel_" + ASC.CRM.ListItemView.CurrentType);
            if ($iconsPanel.length != 1) return;
            $iconsPanel.children("label").unbind("click").click(function() {
                _changeIcon(switcherUI, jq(switcherUI).parents("li").get(0).id.replace("list_item_id_", "") * 1, jq(this));
            });
        },

        showIconsPanelToSelect: function() {
            var $popup_iconsPanel = jq("#popup_iconsPanel_" + ASC.CRM.ListItemView.CurrentType);
            if ($popup_iconsPanel.length != 1) return;
            $popup_iconsPanel.children("label").unbind("click").click(function() {
                var $selectedIcinObj = jq("#manageItem label.selectedIcon"),
                    cssClass = jq(this).attr('data-imgName').split('.')[0];

                $selectedIcinObj.attr('data-imgName', jq(this).attr('data-imgName'));
                $selectedIcinObj.attr('title', jq(this).attr('title'));
                $selectedIcinObj.attr('alt', jq(this).attr('alt'));
                $selectedIcinObj.attr("class", ["selectedIcon ", ASC.CRM.ListItemView.CurrentType == 2 ? "task_category" : "event_category", " ", cssClass].join(''));

                $popup_iconsPanel.hide();
            });
        }
    };
})();


ASC.CRM.DealMilestoneView = (function() {

    var _initSortableDealMilestones = function() {
        jq("#dealMilestoneList").sortable({
            cursor: "move",
            handle: ".sort_drag_handle",
            items: "li",
            start: function(event, ui) {
                jq("#colorsPanel").hide();
                jq("#popup_colorsPanel").hide();
                jq("#dealMilestoneActionMenu").hide();
                jq("#dealMilestoneList .entity-menu.active").removeClass("active");
            },
            beforeStop: function(event, ui) {
                jq(ui.item[0]).attr("style", "");
            },
            update: function(event, ui) {
                var itemsIDs = [];

                jq("#dealMilestoneList li[id^='deal_milestone_id_']").each(function() {
                    itemsIDs.push(jq(this).attr("id").replace("deal_milestone_id_", "") * 1);
                });

                Teamlab.reorderCrmDealMilestones({}, itemsIDs, {});
            }
        });
    };

    var _initDealMilestonesActionMenu = function() {

        jq.dropdownToggle({
            dropdownID: "dealMilestoneActionMenu",
            switcherSelector: "#dealMilestoneList .entity-menu",
            addTop: 0,
            addLeft: 10,
            rightPos: true,
            showFunction: function(switcherObj, dropdownItem) {
                jq("#dealMilestoneList .entity-menu.active").removeClass("active");
                if (dropdownItem.is(":hidden")) {
                    switcherObj.addClass("active");
                    if (switcherObj.attr("dealmilestoneid") != dropdownItem.attr("dealmilestoneid")) {
                        dropdownItem.attr('dealmilestoneid', switcherObj.attr("dealmilestoneid"));
                    }
                }
            },
            hideFunction: function() {
                jq("#dealMilestoneList .entity-menu.active").removeClass("active");
            }
        });
    };

    var _initOtherActionMenu = function() {
        jq("#menuCreateNewTask").bind("click", function() { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    };

    var _resetManageItemPanel = function() {
        jq("#manageDealMilestone .title").val("");
        jq("#manageDealMilestone .probability").val("0");
        jq("#manageDealMilestone textarea").val("");
        jq("#manageDealMilestone [name=deal_milestone_status]:first").prop("checked", true);

        var $divColors = jq("#colorsPanel > span"),
            ind = Math.floor(Math.random() * $divColors.length);
        jq("#manageDealMilestone .selectedColor").css("background-color", ASC.CRM.Common.getHexRGBColor(jq($divColors.get(ind)).css("background-color")));
    };

    var _showAddDealMilestonePanel = function() {
        jq('#manageDealMilestone div.containerHeaderBlock td:first').text(ASC.CRM.Resources.CRMSettingResource.CreateNewDealMilestone);
        jq('#manageDealMilestone .middle-button-container a.button.blue.middle').text(ASC.CRM.Resources.CRMSettingResource.AddThisDealMilestone);
        LoadingBanner.strLoading = ASC.CRM.Resources.CRMSettingResource.CreateDealMilestoneInProgressing;
        _resetManageItemPanel();

        jq('#manageDealMilestone .middle-button-container a.button.blue.middle').unbind('click').click(function () {
            if (jq(this).hasClass("disable"))
                return;

            _createDealMilestone();
        });
        RemoveRequiredErrorClass(jq("#manageDealMilestone .title"));

        PopupKeyUpActionProvider.EnableEsc = false;
        StudioBlockUIManager.blockUI("#manageDealMilestone", 400);

        if (!ASC.CRM.DealMilestoneView.IsDropdownToggleRegistered) {
            ASC.CRM.DealMilestoneView.IsDropdownToggleRegistered = true;
            jq.dropdownToggle({
                dropdownID: "popup_colorsPanel",
                switcherSelector: "#manageDealMilestone .change_color",
                noActiveSwitcherSelector: "#dealMilestoneList .currentColor",
                addTop: 2,
                addLeft: jq("#manageDealMilestone .change_color").width() - 12,
                position: "fixed"
            });
        }
    };

    var _findIndexOfDealMilestoneByID = function(id) {
        for (var i = 0, n = ASC.CRM.DealMilestoneView.dealMilestoneList.length; i < n; i++) {
            if (ASC.CRM.DealMilestoneView.dealMilestoneList[i].id == id) {
                return i;
            }
        }
        return -1;
    };

    var _changeColor = function(Obj, listItemId, color) {
        var data = {
            id: listItemId,
            color: color
        };
        Teamlab.updateCrmDealMilestoneColor({ Obj: Obj }, listItemId, data,
            function(params, dealMilestone) {
                _dealMilestoneItemFactory(dealMilestone);

                var index = _findIndexOfDealMilestoneByID(dealMilestone.id);
                if (index != -1) {
                    ASC.CRM.DealMilestoneView.dealMilestoneList[index] = dealMilestone;
                }

                jq(params.Obj).css("background", dealMilestone.color);
                jq("#colorsPanel").hide();
            }
        );
    };

    var _dealMilestoneItemFactory = function(dealMilestone) {
        if (typeof (dealMilestone.relativeItemsCount) === "undefined") {
            dealMilestone.relativeItemsCount = 0;
        }
        dealMilestone.relativeItemsString = ASC.CRM.Common.getRelativeItemsLinkString(dealMilestone.relativeItemsCount, jq.getURLParam("type"), null);
        var hash = [];
        hash.push('{"id":"sorter","type":"sorter","params":"<KEY>}');

        var filtervaluehash = {
            id: "opportunityStagesID",
            type: "combobox",
            params: jq.base64.encode(jq.toJSON({
                value: dealMilestone.id,
                title: dealMilestone.title
            }))
        };

        hash.push(jq.toJSON(filtervaluehash));
        var anchor = jq.base64.encode(hash.join(';'));
        dealMilestone.relativeItemsUrl = "Deals.aspx#" + anchor;
    };

    var _readDealMilestoneData = function(sortOrder) {
        var dealMilestone =
        {
            title: jq("#manageDealMilestone .title").val().trim(),
            sortOrder: sortOrder
        };

        dealMilestone.description = jq("#manageDealMilestone dl textarea").val().trim();
        dealMilestone.color = ASC.CRM.Common.getHexRGBColor(jq("#manageDealMilestone .selectedColor").css("background-color"));

        var percent = jq("#manageDealMilestone .probability").val();
        if (percent * 1 > 100) { percent = "100"; }

        dealMilestone.successProbability = percent;
        dealMilestone.stageType = jq("#manageDealMilestone [name=deal_milestone_status]:checked").val() * 1;

        return dealMilestone;
    };

    var _editDealMilestone = function(liObj, id) {
        if (jq("#manageDealMilestone .title").val().trim() == "") {
            ShowRequiredError(jq("#manageDealMilestone .title"), true);
            return;
        } else {
            RemoveRequiredErrorClass(jq("#manageDealMilestone .title"));
        }

        var $listItems = jq("#dealMilestoneList li"),
            dealMilestone = _readDealMilestoneData($listItems.length),
            index = 0;

        dealMilestone.id = id;

        for (var i = 0, len = $listItems.length; i < len; i++) {
            if (jq($listItems[i]).find("td.deal_milestone_title").text().trim() == dealMilestone.title && jq($listItems[i]).not(jq(liObj)).length != 0) {
                index = i + 1;
                break;
            }
        }
        if (index == 0) {
            Teamlab.updateCrmDealMilestone({ liObj: liObj }, dealMilestone.id, dealMilestone, {
                before: function () {
                    LoadingBanner.showLoaderBtn("#manageDealMilestone");
                },
                after: function () {
                    LoadingBanner.hideLoaderBtn("#manageDealMilestone");
                },
                success: ASC.CRM.DealMilestoneView.CallbackMethods.edit_dealMilestone
            });
        } else {
            ASC.CRM.Common.animateElement({
                element: jq($listItems[index - 1]),
                afterScrollFunc: jq.unblockUI()
            });
        }
    };

    var _createDealMilestone = function() {
        if (jq("#manageDealMilestone .title").val().trim() == "") {
            ShowRequiredError(jq("#manageDealMilestone .title"), true);
            return;
        } else {
            RemoveRequiredErrorClass(jq("#manageDealMilestone .title"));
        }

        var $listItems = jq("#dealMilestoneList li"),
            dealMilestone = _readDealMilestoneData($listItems.length),
            index = 0;

        for (var i = 0, len = $listItems.length; i < len; i++) {
            if (jq($listItems[i]).find("td.deal_milestone_title").text().trim() == dealMilestone.title) {
                index = i + 1;
                break;
            }
        }

        if (index == 0) {
            Teamlab.addCrmDealMilestone({}, dealMilestone, {
                before: function () {
                    LoadingBanner.showLoaderBtn("#manageDealMilestone");
                },
                after: function () {
                    LoadingBanner.hideLoaderBtn("#manageDealMilestone");
                },
                success: ASC.CRM.DealMilestoneView.CallbackMethods.add_dealMilestone
            });
        } else {
            ASC.CRM.Common.animateElement({
                element: jq($listItems[index - 1]),
                afterScrollFunc: jq.unblockUI()
            });
        }
    };


    var _initManagePanel = function () {

        jq.tmpl("template-blockUIPanel", {
            id: "manageDealMilestone",
            headerTest: ASC.CRM.Resources.CRMCommonResource.Confirmation,
            questionText: "",
            innerHtmlText: jq.tmpl("dealMilestoneActionPanelBodyTmpl", {}).html(),
            OKBtn: ASC.CRM.Resources.CRMSettingResource.AddThisDealMilestone,
            CancelBtn: ASC.CRM.Resources.CRMCommonResource.Cancel,
            progressText: ""
        }).insertAfter("#dealMilestoneList");

        jq("#manageDealMilestone .button.gray").on("click", function () { PopupKeyUpActionProvider.EnableEsc = true; jq.unblockUI(); });
    };

    return {
        CallbackMethods: {
            add_dealMilestone: function(params, dealMilestone) {
                _dealMilestoneItemFactory(dealMilestone);
                ASC.CRM.DealMilestoneView.dealMilestoneList.push(dealMilestone);

                if (jq("#dealMilestoneList li").length == 1) {
                    jq(jq("#dealMilestoneActionMenu>.dropdown-content>li")[1]).show();
                }

                var $itemHTML = jq.tmpl("dealMilestoneTmpl", dealMilestone);
                $itemHTML.appendTo("#dealMilestoneList");

                ASC.CRM.Common.animateElement({
                    element: $itemHTML,
                    afterScrollFunc: jq.unblockUI()
                });
            },

            edit_dealMilestone: function(params, dealMilestone) {
                _dealMilestoneItemFactory(dealMilestone);

                var index = _findIndexOfDealMilestoneByID(dealMilestone.id);
                if (index != -1) {
                    ASC.CRM.DealMilestoneView.dealMilestoneList[index] = dealMilestone;
                }

                var $itemHTML = jq.tmpl("dealMilestoneTmpl", dealMilestone);

                params.liObj.hide();
                $itemHTML.insertAfter(params.liObj);
                params.liObj.remove();

                ASC.CRM.Common.animateElement({
                    element: $itemHTML,
                    afterScrollFunc: jq.unblockUI()
                });
            },

            delete_dealMilestone: function(params, dealMilestone) {
                params.liObj.remove();
                var index = _findIndexOfDealMilestoneByID(dealMilestone.id);
                if (index != -1) {
                    ASC.CRM.DealMilestoneView.dealMilestoneList.splice(index, 1);
                }
                if (jq("#dealMilestoneList li").length == 1) {
                    jq(jq("#dealMilestoneActionMenu>.dropdown-content>li")[1]).hide();
                }
            }
        },

        initData: function () {
            ASC.CRM.DealMilestoneView.dealMilestoneList = [];
            LoadingBanner.displayLoading();

            Teamlab.getCrmDealMilestones({}, function (params, dealMilestones) {
                for (var i = 0, n = dealMilestones.length; i < n; i++) {
                    _dealMilestoneItemFactory(dealMilestones[i]);
                    ASC.CRM.DealMilestoneView.dealMilestoneList.push(dealMilestones[i]);
                }
                jq.tmpl("dealMilestoneTmpl", ASC.CRM.DealMilestoneView.dealMilestoneList).appendTo("#dealMilestoneList");

                if (ASC.CRM.DealMilestoneView.dealMilestoneList.length == 1) {
                    jq(jq("#dealMilestoneActionMenu>.dropdown-content>li")[1]).hide();
                }

                _initSortableDealMilestones();
                LoadingBanner.hideLoading();
            });

        },

        dealMilestoneList: [],
        init: function () {
            ASC.CRM.DealMilestoneView.initData();

            _initManagePanel();
            _initDealMilestonesActionMenu();
            _initOtherActionMenu();
            jq("#createNewDealMilestone").bind("click", function() { _showAddDealMilestonePanel(); });

            ASC.CRM.DealMilestoneView.IsDropdownToggleRegistered = false;
            jq.dropdownToggle({
                dropdownID: "colorsPanel",
                switcherSelector: "#dealMilestoneList .currentColor",
                noActiveSwitcherSelector: "#manageDealMilestone .change_color",
                addTop: 2,
                addLeft: -12
            });

            jq.forceNumber({
                parent: "#manageDealMilestone",
                input: ".probability",
                integerOnly: true,
                positiveOnly: true
            });
        },

        showEditDealMilestonePanel: function() {
            jq("#dealMilestoneActionMenu").hide();
            jq("#dealMilestoneList .entity-menu.active").removeClass("active");

            var dealmilestoneid = jq("#dealMilestoneActionMenu").attr("dealmilestoneid");
            if (typeof (dealmilestoneid) === "undefined" || dealmilestoneid == "") { return; }

            var liObj = jq("#deal_milestone_id_" + dealmilestoneid);
            if (liObj.length != 1) { return; }

            var index = _findIndexOfDealMilestoneByID(dealmilestoneid);
            if (index === -1) { return; }
            var dealMilestone = ASC.CRM.DealMilestoneView.dealMilestoneList[index];


            jq('#manageDealMilestone div.containerHeaderBlock td:first').text(ASC.CRM.Resources.CRMSettingResource.EditSelectedDealMilestone.replace('{0}', dealMilestone.title));
            jq('#manageDealMilestone .middle-button-container a.button.blue.middle').text(ASC.CRM.Resources.CRMJSResource.SaveChanges);
            LoadingBanner.strLoading = ASC.CRM.Resources.CRMCommonResource.SaveChangesProggress;

            jq('#manageDealMilestone .title').val(dealMilestone.title);
            jq('#manageDealMilestone textarea').val(dealMilestone.description);
            jq('#manageDealMilestone .probability').val(dealMilestone.successProbability);
            jq("#manageDealMilestone [name=deal_milestone_status][value=" + dealMilestone.stageType + "]").prop("checked", true);

            jq('#manageDealMilestone .middle-button-container a.button.blue.middle').unbind('click').click(function () {
                _editDealMilestone(liObj, dealMilestone.id);
            });
            jq("#manageDealMilestone .selectedColor").css("background-color", dealMilestone.color);

            RemoveRequiredErrorClass(jq("#manageDealMilestone .title"));
            PopupKeyUpActionProvider.EnableEsc = false;
            StudioBlockUIManager.blockUI("#manageDealMilestone", 400);

            if (!ASC.CRM.DealMilestoneView.IsDropdownToggleRegistered) {
                ASC.CRM.DealMilestoneView.IsDropdownToggleRegistered = true;
                jq.dropdownToggle({
                    dropdownID: "popup_colorsPanel",
                    switcherSelector: "#manageDealMilestone .change_color",
                    noActiveSwitcherSelector: "#dealMilestoneList .currentColor",
                    addTop: 2,
                    addLeft: jq("#manageDealMilestone .change_color").width() - 12,
                    position: "fixed"
                });
            }
        },

        deleteDealMilestone: function() {
            jq("#dealMilestoneActionMenu").hide();
            jq("#dealMilestoneList .entity-menu.active").removeClass("active");

            var dealmilestoneid = jq("#dealMilestoneActionMenu").attr("dealmilestoneid");
            if (typeof (dealmilestoneid) === "undefined" || dealmilestoneid == "") { return; }

            var liObj = jq("#deal_milestone_id_" + dealmilestoneid);
            if (liObj.length != 1) { return; }

            if (jq("#dealMilestoneList li").length == 1) {
                toastr.error(ASC.CRM.Resources.CRMJSResource.ErrorTheLastDealMilestone);
                return;
            }

            Teamlab.removeCrmDealMilestone({ liObj: liObj }, dealmilestoneid, {
                before: function(params) {
                    params.liObj.find(".entity-menu").hide();
                    params.liObj.find("div.ajax_loader").show();
                },
                success: ASC.CRM.DealMilestoneView.CallbackMethods.delete_dealMilestone
            });
        },

        showColorsPanel: function(switcherUI) {
            jq("#colorsPanel > span").unbind("click").click(function() {
                _changeColor(switcherUI, jq(switcherUI).parents('li').get(0).id.replace("deal_milestone_id_", "") * 1, ASC.CRM.Common.getHexRGBColor(jq(this).css("background-color")));
            });
        },

        showColorsPanelToSelect: function() {
            jq("#popup_colorsPanel > span").unbind("click").click(function() {
                jq("#manageDealMilestone .selectedColor").css("background", ASC.CRM.Common.getHexRGBColor(jq(this).css("background-color")));
                jq("#popup_colorsPanel").hide();
            });
        }
    };
})();


ASC.CRM.TagSettingsView = (function() {

    var _initOtherActionMenu = function() {
        if (jq("#otherActions").length == 1) {
            jq.tmpl("deleteUnusedTagsButtonTmpl").appendTo("#otherActions ul.dropdown-content");
            jq("#deleteUnusedTagsButton").bind("click", function() { _deleteUnusedTags(); });
        }

        jq("#menuCreateNewTask").bind("click", function() { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    };

    var _showAddTagPanel = function() {
        jq("#tagTitle").val("");
        RemoveRequiredErrorClass(jq("#tagTitle"));
        PopupKeyUpActionProvider.EnableEsc = false;
        StudioBlockUIManager.blockUI("#manageTag", 400);
    };

    var _deleteUnusedTags = function() {
        jq("#otherActions").hide();
        jq("#deleteUnusedTagsButton").parent().addClass("display-none");

        Teamlab.removeCrmUnusedTag({}, _getCurEntityType(), {
            success: ASC.CRM.TagSettingsView.CallbackMethods.delete_unused_tags
        });
    };

    var _tagItemFactory = function(tag) {
        var type = _getCurEntityType();

        tag.relativeItemsString = ASC.CRM.Common.getRelativeItemsLinkString(tag.relativeItemsCount, jq.getURLParam("type"), type);

        var hash = [],
            filtervaluehash = {},
            anchor = "",
            baseUrl = "Default.aspx";
        //hash.push('{"id":"sorter","type":"sorter","params":"eyJpZCI6InRpdGxlIiwiZGVmIjp0cnVlLCJkc2MiOmZhbHNlLCJzb3J0T3JkZXIiOiJhc2NlbmRpbmcifQ=="}');

        filtervaluehash = {
            id: "tags",
            type: "combobox",
            params: jq.base64.encode(jq.toJSON({
                value: [ASC.CRM.Common.convertText(tag.title,false)],
                title: ASC.CRM.Common.convertText(tag.title,false)
            }))
        };

        hash.push(jq.toJSON(filtervaluehash));
        anchor = jq.base64.encode(hash.join(';'));

        if (type == "contacts") {
            baseUrl = "Default.aspx";
        } else if (type == "opportunity") {
            baseUrl = "Deals.aspx";
        } else if (type == "case") {
            baseUrl = "Cases.aspx";
        }
        tag.relativeItemsUrl = baseUrl + "#" + anchor;
    };

    var _findIndexOfTagByName = function(name) {
        for (var i = 0, n = ASC.CRM.TagSettingsView.tagList.length; i < n; i++) {
            if (ASC.CRM.TagSettingsView.tagList[i].title == name) {
                return i;
            }
        }
        return -1;
    };

    var _doUnusedTagsExist = function() {
        for (var i = 0, n = ASC.CRM.TagSettingsView.tagList.length; i < n; i++) {
            if (ASC.CRM.TagSettingsView.tagList[i].relativeItemsCount == 0) {
                return true;
            }
        }
        return false;
    };
  
    var _initEmptyScreen = function () {
        jq.tmpl("template-emptyScreen",
            {
                ID: "emptyTagContent",
                ImgSrc: ASC.CRM.Data.EmptyScrImgs["empty_screen_tags"],
                Header: ASC.CRM.Resources.CRMSettingResource.EmptyContentTags,
                Describe: ASC.CRM.Resources.CRMSettingResource.EmptyContentTagsDescript,
                ButtonHTML: ['<a id="addTag" class="link dotline plus">', ASC.CRM.Resources.CRMSettingResource.CreateNewTag, '</a>'].join(''),
                CssClass: "display-none"
            }).insertAfter("#tagList");
    };

    var _initTabs = function (type) {

        jq("<div class='fakeTabContainer' id='contTagsFake'></div>\
            <div class='fakeTabContainer' id='dealTagsFake'></div>\
            <div class='fakeTabContainer' id='caseTagsFake'></div>").insertAfter("#TagSettingsTabs");
        window.ASC.Controls.ClientTabsNavigator.init("TagSettingsTabs", {
            tabs: [
            {
                title: ASC.CRM.Resources.CRMSettingResource.BothPersonAndCompany,
                selected: type === "contact",
                anchor: "contact",
                divID: "contTagsFake",
                onclick: "ASC.CRM.TagSettingsView.initData('contact');"
            },
            {
                title: ASC.CRM.Resources.CRMCommonResource.DealModuleName,
                selected: type === "opportunity",
                anchor: "opportunity",
                divID: "dealTagsFake",
                onclick: "ASC.CRM.TagSettingsView.initData('opportunity');"
            },
            {
                title: ASC.CRM.Resources.CRMCommonResource.CasesModuleName,
                selected: type === "case",
                anchor: "case",
                divID: "caseTagsFake",
                onclick: "ASC.CRM.TagSettingsView.initData('case');"
            }]
        });
    };

    var _getCurEntityType = function () {
        var available = ["contact", "opportunity", "case"],
            type = ASC.Controls.AnchorController.getAnchor();
        if (type == null || type == "" || available.indexOf(type) == -1) { type = "contact"; }
        return type;
    };

    var _initManagePanel = function () {

        jq.tmpl("template-blockUIPanel", {
            id: "manageTag",
            headerTest: ASC.CRM.Resources.CRMSettingResource.CreateNewTag,
            questionText: "",
            innerHtmlText: jq.tmpl("tagSettingsActionPanelBodyTmpl", {}).html(),
            OKBtn: ASC.CRM.Resources.CRMSettingResource.AddThisTag,
            CancelBtn: ASC.CRM.Resources.CRMCommonResource.Cancel,
            progressText: ""
        }).insertAfter("#tagList");

        jq("#manageTag .button.gray").on("click", function () { PopupKeyUpActionProvider.EnableEsc = true; jq.unblockUI(); });
        jq("#manageTag .button.blue").on("click", function () {
            if (jq(this).hasClass("disable"))
                return;

            ASC.CRM.TagSettingsView.createTag();
        });
    };

    return {
        CallbackMethods: {
            add_tag: function(params, tag) {
                tag = { title: tag, relativeItemsCount : 0 };
                _tagItemFactory(tag);

                ASC.CRM.TagSettingsView.tagList.push(tag);

                if (jq("#deleteUnusedTagsButton").length == 1) {
                    jq("#deleteUnusedTagsButton").parent().removeClass("display-none");
                }

                var $itemHTML = jq.tmpl("tagRowTemplate", tag);
                if (params.tagsCount == 0) {
                    jq("#emptyTagContent").addClass("display-none");
                    jq("#tagList").show();
                    jq("#createNewTagSettings.display-none").removeClass("display-none");
                    jq(".cbx_AddTagWithoutAskingContainer.display-none").removeClass("display-none");
                }
                $itemHTML.appendTo("#tagList");

                ASC.CRM.Common.animateElement({
                    element: $itemHTML,
                    afterScrollFunc: jq.unblockUI()
                });
            },

            delete_tag: function(params, tag) {
                params.liObj.remove();

                var index = _findIndexOfTagByName(tag);
                if (index != -1) {
                    ASC.CRM.TagSettingsView.tagList.splice(index, 1);
                }
                if (jq("#deleteUnusedTagsButton").length == 1 && !_doUnusedTagsExist()) {
                    jq("#deleteUnusedTagsButton").parent().addClass("display-none");
                }

                if (jq("#tagList li").length == 0) {
                    jq("#tagList").hide();
                    jq("#createNewTagSettings:not(.display-none)").addClass("display-none");
                    jq(".cbx_AddTagWithoutAskingContainer:not(.display-none)").addClass("display-none");
                    if (jq("#deleteUnusedTagsButton").length == 1) {
                        jq("#deleteUnusedTagsButton").parent().addClass("display-none");
                    }
                    jq("#emptyTagContent").removeClass("display-none");
                }
            },

            delete_unused_tags: function(params, tags) {
                var $listTags = jq("#tagList li");

                for (var j = 0, n = tags.length; j < n; j++) {
                    for (var i = 0, m = $listTags.length; i < m; i++) {
                        if (jq($listTags[i]).find(".title").text().trim() == tags[j]) {
                            jq($listTags[i]).remove();
                        }
                    }
                    var index = _findIndexOfTagByName(tags[j]);
                    if (index != -1) {
                        ASC.CRM.TagSettingsView.tagList.splice(index, 1);
                    }
                }

                if (jq("#deleteUnusedTagsButton").length == 1 && !_doUnusedTagsExist()) {
                    jq("#deleteUnusedTagsButton").parent().addClass("display-none");
                }

                if (jq("#tagList li").length == 0) {
                    jq("#tagList").hide();
                    jq("#createNewTagSettings:not(.display-none)").addClass("display-none");
                    jq(".cbx_AddTagWithoutAskingContainer:not(.display-none)").addClass("display-none");
                    if (jq("#deleteUnusedTagsButton").length == 1) {
                        jq("#deleteUnusedTagsButton").parent().addClass("display-none");
                    }
                    jq("#emptyTagContent").removeClass("display-none");
                }
            }
        },


        initData: function (type) {
            ASC.CRM.TagSettingsView.tagList = [];
            jq("#tagList").html("").hide();
            jq("#emptyTagContent:not(.display-none)").addClass("display-none");
            jq(".cbx_AddTagWithoutAskingContainer:not(.display-none)").addClass("display-none");

            LoadingBanner.displayLoading();

            Teamlab.getCrmEntityTags({}, type, function (params, tags) {
                for (var i = 0, len = tags.length; i < len; i++) {
                    _tagItemFactory(tags[i]);
                    ASC.CRM.TagSettingsView.tagList.push(tags[i]);
                }

                if (ASC.CRM.TagSettingsView.tagList.length != 0) {
                    jq.tmpl("tagRowTemplate", ASC.CRM.TagSettingsView.tagList).appendTo("#tagList");
                    jq("#tagList").show();
                    jq("#createNewTagSettings.display-none").removeClass("display-none");
                    if (type === "contact") {
                        jq(".cbx_AddTagWithoutAskingContainer.display-none").removeClass("display-none");
                    }
                } else {
                    jq("#createNewTagSettings:not(.display-none)").addClass("display-none");
                    jq(".cbx_AddTagWithoutAskingContainer:not(.display-none)").addClass("display-none");
                    jq("#emptyTagContent").removeClass("display-none");
                }
                if (jq("#deleteUnusedTagsButton").length == 1) {
                    if (!_doUnusedTagsExist()) {
                        jq("#deleteUnusedTagsButton").parent().addClass("display-none");
                    } else {
                        jq("#deleteUnusedTagsButton").parent().removeClass("display-none");
                    }
                }
                LoadingBanner.hideLoading();
            });

        },

        tagList: [],
        init: function (alreadyExistsErrorText) {
            //jq("#tagList").disableSelection();

            var type = _getCurEntityType();
            _initTabs(type);

            _initOtherActionMenu();
            _initEmptyScreen();
            _initManagePanel();

            jq("#createNewTagSettings").on("click", function() { _showAddTagPanel(); });
            jq("#emptyTagContent .emptyScrBttnPnl > a").on("click", function() { _showAddTagPanel(); });

            ASC.CRM.TagSettingsView.initData(type);

            if (jq("#cbx_AddTagWithoutAsking").length == 1) {
                jq("#cbx_AddTagWithoutAsking").bind("change", function () {
                    var addTagWithoutAsking = jq(this).is(":checked") ? true : null;
                    Teamlab.updateCRMContactTagSettings({}, addTagWithoutAsking,
                        function () {
                        });
                });
            }
        },

        createTag: function () {
            var tagTitle = jq.trim(jq("#tagTitle").val());
            RemoveRequiredErrorClass(jq("#tagTitle"));

            if (tagTitle == "") {
                AddRequiredErrorText(jq("#tagTitle"), ASC.CRM.Resources.CRMSettingResource.EmptyLabelError);
                ShowRequiredError(jq("#tagTitle"), true);
                return;
            }

            var $listTags = jq("#tagList li"),
                tagsCount = $listTags.length;

            for (var i = 0; i < tagsCount; i++) {
                if (jq($listTags[i]).find(".title").text().trim() == tagTitle) {
                    AddRequiredErrorText(jq("#tagTitle"), ASC.CRM.Resources.CRMSettingResource.TagAlreadyExistsError);
                    ShowRequiredError(jq("#tagTitle"), true);
                    return;
                }
            }

            Teamlab.addCrmEntityTag({ tagsCount: tagsCount }, _getCurEntityType(), tagTitle, {
                before: function(params) {
                    LoadingBanner.showLoaderBtn("#manageTag");
                },
                success: ASC.CRM.TagSettingsView.CallbackMethods.add_tag,
                after: function() {
                    LoadingBanner.hideLoaderBtn("#manageTag");
                }
            });

        },

        deleteTag: function(deleteLink) {
            var liObj = jq(jq(deleteLink).parents('li').get(0)),
                tagTitle = liObj.find(".title").text().trim();

            Teamlab.removeCrmEntityTag({ liObj: liObj }, _getCurEntityType(), tagTitle, {
                before: function(params) {
                    params.liObj.find(".crm-deleteLink").hide();
                    params.liObj.find(".ajax_loader").show();
                },
                success: ASC.CRM.TagSettingsView.CallbackMethods.delete_tag
            });
        }
    };
})();


ASC.CRM.SettingsPage.WebToLeadFormView = (function() {
    var _initOtherActionMenu = function() {

        jq("#menuCreateNewTask").bind("click", function () { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    };

    function _renderTable(container) {
        var counter = 0,
            row,
            cell,
            input,
            label;
        var indexRow = 0,
            isCompany = jq("input[name=radio]:checked").val() == "company",
            serverData = isCompany ?
                jQuery.extend(true, [], ASC.CRM.Data.columnSelectorDataCompany) :
                jQuery.extend(true, [], ASC.CRM.Data.columnSelectorDataPerson),
            residue = serverData.length % 3 > 0 ? 3 - serverData.length % 3 : 0;

        jq(serverData).each(function() {
            if (!isCompany && (this.name == "firstName" || this.name == "lastName")) {
                this.disabled = true;
            } else if (isCompany && this.name == "companyName") {
                this.disabled = true;
            } else {
                this.disabled = false;
            }
        });

        for (var i = 0; i < serverData.length + residue; i++) {
            if (counter == 0) {
                row = jq("<tr></tr>");
            }
            cell = jq("<td></td>").attr("width", "33%");

            if (serverData[i] != null) {
                input = jq("<input>")
                                .attr("type", "checkbox")
                                .attr("id", serverData[i].name)
                                .attr("name", serverData[i].name);

                if (serverData[i].disabled) {
                    jq(input).prop("checked", true).prop("disabled", true);
                }

                label = jq("<label>").attr("for", serverData[i].name).text(serverData[i].title);
                input.data("fieldInfo", serverData[i]);
                cell.append(input).append(label);
            }

            row.append(cell);
            counter++;

            if (counter == 3 || i == serverData.length + residue - 1) {
                container.append(row);
                counter = 0;
                indexRow++;
            }
        }
    };

    function _validateInputData() {

        var regexp = /(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;

        var returnURL = jq("#returnURL").val().trim(),
            webFormKey = jq("#properties_webFormKey input").val().trim(),
            isValid = true;

        if (returnURL == "" || !regexp.test(returnURL)) {
            ShowRequiredError(jq("#returnURL"));
            isValid = false;
        } else {
            RemoveRequiredErrorClass(jq("#returnURL"));
        }

        if (webFormKey == "") {
            ShowRequiredError(jq("#properties_webFormKey input"));
            isValid = false;
        } else {
            RemoveRequiredErrorClass(jq("#properties_webFormKey input"));
        }

        var firstName = jq("#tblFieldList input[name='firstName']:checked"),
            lastName = jq("#tblFieldList input[name='lastName']:checked"),
            companyName = jq("#tblFieldList input[name='companyName']:checked");

        if ((firstName.length == 0 || lastName.length == 0) && companyName.length == 0) {
            toastr.error(ASC.CRM.Resources.CRMJSResource.ErrorNotMappingBasicColumn);
            isValid = false;
        }

        return isValid;
    };

    return {
        init: function (webtoleadfromhandlerPath) {
            webtoleadfromhandlerPath = webtoleadfromhandlerPath.replace("http:", "").replace("https:", "");
            ASC.CRM.SettingsPage.WebToLeadFormView.webtoleadfromhandlerPath = webtoleadfromhandlerPath;

            jq.tmpl("tagViewTmpl",
                    {
                        tags          : [],
                        availableTags : ASC.CRM.Data.tagList
                    })
                    .appendTo("#wtlfTags");
            ASC.CRM.TagView.init("contact", true);


            ASC.CRM.UserSelectorListView.Init(
                    "_ContactManager",
                    "UserSelectorListView_ContactManager",
                    false,
                    "",
                    new Array(ASC.CRM.Resources.CurrentUser),
                    null,
                    new Array(Teamlab.profile.id),
                    "#wtlfAccessRights",
                    false);


            var $html = jq.tmpl("makePublicPanelTemplate",
                {
                    Title: ASC.CRM.Resources.CRMContactResource.MakePublicPanelTitleForImportContacts,
                    Description: ASC.CRM.Resources.CRMContactResource.MakePublicPanelDescrForContact,
                    IsPublicItem: false,
                    CheckBoxLabel: ASC.CRM.Resources.CRMContactResource.MakePublicPanelCheckBoxLabelForImportContacts
                });

            $html.find(".makePublicPanelSelector")
                .append(jq("<option value='2'></option>").text(ASC.CRM.Resources.CRMCommonResource.AccessRightsForReading))
                .append(jq("<option value='1'></option>").text(ASC.CRM.Resources.CRMCommonResource.AccessRightsForReadWriting))
                .val("2")
                .tlCombobox();

            $html.appendTo("#wtlfMakePublicPanel");
            //isPublic


            ASC.CRM.UserSelectorListView.Init(
                                "_Notify",
                                "UserSelectorListView_Notify",
                                false,
                                "",
                                [],
                                null,
                                [],
                                "#userSelectorListViewContainer",
                                false);

            for (var i = 0, n = ASC.CRM.Data.columnSelectorDataCompany.length; i < n; i++) {
                var field = ASC.CRM.Data.columnSelectorDataCompany[i];
                if (jq.trim(field.mask) != "") {
                    field.mask = jq.parseJSON(field.mask);
                }
            }
            for (var i = 0, n = ASC.CRM.Data.columnSelectorDataPerson.length; i < n; i++) {
                var field = ASC.CRM.Data.columnSelectorDataPerson[i];
                if (jq.trim(field.mask) != "") {
                    field.mask = jq.parseJSON(field.mask);
                }
            }
            _renderTable(jq("#tblFieldList tbody"));

            jq("#privateSettingsBlock").parent().css("padding", "0px");
            var text = jq("#privateSettingsBlock").parent().find("span:first").text() + ":";
            jq("#privateSettingsBlock").parent().find("span:first").replaceWith(
                jq("<div><div>").text(text).css("font-weight", "bold")
            );

            _initOtherActionMenu();
        },

        changeContactType: function() {
            jq("#tblFieldList tbody").html("");

            _renderTable(jq("#tblFieldList tbody"));
        },

        changeWebFormKey: function() {

            if (!confirm(ASC.CRM.Resources.CRMJSResource.ConfirmChangeKey + "\n" + ASC.CRM.Resources.CRMJSResource.ConfirmChangeKeyNote))
            { return false; }

            Teamlab.updateWebToLeadFormKey({}, {
                success: function (params, response) {
                    jq("#properties_webFormKey input").val(response);
                    jq("#webFormKeyContainer").html(response);
                },
                error: function (params, errors) {
                    var err = errors[0];
                    if (err != null) {
                        toastr.error(err);
                    }
                }
            });
        },

        generateSampleForm: function() {
            if (!_validateInputData()) { return; }

            var fieldListInfo = jQuery.map(jq("#tblFieldList input:checked"),
                   function(a) {
                       return jq(a).data("fieldInfo");
                   });
            var tagListInfo = jq.map(jq("#tagContainer .tag_title"),
                   function(item) {
                       return {
                           name: "tag_" + jq(item).text().trim(),
                           title: jq(item).text().trim()
                       };
                   });

            if (fieldListInfo.length == 0) {
                jq("#resultContainer, #previewHeader").hide();
                jq("#previewHeader div.content").html("");
                return;
            }

            var notifyList = [],
                managersList = new Array(window.SelectedUsers_ContactManager.CurrentUserID);

            for (var i = 0, n = window.SelectedUsers_ContactManager.IDs.length; i < n; i++) {
                managersList.push(window.SelectedUsers_ContactManager.IDs[i]);
            }
            managersList = managersList.join(",");

            if (window.SelectedUsers_Notify.IDs.length != 0) {
                for (var i = 0, n = window.SelectedUsers_Notify.IDs.length; i < n; i++) {
                    notifyList.push(window.SelectedUsers_Notify.IDs[i]);
                }
                notifyList = notifyList.join(",");
            } else {
                notifyList = "";
            }

            var formContainer = jq("<div>");

            jq.tmpl("sampleFormTmpl", {
                webtoleadfromhandlerPath: ASC.CRM.SettingsPage.WebToLeadFormView.webtoleadfromhandlerPath,
                fieldListInfo: fieldListInfo,
                tagListInfo: tagListInfo,
                returnURL: jq("#returnURL").val(),
                webFormKey: jq("#properties_webFormKey input").val(),
                notifyList: notifyList,
                managersList: managersList,
                shareType: jq("#isPublic").is(":checked") ? jq(".makePublicPanel select.makePublicPanelSelector").val() : 0,
                isCompany: jq("input[name=radio]:checked").val() == "company"
            }).appendTo(formContainer);

            var sampleFrom = formContainer.html().replace(/\s{1,}/g, " ");

            jq("#resultContainer textarea").val(sampleFrom);
            jq("#resultContainer").show();
            jq("#previewHeader div.content").html(sampleFrom);
            jq("#previewHeader").show();

        }
    };
})();


ASC.CRM.TaskTemplateView = (function() {

    var _initOtherActionMenu = function() {
        jq("#menuCreateNewTask").bind("click", function() { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    };

    var _getCurEntityType = function () {
        var available = ["contact", "person", "company", "opportunity", "case"],
            type = jq.getURLParam("view");
        if (type == null || type == "" || available.indexOf(type) == -1) { type = "contact"; }
        return type;
    };

    var _initTabs = function (type) {

        jq("<div class='fakeTabContainer' id='contTagsFake'></div>\
            <div class='fakeTabContainer' id='compTagsFake'></div>\
            <div class='fakeTabContainer' id='persTagsFake'></div>\
            <div class='fakeTabContainer' id='dealTagsFake'></div>\
            <div class='fakeTabContainer' id='caseTagsFake'></div>").insertAfter("#TaskTemplateViewTabs");

        window.ASC.Controls.ClientTabsNavigator.init("TaskTemplateViewTabs", {
            tabs: [
            {
                title: ASC.CRM.Resources.CRMSettingResource.BothPersonAndCompany,
                selected: type === "contact",
                divID: "contTagsFake",
                href: "Settings.aspx?type=task_template&view=contact"
            },
            {
                title: ASC.CRM.Resources.CRMSettingResource.JustForCompany,
                selected: type === "company",
                divID: "contTagsFake",
                href: "Settings.aspx?type=task_template&view=company"
            },
            {
                title: ASC.CRM.Resources.CRMSettingResource.JustForPerson,
                selected: type === "person",
                divID: "contTagsFake",
                href: "Settings.aspx?type=task_template&view=person"
            },
            {
                title: ASC.CRM.Resources.CRMCommonResource.DealModuleName,
                selected: type === "opportunity",
                divID: "dealTagsFake",
                href: "Settings.aspx?type=task_template&view=opportunity"
            },
            {
                title: ASC.CRM.Resources.CRMCommonResource.CasesModuleName,
                selected: type === "case",
                divID: "caseTagsFake",
                href: "Settings.aspx?type=task_template&view=case"
            }]
        });
    };


    function checkTemplateConatainers() {
        if (jq("#templateConatainerContent li").length != 0) {
            jq("#emptyContent").hide();
            jq("#templateConatainerContent").show();
        } else {
            jq("#templateConatainerContent").hide();
            jq("#emptyContent").show();
        }
    };

    return {
        init: function () {

            var type = _getCurEntityType();
            _initTabs(type);


            if (typeof (window.templateConatainerList) != "undefined") {
                window.templateConatainerList = jq.parseJSON(jQuery.base64.decode(window.templateConatainerList)).response;
            } else {
                window.templateConatainerList = [];
            }

            jq.forceNumber({
                parent: "#templatePanel",
                input: "#tbxTemplateDisplacement",
                integerOnly: true,
                positiveOnly: true
            });

            jq.tmpl("templateContainerRow", window.templateConatainerList).appendTo("#templateConatainerContent");
            checkTemplateConatainers();

            _initOtherActionMenu();

            for (var i = 0, n = window.templateConatainerList.length; i < n; i++) {
                if (window.templateConatainerList[i].items) {
                    for (var j = 0, m = window.templateConatainerList[i].items.length; j < m; j++) {
                        ASC.CRM.Common.tooltip("#templateTitle_" + window.templateConatainerList[i].items[j].id, "tooltip");
                    }
                }
            }
        },

        showTemplateConatainerPanel: function(id) {
            if (!id) {
                ASC.CRM.TaskTemplateView.initTemplateConatainerPanel();
                PopupKeyUpActionProvider.EnableEsc = false;
                StudioBlockUIManager.blockUI("#templateConatainerPanel", 500);
            } else {
                Teamlab.getCrmEntityTaskTemplateContainer({}, id, {
                    success: function(params, templateContainer) {
                        ASC.CRM.TaskTemplateView.initTemplateConatainerPanel(templateContainer);
                        PopupKeyUpActionProvider.EnableEsc = false;
                        StudioBlockUIManager.blockUI("#templateConatainerPanel", 500);
                    }
                });
            }
        },

        createTemplateConatainer: function() {
            var title = jq("#templateConatainerTitle").val().trim(),
                view = jq.getURLParam("view"),
                entityType = view != null && view != ""
                            ? view
                            : "contact";

            if (title == "") {
                ShowRequiredError(jq("#templateConatainerTitle"), true);
                return false;
            } else {
                RemoveRequiredErrorClass(jq("#templateConatainerTitle"));
            }

            Teamlab.addCrmEntityTaskTemplateContainer({}, { entityType: entityType, title: title }, {
                success: function(params, templateContainer) {
                    jq.tmpl("templateContainerRow", templateContainer).appendTo("#templateConatainerContent");
                    checkTemplateConatainers();
                },
                before: function(params) {
                    jq("#templateConatainerPanel div.action_block").hide();
                    jq("#templateConatainerPanel div.ajax_info_block").show();
                },
                after: function(params) {
                    jq("#templateConatainerPanel div.ajax_info_block").hide();
                    jq("#templateConatainerPanel div.action_block").show();
                    PopupKeyUpActionProvider.EnableEsc = true;
                    jq.unblockUI();
                }
            });
        },

        editTemplateConatainer: function(containerid) {
            var title = jq("#templateConatainerTitle").val().trim(),
                view = jq.getURLParam("view"),
                entityType = view != null && view != "" ? view : "contact";

            if (title == "") {
                ShowRequiredError(jq("#templateConatainerTitle"), true);
                return false;
            }
            else RemoveRequiredErrorClass(jq("#templateConatainerTitle"));

            Teamlab.updateCrmEntityTaskTemplateContainer({}, containerid, { entityType: entityType, title: title }, {
                success: function(params, templateContainer) {
                    jq("#templateContainerBody_" + containerid).remove();
                    var newTemlateContainer = jq.tmpl("templateContainerRow", templateContainer);
                    jq("#templateContainerHeader_" + containerid).replaceWith(newTemlateContainer);
                },
                before: function(params) {
                    jq("#templateConatainerPanel div.action_block").hide();
                    jq("#templateConatainerPanel div.ajax_info_block").show();
                },
                after: function(params) {
                    jq("#templateConatainerPanel div.ajax_info_block").hide();
                    jq("#templateConatainerPanel div.action_block").show();
                    PopupKeyUpActionProvider.EnableEsc = true;
                    jq.unblockUI();
                }
            });
        },

        deleteTemplateConatainer: function(containerid) {
            Teamlab.removeCrmEntityTaskTemplateContainer({}, containerid, {
                success: function(params, templateContainer) {
                    jq("#templateContainerHeader_" + containerid).remove();
                    jq("#templateContainerBody_" + containerid).remove();
                    checkTemplateConatainers();
                },
                before: function(params) {
                    jq("#templateContainerHeader_" + containerid + " .crm-addNewLink").hide();
                    jq("#templateContainerHeader_" + containerid + " .crm-editLink").hide();
                    jq("#templateContainerHeader_" + containerid + " .crm-deleteLink").hide();
                    jq("#templateContainerHeader_" + containerid + " .loaderImg").show();
                }
            });
        },

        initTemplateConatainerPanel: function(container) {
            if (!container) {
                jq("#templateConatainerTitle").val("");
                RemoveRequiredErrorClass(jq("#templateConatainerTitle"));
                jq("#templateConatainerPanel div.containerHeaderBlock td:first")
                        .text(ASC.CRM.TaskTemplateView.ConatainerPanel_AddHeaderText);
                jq("#templateConatainerPanel div.action_block a.button.blue")
                        .text(ASC.CRM.TaskTemplateView.ConatainerPanel_AddButtonText)
                        .unbind("click").click(function() {
                            ASC.CRM.TaskTemplateView.createTemplateConatainer();
                        });
            } else {
                jq("#templateConatainerTitle").val(container.title);
                RemoveRequiredErrorClass(jq("#templateConatainerTitle"));
                jq("#templateConatainerPanel div.containerHeaderBlock td:first")
                        .text(jq.format(ASC.CRM.TaskTemplateView.ConatainerPanel_EditHeaderText, container.title));
                jq("#templateConatainerPanel div.action_block a.button.blue")
                        .text(ASC.CRM.Resources.CRMJSResource.SaveChanges)
                        .unbind("click").click(function() {
                            ASC.CRM.TaskTemplateView.editTemplateConatainer(container.id);
                        });
            }
        },

        toggleCollapceExpand: function(elem) {
            $Obj = jq(elem);

            if ($Obj.hasClass("headerCollapse")) {
                var body = $Obj.parents("li").next();
                if (body.find("table").length > 0) {
                    body.show();
                }
            } else {
                $Obj.parents("li").next().hide();
            }
            $Obj.toggleClass("headerExpand");
            $Obj.toggleClass("headerCollapse");
        },

        showTemplatePanel: function(containerid, id) {
            if (!id) {
                ASC.CRM.TaskTemplateView.initTemplatePanel(containerid);
                PopupKeyUpActionProvider.EnableEsc = false;
                StudioBlockUIManager.blockUI("#templatePanel", 500);
            } else {
                Teamlab.getCrmEntityTaskTemplate({}, id, {
                    success: function(params, template) {
                        ASC.CRM.TaskTemplateView.initTemplatePanel(containerid, template);
                        PopupKeyUpActionProvider.EnableEsc = false;
                        StudioBlockUIManager.blockUI("#templatePanel", 500);
                    }
                });
            }
        },

        createTemplate: function(containerid) {
            var data = ASC.CRM.TaskTemplateView.getCurrentTemplateData();
            data.containerid = containerid;

            if (data.title == "") {
                ShowRequiredError(jq("#tbxTemplateTitle"), true);
                return false;
            } else {
                RemoveRequiredErrorClass(jq("#tbxTemplateTitle"));
            }

            if (data.responsibleid == null || data.responsibleid == "") {
                if (jq.browser.mobile === true) {
                    RemoveRequiredErrorClass(jq("#taskTemplateViewAdvUsrSrContainer select:first"), true);
                } else {
                    RemoveRequiredErrorClass(jq("#templatePanel .inputUserName:first"), true);
                }
                return false;
            } else {
                if (jq.browser.mobile === true) {
                    RemoveRequiredErrorClass(jq("#taskTemplateViewAdvUsrSrContainer select:first"));
                } else {
                    RemoveRequiredErrorClass(jq("#templatePanel .inputUserName:first"));
                }
            }

            Teamlab.addCrmEntityTaskTemplate({}, data, {
                success: function(params, template) {
                    jq.tmpl("templateRow", template).appendTo("#templateContainerBody_" + containerid);
                    if (jq("#templateContainerBody_" + containerid + " table").length > 0) {
                        jq("#templateContainerBody_" + containerid).show();
                    }
                    ASC.CRM.Common.tooltip("#templateTitle_" + template.id, "tooltip");
                },
                before: function(params) {
                    jq("#templatePanel div.action_block").hide();
                    jq("#templatePanel div.ajax_info_block").show();
                },
                after: function(params) {
                    jq("#templatePanel div.ajax_info_block").hide();
                    jq("#templatePanel div.action_block").show();
                    PopupKeyUpActionProvider.EnableEsc = true;
                    jq.unblockUI();
                }
            });
        },

        editTemplate: function(containerid, templateid) {
            var data = ASC.CRM.TaskTemplateView.getCurrentTemplateData();
            data.containerid = containerid,
            data.id = templateid;

            if (data.title == "") {
                ShowRequiredError(jq("#tbxTemplateTitle"), true);
                return false;
            } else {
                RemoveRequiredErrorClass(jq("#tbxTemplateTitle"));
            }

            if (data.responsibleid == null) {
                if (jq.browser.mobile === true) {
                    ShowRequiredError(jq("#taskTemplateViewAdvUsrSrContainer select:first"), true);
                } else {
                    ShowRequiredError(jq("#templatePanel .inputUserName:first"), true);
                }
                return false;
            } else {
                if (jq.browser.mobile === true) {
                    RemoveRequiredErrorClass(jq("#taskTemplateViewAdvUsrSrContainer select:first"));
                } else {
                    RemoveRequiredErrorClass(jq("#templatePanel .inputUserName:first"));
                }
            }

            Teamlab.updateCrmEntityTaskTemplate({}, data, {
                success: function(params, template) {
                    var newTemlate = jq.tmpl("templateRow", template);
                    jq("#templateRow_" + templateid).replaceWith(newTemlate);
                    ASC.CRM.Common.tooltip("#templateTitle_" + template.id, "tooltip");
                },
                before: function(params) {
                    jq("#templatePanel div.action_block").hide();
                    jq("#templatePanel div.ajax_info_block").show();
                },
                after: function(params) {
                    jq("#templatePanel div.ajax_info_block").hide();
                    jq("#templatePanel div.action_block").show();
                    PopupKeyUpActionProvider.EnableEsc = true;
                    jq.unblockUI();
                }
            });
        },

        deleteTemplate: function(templateid) {
            Teamlab.removeCrmEntityTaskTemplate({}, templateid, {
                success: function(params, template) {
                    jq("#templateRow_" + templateid).remove();
                    if (jq("#templateContainerBody_" + template.containerID + " table").length == 0)
                        jq("#templateContainerBody_" + template.containerID).hide();
                },
                before: function(params) {
                    jq("#templateRow_" + templateid + " .crm-addNewLink").hide();
                    jq("#templateRow_" + templateid + " .crm-editLink").hide();
                    jq("#templateRow_" + templateid + " .crm-deleteLink").hide();
                    jq("#templateRow_" + templateid + " .loaderImg").show();
                }
            });
        },

        initTemplatePanel: function(containerid, template) {
            if (!template) {
                jq("#templatePanel div.containerHeaderBlock td:first")
                        .text(ASC.CRM.TaskTemplateView.TemplatePanel_AddHeaderText);
                jq("#templatePanel div.action_block a.button.blue")
                        .text(ASC.CRM.TaskTemplateView.TemplatePanel_AddButtonText)
                        .unbind("click").click(function() {
                            ASC.CRM.TaskTemplateView.createTemplate(containerid);
                        });
                jq("#tbxTemplateTitle").val("");
                jq("#tbxTemplateDescribe").val("");
                ASC.CRM.TaskTemplateView.setTemplateDeadlineFromTicks();
                jq("#notifyResponsible").removeAttr("checked");
                window.taskTemplateResponsibleSelector.ClearFilter();
                window.taskTemplateResponsibleSelector.ChangeDepartment(window.taskTemplateResponsibleSelector.Groups[0].ID);
                var obj = window.taskTemplateCategorySelector.getRowByContactID(0);
                window.taskTemplateCategorySelector.changeContact(obj);

            } else {
                jq("#templatePanel div.containerHeaderBlock td:first")
                        .text(jq.format(ASC.CRM.TaskTemplateView.TemplatePanel_EditHeaderText, template.title));
                jq("#templatePanel div.action_block a.button.blue")
                        .text(ASC.CRM.Resources.CRMJSResource.SaveChanges).unbind("click").click(function() {
                            ASC.CRM.TaskTemplateView.editTemplate(containerid, template.id);
                        });
                jq("#tbxTemplateTitle").val(template.title);
                jq("#tbxTemplateDescribe").val(template.description);
                ASC.CRM.TaskTemplateView.setTemplateDeadlineFromTicks(template.offsetTicks, template.deadLineIsFixed);
                jq("#notifyResponsible").prop("checked", template.isNotify);
                window.taskTemplateResponsibleSelector.ClearFilter();
                window.taskTemplateResponsibleSelector.ChangeDepartment(window.taskTemplateResponsibleSelector.Groups[0].ID);

                var obj;
                if (!jq.browser.mobile) {
                    obj = document.getElementById("User_" + template.responsible.id);
                    if (obj != null)
                        window.taskTemplateResponsibleSelector.SelectUser(obj);
                } else {
                    obj = jq("#taskResponsibleSelector select option[value=" + template.responsible.id + "]");
                    if (obj.length > 0) {
                        window.taskTemplateResponsibleSelector.SelectUser(obj);
                        jq(obj).prop("selected", true);
                    }
                }

                obj = window.taskTemplateCategorySelector.getRowByContactID(template.category.id);
                window.taskTemplateCategorySelector.changeContact(obj);
            }
        },

        getTemplateDeadlineTicks: function() {
            var displacement = jq("#tbxTemplateDisplacement").val().trim() != ""
                    ? parseInt(jq("#tbxTemplateDisplacement").val())
                    : 0,
                hour = displacement * 24 + parseInt(jq("#templateDeadlineHours option:selected").val()),
                minute = parseInt(jq("#templateDeadlineMinutes option:selected").val());

            return ((hour * 3600) + minute * 60) * 10000000;
        },

        setTemplateDeadlineFromTicks: function(ticks, isFixed) {
            if (!ticks && !isFixed) {
                jq("#deadLine_fixed").prop("checked", true);
                jq("#tbxTemplateDisplacement").val("0");
                jq("#templateDeadlineHours option:first").prop("selected", true);
                jq("#templateDeadlineMinutes option:first").prop("selected", true);
            } else {
                if (isFixed) {
                    jq("#deadLine_fixed").prop("checked", true);
                } else {
                    jq("#deadLine_not_fixed").prop("checked", true);
                }

                var minute = ((ticks / 10000000) % 3600) / 60,
                    hour = (parseInt((ticks / 10000000) / 3600)) % 24,
                    displacement = parseInt((parseInt((ticks / 10000000) / 3600)) / 24);

                jq("#tbxTemplateDisplacement").val(displacement);
                jq("#optDeadlineHours_" + hour).prop("selected", true);
                jq("#optDeadlineMinutes_" + minute).prop("selected", true);
            }
        },

        getCurrentTemplateData: function() {
            var data = {
                title: jq("#tbxTemplateTitle").val().trim(),
                description: jq("#tbxTemplateDescribe").val().trim(),
                responsibleid: window.taskTemplateResponsibleSelector.SelectedUserId,
                categoryid: window.taskTemplateCategorySelector.CategoryID,
                isNotify: jq("#notifyResponsible").is(":checked"),
                offsetTicks: ASC.CRM.TaskTemplateView.getTemplateDeadlineTicks(),
                deadLineIsFixed: jq('#templatePanel #deadLine_fixed').is(":checked")
            };
            return data;
        },

        getDeadlineDisplacement: function(ticks, isFixed) {
            var minute = ((ticks / 10000000) % 3600) / 60,
                hour = (parseInt((ticks / 10000000) / 3600)) % 24,
                displacement = parseInt((parseInt((ticks / 10000000) / 3600)) / 24);

            if (isFixed) {
                return jq.format(ASC.CRM.Resources.CRMJSResource.TemplateFixedDeadline, displacement, hour, minute);
            } else {
                return jq.format(ASC.CRM.Resources.CRMJSResource.TemplateNotFixedDeadline, displacement, hour, minute);
            }
        }
    };
})();

ASC.CRM.CurrencySettingsView = (function () {
    
    function initOtherActionMenu () {
        jq("#menuCreateNewTask").bind("click", function () { ASC.CRM.TaskActionView.showTaskPanel(0, "", 0, null, {}); });
    }

    function setBindings() {
        jq("#defaultCurrency").bind("change", changeDefaultCurrency);
        jq("#currencySelector").bind("change", changeCurrency);
        jq("#addCurrencyRate").bind("click", addCurrencyRate);
        jq("#currencyRateList").on("click", ".crm-deleteLink", deleteCurrencyRate);
        jq("#currencyRateList").on("change", ".textEdit", changeCurrencyRate);
        jq("#saveCurrencySettings").bind("click", saveCurrencySettings);
        jq("#cancelCurrencySettings").bind("click", cancelCurrencySettings);
    }

    function renderCurrencyRateList(items, clear) {
        if (clear) {
            jq("#currencyRateList").empty();
        }

        if (items) {
            render(items);
            return;
        }

        Teamlab.getCrmCurrencyRates({},
            {
                before: function () {
                    LoadingBanner.displayLoading();
                },
                after: function () {
                    LoadingBanner.hideLoading();
                },
                success: function (params, response) {
                    render(response);
                },
                error: function (params, errors) {
                    console.log(errors);
                    toastr.error(errors[0]);
                }
            });

        function render(data) {
            jq.tmpl("currencyRateItemTmpl", data).appendTo("#currencyRateList");
            
            jq(data).each(function (index, item) {
                jq.forceNumber({
                    parent: "#currencyRateList",
                    input: "#currencyRate_" + item.fromCurrency,
                    integerOnly: false,
                    positiveOnly: true
                });
            });
            
            jq("#currencySelector").change();
        }
    }

    function changeDefaultCurrency() {
        renderCurrencyRateList(jq(this).val() == window.defaultCurrency ? window.currencyRates : [], true);
        jq("#currencySelector").change();
    }

    function changeCurrency() {
        var value = jq(this).val();
        var exist = value == jq("#defaultCurrency").val();

        if (!exist) {
            jq("#currencyRateList .currency-rate-item span:first-child").each(function(index, item) {
                if (jq(item).text().trim() == value)
                    exist = true;
            });
        }

        if (exist) {
            jq("#addCurrencyRate").addClass("disable");
        } else {
            jq("#addCurrencyRate").removeClass("disable");
        }
    }

    function addCurrencyRate() {
        if (jq(this).hasClass("disable"))
            return;

        var data = [{
            fromCurrency: jq("#currencySelector").val(),
            rate: "1.00",
            toCurrency: jq("#defaultCurrency").val()
        }];

        renderCurrencyRateList(data, false);
        jq("#currencySelector").change();
    }

    function deleteCurrencyRate() {
        jq(this).parent().remove();
        jq("#currencySelector").change();
    }

    function changeCurrencyRate() {
        var obj = jq(this);
        var rate = Number(obj.val());

        if (rate <= 0) {
            obj.val("1.00");
        } else {
            obj.val(rate.toFixed(2));
        }
    }

    function saveCurrencySettings() {
        var newDefaultCurrency = jq("#defaultCurrency").val();
        var newCurrencyRates = [];

        jq("#currencyRateList .currency-rate-item").each(function (index, item) {
            var obj = jq(item);

            newCurrencyRates.push({
                fromCurrency: obj.find("span:first-child").text().trim(),
                rate: obj.find("input").val().trim(),
                toCurrency: newDefaultCurrency
            });
        });

        Teamlab.setCrmCurrencyRates({ newDefaultCurrency: newDefaultCurrency }, newDefaultCurrency, newCurrencyRates,
            {
                before: function() {
                    LoadingBanner.displayLoading();
                },
                after: function() {
                    LoadingBanner.hideLoading();
                },
                success: function(params, response) {
                    window.defaultCurrency = params.newDefaultCurrency;
                    window.currencyRates = response;
                    toastr.success(ASC.CRM.Resources.CRMJSResource.SettingsUpdated);
                },
                error: function(params, errors) {
                    console.log(errors);
                    toastr.error(errors[0]);
                }
            });
    }

    function cancelCurrencySettings() {
        jq("#defaultCurrency").val(window.defaultCurrency);
        renderCurrencyRateList(window.currencyRates, true);
        jq("#currencySelector").change();
    }

    return {
        init: function () {
            initOtherActionMenu();
            setBindings();
            renderCurrencyRateList(window.currencyRates, true);
        }
    };
})();

<|start_filename|>web/studio/ASC.Web.Studio/Default.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;

using ASC.Core;
using ASC.Core.Users;
using ASC.Web.Core;
using ASC.Web.Core.Files;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.EmptyScreens;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio
{
    public partial class _Default : MainPage
    {
        protected Product _showDocs;

        protected UserInfo CurrentUser;

        protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);
            if (CoreContext.Configuration.Personal)
                Context.Response.Redirect(FilesLinkUtility.FilesBaseAbsolutePath);
        }


        protected bool? IsAutorizePartner { get; set; }
        protected Partner Partner { get; set; }

        protected List<IWebItem> defaultListProducts;

        protected IEnumerable<CustomNavigationItem> CustomNavigationItems { get; set; }

        protected int ProductsCount { get; set; }

        protected string ResetCacheKey;

        protected void Page_Load(object sender, EventArgs e)
        {
            CurrentUser = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);

            Page.RegisterStyle("~/skins/page_default.less");

            var defaultPageSettings = StudioDefaultPageSettings.Load();
            if (defaultPageSettings != null && defaultPageSettings.DefaultProductID != Guid.Empty)
            {
                if (defaultPageSettings.DefaultProductID == defaultPageSettings.FeedModuleID && !CurrentUser.IsOutsider())
                {
                    Response.Redirect("Feed.aspx", true);
                }

                var webItem = WebItemManager.Instance[defaultPageSettings.DefaultProductID];
                if (webItem != null && webItem.Visible)
                {
                    var securityInfo = WebItemSecurity.GetSecurityInfo(defaultPageSettings.DefaultProductID.ToString());
                    if (securityInfo.Enabled && WebItemSecurity.IsAvailableForMe(defaultPageSettings.DefaultProductID))
                    {
                        var url = webItem.StartURL;
                        if (Request.DesktopApp())
                        {
                            url += "?desktop=true";
                            if (!string.IsNullOrEmpty(Request["first"]))
                            {
                                url += "&first=true";
                            }
                        }
                        Response.Redirect(url, true);
                    }
                }
            }

            Master.DisabledSidePanel = true;

            Title = Resource.MainPageTitle;
            defaultListProducts = WebItemManager.Instance.GetItems(Web.Core.WebZones.WebZoneType.StartProductList);
            _showDocs = (Product)defaultListProducts.Find(r => r.ID == WebItemManager.DocumentsProductID);
            if (_showDocs != null)
            {
                defaultListProducts.RemoveAll(r => r.ID == _showDocs.ProductID);
            }

            var mailProduct = WebItemManager.Instance[WebItemManager.MailProductID];
            if (mailProduct != null && !mailProduct.IsDisabled())
            {
                defaultListProducts.Add(mailProduct);
            }

            var calendarProduct = WebItemManager.Instance[WebItemManager.CalendarProductID];
            if (calendarProduct != null && !calendarProduct.IsDisabled())
            {
                defaultListProducts.Add(calendarProduct);
            }

            var talkProduct = WebItemManager.Instance[WebItemManager.TalkProductID];
            if (talkProduct != null && !talkProduct.IsDisabled())
            {
                defaultListProducts.Add(talkProduct);
            }

            var priority = GetStartProductsPriority();

            defaultListProducts = defaultListProducts
                .Where(p => priority.Keys.Contains(p.ID))
                .OrderBy(p => priority[p.ID])
                .ToList();

            CustomNavigationItems = CustomNavigationSettings.Load().Items.Where(x => x.ShowOnHomePage);

            ProductsCount = defaultListProducts.Count() + CustomNavigationItems.Count() + (TenantExtra.EnableControlPanel ? 1 : 0);

            ResetCacheKey = ConfigurationManagerExtension.AppSettings["web.client.cache.resetkey"] ?? "";

            if (CurrentUser.IsOwner() && TenantExtra.Saas && !CoreContext.Configuration.CustomMode && !TenantExtra.GetTenantQuota().Free)
            {
                var collaboratorPopupSettings = CollaboratorSettings.LoadForCurrentUser();
                if (collaboratorPopupSettings.FirstVisit)
                {
                    WelcomePanelHolder.Controls.Add(LoadControl(WelcomeDashboard.Location));
                }
            }
        }

        private static Dictionary<Guid, Int32> GetStartProductsPriority()
        {
            var priority = new Dictionary<Guid, Int32>
                    {
                        {WebItemManager.ProjectsProductID, 0},
                        {WebItemManager.CRMProductID, 1},
                        {WebItemManager.MailProductID, 2},
                        {WebItemManager.PeopleProductID, 3},
                        {WebItemManager.CommunityProductID, 4},
                        {WebItemManager.SampleProductID, 5}
                    };

            if (!string.IsNullOrEmpty(SetupInfo.StartProductList))
            {
                var products = SetupInfo.StartProductList.Split(',');

                if (products.Any())
                {
                    priority = new Dictionary<Guid, int>();

                    for (var i = 0; i < products.Length; i++)
                    {
                        var productId = GetProductId(products[i]);
                        if (productId != Guid.Empty)
                            priority.Add(productId, i);
                    }
                }
            }

            return priority;
        }

        private static Guid GetProductId(string productName)
        {
            Guid productId;

            if (Guid.TryParse(productName, out productId))
            {
                var product = WebItemManager.Instance[productId];
                if (product != null) return productId;
            }

            switch (productName.ToLowerInvariant())
            {
                case "documents":
                    return WebItemManager.DocumentsProductID;
                case "projects":
                    return WebItemManager.ProjectsProductID;
                case "crm":
                    return WebItemManager.CRMProductID;
                case "people":
                    return WebItemManager.PeopleProductID;
                case "community":
                    return WebItemManager.CommunityProductID;
                case "mail":
                    return WebItemManager.MailProductID;
                case "calendar":
                    return WebItemManager.CalendarProductID;
                case "talk":
                    return WebItemManager.TalkProductID;
                default:
                    return Guid.Empty;
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/UserFolderDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Expressions.UserFolder;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class UserFolderDao : BaseDao, IUserFolderDao
    {
        protected static ITable table = new MailTableFactory().Create<UserFolderTable>();

        protected string CurrentUserId { get; private set; }

        public UserFolderDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public UserFolder Get(uint id)
        {
            var query = Query()
                .Where(UserFolderTable.Columns.Tenant, Tenant)
                .Where(UserFolderTable.Columns.User, CurrentUserId)
                .Where(UserFolderTable.Columns.Id, id);

            var result = Db.ExecuteList(query)
                .ConvertAll(ToUserFolder)
                .SingleOrDefault();

            return result;
        }

        public UserFolder GetByMail(uint mailId)
        {
            var subQuery = new SqlQuery(UserFoldertXMailTable.TABLE_NAME)
                .Select(UserFoldertXMailTable.Columns.FolderId)
                .Where(UserFoldertXMailTable.Columns.MailId, mailId)
                .Distinct();

            var query = Query()
                .Where(Exp.EqColumns(UserFolderTable.Columns.Id, subQuery));

            var result = Db.ExecuteList(query)
                .ConvertAll(ToUserFolder)
                .SingleOrDefault();

            return result;
        }

        public List<UserFolder> GetList(IUserFoldersExp exp)
        {
            var query = Query()
                .Where(exp.GetExpression());

            if (exp.StartIndex.HasValue)
            {
                query.SetFirstResult(exp.StartIndex.Value);
            }

            if (exp.Limit.HasValue)
            {
                query.SetMaxResults(exp.Limit.Value);
            }

            if (!string.IsNullOrEmpty(exp.OrderBy))
            {
                var sortField = UserFolderTable.Columns.Name;

                if (exp.OrderBy == "timeModified")
                {
                    sortField = UserFolderTable.Columns.TimeModified;
                }

                query.OrderBy(sortField, exp.OrderAsc != null && exp.OrderAsc.Value);
            }

            var list = Db.ExecuteList(query)
                .ConvertAll(ToUserFolder);

            return list;
        }

        public UserFolder GetRootFolder(uint folderId)
        {
            var subQuery = new SqlQuery(UserFolderTreeTable.TABLE_NAME)
                .Select(UserFolderTreeTable.Columns.ParentId)
                .Where(UserFolderTreeTable.Columns.FolderId, folderId)
                .SetMaxResults(1)
                .OrderBy(UserFolderTreeTable.Columns.Level, false);

            var query = Query()
                .Where(Exp.EqColumns(UserFolderTable.Columns.Id, subQuery));

            var result = Db.ExecuteList(query)
                .ConvertAll(ToUserFolder)
                .SingleOrDefault();

            return result;
        }

        public UserFolder GetRootFolderByMailId(int mailId)
        {
            var subSubQuery = new SqlQuery(UserFoldertXMailTable.TABLE_NAME)
                .Select(UserFoldertXMailTable.Columns.FolderId)
                .Where(UserFoldertXMailTable.Columns.MailId, mailId)
                .Distinct();

            var subQuery = new SqlQuery(UserFolderTreeTable.TABLE_NAME)
                .Select(UserFolderTreeTable.Columns.ParentId)
                .Where(Exp.EqColumns(UserFolderTreeTable.Columns.FolderId, subSubQuery))
                .SetMaxResults(1)
                .OrderBy(UserFolderTreeTable.Columns.Level, false);

            var query = Query()
                .Where(Exp.EqColumns(UserFolderTable.Columns.Id, subQuery));

            var result = Db.ExecuteList(query)
                .ConvertAll(ToUserFolder)
                .SingleOrDefault();

            return result;
        }

        public List<UserFolder> GetParentFolders(uint folderId)
        {
            const string folder_alias = "f";
            const string folder_tree_alias = "ft";

            var query = Query(folder_alias)
                .InnerJoin(UserFolderTreeTable.TABLE_NAME.Alias(folder_tree_alias),
                    Exp.EqColumns(UserFolderTable.Columns.Id.Prefix(folder_alias),
                        UserFolderTreeTable.Columns.ParentId.Prefix(folder_tree_alias)))
                .Where(UserFolderTreeTable.Columns.FolderId.Prefix(folder_tree_alias), folderId)
                .OrderBy(UserFolderTreeTable.Columns.Level.Prefix(folder_tree_alias), false);

            var list = Db.ExecuteList(query)
                .ConvertAll(ToUserFolder);

            return list;
        }

        public uint Save(UserFolder folder)
        {
            var query = new SqlInsert(UserFolderTable.TABLE_NAME, true)
                .InColumnValue(UserFolderTable.Columns.Id, folder.Id)
                .InColumnValue(UserFolderTable.Columns.ParentId, folder.ParentId)
                .InColumnValue(UserFolderTable.Columns.Tenant, folder.Tenant)
                .InColumnValue(UserFolderTable.Columns.User, folder.User)
                .InColumnValue(UserFolderTable.Columns.Name, folder.Name)
                .InColumnValue(UserFolderTable.Columns.FolderCount, folder.FolderCount)
                .InColumnValue(UserFolderTable.Columns.UnreadMessagesCount, folder.UnreadCount)
                .InColumnValue(UserFolderTable.Columns.TotalMessagesCount, folder.TotalCount)
                .InColumnValue(UserFolderTable.Columns.UnreadConversationsCount, folder.UnreadChainCount)
                .InColumnValue(UserFolderTable.Columns.TotalConversationsCount, folder.TotalChainCount)
                .InColumnValue(UserFolderTable.Columns.TimeModified, folder.TimeModified)
                .Identity(0, (uint)0, true);

            return Db.ExecuteScalar<uint>(query);
        }

        public int Remove(uint id)
        {
            var query = new SqlDelete(UserFolderTable.TABLE_NAME)
                .Where(UserFolderTable.Columns.Tenant, Tenant)
                .Where(UserFolderTable.Columns.User, CurrentUserId)
                .Where(UserFolderTable.Columns.Id, id);

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        public int Remove(IUserFoldersExp exp)
        {
            var query = new SqlDelete(UserFolderTable.TABLE_NAME)
                .Where(exp.GetExpression());

            var result = Db.ExecuteNonQuery(query);

            return result;
        }

        private static readonly string SetFolderCount =
            string.Format("{0} = (select count(*) - 1 from {1} where {2} = {3})",
                UserFolderTable.Columns.FolderCount, UserFolderTreeTable.TABLE_NAME,
                UserFolderTreeTable.Columns.ParentId, UserFolderTable.Columns.Id);

        public void RecalculateFoldersCount(uint id)
        {
            var subQuery = new SqlQuery(UserFolderTreeTable.TABLE_NAME)
                .Select(UserFolderTreeTable.Columns.ParentId)
                .Where(UserFolderTreeTable.Columns.FolderId, id);

            var query = new SqlUpdate(UserFolderTable.TABLE_NAME)
                .Set(SetFolderCount)
                .Where(Exp.In(UserFolderTable.Columns.Id, subQuery));

            // ReSharper disable once UnusedVariable
            var result = Db.ExecuteNonQuery(query);
        }

        private const string INCR_VALUE_FORMAT = "{0}={0}+({1})";
        private const string SET_VALUE_FORMAT = "{0}={1}";

        public int SetFolderCounters(uint folderId, int? unreadMess = null, int? totalMess = null,
            int? unreadConv = null, int? totalConv = null)
        {
            if (!unreadMess.HasValue
                && !totalMess.HasValue
                && !unreadConv.HasValue
                && !totalConv.HasValue)
            {
                return -1;
            }

            var updateQuery = new SqlUpdate(UserFolderTable.TABLE_NAME)
                .Where(UserFolderTable.Columns.Tenant, Tenant)
                .Where(UserFolderTable.Columns.User, CurrentUserId)
                .Where(UserFolderTable.Columns.Id, folderId);

            Action<string, int?> setColumnValue = (column, item) =>
            {
                if (!item.HasValue)
                    return;

                updateQuery.Set(string.Format(SET_VALUE_FORMAT, column, item.Value));
            };

            setColumnValue(UserFolderTable.Columns.UnreadMessagesCount, unreadMess);

            setColumnValue(UserFolderTable.Columns.TotalMessagesCount, totalMess);

            setColumnValue(UserFolderTable.Columns.UnreadConversationsCount, unreadConv);

            setColumnValue(UserFolderTable.Columns.TotalConversationsCount, totalConv);

            var result = Db.ExecuteNonQuery(updateQuery);

            return result;
        }

        public int ChangeFolderCounters(uint folderId, int? unreadMessDiff = null, int? totalMessDiff = null,
            int? unreadConvDiff = null, int? totalConvDiff = null)
        {
            if (!unreadMessDiff.HasValue
                && !totalMessDiff.HasValue
                && !unreadConvDiff.HasValue
                && !totalConvDiff.HasValue)
            {
                return -1;
            }

            var updateQuery = new SqlUpdate(UserFolderTable.TABLE_NAME)
                .Where(UserFolderTable.Columns.Tenant, Tenant)
                .Where(UserFolderTable.Columns.User, CurrentUserId)
                .Where(UserFolderTable.Columns.Id, folderId);

            Action<string, int?> setColumnValue = (column, item) =>
            {
                if (!item.HasValue)
                    return;

                updateQuery.Set(item.Value != 0
                    ? string.Format(INCR_VALUE_FORMAT, column, item.Value)
                    : string.Format(SET_VALUE_FORMAT, column, 0));
            };

            setColumnValue(UserFolderTable.Columns.UnreadMessagesCount, unreadMessDiff);

            setColumnValue(UserFolderTable.Columns.TotalMessagesCount, totalMessDiff);

            setColumnValue(UserFolderTable.Columns.UnreadConversationsCount, unreadConvDiff);

            setColumnValue(UserFolderTable.Columns.TotalConversationsCount, totalConvDiff);

            var result = Db.ExecuteNonQuery(updateQuery);

            return result;
        }

        protected UserFolder ToUserFolder(object[] r)
        {
            var folder = new UserFolder
            {
                Id = Convert.ToUInt32(r[0]),
                ParentId = Convert.ToUInt32(r[1]),

                Tenant = Convert.ToInt32(r[2]),
                User = Convert.ToString(r[3]),

                Name = Convert.ToString(r[4]),
                FolderCount = Convert.ToInt32(r[5]),

                UnreadCount = Convert.ToInt32(r[6]),
                TotalCount = Convert.ToInt32(r[7]),

                UnreadChainCount = Convert.ToInt32(r[8]),
                TotalChainCount = Convert.ToInt32(r[9]),

                TimeModified = Convert.ToDateTime(r[10])
            };

            return folder;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/js/filter.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC.Files.Filter = (function () {
    var isInit = false;
    var advansedFilter = null;

    var init = function () {
        if (!isInit) {

            var filterOptions = {
                anykey: true,
                anykeytimeout: 800,
                colcount: 3,
                filters: getFilterItems(),
                hintDefaultDisable: false,
                maxlength: ASC.Files.Constants.MAX_NAME_LENGTH,
                sorters: getSorterItems()
            };

            ASC.Files.Filter.advansedFilter =
                jq(".files-filter div")
                    .advansedFilter(filterOptions)
                    .bind("setfilter", ASC.Files.Filter.setFilter)
                    .bind("resetfilter", ASC.Files.Filter.setFilter);
        }
    };

    var getFilterItems = function () {
        var isFavorites = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_FAVORITES;
        var isRecent = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_RECENT;
        var isTemplates = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_TEMPLATES;

        var filterItems = [
            {
                id: "selected-type-folder",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.FoldersOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterFolder,
                visible: !isFavorites && !isRecent && !isTemplates
            },
            {
                id: "selected-type-text",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.DocumentsOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterDocument
            },
            {
                id: "selected-type-presentation",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.PresentationsOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterPresentation
            },
            {
                id: "selected-type-spreadsheet",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.SpreadsheetsOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterSpreadsheet
            },
            {
                id: "selected-type-image",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.ImagesOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterImage,
                visible: !isRecent && !isTemplates
            },
            {
                id: "selected-type-media",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.MediaOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterMedia,
                visible: !isRecent && !isTemplates
            },
            {
                id: "selected-type-archive",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.ArchiveOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterArchive,
                visible: !isRecent && !isTemplates
            },
            {
                id: "selected-type-file",
                filtertitle: ASC.Files.FilesJSResource.ButtonFilterType,
                group: ASC.Files.FilesJSResource.ButtonFilterType,
                groupby: "type",
                options: getTypeOptions(ASC.Files.Constants.FilterType.FilesOnly),
                type: "combobox",
                title: ASC.Files.FilesJSResource.ButtonFilterFiles,
                visible: !isFavorites && !isRecent && !isTemplates
            }
        ];

        if (ASC.Resources.Master.Personal != true) {
            filterItems.push({
                id: "selected-person",
                group: ASC.Files.FilesJSResource.ButtonFilterAuthor,
                groupby: "owner",
                title: ASC.Files.FilesJSResource.Users,
                type: "person"
            });

            filterItems.push({
                id: "selected-group",
                group: ASC.Files.FilesJSResource.ButtonFilterAuthor,
                groupby: "owner",
                title: ASC.Files.FilesJSResource.Departments,
                type: "group"
            });
        }

        var isRootTrash = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_TRASH;

        if (jq(".files-filter").data("content")) {
            filterItems.push({
                id: "with-content",
                group: ASC.Files.FilesJSResource.ButtonFilterOther,
                title: ASC.Files.FilesJSResource.ButtonFilterInContent,
                type: "flag",
                visible: !isRootTrash
            });
        }

        filterItems.push({
            id: "current-folder",
            group: ASC.Files.FilesJSResource.ButtonFilterOther,
            title: ASC.Files.FilesJSResource.ButtonFilterCurrentFolderOnly,
            type: "flag",
            visible: !isRootTrash && !isFavorites && !isRecent && !isTemplates
                && (!ASC.Files.ThirdParty || !ASC.Files.ThirdParty.isThirdParty())
        });

        return filterItems;
    };

    var getTypeOptions = function (defaultType) {
        var isFavorites = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_FAVORITES;
        var isRecent = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_RECENT;
        var isTemplates = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_TEMPLATES;

        var options = [];
        if (!isFavorites && !isRecent && !isTemplates) {
            options = [{
                def: defaultType == ASC.Files.Constants.FilterType.FoldersOnly,
                title: ASC.Files.FilesJSResource.ButtonFilterFolder,
                value: ASC.Files.Constants.FilterType.FoldersOnly
            }];
        }

        options.push({
                def: defaultType == ASC.Files.Constants.FilterType.DocumentsOnly,
                title: ASC.Files.FilesJSResource.ButtonFilterDocument,
                value: ASC.Files.Constants.FilterType.DocumentsOnly
            },
            {
                def: defaultType == ASC.Files.Constants.FilterType.PresentationsOnly,
                title: ASC.Files.FilesJSResource.ButtonFilterPresentation,
                value: ASC.Files.Constants.FilterType.PresentationsOnly
            },
            {
                def: defaultType == ASC.Files.Constants.FilterType.SpreadsheetsOnly,
                title: ASC.Files.FilesJSResource.ButtonFilterSpreadsheet,
                value: ASC.Files.Constants.FilterType.SpreadsheetsOnly
            });

        if (!isRecent && !isTemplates) {
            options.push({
                    def: defaultType == ASC.Files.Constants.FilterType.ImagesOnly,
                    title: ASC.Files.FilesJSResource.ButtonFilterImage,
                    value: ASC.Files.Constants.FilterType.ImagesOnly
                },
                {
                    def: defaultType == ASC.Files.Constants.FilterType.MediaOnly,
                    title: ASC.Files.FilesJSResource.ButtonFilterMedia,
                    value: ASC.Files.Constants.FilterType.MediaOnly
                },
                {
                    def: defaultType == ASC.Files.Constants.FilterType.ArchiveOnly,
                    title: ASC.Files.FilesJSResource.ButtonFilterArchive,
                    value: ASC.Files.Constants.FilterType.ArchiveOnly
                });
        }

        if (!isFavorites && !isRecent && !isTemplates) {
            options.push({
                def: defaultType == ASC.Files.Constants.FilterType.FilesOnly,
                title: ASC.Files.FilesJSResource.ButtonFilterFiles,
                value: ASC.Files.Constants.FilterType.FilesOnly
            });
        }

        return options;
    };

    var getSorterItems = function () {
        var startOrderBy = getOrderDefault();
        
        var sorterItems = [
            {
                def: (startOrderBy.property == "DateAndTime"),
                dsc: (startOrderBy.property == "DateAndTime" ? !startOrderBy.is_asc : false),
                id: "DateAndTime",
                title: ASC.Files.FilesJSResource.ButtonSortModifiedNew
            },
            {
                def: (startOrderBy.property == "DateAndTimeCreation"),
                dsc: (startOrderBy.property == "DateAndTimeCreation" ? !startOrderBy.is_asc : false),
                id: "DateAndTimeCreation",
                title: ASC.Files.FilesJSResource.ButtonSortCreated
            },
            {
                def: (startOrderBy.property == "AZ"),
                dsc: (startOrderBy.property == "AZ" ? !startOrderBy.is_asc : true),
                id: "AZ",
                title: ASC.Files.FilesJSResource.ButtonSortName
            },
            {
                def: (startOrderBy.property == "Type"),
                dsc: (startOrderBy.property == "Type" ? !startOrderBy.is_asc : true),
                id: "Type",
                title: ASC.Files.FilesJSResource.ButtonSortType
            },
            {
                def: (startOrderBy.property == "Size"),
                dsc: (startOrderBy.property == "Size" ? !startOrderBy.is_asc : false),
                id: "Size",
                title: ASC.Files.FilesJSResource.ButtonSortSize
            }
        ];

        if (ASC.Resources.Master.Personal != true) {
            sorterItems.push({
                def: (startOrderBy.property == "Author"),
                dsc: (startOrderBy.property == "Author" ? !startOrderBy.is_asc : false),
                id: "Author",
                title: ASC.Files.FilesJSResource.ButtonSortAuthor
            });
        }

        return sorterItems;
    };

    var disableFilter = function () {
        ASC.Files.Filter.advansedFilter.advansedFilter({
            filters: getFilterItems()
        });

        var isRecent = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_RECENT;
        ASC.Files.Filter.advansedFilter.advansedFilter("sort", !isRecent);
    };

    var setFilter = function (evt, $container, filter, params, selectedfilters) {
        if (!isInit) {
            isInit = true;
            return;
        }

        ASC.Files.Anchor.navigationSet(ASC.Files.Folders.currentFolder.id, false);
    };

    var clearFilter = function (safeMode) {
        safeMode = safeMode === true;
        var mustTrue = false;
        if (safeMode && isInit) {
            mustTrue = true;
            isInit = false;
        }
        ASC.Files.Filter.advansedFilter.advansedFilter(null);
        if (safeMode && mustTrue) {
            isInit = true;
        }
    };

    var setWithoutSubfolders = function () {
        ASC.Files.Filter.advansedFilter.advansedFilter({
            filters: [
                { id: "current-folder", params: {}}
            ]
        });
    };

    var resize = function () {
        ASC.Files.Filter.advansedFilter.advansedFilter("resize");
    };

    var getDefaultFilterSettings = function () {
        var settings =
            {
                sorter: getOrderDefault(),
                text: "",
                filter: ASC.Files.Constants.FilterType.None,
                subject: "",
                isSet: false,
                withSubfolders: false,
                searchInContent: false
            };
        return settings;
    };

    var getFilterSettings = function () {
        var settings = ASC.Files.Filter.getDefaultFilterSettings();

        if (ASC.Files.Filter.advansedFilter == null) {
            return settings;
        }

        var currentFolderOnly = ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_TRASH
            || ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_FAVORITES
            || ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_RECENT
            || ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_TEMPLATES;
        var param = ASC.Files.Filter.advansedFilter.advansedFilter();
        jq(param).each(function (i, item) {
            switch (item.id) {
                case "sorter":
                    var curOrderBy = getOrderBy(item.params.id, !item.params.dsc);
                    settings.sorter = curOrderBy;
                    break;
                case "text":
                    settings.text = item.params.value;
                    settings.isSet = true;
                    break;
                case "selected-person":
                    settings.subject = item.params.id;
                    settings.isSet = true;
                    break;
                case "selected-group":
                    settings.subjectGroup = true;
                    settings.subject = item.params.id;
                    settings.isSet = true;
                    break;
                case "selected-type-folder":
                case "selected-type-text":
                case "selected-type-presentation":
                case "selected-type-spreadsheet":
                case "selected-type-image":
                case "selected-type-media":
                case "selected-type-archive":
                case "selected-type-file":
                    settings.filter = parseInt(item.params.value || ASC.Files.Constants.FilterType.None);
                    settings.isSet = settings.filter != ASC.Files.Constants.FilterType.None;
                    break;
                case "current-folder":
                    currentFolderOnly = true;
                    break;
                case "with-content":
                    settings.searchInContent = true;
                    break;
            }
        });

        if (!currentFolderOnly && settings.isSet) {
            settings.withSubfolders = true;
        }

        if (ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_TRASH) {
            settings.searchInContent = false;
        }

        return settings;
    };

    var getOrderDefault = function () {
        return getOrderBy(jq(".files-filter").data("sort"), jq(".files-filter").data("asc"));
    };

    var getOrderBy = function (name, asc) {
        name = (typeof name != "undefined" && name != "" ? name : "DateAndTime");
        asc = asc === true;
        return {
            is_asc: asc,
            property: name
        };
    };

    return {
        init: init,

        advansedFilter: advansedFilter,
        disableFilter: disableFilter,

        getDefaultFilterSettings: getDefaultFilterSettings,
        getFilterSettings: getFilterSettings,

        setFilter: setFilter,
        clearFilter: clearFilter,
        setWithoutSubfolders: setWithoutSubfolders,
        resize: resize
    };
})();

(function ($) {
    $(function () {
        ASC.Files.Filter.init();

        jq(".files-clear-filter").click(function () {
            ASC.Files.Filter.clearFilter();
            return false;
        });

        jq("#filesWithoutSubfolders").click(function () {
            ASC.Files.Filter.setWithoutSubfolders();
            return false;
        });
    });
})(jQuery);


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/TariffSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;

namespace ASC.Web.Studio.UserControls.Management
{
    [Serializable]
    [DataContract]
    public class TariffSettings : BaseSettings<TariffSettings>
    {
        private static readonly CultureInfo CultureInfo = CultureInfo.CreateSpecificCulture("en-US");

        [DataMember(Name = "HideNotify")]
        public bool HideNotifySetting { get; set; }

        [DataMember(Name = "HidePricingPage")]
        public bool HidePricingPageForUsers { get; set; }

        [DataMember(Name = "LicenseAccept")]
        public string LicenseAcceptSetting { get; set; }

        public override ISettings GetDefault()
        {
            return new TariffSettings
            {
                HideNotifySetting = false,
                HidePricingPageForUsers = false,
                LicenseAcceptSetting = DateTime.MinValue.ToString(CultureInfo),
            };
        }

        public override Guid ID
        {
            get { return new Guid("{07956D46-86F7-433b-A657-226768EF9B0D}"); }
        }

        public static bool HideNotify
        {
            get { return LoadForCurrentUser().HideNotifySetting; }
            set
            {
                var tariffSettings = LoadForCurrentUser();
                tariffSettings.HideNotifySetting = value;
                tariffSettings.SaveForCurrentUser();
            }
        }

        public static bool HidePricingPage
        {
            get { return Load().HidePricingPageForUsers; }
            set
            {
                var tariffSettings = Load();
                tariffSettings.HidePricingPageForUsers = value;
                tariffSettings.Save();
            }
        }

        public static bool LicenseAccept
        {
            get
            {
                return !DateTime.MinValue.ToString(CultureInfo).Equals(LoadForDefaultTenant().LicenseAcceptSetting);
            }
            set
            {
                var tariffSettings = LoadForDefaultTenant();
                if (DateTime.MinValue.ToString(CultureInfo).Equals(tariffSettings.LicenseAcceptSetting))
                {
                    tariffSettings.LicenseAcceptSetting = DateTime.UtcNow.ToString(CultureInfo);
                    tariffSettings.SaveForDefaultTenant();
                }
            }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Search/MailContactsWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.ElasticSearch;

namespace ASC.Mail.Data.Search
{
    public sealed class MailContactWrapper : Wrapper
    {
        [ColumnId("id")]
        public override int Id { get; set; }

        [ColumnTenantId("tenant")]
        public override int TenantId { get; set; }

        [ColumnLastModified("last_modified")]
        public override DateTime LastModifiedOn { get; set; }

        [ColumnMeta("id_user", 1)]
        public Guid User { get; set; }

        [Column("name", 2)]
        public string Name { get; set; }

        [Column("description", 3, Analyzer = Analyzer.uax_url_email)]
        public string Description { get; set; }

        [ColumnMeta("type", 4)]
        public int ContactType { get; set; }

        [Join(JoinTypeEnum.Sub, "id:id_contact")]
        public List<MailContactInfoWrapper> InfoList { get; set; }

        protected override string Table
        {
            get { return "mail_contacts"; }
        }
    }

    public sealed class MailContactInfoWrapper : Wrapper
    {
        [ColumnId("id")]
        public override int Id { get; set; }

        [ColumnTenantId("tenant")]
        public override int TenantId { get; set; }

        [ColumnLastModified("last_modified")]
        public override DateTime LastModifiedOn { get; set; }

        [ColumnMeta("id_user", 1)]
        public Guid User { get; set; }

        [ColumnMeta("id_contact", 2)]
        public int ContactId { get; set; }

        [Column("data", 3)]
        public string Text { get; set; }

        [ColumnMeta("type", 4)]
        public int InfoType { get; set; }

        [ColumnMeta("is_primary", 5)]
        public bool IsPrimary { get; set; }

        protected override string Table
        {
            get { return "mail_contact_info"; }
        }
    }
}


<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Settings/HealthCheckSettingsAccessor.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Core;
using log4net;
using Newtonsoft.Json;
using System;

namespace ASC.HealthCheck.Settings
{
    public class HealthCheckSettingsAccessor
    {
        public static HealthCheckSettings GetHealthCheckSettings()
        {
            try
            {
                var healthcheckSettingsString = CoreContext.Configuration.GetSetting("HealthCheckSettings");
                return !string.IsNullOrWhiteSpace(healthcheckSettingsString) ? 
                    JsonConvert.DeserializeObject<HealthCheckSettings>(healthcheckSettingsString) : 
                    new HealthCheckSettings();
            }
            catch(Exception ex)
            {
                LogManager.GetLogger(typeof(HealthCheckSettingsAccessor)).ErrorFormat("GetHealthCheckSettings. Error! {0}, {1}", ex.ToString(), ex.InnerException != null ? ex.InnerException.ToString() : string.Empty);
                return new HealthCheckSettings();
            }
        }

        public static void SaveHealthCheckSettings(HealthCheckSettings healthcheckSettings)
        {
            try
            {
                CoreContext.Configuration.SaveSetting("HealthCheckSettings", JsonConvert.SerializeObject(healthcheckSettings));
            }
            catch (Exception ex)
            {
                LogManager.GetLogger(typeof(HealthCheckSettingsAccessor)).ErrorFormat("SaveHealthCheckSettings. Error! {0}, {1}", ex.ToString(), ex.InnerException != null ? ex.InnerException.ToString() : string.Empty);
            }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_AuthenticationInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;
    using System.Text;

    #endregion

    /// <summary>
    /// Implements SIP "Authentication-Info" value. Defined in RFC 3261.
    /// According RFC 3261 authentication info can contain Digest authentication info only.
    /// </summary>
    public class SIP_t_AuthenticationInfo : SIP_t_Value
    {
        #region Members

        private string m_CNonce;
        private string m_NextNonce;
        private int m_NonceCount = -1;
        private string m_Qop;
        private string m_ResponseAuth;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets server next predicted nonce value. Value null means that value not specified.
        /// </summary>
        public string NextNonce
        {
            get { return m_NextNonce; }

            set { m_NextNonce = value; }
        }

        /// <summary>
        /// Gets or sets QOP value. Value null means that value not specified.
        /// </summary>
        public string Qop
        {
            get { return m_Qop; }

            set { m_Qop = value; }
        }

        /// <summary>
        /// Gets or sets rspauth value. Value null means that value not specified.
        /// This can be only HEX value.
        /// </summary>
        public string ResponseAuth
        {
            get { return m_ResponseAuth; }

            set
            {
                // TODO: Check that value is hex value

                m_ResponseAuth = value;
            }
        }

        /// <summary>
        /// Gets or sets cnonce value. Value null means that value not specified.
        /// </summary>
        public string CNonce
        {
            get { return m_CNonce; }

            set { m_CNonce = value; }
        }

        /// <summary>
        /// Gets or sets nonce count. Value -1 means that value not specified.
        /// </summary>
        public int NonceCount
        {
            get { return m_NonceCount; }

            set
            {
                if (value < 0)
                {
                    m_NonceCount = -1;
                }
                else
                {
                    m_NonceCount = value;
                }
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="value">Authentication-Info valu value.</param>
        public SIP_t_AuthenticationInfo(string value)
        {
            Parse(new StringReader(value));
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "Authentication-Info" from specified value.
        /// </summary>
        /// <param name="value">SIP "Authentication-Info" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>value</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "Authentication-Info" from specified reader.
        /// </summary>
        /// <param name="reader">Reader what contains Authentication-Info value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            /*
                Authentication-Info  =  "Authentication-Info" HCOLON ainfo *(COMMA ainfo)
                ainfo                =  nextnonce / message-qop / response-auth / cnonce / nonce-count
                nextnonce            =  "nextnonce" EQUAL nonce-value
                response-auth        =  "rspauth" EQUAL response-digest
                response-digest      =  LDQUOT *LHEX RDQUOT
                nc-value             =  8LHEX
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            while (reader.Available > 0)
            {
                string word = reader.QuotedReadToDelimiter(',');
                if (word != null && word.Length > 0)
                {
                    string[] name_value = word.Split(new[] {'='}, 2);
                    if (name_value[0].ToLower() == "nextnonce")
                    {
                        NextNonce = name_value[1];
                    }
                    else if (name_value[0].ToLower() == "qop")
                    {
                        Qop = name_value[1];
                    }
                    else if (name_value[0].ToLower() == "rspauth")
                    {
                        ResponseAuth = name_value[1];
                    }
                    else if (name_value[0].ToLower() == "cnonce")
                    {
                        CNonce = name_value[1];
                    }
                    else if (name_value[0].ToLower() == "nc")
                    {
                        NonceCount = Convert.ToInt32(name_value[1]);
                    }
                    else
                    {
                        throw new SIP_ParseException("Invalid Authentication-Info value !");
                    }
                }
            }
        }

        /// <summary>
        /// Converts SIP_t_AuthenticationInfo to valid Authentication-Info value.
        /// </summary>
        /// <returns></returns>
        public override string ToStringValue()
        {
            /*
                Authentication-Info  =  "Authentication-Info" HCOLON ainfo *(COMMA ainfo)
                ainfo                =  nextnonce / message-qop / response-auth / cnonce / nonce-count
                nextnonce            =  "nextnonce" EQUAL nonce-value
                response-auth        =  "rspauth" EQUAL response-digest
                response-digest      =  LDQUOT *LHEX RDQUOT
                nc-value             =  8LHEX
            */

            StringBuilder retVal = new StringBuilder();

            if (m_NextNonce != null)
            {
                retVal.Append("nextnonce=" + m_NextNonce);
            }

            if (m_Qop != null)
            {
                if (retVal.Length > 0)
                {
                    retVal.Append(',');
                }

                retVal.Append("qop=" + m_Qop);
            }

            if (m_ResponseAuth != null)
            {
                if (retVal.Length > 0)
                {
                    retVal.Append(',');
                }

                retVal.Append("rspauth=" + TextUtils.QuoteString(m_ResponseAuth));
            }

            if (m_CNonce != null)
            {
                if (retVal.Length > 0)
                {
                    retVal.Append(',');
                }

                retVal.Append("cnonce=" + m_CNonce);
            }

            if (m_NonceCount != -1)
            {
                if (retVal.Length > 0)
                {
                    retVal.Append(',');
                }

                retVal.Append("nc=" + m_NonceCount.ToString("X8"));
            }

            return retVal.ToString();
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/js/contacts.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.Projects.Contacts = (function($) {
    var baseObject = ASC.Projects,
        currentProjectId,
        ProjectsJSResource = baseObject.Resources.ProjectsJSResource,
        displayNoneClass = "display-none";

    var teamlab;
    var $contactsForProjectPanel = $("#contactsForProjectPanel"),
        $escNoContacts = $("#escNoContacts");

    var init = function () {
        teamlab = Teamlab;
        currentProjectId = jq.getURLParam("prjID");

        if (!currentProjectId)
            return;
        
        var dataForContactSelectorInit = {
            SelectorType: -1,
            EntityType: 0,
            EntityID: 0,

            ShowOnlySelectorContent: true,
            DescriptionText: ProjectsJSResource.CRMDescrForSelector,
            DeleteContactText: "",
            AddContactText: "",
            IsInPopup: false,
            NewCompanyTitleWatermark: ProjectsJSResource.CRMCompanyName,
            NewContactFirstNameWatermark: ProjectsJSResource.CRMFirstName,
            NewContactLastNameWatermark: ProjectsJSResource.CRMLastName,

            ShowChangeButton: false,
            ShowAddButton: false,
            ShowDeleteButton: false,
            ShowContactImg: false,
            ShowNewCompanyContent: true,
            ShowNewContactContent: true,

            ExcludedContacts: [],
            HTMLParent: "#projContactSelectorParent"
        };

        if (typeof (ASC.Projects.Master.Team) == 'undefined') {
            teamlab.getPrjTeam({}, currentProjectId, {
                success: function(param, team) {
                    ASC.Projects.Master.Team = team;
                }
            });
        }

        teamlab.bind(teamlab.events.getCrmContactsForProject,
            function(param, data) {
                if (data.length !== 0) {
                    jq.extend(dataForContactSelectorInit, { presetSelectedContactsJson: jq.toJSON(data) });
                }
                window["projContactSelector"] = new ASC.CRM.ContactSelector
                    .ContactSelector("projContactSelector", dataForContactSelectorInit);

                if (data.length === 0) {
                    $escNoContacts.removeClass(displayNoneClass).show();
                } else {
                    $contactsForProjectPanel.show();
                }

                window.projContactSelector.SelectItemEvent = addContactToProject;
                ASC.CRM.ListContactView.removeMember = removeContactFromProject;

                ASC.CRM.ListContactView.CallbackMethods.render_simple_content(param, data);
            });
        //remove success
        setTimeout(function() {
            teamlab.getCrmContactsForProject(makeParams(), currentProjectId);
        }, 0);

        jq("#escNoContacts .emptyScrBttnPnl>a").bind("click", function() {
            $escNoContacts.addClass(displayNoneClass);
            $contactsForProjectPanel.show();
        });
    };

    function addContactToProject (obj, params) {
        if (jq("#contactItem_" + obj.id).length > 0) {
            return false;
        }
        var data = {
            contactid: obj.id,
            projectid: currentProjectId
        };

        if (params.newContact === true) {
            var dataRights = {
                    contactid: [obj.id],
                    isShared: false,
                    managerList: new Array(teamlab.profile.id)
                };

            teamlab.updateCrmContactRights({}, dataRights, {});
        }

        teamlab.addCrmEntityMember(makeParams(), "project", data.projectid, data.contactid, data, {
            success: function(par, contact) {
                ASC.CRM.ListContactView.CallbackMethods.addMember(par, contact);
                window.projContactSelector.SelectedContacts.push(contact.id);
            }
        });

        return true;
    };

    function removeContactFromProject (id) {
        teamlab.removeCrmEntityMember({ contactID: id }, "project", currentProjectId, id, {
            before: function(params) {
                jq("#trashImg_" + params.contactID).hide();
                jq("#loaderImg_" + params.contactID).show();
            },
            after: function(params) {

                var index = jq.inArray(params.contactID, window.projContactSelector.SelectedContacts);
                window.projContactSelector.SelectedContacts.splice(index, 1);

                jq("#contactItem_" + params.contactID).animate({ opacity: "hide" }, 500);

                setTimeout(function() {
                    jq("#contactItem_" + params.contactID).remove();
                    if (window.projContactSelector.SelectedContacts.length === 0) {
                        $contactsForProjectPanel.hide();
                        $escNoContacts.removeClass(displayNoneClass).show();
                    }
                }, 500);

            }
        });
    };

    function makeParams() {
        var param = {
            showCompanyLink: true,
            showUnlinkBtn: false
        };

        if ($contactsForProjectPanel.length) {
            param.showUnlinkBtn = true;
        }
        return param;
    }

    return {
        init: init
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/js/talk.customevents.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.CustomEvent = function (newEvents) {
  if (typeof this.supportedEvents === 'undefined') {
    this.supportedEvents = [];
  }
  if (typeof this.eventHandlers === 'undefined') {
    this.eventHandlers = [];
    this.handlerIds = {};
  }
  if (!newEvents) {
    return undefined;
  }
  if (typeof newEvents === 'object') {
    if (newEvents instanceof Array) {
      for (var i = 0, n = newEvents.length; i < n; i++) {
        if (typeof newEvents[i] === 'string') {
          this.supportedEvents.push(newEvents[i].toLowerCase());
        }
      }
    } else {
      for (var fld in newEvents) {
        if (newEvents.hasOwnProperty(fld)) {
          if (typeof newEvents[fld] === 'string') {
            this.supportedEvents.push(newEvents[fld].toLowerCase());
          }
        }
      }
    }
  } else if (typeof newEvents === 'string') {
    this.supportedEvents.push(newEvents.toLowerCase());
  }
};

window.CustomEvent.prototype.isSupported = function (eventName) {
  if (!(this.supportedEvents instanceof Array) || !(this.eventHandlers instanceof Array)) {
    return false;
  }
  var eInd = this.supportedEvents.length;
  while (eInd--) {
    if (this.supportedEvents[eInd] === eventName) {
      return true;
    }
  }
  return false;
};

window.CustomEvent.prototype.bind = function (eventName, handler, params) {
  if (!(this.supportedEvents instanceof Array) || !(this.eventHandlers instanceof Array)) {
    throw 'Invalid CustomEvent object';
  }
  if (typeof eventName !== 'string' || typeof handler !== 'function') {
    throw 'Incorrect params';
  }
  if (!this.isSupported(eventName = eventName.toLowerCase())) {
    throw 'Unsupported event ' + eventName;
  }

  params = params || {};
  var isOnceExec = params.hasOwnProperty('once') ? params.once : false;

  // generate handler mask
  var handlerType = 0;
  handlerType |= +isOnceExec * 1;  // isOnceExec - execute once

  var
    iterCount = 0,
    maxIterations = 1000,
    handlerId = Math.floor(Math.random() * 1000000);
  while (this.handlerIds.hasOwnProperty(handlerId) && iterCount++ < maxIterations) {
    handlerId = Math.floor(Math.random() * 1000000);
  }

  this.handlerIds[handlerId] = {};
  this.eventHandlers.push({id : handlerId, name : eventName, handler : handler, type : handlerType});
  return handlerId;
};

window.CustomEvent.prototype.unbind = function (handlerId) {
  if (!(this.supportedEvents instanceof Array) || !(this.eventHandlers instanceof Array)) {
    throw 'Invalid CustomEvent object';
  }
  if (typeof eventId === 'undefined') {
    return undefined;
  }
  if (this.handlerIds.hasOwnProperty(handlerId)) {
    var
      handlers = this.eventHandlers,
      handlerInd = this.eventHandlers.length;
    while (handlerInd--) {
      if (handlers[i].id === handlerId) {
        delete this.handlerIds[handlerId];
        handlers.splice(i, 1);
        break;
      }
    }
  }
};

window.CustomEvent.prototype.call = function (eventName, thisArg, argsArray) {
  if (!(this.supportedEvents instanceof Array) || !(this.eventHandlers instanceof Array)) {
    throw 'Invalid CustomEvent object';
  }
  if (typeof eventName !== 'string') {
    throw 'Incorrect params';
  }
  if (!this.isSupported(eventName = eventName.toLowerCase())) {
    throw 'Unsupported event ' + eventName;
  }

  thisArg = thisArg || window;
  argsArray = argsArray || [];
  var handlers = this.eventHandlers;
  for (var i = 0, n = handlers.length; i < n; i++) {
    if (handlers[i].name === eventName) {
        handlers[i].handler.apply(thisArg, argsArray);
      n = handlers.length;
      if (handlers[i] && handlers[i].type & 1) {
        handlers.splice(i, 1);
        i--; n--;
      }
    }
  }
};


<|start_filename|>web/core/ASC.Web.Core/Helpers/ImageHelpers.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

using ASC.Data.Storage;

namespace ASC.Web.Studio.Helpers
{
    public class ImageInfo
    {
        #region Members

        private string name;

        private int originalWidth;
        private int originalHeight;
        private int previewWidth;
        private int previewHeight;
        private int thumbnailWidth;
        private int thumbnailHeight;

        private string originalPath;
        private string previewPath;
        private string thumbnailPath;

        private string actionDate;

        #endregion

        #region Properties

        public virtual string Name
        {
            get { return name; }
            set { name = value; }
        }

        public virtual int OriginalWidth
        {
            get { return originalWidth; }
            set { originalWidth = value; }
        }
        public virtual int OriginalHeight
        {
            get { return originalHeight; }
            set { originalHeight = value; }
        }
        public virtual int PreviewWidth
        {
            get { return previewWidth; }
            set { previewWidth = value; }
        }
        public virtual int PreviewHeight
        {
            get { return previewHeight; }
            set { previewHeight = value; }
        }
        public virtual int ThumbnailWidth
        {
            get { return thumbnailWidth; }
            set { thumbnailWidth = value; }
        }
        public virtual int ThumbnailHeight
        {
            get { return thumbnailHeight; }
            set { thumbnailHeight = value; }
        }

        public virtual string OriginalPath
        {
            get { return originalPath; }
            set { originalPath = value; }
        }
        public virtual string PreviewPath
        {
            get { return previewPath; }
            set { previewPath = value; }
        }
        public virtual string ThumbnailPath
        {
            get { return thumbnailPath; }
            set { thumbnailPath = value; }
        }

        public virtual string ActionDate
        {
            get { return actionDate; }
            set { actionDate = value; }
        }

        #endregion
    }

    public class ThumbnailGenerator
    {
        readonly bool _crop = false;
        readonly int _width;
        readonly int _heigth;
        readonly int _widthPreview;
        readonly int _heightPreview;

        public IDataStore store
        {
            get;
            set;
        }

        public ThumbnailGenerator(string tmpPath, bool crop, int width, int heigth, int widthPreview, int heightPreview)
        {
            _crop = crop;
            _width = width;
            _heigth = heigth;
            _widthPreview = widthPreview;
            _heightPreview = heightPreview;
        }

        public void DoThumbnail(string path, string outputPath, ref ImageInfo imageInfo)
        {
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                DoThumbnail(fs, outputPath, ref imageInfo);
            }
        }
        public void DoThumbnail(Stream image, string outputPath, ref ImageInfo imageInfo)
        {
            using (Image img = Image.FromStream(image))
            {
                DoThumbnail(img, outputPath, ref imageInfo);
            }
        }
        public void DoThumbnail(Image image, string outputPath, ref ImageInfo imageInfo)
        {
            int realWidth = image.Width;
            int realHeight = image.Height;

            imageInfo.OriginalWidth = realWidth;
            imageInfo.OriginalHeight = realHeight;

            EncoderParameters ep = new EncoderParameters(1);

            ep.Param[0] = new EncoderParameter(Encoder.Quality, (long)90);

            ImageCodecInfo icJPG = getCodecInfo("image/jpeg");

            if (!String.IsNullOrEmpty(imageInfo.Name) && imageInfo.Name.Contains("."))
            {
                int indexDot = imageInfo.Name.ToLower().LastIndexOf(".");

                if (imageInfo.Name.ToLower().IndexOf("png", indexDot) > indexDot)
                    icJPG = getCodecInfo("image/png");
                else if (imageInfo.Name.ToLower().IndexOf("gif", indexDot) > indexDot)
                    icJPG = getCodecInfo("image/png");
            }
            Bitmap thumbnail;

            if (realWidth < _width && realHeight < _heigth)
            {
                imageInfo.ThumbnailWidth = realWidth;
                imageInfo.ThumbnailHeight = realHeight;

                if (store == null)
                    image.Save(outputPath);
                else
                {

                    MemoryStream ms = new MemoryStream();
                    image.Save(ms, icJPG, ep);
                    ms.Seek(0, SeekOrigin.Begin);
                    store.Save(outputPath, ms);
                    ms.Dispose();
                }
                return;
            }
            else
            {
                thumbnail = new Bitmap(_width < realWidth ? _width : realWidth, _heigth < realHeight ? _heigth : realHeight);

                int maxSide = realWidth > realHeight ? realWidth : realHeight;
                int minSide = realWidth < realHeight ? realWidth : realHeight;

                bool alignWidth = true;
                if (_crop)
                    alignWidth = (minSide == realWidth);
                else
                    alignWidth = (maxSide == realWidth);

                double scaleFactor = (alignWidth) ? (realWidth / (1.0 * _width)) : (realHeight / (1.0 * _heigth));

                if (scaleFactor < 1) scaleFactor = 1;

                int locationX, locationY;
                int finalWidth, finalHeigth;

                finalWidth = (int)(realWidth / scaleFactor);
                finalHeigth = (int)(realHeight / scaleFactor);


                locationY = (int)(((_heigth < realHeight ? _heigth : realHeight) / 2.0) - (finalHeigth / 2.0));
                locationX = (int)(((_width < realWidth ? _width : realWidth) / 2.0) - (finalWidth / 2.0));

                Rectangle rect = new Rectangle(locationX, locationY, finalWidth, finalHeigth);

                imageInfo.ThumbnailWidth = thumbnail.Width;
                imageInfo.ThumbnailHeight = thumbnail.Height;


                using (Graphics graphic = Graphics.FromImage(thumbnail))
                {
                    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    graphic.SmoothingMode = SmoothingMode.HighQuality;
                    graphic.DrawImage(image, rect);
                }
            }

            if (store == null)
                thumbnail.Save(outputPath, icJPG, ep);
            else
            {

                MemoryStream ms = new MemoryStream();
                thumbnail.Save(ms, icJPG, ep);
                ms.Seek(0, SeekOrigin.Begin);
                store.Save(outputPath, ms);
                ms.Dispose();
            }

            thumbnail.Dispose();
        }



        public void DoPreviewImage(string path, string outputPath, ref ImageInfo imageInfo)
        {
            using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
            {
                DoPreviewImage(fs, outputPath, ref imageInfo);
            }
        }
        public void DoPreviewImage(Stream image, string outputPath, ref ImageInfo imageInfo)
        {
            using (Image img = Image.FromStream(image))
            {
                DoPreviewImage(img, outputPath, ref imageInfo);
            }
        }
        public void DoPreviewImage(Image image, string outputPath, ref ImageInfo imageInfo)
        {
            int realWidth = image.Width;
            int realHeight = image.Height;

            int heightPreview = realHeight;
            int widthPreview = realWidth;

            EncoderParameters ep = new EncoderParameters(1);
            ImageCodecInfo icJPG = getCodecInfo("image/jpeg");
            ep.Param[0] = new EncoderParameter(Encoder.Quality, (long)90);

            if (realWidth <= _widthPreview && realHeight <= _heightPreview)
            {
                imageInfo.PreviewWidth = widthPreview;
                imageInfo.PreviewHeight = heightPreview;

                if (store == null)
                    image.Save(outputPath);
                else
                {

                    MemoryStream ms = new MemoryStream();
                    image.Save(ms, icJPG, ep);
                    ms.Seek(0, SeekOrigin.Begin);
                    store.Save(outputPath, ms);
                    ms.Dispose();
                }

                return;
            }
            else if ((double)realHeight / (double)_heightPreview > (double)realWidth / (double)_widthPreview)
            {
                if (heightPreview > _heightPreview)
                {
                    widthPreview = (int)(realWidth * _heightPreview * 1.0 / realHeight + 0.5);
                    heightPreview = _heightPreview;
                }
            }
            else
            {
                if (widthPreview > _widthPreview)
                {
                    heightPreview = (int)(realHeight * _widthPreview * 1.0 / realWidth + 0.5);
                    widthPreview = _widthPreview;
                }
            }

            imageInfo.PreviewWidth = widthPreview;
            imageInfo.PreviewHeight = heightPreview;

            Bitmap preview = new Bitmap(widthPreview, heightPreview);

            using (Graphics graphic = Graphics.FromImage(preview))
            {
                graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphic.SmoothingMode = SmoothingMode.HighQuality;
                graphic.DrawImage(image, 0, 0, widthPreview, heightPreview);
            }

            if (store == null)
                preview.Save(outputPath, icJPG, ep);
            else
            {

                MemoryStream ms = new MemoryStream();
                preview.Save(ms, icJPG, ep);
                ms.Seek(0, SeekOrigin.Begin);
                store.Save(outputPath, ms);
                ms.Dispose();
            }

            preview.Dispose();
        }

        public void RotateImage(string path, string outputPath, bool back)
        {
            try
            {
                using (var stream = store.GetReadStream(path))
                using (var image = Image.FromStream(stream))
                {
                    if (back)
                    {
                        image.RotateFlip(RotateFlipType.Rotate270FlipNone);
                    }
                    else
                    {
                        image.RotateFlip(RotateFlipType.Rotate90FlipNone);
                    }

                    var ep = new EncoderParameters(1);
                    var icJPG = getCodecInfo("image/jpeg");
                    ep.Param[0] = new EncoderParameter(Encoder.Quality, (long)100);

                    if (store == null)
                    {
                        image.Save(outputPath, icJPG, ep);
                    }
                    else
                    {
                        using (var ms = new MemoryStream())
                        {
                            image.Save(ms, icJPG, ep);
                            ms.Seek(0, SeekOrigin.Begin);
                            store.Save(outputPath, ms);
                        }
                    }

                    store.Delete(path);
                }
            }
            catch { }
        }

        private static ImageCodecInfo getCodecInfo(string mt)
        {
            ImageCodecInfo[] ici = ImageCodecInfo.GetImageEncoders();
            int idx = 0;
            for (int ii = 0; ii < ici.Length; ii++)
            {
                if (ici[ii].MimeType == mt)
                {
                    idx = ii;
                    break;
                }
            }
            return ici[idx];
        }
    }

    public class ImageHelper
    {
        public const int maxSize = 200;
        public const int maxWidthPreview = 933;
        public const int maxHeightPreview = 700;

        public static void GenerateThumbnail(string path, string outputPath, ref ImageInfo imageInfo)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxSize,
                maxSize,
                maxWidthPreview,
                maxHeightPreview);

            _generator.DoThumbnail(path, outputPath, ref imageInfo);
        }

        public static void GenerateThumbnail(string path, string outputPath, ref ImageInfo imageInfo, int maxWidth, int maxHeight)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxWidth,
                maxHeight,
                maxWidthPreview,
                maxHeightPreview);

            _generator.DoThumbnail(path, outputPath, ref imageInfo);
        }
        public static void GenerateThumbnail(Stream stream, string outputPath, ref ImageInfo imageInfo, int maxWidth, int maxHeight)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxWidth,
                maxHeight,
                maxWidthPreview,
                maxHeightPreview);

            _generator.DoThumbnail(stream, outputPath, ref imageInfo);
        }

        public static void GenerateThumbnail(string path, string outputPath, ref ImageInfo imageInfo, int maxWidth, int maxHeight, IDataStore store)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxWidth,
                maxHeight,
                maxWidthPreview,
                maxHeightPreview);
            _generator.store = store;

            _generator.DoThumbnail(path, outputPath, ref imageInfo);
        }
        public static void GenerateThumbnail(Stream stream, string outputPath, ref ImageInfo imageInfo, int maxWidth, int maxHeight, IDataStore store)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxWidth,
                maxHeight,
                maxWidthPreview,
                maxHeightPreview);
            _generator.store = store;

            _generator.DoThumbnail(stream, outputPath, ref imageInfo);
        }


        public static void GenerateThumbnail(Stream stream, string outputPath, ref ImageInfo imageInfo)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxSize,
                maxSize,
                maxWidthPreview,
                maxHeightPreview);

            _generator.DoThumbnail(stream, outputPath, ref imageInfo);
        }

        public static void GenerateThumbnail(Stream stream, string outputPath, ref ImageInfo imageInfo, IDataStore store)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxSize,
                maxSize,
                maxWidthPreview,
                maxHeightPreview);

            _generator.store = store;
            _generator.DoThumbnail(stream, outputPath, ref imageInfo);
        }


        public static void GeneratePreview(string path, string outputPath, ref ImageInfo imageInfo)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxSize,
                maxSize,
                maxWidthPreview,
                maxHeightPreview);

            _generator.DoPreviewImage(path, outputPath, ref imageInfo);

        }
        public static void GeneratePreview(Stream stream, string outputPath, ref ImageInfo imageInfo)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxSize,
                maxSize,
                maxWidthPreview,
                maxHeightPreview);

            _generator.DoPreviewImage(stream, outputPath, ref imageInfo);

        }
        public static void GeneratePreview(Stream stream, string outputPath, ref ImageInfo imageInfo, IDataStore store)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxSize,
                maxSize,
                maxWidthPreview,
                maxHeightPreview);

            _generator.store = store;
            _generator.DoPreviewImage(stream, outputPath, ref imageInfo);

        }


        public static void RotateImage(string path, string outputPath, bool back, IDataStore store)
        {
            ThumbnailGenerator _generator = new ThumbnailGenerator(null, true,
                maxSize,
                maxSize,
                maxWidthPreview,
                maxHeightPreview);
            _generator.store = store;

            _generator.RotateImage(path, outputPath, back);
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Autoreply/AddressParsers/ProjectAddressParser.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Text.RegularExpressions;
using ASC.Core.Tenants;
using ASC.Mail.Autoreply.ParameterResolvers;

namespace ASC.Mail.Autoreply.AddressParsers
{
    internal class ProjectAddressParser : AddressParser
    {
        protected override Regex GetRouteRegex()
        {
            return new Regex(@"^(?'type'task|message)_(?'projectId'\d+)$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase);
        }

        protected override ApiRequest ParseRequestInfo(IDictionary<string, string> groups, Tenant t)
        {
            var type = groups["type"];
            if (type == "task")
            {
                return new ApiRequest(string.Format("project/{0}/task", groups["projectId"]))
                {
                    Parameters = new List<RequestParameter>
                        {
                            new RequestParameter("description", new PlainTextContentResolver()),
                            new RequestParameter("deadline", new TaskDeadlineResolver()),
                            new RequestParameter("priority", new TaskPriorityResolver()),
                            new RequestParameter("milestoneid", new TaskMilestoneResolver()),
                            new RequestParameter("responsibles", new TaskResponsiblesResolver()),
                            new RequestParameter("responsible", new TaskResponsibleResolver()),
                            new RequestParameter("title", new TitleResolver(TaskDeadlineResolver.Pattern, TaskPriorityResolver.Pattern, TaskMilestoneResolver.Pattern, TaskResponsiblesResolver.Pattern))
                        }
                };
            }

            return new ApiRequest(string.Format("project/{0}/message", groups["projectId"]))
                {
                    Parameters = new List<RequestParameter>
                        {
                            new RequestParameter("title", new TitleResolver()),
                            new RequestParameter("content", new HtmlContentResolver())
                        }
                };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Masters/ClientScripts/ClientLocalizationResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web;

using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Core.Helpers;
using ASC.Web.Mail.Resources;
using ASC.Web.Studio.PublicResources;

namespace ASC.Web.Mail.Masters.ClientScripts
{
    public class ClientLocalizationResources : ClientScriptLocalization
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Mail.Resources"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            var autoreplyDaysInterval = Convert.ToInt32(ConfigurationManagerExtension.AppSettings["mail.autoreply-days-interval"] ?? "1");

            return new List<KeyValuePair<string, object>>(6)
            {
                RegisterResourceSet("MailResource", MailResource.ResourceManager),
                RegisterResourceSet("MailScriptResource", MailScriptResource.ResourceManager),
                RegisterResourceSet("MailAttachmentsResource", MailAttachmentsResource.ResourceManager),
                RegisterResourceSet("MailActionCompleteResource", MailActionCompleteResource.ResourceManager),
                RegisterResourceSet("MailAdministrationResource", MailAdministrationResource.ResourceManager),
                RegisterResourceSet("MailApiErrorsResource", MailApiErrorsResource.ResourceManager),
                RegisterResourceSet("MailApiResource",MailApiResource.ResourceManager),
                RegisterObject(new
                {
                    ErrorOpenMessageHelp = string.Format(MailScriptResource.ErrorOpenMessageHelp.HtmlEncode(), "<a href=\"" + MailPage.GetMailSupportUri() + "\" target=\"_blank\">", "</a>"),
                    ErrorParseMessageHelp = string.Format(MailScriptResource.ErrorParseMessageHelp.HtmlEncode(), "<a href=\"" + MailPage.GetMailSupportUri() + "\" target=\"_blank\">", "</a>"),
                    FilesCannotBeAttachedAsLinks = string.Format(MailResource.FilesCannotBeAttachedAsLinks_Body, "<br/>"),
                    Autoreply = string.Format(MailResource.AutoreplyInformationText, string.Format(GrammaticalHelper.ChooseNumeralCase(autoreplyDaysInterval, Resource.DrnAgoDaysI, Resource.DrnAgoDaysR1, Resource.DrnAgoDaysRm), autoreplyDaysInterval)),
                    Resource.ErrorPasswordMessage,
                    Resource.ErrorPasswordLength,
                    Resource.ErrorPasswordNoDigits,
                    Resource.ErrorPasswordNoUpperCase,
                    Resource.ErrorPasswordNoSpecialSymbols,
                    Resource.CopyEmailAndPassword,
                    Resource.EmailAndPasswordCopiedToClipboard,
                    Resource.ChangePasswordSuccess,
                    Resource.ErrorPasswordOnlyLatinLetters,
                    Resource.ErrorPasswordNoSpaces
                })
            };
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailSieveFilterOptionsData.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Mail.Enums;
using ASC.Mail.Enums.Filter;

namespace ASC.Mail.Data.Contracts
{
    [Serializable]
    [DataContract(Namespace = "", Name = "FilterOptions")]
    public class MailSieveFilterOptionsData
    {
        public MailSieveFilterOptionsData()
        {
            ApplyTo = new MailSieveFilterOptionsApplyToData();
        }

        [DataMember(Name = "matchMultiConditions")]
        public MatchMultiConditionsType MatchMultiConditions { get; set; }

        [DataMember(Name = "applyTo")]
        public MailSieveFilterOptionsApplyToData ApplyTo { get; set; }

        [DataMember(Name = "ignoreOther")]
        public bool IgnoreOther { get; set; }
    }

    [Serializable]
    [DataContract(Namespace = "", Name = "FilterOptionsApplyTo")]
    public class MailSieveFilterOptionsApplyToData
    {
        public MailSieveFilterOptionsApplyToData()
        {
            Folders = new[] { (int)FolderType.Inbox };
            Mailboxes = new int[] { };
        }

        [DataMember(Name = "folders")]
        public int[] Folders { get; set; }

        [DataMember(Name = "mailboxes")]
        public int[] Mailboxes { get; set; }

        [DataMember(Name = "withAttachments")]
        public ApplyToAttachmentsType WithAttachments { get; set; }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/News/Resources/NewsPatternResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Community.Modules.News.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class NewsPatternResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal NewsPatternResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Community.Modules.News.Resources.NewsPatternResource", typeof(NewsPatternResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.#if($FEED_TYPE == &quot;feed&quot;)New Event Added: &quot;$Caption&quot;:&quot;$URL&quot;
        ///
        ///$Date &quot;$UserName&quot;:&quot;$UserURL&quot; has added a new event: &quot;$Caption&quot;:&quot;$URL&quot;
        ///
        ///$Text
        ///
        ///&quot;Read more&quot;:&quot;$URL&quot;
        ///
        ///#end#if($FEED_TYPE == &quot;poll&quot;)New Poll Added: &quot;$Caption&quot;:&quot;$URL&quot;
        ///
        ///$Date &quot;$UserName&quot;:&quot;$UserURL&quot; has added a new poll: &quot;$Caption&quot;:&quot;$URL&quot;
        ///
        ///#foreach($Answer in $Answers)
        ///
        ///#each
        ///
        ///* $Answer
        ///
        ///#end
        ///
        ///&quot;Vote&quot;:&quot;$URL&quot;
        ///
        ///#end
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you do not want to [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_new_text {
            get {
                return ResourceManager.GetString("pattern_new_text", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to h1.#if($FEED_TYPE == &quot;poll&quot;)New Comment to Poll#end#if($FEED_TYPE == &quot;feed&quot;)New Comment to Event#end: &quot;$Caption&quot;:&quot;$URL&quot;
        ///
        ///$Date &quot;$UserName&quot;:&quot;$UserURL&quot; has added a new comment to the &quot;$Caption&quot;:&quot;$URL&quot; #if($FEED_TYPE == &quot;poll&quot;)poll#end#if($FEED_TYPE == &quot;feed&quot;)event#end:
        ///
        ///$CommentBody
        ///
        ///&quot;Read More&quot;:&quot;$CommentURL&quot;
        ///
        ///^You receive this email because you are a registered user of the &quot;${__VirtualRootPath}&quot;:&quot;${__VirtualRootPath}&quot; portal. If you do not want to receive the notifications about new comments added to this ev [rest of string was truncated]&quot;;.
        /// </summary>
        public static string pattern_new_text_comment {
            get {
                return ResourceManager.GetString("pattern_new_text_comment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. #if($FEED_TYPE == &quot;poll&quot;)New poll added#end#if($FEED_TYPE == &quot;feed&quot;)New event added#end: $Caption.
        /// </summary>
        public static string subject_new_text {
            get {
                return ResourceManager.GetString("subject_new_text", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. #if($FEED_TYPE == &quot;poll&quot;)New comment to poll#end#if($FEED_TYPE == &quot;feed&quot;)New comment to event#end: $Caption.
        /// </summary>
        public static string subject_new_text_comment {
            get {
                return ResourceManager.GetString("subject_new_text_comment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. #if($FEED_TYPE == &quot;poll&quot;)New comment to poll#end#if($FEED_TYPE == &quot;feed&quot;)New comment to event#end: [$Caption]($CommentURL).
        /// </summary>
        public static string subject_new_text_comment_tg {
            get {
                return ResourceManager.GetString("subject_new_text_comment_tg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Community. #if($FEED_TYPE == &quot;poll&quot;)New poll added#end#if($FEED_TYPE == &quot;feed&quot;)New event added#end: [$Caption]($URL).
        /// </summary>
        public static string subject_new_text_tg {
            get {
                return ResourceManager.GetString("subject_new_text_tg", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/ViewBlog.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using AjaxPro;

using ASC.Blogs.Core;
using ASC.Blogs.Core.Domain;
using ASC.Core;
using ASC.Web.Community.Modules.Blogs.Core.Resources;
using ASC.Web.Community.Product;
using ASC.Web.Core.Users;
using ASC.Web.Studio.UserControls.Common.Comments;
using ASC.Web.Studio.Utility;
using ASC.Web.Studio.Utility.HtmlUtility;

namespace ASC.Web.Community.Blogs
{
    public partial class ViewBlog : BasePage
    {
        #region Members

        private string BlogId
        {
            get { return Request.QueryString["blogid"]; }
        }

        protected string BlogTitle { get; set; }
        protected string SubscribeStatus { get; set; }

        #endregion

        #region Methods

        protected override void PageLoad()
        {
            if (String.IsNullOrEmpty(BlogId))
                Response.Redirect(Constants.DefaultPageUrl);

            Utility.RegisterTypeForAjax(typeof(Subscriber));

            var engine = GetEngine();
            ShowPost(engine);

            Title = HeaderStringHelper.GetPageTitle(mainContainer.CurrentPageCaption ?? BlogsResource.AddonName);
        }

        private void ShowPost(BlogsEngine engine)
        {
            //EditBlogPresenter presenter = new EditBlogPresenter(ctrlViewBlogView, DaoFactory.GetBlogDao());
            //ctrlViewBlogView.AttachPresenter(presenter);

            if (IsPostBack) return;

            Post post;
            try
            {
                post = engine.GetPostById(new Guid(BlogId));
            }
            catch (Exception)
            {
                post = null;
            }

            if (post != null)
            {
                ctrlViewBlogView.post = post;
                var subscriber = new Subscriber();
                var postId = String.IsNullOrEmpty(BlogId) ? new Guid() : new Guid(BlogId);
                var isBlogSubscribe = subscriber.IsCommentsSubscribe(postId);
                var subscribeTopicLink = subscriber.RenderCommentsSubscriptionLink(!isBlogSubscribe, postId);

                SubscribeLinkBlock.Text = subscribeTopicLink;

                BlogTitle = post.Title;

                var loadedComments = engine.GetPostComments(post.ID);

                commentList.Items = BuildCommentsList(post, loadedComments);

                ConfigureComments(commentList, loadedComments.Count, post);
                engine.SavePostReview(post, SecurityContext.CurrentAccount.ID);
            }
            else
            {
                ctrlViewBlogView.Visible = false;
                lblMessage.Visible = true;
                mainContainer.CurrentPageCaption = BlogsResource.AddonName;
                commentList.Visible = false;
                ConfigureComments(commentList, 0, null);
            }
        }

        private static List<CommentInfo> BuildCommentsList(Post post, List<Comment> loaded)
        {
            return BuildCommentsList(post, loaded, Guid.Empty);
        }

        private static List<CommentInfo> BuildCommentsList(Post post, List<Comment> loaded, Guid parentId)
        {
            var result = new List<CommentInfo>();
            foreach (var comment in Comment.SelectChildLevel(parentId, loaded))
            {
                var info = new CommentInfo
                {
                    CommentID = comment.ID.ToString(),
                    UserID = comment.UserID,
                    TimeStamp = comment.Datetime,
                    TimeStampStr = comment.Datetime.Ago(),
                    IsRead = true,
                    Inactive = comment.Inactive,
                    CommentBody = HtmlUtility.GetFull(comment.Content),
                    UserFullName = DisplayUserSettings.GetFullUserName(comment.UserID),
                    UserProfileLink = CommonLinkUtility.GetUserProfile(comment.UserID),
                    UserAvatarPath = UserPhotoManager.GetBigPhotoURL(comment.UserID),
                    UserPost = CoreContext.UserManager.GetUsers(comment.UserID).Title,
                    IsEditPermissions = CommunitySecurity.CheckPermissions(comment, Constants.Action_EditRemoveComment),
                    IsResponsePermissions = CommunitySecurity.CheckPermissions(post, Constants.Action_AddComment),
                    CommentList = BuildCommentsList(post, loaded, comment.ID)
                };

                result.Add(info);
            }
            return result;
        }

        private static void ConfigureComments(CommentsList commentList, int totalCount, Post postToUpdate)
        {
            CommonControlsConfigurer.CommentsConfigure(commentList);

            commentList.IsShowAddCommentBtn = CommunitySecurity.CheckPermissions(postToUpdate, Constants.Action_AddComment);
            commentList.FckDomainName = commentList.ObjectID = postToUpdate != null ? postToUpdate.ID.ToString() : "";

            commentList.BehaviorID = "commentsObj";
            commentList.ModuleName = "blogs";
            commentList.FckDomainName = "blogs_comments";

            commentList.TotalCount = totalCount;
        }

        #endregion

    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Constants.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Notify.Model;

using Action = ASC.Common.Security.Authorizing.Action;

namespace ASC.Blogs.Core
{
    public sealed class Constants
    {
        public static readonly Guid ModuleId = new Guid("{6A598C74-91AE-437d-A5F4-AD339BD11BB2}");

        public static readonly Action Action_AddPost = new Action(new Guid("{948AD738-434B-4a88-8E38-7569D332910A}"), "Add post");
        public static readonly Action Action_EditRemovePost = new Action(new Guid("{00E7DFC5-AC49-4fd3-A1D6-98D84E877AC4}"), "Edit post");
        public static readonly Action Action_AddComment = new Action(new Guid("{388C29D3-C662-4a61-BF47-FC2F7094224A}"), "Add comment");
        public static readonly Action Action_EditRemoveComment = new Action(new Guid("{724CBB75-D1C9-451e-BAE0-4DE0DB96B1F7}"), "Edit comment");

        public static INotifyAction NewPost = new NotifyAction("new post");
        public static INotifyAction NewPostByAuthor = new NotifyAction("new personal post");
        public static INotifyAction NewComment = new NotifyAction("new comment");

        public const string _NewBlogSubscribeCategory = "{9C8ED95F-07D2-42d0-B241-C0A51F7D26D5}";

        public static string TagPostSubject = "PostSubject";
        public static string TagURL = "URL";
        public static string TagUserName = "UserName";
        public static string TagUserURL = "UserURL";
        public static string TagDate = "Date";
        public static string TagPostPreview = "PostPreview";
        public static string TagCommentBody = "CommentBody";
        public static string TagCommentURL = "CommentURL";

        public static Guid ModuleID = ASC.Blogs.Core.BlogsSettings.ModuleID;
        public const int MAX_TEXT_LENGTH = 255;

        #region Virtual Path

        public const string BaseVirtualPath = "~/Products/Community/Modules/Blogs/";
        public static string GetModuleAbsolutePath(string virualPath)
        {
            if (virualPath == "" || virualPath == "/")
                virualPath = "./";

            return VirtualPathUtility.ToAbsolute(VirtualPathUtility.Combine(BaseVirtualPath, virualPath));
        }

        public static string DefaultPageUrl { get { return GetModuleAbsolutePath(""); } }
        public static string ViewBlogPageUrl { get { return GetModuleAbsolutePath("ViewBlog.aspx"); } }
        public static string UserPostsPageUrl { get { return GetModuleAbsolutePath("/") + "?userid="; } }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/LdapSettings/css/Default/ldapsettings.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.ldap-settings-crt-details-val {
    font-weight: normal;
    white-space: pre-wrap;
    white-space: -moz-pre-wrap;
    white-space: -pre-wrap;
    white-space: -o-pre-wrap;
    word-wrap: break-word;
    -ms-word-break: break-all;
}
.uppercase {
    text-transform: uppercase;
}
input[type="text" i] {
    width: 100%;
}
input[type="password" i] {
    width: 100%;
}
.ldap-settings-main-container .link.dotted {
    border-bottom: 1px dotted;
}
.requiredField .ldap-settings-text-title::after {
    color: #CC0000;
    content: " *";
    font-size: 12px;
    vertical-align: text-top;
}
.settings-checkbox-text {
    display: inline-block;
    vertical-align: top;
    margin-left: 5px;
}
.ldap-mapping-row {
    margin-bottom: 20px;
    line-height: 21px;
    position: relative;
}
.clear-fix {
    zoom: 1;
    display: block;
}
.ldap-settings-crt-serial-number {
    margin-top: 0;
}
.ldap-settings-crt-details {
    font-weight: bold;
    margin: 15px 0;
}
.ldap-mapping-row .selectBox {
    width: 164px;
    float: left;
    height: 21px;
    box-sizing: border-box;
    color: #333;
}
.selectBox {
    display: block;
    margin: 0;
    padding: 0 14px;
    height: 26px;
    line-height: 20px;
    font-size: 12px;
    border: 1px solid #c1c1c1;
    cursor: pointer;
    -moz-border-radius: 3px;
    -webkit-border-radius: 3px;
    border-radius: 3px;
}
.selectBox.disabled {
    background-color: #f4f4f4;
    cursor: default;
}
.selectBox .selectBoxValue {
    float: left;
    width: calc(100% - 8px);
    height:100%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis; 
}
.selectBox .selectBoxSwitch {
    float: right;
    width: 0;
    height: 0;
    margin-top: 8px;
    border-style: solid;
    border-width: 4px 4px 0 4px;
    border-color: #4c4c4c transparent transparent transparent;
}
.selectBox .selectOptionsBox {
    display: none;
    position: absolute;
    padding: 5px;
    background-color: #ffffff;
    border: 1px solid #c1c1c1;
    -moz-border-radius: 2px;
    -webkit-border-radius: 2px;
    border-radius: 2px;
    -moz-box-shadow: 1px 1px 8px rgba(0,0,0,0.2);
    -webkit-box-shadow: 1px 1px 8px rgba(0,0,0,0.2);
    box-shadow: 1px 1px 8px rgba(0,0,0,0.2);
    z-index: 1000;
}
.ldap-mapping-row .selectBox .selectOptionsBox {
    width: 164px;
    box-sizing: border-box;
}
.selectBox .selectOptionsBox .selectOptionsInnerBox {
    max-height: 200px;
    padding-right: 20px;
    overflow-y: auto;
}

.selectBox .selectOptionsBox .selectOptionsInnerBox .option.selected {
    color: #2e94c9;
}

.selectBox .selectOptionsBox .selectOptionsInnerBox .option {
    display: block;
    text-decoration: none;
    padding: 2px 14px 2px 4px;
    min-width: 50px;
}

.ldap-mapping-row .ldap-mapping-remove-row {
    position: absolute;
    right: -32px;
}

#ldapMappingAddBtn{
    margin-bottom: 20px;
}
.unselectable {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.remove-btn-icon {
    cursor: pointer;
    display: inline-block;
    height: 16px;
    width: 16px;
    vertical-align: middle;
}
.remove-btn-icon.disabled{
    cursor:default;
}

.remove-btn-icon svg {
    fill: #CECECE;
}
.remove-btn-icon svg path:not(:first-child) {
    stroke: #CECECE;
}


#ldapMappingSettings .comboBox {
    width: 170px;
    height: 21px;
    float: left;
}
#ldapMappingSettings input {
    width: 164px;
    margin-left: 10px;
}
#ldapSettingsUserFilter, #ldapSettingsGroupFilter {
    width: 100%;
    height: 80px;
    resize: none;
}

.ldap-settings-main-container{
    margin-top: 22px;
}

.ldap-settings-main-container .HelpCenterSwitcher{
    margin: 0px 0px -3px;
}

.ldap-settings-user-container, .ldap-settings-group-container, .ldap-settings-auth-container {
    clear: both;
}

.ldap-settings-user-container, .ldap-settings-group-container {
    margin: 0 0 42px 0;
}
.ldap-settings-user-container.ldap-settings-authentication {
    margin-bottom: 28px;
}

.ldap-settings-column {
    float: left;
    margin: 0 40px 0 0;
}

.ldap-settings-second-column {
    float: left;
}

.ldap-settings-title {
    display: inline-block;
    margin: 0 0 20px 0;
}
.ldap-settings-spoiler-link {
    margin-left: 16px;
}

.ldap-settings-empty-field, .ldap-settings-incorrect-number {
    float: right;
}

.ldap-settings-disabled, .ldap-settings-disabled-all {
    color: #d1d1d1;
    cursor: default;
    -moz-user-select:-moz-none;
    -moz-user-select: none;
    -o-user-select:none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

.ldap-settings-label-checkbox {
    margin: 0 2px 22px 0;
    float: left;
    clear: both;
}

.ldap-settings-label-checkbox input {
    margin: 0 8px 2px 0;
    vertical-align: middle;
}

.ldap-settings-block {
    margin: 14px 0 0 0;
}

.ldap-settings-text {
    padding: 0 0 4px 0;
    font-weight: bold;
}


.ldap-settings-helper-help-class {
    float: left;
}

.ldap-settings-sync-progressbar-container,
.ldap-settings-progressbar-container {
    width: 355px;
    margin: 20px 0 0 0;
}

.ldap-settings-descr {
    margin-bottom: 28px;
}
.ldap-settings_warnings {
    margin-bottom: 14px;
}

.ldap-settings_warnings .header-base-medium {
    font-size: 12px;
}

#ldapSettingsSpoiler .middle-button-container .button {
    margin-bottom: 5px;
}

.ldap-settings-security-container .ldap-settings-label-checkbox,
.ldap-attributes-container .ldap-settings-text,
.ldap-settings-advanced-container .ldap-settings-text{
    margin-bottom: 10px;
}

.ldap-settings-user-container .ldap-settings-block:first-child{
    margin-top: 0px;
}
#ldapMappingAddBtn.disabled:hover {
    background-color: #ebebeb;
    border-color: #c4c4c4;
    cursor: default;
}
.ldap-settings-user-container.ldap-attributes-container{
    margin-bottom: 22px;
}

.ldap-settings-group-membership .ldap-settings-label-checkbox,
.ldap-settings-authentication .ldap-settings-label-checkbox,
.ldap-settings-authentication .ldap-settings-auth-container .ldap-settings-block {
    margin-bottom: 14px;
}

.ldap-settings-main-container .middle-button-container{
    margin-top: 10px;
}

#ldapSettingsAutoSyncCron{
    margin-top: 15px;
}
.cronHumanReadableContainer {
    margin-bottom: 40px;
}
#ldapSettingsAutoSyncCron .jqCron-selector-title {
    padding: 2px 2px;
    font-size: 12px;
}

#ldapSettingsAutoSyncCron .jqCron-selector-list {
    font-size: 12px;
    padding: 3px;
    top: 10px;
}
#ldapSettingsAutoSyncCron .ldap-settings-label-checkbox {
    margin: 0 2px 14px 0;
}
#ldapSettingsSyncBtn {
    margin-top: 10px;
}
#ldapCronHumanText {
    display: block;
    margin-bottom: 21px;
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/js/peopleactions.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


;
window.peopleActions = (function() {
    function getProfile(id) {
        var 
            profiles = ASC.People.model.profiles || [],
            profilesInd;

        var profilesInd = profiles.length;
        while (profilesInd--) {
            if (profiles[profilesInd].id == id) {
                return profiles[profilesInd];
            }
        }
        return null;
    };
    
    var callMethodByClassname = function(classname, thisArg, argsArray) {
        if ((' ' + classname + ' ').indexOf(' disabled ') !== -1) {
            return undefined;
        }

        var cls = '',
            classesInd = 0,
            classes = typeof classname === 'string' ? classname.split(/\s+/) : [],
            classesInd = classes ? classes.length : 0;
        while (classesInd--) {
            cls = classes[classesInd].replace(/-/g, '_');
            if (typeof peopleActions[cls] === 'function') {
                peopleActions[cls].apply(thisArg, argsArray);
            }
        }
    };
	
	var callbackAddUser = function(result) {
        var $o = jq.tmpl("userListTemplate", { users: [result.Data], isAdmin: Teamlab.profile.isAdmin || window.ASC.Resources.Master.IsProductAdmin });

        if (jq("#peopleData tr.profile").length == 0) {
            jq("#emptyContentForPeopleFilter").addClass("display-none");
            jq(".people-content").removeClass("display-none");
        }
        jq("#peopleData").prepend($o);
        ASC.Controls.AnchorController.trigger();
    };

    return {
        callMethodByClassname: callMethodByClassname,

        add_group: function(evt, $btn) {
            DepartmentManagement.AddDepartmentOpenDialog();
        },

        update_group: function(evt, $btn) {
            ASC.People.PeopleController.getEditGroup();
        },

        delete_group: function(evt, $btn) {
            jq("#confirmationDeleteDepartmentPanel .confirmationAction").html(jq.format(ASC.Resources.Master.ConfirmRemoveDepartment, "<b>" + jq(".profile-title:first>.header").html() + "</b>"));
            jq("#confirmationDeleteDepartmentPanel .middle-button-container>.button.blue.middle").unbind("click").bind("click", function() {
                ASC.People.PeopleController.deleteGroup();
            });
            StudioBlockUIManager.blockUI("#confirmationDeleteDepartmentPanel", 500);
            PopupKeyUpActionProvider.ClearActions();
            PopupKeyUpActionProvider.EnterAction = 'ASC.People.PeopleController.deleteGroup();';
        },

        add_profiles: function(evt, $btn) {
            location.href = "/Products/People/Import.aspx";
        },

        send_invites: function(evt, $btn) {
            InvitesResender.Show();
        },

        send_email: function(evt, $btn) {
            var userId = $btn.parents('tr.item.profile:first').attr('data-id');
            if (userId) {
                var email = $btn.parents('tr.item.profile:first').attr('data-email');
                if (email) {
                    window.open('../../addons/mail/#composeto/email=' + email, "_blank");
                }
                //var profile = getProfile(userId);
                //if (profile) {
                //  location.href = 'mailto:' + profile.email;
                //}
            }
        },
		
		open_dialog: function(evt, $btn) {
            var userId = $btn.parents('tr.item.profile:first').attr('data-id');
            if (userId) {
                var userName = $btn.parents('tr.item.profile:first').attr('data-username');
                if (userName) {
                    try {
                        ASC.Controls.JabberClient.open(userName);
                    } catch (err) { }
                }
                //var profile = getProfile(userId);
                //if (profile) {
                //  try { ASC.Controls.JabberClient.open(profile.userName) } catch (err) {console.log(err)}
                //}
            }
        },

        invite_link: function (evt, $btn) {
            PopupKeyUpActionProvider.ClearActions();
            jq("#otherActions").hide();
            StudioBlockUIManager.blockUI("#inviteLinkContainer", 550);
            ASC.InvitePanel.bindClipboardEvent();
        }
    };
})();

<|start_filename|>common/ASC.Data.Storage/S3/UnencodedUri.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

namespace ASC.Data.Storage.S3
{
    public class UnencodedUri : Uri
    {
        public UnencodedUri(string uriString)
            : base(uriString)
        {
        }

        public UnencodedUri(string uriString, UriKind uriKind)
            : base(uriString, uriKind)
        {
        }

        public UnencodedUri(Uri baseUri, string relativeUri)
            : base(baseUri, relativeUri)
        {
        }

        public UnencodedUri(Uri baseUri, Uri relativeUri)
            : base(baseUri, relativeUri)
        {
        }

        protected UnencodedUri(SerializationInfo serializationInfo, StreamingContext streamingContext)
            : base(serializationInfo, streamingContext)
        {
        }

        public override string ToString()
        {
            return OriginalString;
        }
    }
}


<|start_filename|>common/ASC.Common/Data/Sql/Dialects/MySQLDialect.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Data;

namespace ASC.Common.Data.Sql.Dialects
{
    class MySQLDialect : ISqlDialect
    {
        public string IdentityQuery
        {
            get { return "last_insert_id()"; }
        }

        public string Autoincrement
        {
            get { return "auto_increment"; }
        }

        public virtual string InsertIgnore
        {
            get { return "insert ignore"; }
        }

        public bool SupportMultiTableUpdate
        {
            get { return true; }
        }

        public bool SeparateCreateIndex
        {
            get { return false; }
        }

        public string DbTypeToString(DbType type, int size, int precision)
        {
            switch (type)
            {
                case DbType.Guid:
                    return "char(38)";

                case DbType.AnsiString:
                case DbType.String:
                    if (size <= 8192) return string.Format("VARCHAR({0})", size);
                    else if (size <= UInt16.MaxValue) return "TEXT";
                    else if (size <= ((int)Math.Pow(2, 24) - 1)) return "MEDIUMTEXT";
                    else return "LONGTEXT";

                case DbType.AnsiStringFixedLength:
                case DbType.StringFixedLength:
                    return string.Format("CHAR({0})", size);

                case DbType.Xml:
                    return "MEDIUMTEXT";

                case DbType.Binary:
                case DbType.Object:
                    if (size <= 8192) return string.Format("BINARY({0})", size);
                    else if (size <= UInt16.MaxValue) return "BLOB";
                    else if (size <= ((int)Math.Pow(2, 24) - 1)) return "MEDIUMBLOB";
                    else return "LONGBLOB";

                case DbType.Boolean:
                case DbType.Byte:
                    return "TINYINY";
                case DbType.SByte:
                    return "TINYINY UNSIGNED";

                case DbType.Int16:
                    return "SMALLINT";
                case DbType.UInt16:
                    return "SMALLINT UNSIGNED";

                case DbType.Int32:
                    return "INT";
                case DbType.UInt32:
                    return "INT UNSIGNED";

                case DbType.Int64:
                    return "BIGINT";
                case DbType.UInt64:
                    return "BIGINT UNSIGNED";

                case DbType.Date:
                    return "DATE";
                case DbType.DateTime:
                case DbType.DateTime2:
                    return "DATETIME";
                case DbType.Time:
                    return "TIME";

                case DbType.Decimal:
                    return string.Format("DECIMAL({0},{1})", size, precision);
                case DbType.Double:
                    return "DOUBLE";
                case DbType.Single:
                    return "FLOAT";

                default:
                    throw new ArgumentOutOfRangeException(type.ToString());
            }
        }

        public IsolationLevel GetSupportedIsolationLevel(IsolationLevel il)
        {
            return il;
        }

        public string UseIndex(string index)
        {
            return string.Format("use index ({0})", index);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/skins/default/filetype_style.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.ftFile_21,
.ftFile_32,
.ftFolder_21,
.ftFolder_32 {
    background-repeat: no-repeat;
    background-position: 0 0;
    background-color: transparent;
}
.ftFile_32,
.ftFolder_32 {
    background-position: 0 0;
    height: 32px;
    width: 32px;
}
.ftFile_21,
.ftFolder_21,
.compact .ftFile_32,
.compact .ftFolder_32 {
    background-position: 0 -39px;
    height: 21px;
    width: 21px;
}
.compact .ftFolder_32 {
    background-position: 50% 50%;
    background-size:100%;
}
/*folder default*/
.ftFolder_21,
.ftFolder_32 {
    background: url('images/svg/documents/folder.svg') no-repeat;
    background-position: 50% 50%;
    left: 1px;
    background-size: 32px;
}
/*file default*/
.ftFile_21,
.ftFile_32{
    background-image: url('images/filetype/file.png');
    background-size: 32px 60px;
}

/*".zip", ".rar", ".ace", ".arc", ".arj", ".bh", ".cab", ".enc", ".gz", ".ha", ".jar", ".lha", ".lzh", ".pak", ".pk3", ".tar", ".tgz", ".uu", ".uue", ".xxe", ".z", ".zoo"*/
.ft_Archive{background-image:url('images/filetype/file_archive.png');}
.ft_Avi{background-image:url('images/filetype/file_avi.png');}
.ft_Cal{background-image:url('images/filetype/file_cal.png');}
.ft_Csv{background-image:url('images/filetype/file_csv.png');}
.ft_Djvu{background-image:url('images/filetype/file_djvu.png');}
.ft_Doc{background-image:url('images/filetype/file_doc.png');}
.ft_Docm{background-image:url('images/filetype/file_docm.png');}
.ft_Doct{background-image:url('images/filetype/file_doct.png');}
.ft_Docx{background-image:url('images/filetype/file_docx.png');}
.ft_Dot{background-image:url('images/filetype/file_dot.png');}
.ft_Dotm{background-image:url('images/filetype/file_dotm.png');}
.ft_Dotx{background-image:url('images/filetype/file_dotx.png');}
.ft_Dvd{background-image:url('images/filetype/file_dvd.png');}
/*.ft_Ebook{background-image:url('images/filetype/file_ebook.png');}*/
.ft_Epub{background-image:url('images/filetype/file_epub.png');}
.ft_Fb2{background-image:url('images/filetype/file_fb2.png');}
.ft_Flv{background-image:url('images/filetype/file_flv.png');}
.ft_Fodp{background-image:url('images/filetype/file_fodp.png');}
.ft_Fods{background-image:url('images/filetype/file_fods.png');}
.ft_Fodt{background-image:url('images/filetype/file_fodt.png');}
.ft_Gdoc{background-image:url('images/filetype/file_gdoc.png');}
.ft_Gsheet{background-image:url('images/filetype/file_gsheet.png');}
.ft_Gslides{background-image:url('images/filetype/file_gslides.png');}
.ft_Htm{background-image:url('images/filetype/file_htm.png');}
.ft_Html{background-image:url('images/filetype/file_html.png');}
.ft_Iaf{background-image:url('images/filetype/file_iaf.png');}
.ft_Ics{background-image:url('images/filetype/file_ics.png');}
/*".bmp", ".cod", ".gif", ".ief", ".jpe", ".jpeg", ".jpg", ".jfif", ".tiff", ".tif", ".cmx", ".ico", ".png", ".pnm", ".pbm", ".ppm", ".rgb", ".xbm", ".xpm", ".xwd"*/
.ft_Image{background-image:url('images/filetype/file_image.png');}
.ft_M2ts{background-image:url('images/filetype/file_m2ts.png');}
.ft_Mht{background-image:url('images/filetype/file_mht.png');}
.ft_Mkv{background-image:url('images/filetype/file_mkv.png');}
.ft_Mov{background-image:url('images/filetype/file_mov.png');}
.ft_Mp4{background-image:url('images/filetype/file_mp4.png');}
.ft_Mpg{background-image:url('images/filetype/file_mpg.png');}
.ft_Odp{background-image:url('images/filetype/file_odp.png');}
.ft_Ods{background-image:url('images/filetype/file_ods.png');}
.ft_Odt{background-image:url('images/filetype/file_odt.png');}
.ft_Otp{background-image:url('images/filetype/file_otp.png');}
.ft_Ots{background-image:url('images/filetype/file_ots.png');}
.ft_Ott{background-image:url('images/filetype/file_ott.png');}
.ft_Pdf{background-image:url('images/filetype/file_pdf.png');}
.ft_Pot{background-image:url('images/filetype/file_pot.png');}
.ft_Potm{background-image:url('images/filetype/file_potm.png');}
.ft_Potx{background-image:url('images/filetype/file_potx.png');}
.ft_Pps{background-image:url('images/filetype/file_pps.png');}
.ft_Ppsm{background-image:url('images/filetype/file_ppsm.png');}
.ft_Ppsx{background-image:url('images/filetype/file_ppsx.png');}
.ft_Ppt{background-image:url('images/filetype/file_ppt.png');}
.ft_Pptm{background-image:url('images/filetype/file_pptm.png');}
.ft_Pptt{background-image:url('images/filetype/file_pptt.png');}
.ft_Pptx{background-image:url('images/filetype/file_pptx.png');}
.ft_Rtf{background-image:url('images/filetype/file_rtf.png');}
/*".mp3", ".wav", ".pcm", ".aiff", ".3gp", ".flac", ".fla", ".cda"*/
.ft_Sound{background-image:url('images/filetype/file_sound.png');}
.ft_SoundUnk{background-image:url('images/filetype/file_soundunk.png');}
.ft_Svg{background-image:url('images/filetype/file_svg.png');}
.ft_Txt{background-image:url('images/filetype/file_txt.png');}
.ft_Video{background-image:url('images/filetype/file_video.png');}
.ft_VideoUnk{background-image:url('images/filetype/file_videounk.png');}
.ft_Xls{background-image:url('images/filetype/file_xls.png');}
.ft_Xlsm{background-image:url('images/filetype/file_xlsm.png');}
.ft_Xlst{background-image:url('images/filetype/file_xlst.png');}
.ft_Xlsx{background-image:url('images/filetype/file_xlsx.png');}
.ft_Xlt{background-image:url('images/filetype/file_xlt.png');}
.ft_Xltm{background-image:url('images/filetype/file_xltm.png');}
.ft_Xltx{background-image:url('images/filetype/file_xltx.png');}
.ft_Xml{background-image:url('images/filetype/file_xml.png');}
.ft_Xps{background-image:url('images/filetype/file_xps.png');}

.thumbnails .thumb-img.ftFile_32,
.thumbnails .thumb-img.ftFolder_32 {
    background-position: 50% 50%;
    background-size: 0;
}
.thumbnails .thumb-img.ftFile_32 {
    background-image: url('images/filetype/thumb/file.png');
}
.thumbnails .thumb-img.ftFolder_32 {
    background-image: url(images/filetype/thumb/folder.png);
}
.thumbnails .thumb-img:empty,
.thumbnails .thumb-img.ftFolder_21,
.thumbnails .thumb-img.ftFolder_32 {
    background-size: 96px;
}


.thumbnails .thumb-img.ft_Archive{background-image:url('images/filetype/thumb/file_archive.png');}
.thumbnails .thumb-img.ft_Avi{background-image:url('images/filetype/thumb/file_avi.png');}
.thumbnails .thumb-img.ft_Cal{background-image:url('images/filetype/thumb/file_cal.png');}
.thumbnails .thumb-img.ft_Csv{background-image:url('images/filetype/thumb/file_csv.png');}
.thumbnails .thumb-img.ft_Djvu{background-image:url('images/filetype/thumb/file_djvu.png');}
.thumbnails .thumb-img.ft_Doc{background-image:url('images/filetype/thumb/file_doc.png');}
.thumbnails .thumb-img.ft_Docm{background-image:url('images/filetype/thumb/file_docm.png');}
.thumbnails .thumb-img.ft_Doct{background-image:url('images/filetype/thumb/file_doct.png');}
.thumbnails .thumb-img.ft_Docx{background-image:url('images/filetype/thumb/file_docx.png');}
.thumbnails .thumb-img.ft_Dot{background-image:url('images/filetype/thumb/file_dot.png');}
.thumbnails .thumb-img.ft_Dotm{background-image:url('images/filetype/thumb/file_dotm.png');}
.thumbnails .thumb-img.ft_Dotx{background-image:url('images/filetype/thumb/file_dotx.png');}
.thumbnails .thumb-img.ft_Dvd{background-image:url('images/filetype/thumb/file_dvd.png');}
/*.thumbnails .thumb-img.ft_Ebook{background-image:url('images/filetype/thumb/file_ebook.png');}*/
.thumbnails .thumb-img.ft_Epub{background-image:url('images/filetype/thumb/file_epub.png');}
.thumbnails .thumb-img.ft_Fb2{background-image:url('images/filetype/thumb/file_fb2.png');}
.thumbnails .thumb-img.ft_Flv{background-image:url('images/filetype/thumb/file_flv.png');}
.thumbnails .thumb-img.ft_Fodp{background-image:url('images/filetype/thumb/file_fodp.png');}
.thumbnails .thumb-img.ft_Fods{background-image:url('images/filetype/thumb/file_fods.png');}
.thumbnails .thumb-img.ft_Fodt{background-image:url('images/filetype/thumb/file_fodt.png');}
.thumbnails .thumb-img.ft_Gdoc{background-image:url('images/filetype/thumb/file_gdoc.png');}
.thumbnails .thumb-img.ft_Gsheet{background-image:url('images/filetype/thumb/file_gsheet.png');}
.thumbnails .thumb-img.ft_Gslides{background-image:url('images/filetype/thumb/file_gslides.png');}
.thumbnails .thumb-img.ft_Htm{background-image:url('images/filetype/thumb/file_htm.png');}
.thumbnails .thumb-img.ft_Html{background-image:url('images/filetype/thumb/file_html.png');}
.thumbnails .thumb-img.ft_Iaf{background-image:url('images/filetype/thumb/file_iaf.png');}
.thumbnails .thumb-img.ft_Ics{background-image:url('images/filetype/thumb/file_ics.png');}
.thumbnails .thumb-img.ft_Image{background-image:url('images/filetype/thumb/file_image.png');}
.thumbnails .thumb-img.ft_M2ts{background-image:url('images/filetype/thumb/file_m2ts.png');}
.thumbnails .thumb-img.ft_Mht{background-image:url('images/filetype/thumb/file_mht.png');}
.thumbnails .thumb-img.ft_Mkv{background-image:url('images/filetype/thumb/file_mkv.png');}
.thumbnails .thumb-img.ft_Mov{background-image:url('images/filetype/thumb/file_mov.png');}
.thumbnails .thumb-img.ft_Mp4{background-image:url('images/filetype/thumb/file_mp4.png');}
.thumbnails .thumb-img.ft_Mpg{background-image:url('images/filetype/thumb/file_mpg.png');}
.thumbnails .thumb-img.ft_Odp{background-image:url('images/filetype/thumb/file_odp.png');}
.thumbnails .thumb-img.ft_Ods{background-image:url('images/filetype/thumb/file_ods.png');}
.thumbnails .thumb-img.ft_Odt{background-image:url('images/filetype/thumb/file_odt.png');}
.thumbnails .thumb-img.ft_Otp{background-image:url('images/filetype/thumb/file_otp.png');}
.thumbnails .thumb-img.ft_Ots{background-image:url('images/filetype/thumb/file_ots.png');}
.thumbnails .thumb-img.ft_Ott{background-image:url('images/filetype/thumb/file_ott.png');}
.thumbnails .thumb-img.ft_Pdf{background-image:url('images/filetype/thumb/file_pdf.png');}
.thumbnails .thumb-img.ft_Pot{background-image:url('images/filetype/thumb/file_pot.png');}
.thumbnails .thumb-img.ft_Potm{background-image:url('images/filetype/thumb/file_potm.png');}
.thumbnails .thumb-img.ft_Potx{background-image:url('images/filetype/thumb/file_potx.png');}
.thumbnails .thumb-img.ft_Pps{background-image:url('images/filetype/thumb/file_pps.png');}
.thumbnails .thumb-img.ft_Ppsm{background-image:url('images/filetype/thumb/file_ppsm.png');}
.thumbnails .thumb-img.ft_Ppsx{background-image:url('images/filetype/thumb/file_ppsx.png');}
.thumbnails .thumb-img.ft_Ppt{background-image:url('images/filetype/thumb/file_ppt.png');}
.thumbnails .thumb-img.ft_Pptm{background-image:url('images/filetype/thumb/file_pptm.png');}
.thumbnails .thumb-img.ft_Pptt{background-image:url('images/filetype/thumb/file_pptt.png');}
.thumbnails .thumb-img.ft_Pptx{background-image:url('images/filetype/thumb/file_pptx.png');}
.thumbnails .thumb-img.ft_Rtf{background-image:url('images/filetype/thumb/file_rtf.png');}
.thumbnails .thumb-img.ft_Sound{background-image:url('images/filetype/thumb/file_sound.png');}
.thumbnails .thumb-img.ft_SoundUnk{background-image:url('images/filetype/thumb/file_soundunk.png');}
.thumbnails .thumb-img.ft_Svg{background-image:url('images/filetype/thumb/file_svg.png');}
.thumbnails .thumb-img.ft_Txt{background-image:url('images/filetype/thumb/file_txt.png');}
.thumbnails .thumb-img.ft_Video{background-image:url('images/filetype/thumb/file_video.png');}
.thumbnails .thumb-img.ft_VideoUnk{background-image:url('images/filetype/thumb/file_videounk.png');}
.thumbnails .thumb-img.ft_Xls{background-image:url('images/filetype/thumb/file_xls.png');}
.thumbnails .thumb-img.ft_Xlsm{background-image:url('images/filetype/thumb/file_xlsm.png');}
.thumbnails .thumb-img.ft_Xlst{background-image:url('images/filetype/thumb/file_xlst.png');}
.thumbnails .thumb-img.ft_Xlsx{background-image:url('images/filetype/thumb/file_xlsx.png');}
.thumbnails .thumb-img.ft_Xlt{background-image:url('images/filetype/thumb/file_xlt.png');}
.thumbnails .thumb-img.ft_Xltm{background-image:url('images/filetype/thumb/file_xltm.png');}
.thumbnails .thumb-img.ft_Xltx{background-image:url('images/filetype/thumb/file_xltx.png');}
.thumbnails .thumb-img.ft_Xml{background-image:url('images/filetype/thumb/file_xml.png');}
.thumbnails .thumb-img.ft_Xps{background-image:url('images/filetype/thumb/file_xps.png');}

/*******************************************************************************
   For Retina
*******************************************************************************/
@media only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (   min--moz-device-pixel-ratio: 2),
only screen and (     -o-min-device-pixel-ratio: 2/1),
only screen and (        min-device-pixel-ratio: 2),
only screen and (                min-resolution: 192dpi),
only screen and (                min-resolution: 2dppx)
{
.ftFile_21,
.ftFile_32 {
    background-image:url('images/filetype/retina/file.png');
}
.ft_Archive{background-image:url('images/filetype/retina/file_archive.png');}
.ft_Avi{background-image:url('images/filetype/retina/file_avi.png');}
.ft_Cal{background-image:url('images/filetype/retina/file_cal.png');}
.ft_Csv{background-image:url('images/filetype/retina/file_csv.png');}
.ft_Djvu{background-image:url('images/filetype/retina/file_djvu.png');}
.ft_Doc{background-image:url('images/filetype/retina/file_doc.png');}
.ft_Docm{background-image:url('images/filetype/retina/file_docm.png');}
.ft_Doct{background-image:url('images/filetype/retina/file_doct.png');}
.ft_Docx{background-image:url('images/filetype/retina/file_docx.png');}
.ft_Dot{background-image:url('images/filetype/retina/file_dot.png');}
.ft_Dotm{background-image:url('images/filetype/retina/file_dotm.png');}
.ft_Dotx{background-image:url('images/filetype/retina/file_dotx.png');}
.ft_Dvd{background-image:url('images/filetype/retina/file_dvd.png');}
/*.ft_Ebook{background-image:url('images/filetype/retina/file_ebook.png');}*/
.ft_Epub{background-image:url('images/filetype/retina/file_epub.png');}
.ft_Fb2{background-image:url('images/filetype/retina/file_fb2.png');}
.ft_Flv{background-image:url('images/filetype/retina/file_flv.png');}
.ft_Fodp{background-image:url('images/filetype/retina/file_fodp.png');}
.ft_Fods{background-image:url('images/filetype/retina/file_fods.png');}
.ft_Fodt{background-image:url('images/filetype/retina/file_fodt.png');}
.ft_Gdoc{background-image:url('images/filetype/retina/file_gdoc.png');}
.ft_Gsheet{background-image:url('images/filetype/retina/file_gsheet.png');}
.ft_Gslides{background-image:url('images/filetype/retina/file_gslides.png');}
.ft_Htm{background-image:url('images/filetype/retina/file_htm.png');}
.ft_Html{background-image:url('images/filetype/retina/file_html.png');}
.ft_Iaf{background-image:url('images/filetype/retina/file_iaf.png');}
.ft_Ics{background-image:url('images/filetype/retina/file_ics.png');}
.ft_Image{background-image:url('images/filetype/retina/file_image.png');}
.ft_M2ts{background-image:url('images/filetype/retina/file_m2ts.png');}
.ft_Mht{background-image:url('images/filetype/retina/file_mht.png');}
.ft_Mkv{background-image:url('images/filetype/retina/file_mkv.png');}
.ft_Mov{background-image:url('images/filetype/retina/file_mov.png');}
.ft_Mp4{background-image:url('images/filetype/retina/file_mp4.png');}
.ft_Mpg{background-image:url('images/filetype/retina/file_mpg.png');}
.ft_Odp{background-image:url('images/filetype/retina/file_odp.png');}
.ft_Ods{background-image:url('images/filetype/retina/file_ods.png');}
.ft_Odt{background-image:url('images/filetype/retina/file_odt.png');}
.ft_Otp{background-image:url('images/filetype/retina/file_otp.png');}
.ft_Ots{background-image:url('images/filetype/retina/file_ots.png');}
.ft_Ott{background-image:url('images/filetype/retina/file_ott.png');}
.ft_Pdf{background-image:url('images/filetype/retina/file_pdf.png');}
.ft_Pot{background-image:url('images/filetype/retina/file_pot.png');}
.ft_Potm{background-image:url('images/filetype/retina/file_potm.png');}
.ft_Potx{background-image:url('images/filetype/retina/file_potx.png');}
.ft_Pps{background-image:url('images/filetype/retina/file_pps.png');}
.ft_Ppsm{background-image:url('images/filetype/retina/file_ppsm.png');}
.ft_Ppsx{background-image:url('images/filetype/retina/file_ppsx.png');}
.ft_Ppt{background-image:url('images/filetype/retina/file_ppt.png');}
.ft_Pptm{background-image:url('images/filetype/retina/file_pptm.png');}
.ft_Pptt{background-image:url('images/filetype/retina/file_pptt.png');}
.ft_Pptx{background-image:url('images/filetype/retina/file_pptx.png');}
.ft_Rtf{background-image:url('images/filetype/retina/file_rtf.png');}
.ft_Sound{background-image:url('images/filetype/retina/file_sound.png');}
.ft_SoundUnk{background-image:url('images/filetype/retina/file_soundunk.png');}
.ft_Svg{background-image:url('images/filetype/retina/file_svg.png');}
.ft_Txt{background-image:url('images/filetype/retina/file_txt.png');}
.ft_Video{background-image:url('images/filetype/retina/file_video.png');}
.ft_VideoUnk{background-image:url('images/filetype/retina/file_videounk.png');}
.ft_Xls{background-image:url('images/filetype/retina/file_xls.png');}
.ft_Xlsm{background-image:url('images/filetype/retina/file_xlsm.png');}
.ft_Xlst{background-image:url('images/filetype/retina/file_xlst.png');}
.ft_Xlsx{background-image:url('images/filetype/retina/file_xlsx.png');}
.ft_Xlt{background-image:url('images/filetype/retina/file_xlt.png');}
.ft_Xltm{background-image:url('images/filetype/retina/file_xltm.png');}
.ft_Xltx{background-image:url('images/filetype/retina/file_xltx.png');}
.ft_Xml{background-image:url('images/filetype/retina/file_xml.png');}
.ft_Xps{background-image:url('images/filetype/retina/file_xps.png');}
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/News/Code/PollVoteHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Core;
using ASC.Web.Community.Modules.News.Resources;
using ASC.Web.Community.News.Code.DAO;
using ASC.Web.Studio.UserControls.Common.PollForm;

namespace ASC.Web.Community.News.Code
{
    public class PollVoteHandler : IVoteHandler
    {
        #region IVoteHandler Members

        public bool VoteCallback(string pollID, List<string> selectedVariantIDs, string additionalParams, out string errorMessage)
        {
            errorMessage = string.Empty;
            var userAnswersIDs = new List<long>();
            selectedVariantIDs.ForEach(strId => { if (!string.IsNullOrEmpty(strId)) userAnswersIDs.Add(Convert.ToInt64(strId)); });
            long pollId = Convert.ToInt64(additionalParams);
            var storage = FeedStorageFactory.Create();

            return VoteForPoll(userAnswersIDs, storage, pollId, out errorMessage);
        }

        public static bool VoteForPoll(List<long> userAnswersIDs, IFeedStorage storage, long pollId, out string errorMessage)
        {
            errorMessage = string.Empty;
            storage.PollVote(SecurityContext.CurrentAccount.ID.ToString(), userAnswersIDs);
            var pollFeed = storage.GetFeed(pollId);
            if (pollFeed == null)
            {
                errorMessage = NewsResource.ErrorAccessDenied;
                return false;
            }
            return true;
        }

        #endregion
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/js/talk.common.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


String.prototype.format = function () {
  if (arguments.length === 0) {
    return '';
  }

  var pos = -1, str = this, cnd = '', ind = -1, cnds = str.match(/{(\d+)}/g), cndsInd = cnds ? cnds.length : 0;
  while (cndsInd--) {
    pos = -1;
    cnd = cnds[cndsInd];
    ind = cnd.replace(/[{}]+/g, '');
    while ((pos = str.indexOf(cnd, pos + 1)) !== -1) {
      str = str.substring(0, pos) + (arguments[+ind] || '') + str.substring(pos + cnd.length);
    }
  }
  return str;
};

window.ASC = window.ASC || {};

window.ASC.TMTalk = window.ASC.TMTalk || {};

window.ASC.TMTalk.flashPlayer = (function () {
  var
    description = null,
    SHOCKWAVE_FLASH = 'Shockwave Flash',
    FLASH_MIME_TYPE = 'application/x-shockwave-flash',
    SHOCKWAVE_FLASH_AX = 'ShockwaveFlash.ShockwaveFlash',
    requestedVersion = '9.0.0',
    playerVersion = [0, 0, 0];

  var hasPlayerVersion = function (reqVersion) {
	  var rv = reqVersion.split('.');
	  rv = [
	    parseInt(rv[0], 10),
	    parseInt(rv[1], 10) || 0,
	    parseInt(rv[2], 10) || 0
	  ];
	  return (playerVersion[0] > rv[0] || (playerVersion[0] == rv[0] && playerVersion[1] > v[1]) || (playerVersion[0] == rv[0] && playerVersion[1] == rv[1] && playerVersion[2] >= rv[2])) ? true : false;
  }

  if (typeof navigator.plugins !== 'undefined' && typeof navigator.plugins[SHOCKWAVE_FLASH] === 'object') {
		var description = navigator.plugins[SHOCKWAVE_FLASH].description;
		if (description && !(typeof navigator.mimeTypes !== 'undefined' && navigator.mimeTypes[FLASH_MIME_TYPE] && !navigator.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) {
			description = description.replace(/^.*\s+(\S+\s+\S+$)/, '$1');
			playerVersion = [
			  parseInt(description.replace(/^(.*)\..*$/, '$1'), 10),
			  parseInt(description.replace(/^.*\.(.*)\s.*$/, '$1'), 10),
			  /[a-zA-Z]/.test(description) ? parseInt(description.replace(/^.*[a-zA-Z]+(.*)$/, '$1'), 10) : 0
			];
		}
	}
	else if (typeof window.ActiveXObject !== 'undefined') {
		try {
			var ax = new ActiveXObject(SHOCKWAVE_FLASH_AX);
			if (ax) {
				var description = ax.GetVariable('$version');
				if (description) {
					description = description.split(' ')[1].split(',');
					playerVersion = [
					  parseInt(description[0], 10),
					  parseInt(description[1], 10),
					  parseInt(description[2], 10)
					];
				}
			}
		} catch(err) {
		}
	}

  return {
    version     : playerVersion,
    hasVersion  : hasPlayerVersion,
    isInstalled : playerVersion[0] !== 0,
    isCorrect   : hasPlayerVersion(requestedVersion)
  };
})();

window.ASC.TMTalk.sounds = (function () {
  var
    isEnabled = null,
    soundsContainer = null;

    var initHtml = function() {
        var o = document.createElement('div'),
            soundsContainerId = 'talkHtmlSoundsContainer';
        o.setAttribute('id', soundsContainerId);
        
        for (var i = 0; i < ASC.TMTalk.Config.soundsHtml.length; i++) {
            var audioFindName = ASC.TMTalk.Config.soundsHtml[i].match(/\/\w+\./g);
            if (audioFindName.length > 0) {
                var audio = document.createElement('audio');
                var audioName = audioFindName[audioFindName.length - 1].substring(1, audioFindName[audioFindName.length - 1].length - 1);
                
                audio.setAttribute('id', audioName);
                audio.setAttribute('src', ASC.TMTalk.Config.soundsHtml[i]);
                o.appendChild(audio);
            }
        }
        document.getElementById('talkWrapper').appendChild(o);
    };
    var init = function (o) {
    if (typeof o === 'string') {
      o = document.getElementById(o);
    }
    if (!o || typeof o === 'undefined') {
      return null;
    }
    soundsContainer = o;
    if (isEnabled === null) {
      isEnabled = true;
    }
  };

    var play = function (soundname) {
    if (isEnabled === true && typeof soundname === 'string') {
        var sound = document.getElementById(soundname + 'sound');
        if (sound != null) {
            try {
                sound.play().catch(function (e) {
                    console.log(e.message);
                });
            } catch(e) {}
        }
        //try { soundsContainer.playSound(soundname) } catch (err) { }
    }
  };

  var enable = function () {
      isEnabled = true;
  };

  var disable = function () {
    isEnabled = false;
  };

  var supported = function () {
      return true;
      //return ASC.TMTalk.flashPlayer.isCorrect;
  };

  return {
    supported : supported,

    init  : init,
    play  : play,

    initHtml: initHtml,
    
    enable  : enable,
    disable : disable
  };
})();

window.ASC.TMTalk.indicator = (function () {
  var
    indicators = {},
    timeoutValue = 500,
    timeoutHandler = null,
    customEvents = {
      show : 'onshow',
      start : 'onstart',
      stop : 'onstop'
    },
    eventManager = new CustomEvent(customEvents);

  var bind = function (eventName, handler, params) {
    return eventManager.bind(eventName, handler, params);
  };

  var unbind = function (handlerId) {
    return eventManager.unbind(handlerId);
  };

  var show = function () {
    eventManager.call(customEvents.show, window, []);
  };

  var start = function (id) {
    if (indicators.hasOwnProperty(id)) {
      return undefined;
    }
    indicators[id] = true;

    eventManager.call(customEvents.start, window, []);

    if (timeoutHandler === null) {
      timeoutHandler = setInterval(show, timeoutValue);
    }
  };

  var stop = function (id) {
    if (!indicators.hasOwnProperty(id)) {
      return undefined;
    }

    delete indicators[id];
    for(var id in indicators) {
      if (indicators.hasOwnProperty(id)) {
        return undefined;
      }
    }
    clearInterval(timeoutHandler);
    timeoutHandler = null;

    eventManager.call(customEvents.stop, window, []);
  };

  return {
    events  : customEvents,

    bind    : bind,
    unbind  : unbind,

    start : start,
    stop  : stop
  };
})();

window.ASC.TMTalk.properties = (function () {
  var
    isInit = false,
    cookieName = 'tmtalk',
    fieldSeparator = ':',
    propertySeparator = '::',
    storage = {},
    properties = {},
    customEvents = {
      load : 'onload',
      updateProperty : 'onupdateproperty'
    },
    eventManager = new CustomEvent(customEvents);

  var init = function (ver) {
    if (isInit === true) {
      return undefined;
    }
    // TODO
    load();

    if (typeof ver === 'string') {
      if (!properties.hasOwnProperty('ver') || properties.ver !== ver) {
        for (var fld in properties) {
          if (properties.hasOwnProperty(fld)) {
            delete properties[fld];
          }
          if (storage.hasOwnProperty(fld)) {
            delete storage[fld];
          }
        }
        ASC.TMTalk.cookies.remove(cookieName);
        storage['ver'] = ver;
        properties['ver'] = ver;
        ASC.TMTalk.cookies.set(cookieName, 'ver' + fieldSeparator + ver);
      }
    }
  };

  var bind = function (eventName, handler, params) {
    return eventManager.bind(eventName, handler, params);
  };

  var unbind = function (handlerId) {
    return eventManager.unbind(handlerId);
  };

  var item = function (name, value, inStorage) {
    if (typeof name !== 'string') {
      return '';
    }
    if (typeof value === 'undefined') {
      return properties.hasOwnProperty(name) ? properties[name] : undefined;
    }
    var oldvalue = properties[name] || '';
    properties[name] = value;
    if (inStorage === true) {
        if (jQuery.isEmptyObject(storage) && ASC.TMTalk.cookies.get(cookieName)) {
            var cookieProperty = ASC.TMTalk.cookies.get(cookieName).split(propertySeparator);
            for (var i = 0; i < cookieProperty.length; i++) {
                var field = cookieProperty[i].split(fieldSeparator);
                storage[field[0]] = field[1];
            }
        }
      storage[name] = value;
      save();
    }
    eventManager.call(customEvents.updateProperty, window, [name, value, oldvalue]);
  };

  var save = function () {
    var collect = [];
    for (var name in storage) {
      if (storage.hasOwnProperty(name)) {
        collect.push(name + fieldSeparator + storage[name]);
      }
    }
    ASC.TMTalk.cookies.set(cookieName, collect.join(propertySeparator));
  };

  var load = function () {
    var
      pos = -1,
      name = '',
      value = '',
      collect = ASC.TMTalk.cookies.get(cookieName).split(propertySeparator);

    for (var i = 0, n = collect.length; i < n; i++) {
      if ((pos = collect[i].indexOf(fieldSeparator)) === -1) {
        continue;
      }
      name = collect[i].substring(0, pos);
      value = collect[i].substring(pos + 1);
      if (!name.length) {
        continue;
      }
      storage[name] = value;
      properties[name] = value;
    }
  };

  return {
    events  : customEvents,

    init  : init,
    item  : item,

    bind    : bind,
    unbind  : unbind
  };
})();

window.ASC.TMTalk.events = (function () {
  var add = (function () {
    if (typeof window.addEventListener === 'function') {
      return function (o, event, handler) {
        if (typeof o === 'string') {
          o = document.getElementById(o);
        }
        if (!o || typeof o !== 'object') {
          return undefined;
        }
        o.addEventListener(event, handler, false);
        return handler;
      };
    } else if (typeof window.attachEvent === 'object') {
      return function (o, event, handler) {
        if (typeof o === 'string') {
          o = document.getElementById(o);
        }
        if (!o || typeof o !== 'object') {
          return undefined;
        }
        o.attachEvent('on' + event, handler);
        return handler;
      };
    } else {
      return function (o, event, handler) {
        if (typeof o === 'string') {
          o = document.getElementById(o);
        }
        if (!o || typeof o !== 'object') {
          return undefined;
        }
        if (o.hasOwnProperty('on' + event)) {
          o['on' + event] = handler;
        }
        return handler;
      };
    }
  })();

  var remove = (function () {
    if (typeof window.removeEventListener === 'function') {
      return function (o, event, handler) {
        if (typeof o === 'string') {
          o = document.getElementById(o);
        }
        if (o && typeof o === 'object') {
          o.removeEventListener(event, handler, false);
        }
      };
    } else if (typeof window.detachEvent === 'object') {
      return function (o, event, handler) {
        if (typeof o === 'string') {
          o = document.getElementById(o);
        }
        if (o && typeof o === 'object') {
          o.detachEvent('on' + event, handler);
        }
      };
    }
    return function (o, event, handler) {
      if (typeof o === 'string') {
        o = document.getElementById(o);
      }
      if (o && typeof o === 'object') {
        if (o.hasOwnProperty('on' + event)) {
          o['on' + event] = null;
        }
      }
    };
  })();

  var fix = (function () {
    if (typeof document.documentElement === 'object') {
      return function (evt) {
        evt = evt || window.event;
        if (!evt.pageX) {
          try {
            evt.pageX = evt.clientX + document.documentElement.scrollLeft;
            evt.pageY = evt.clientY + document.documentElement.scrollTop;
          } catch (err) {
          }
        }
        if (!evt.which && evt.button) {
          evt.which = evt.button & 1 ? 1 : (evt.button & 2 ? 3 : (evt.button & 4 ? 2 : 0));
        }
        return evt;
      };
    }
    return function (evt) {
      evt = evt || window.event;
      if (!evt.pageX) {
        evt.pageX = evt.clientX + document.body.scrollLeft;
        evt.pageY = evt.clientY + document.body.scrollTop;
      }
      if (!evt.which && evt.button) {
        evt.which = evt.button & 1 ? 1 : (evt.button & 2 ? 3 : (evt.button & 4 ? 2 : 0));
      }
      return evt;
    };
  })();

  return {
    fix     : fix,
    add     : add,
    remove  : remove
  };
})();

window.ASC.TMTalk.style = (function () {
  var get = (function () {
    if (typeof document.defaultView !== 'undefined' && typeof document.defaultView.getComputedStyle !== 'undefined') {
      return function (o, property) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        if (typeof property !== 'string' || !property) {
          return o;
        }
        return document.defaultView.getComputedStyle(o, '').getPropertyValue(property);
      };
    }
    return function (o, property) {
      if (typeof o === 'string'){
	      o = document.getElementById(o);
	    }
      if (!o) {
        return null;
      }
      if (typeof property !== 'string' || !property) {
        return o;
      }
      return o.currentStyle !== 'undefined' ? o.currentStyle[property] : '';
    };
  })();

  return {
    get : get
  };
})();

window.ASC.TMTalk.dragMaster = (function () {
  var
    cursorStartPosition = null,
    selectedElement = null,
    dragableElement = null,
    cursorOffset = null,
    cursorMaxShift = 20,
    targets = [],
    onDrop = null,
    onDrag = null,
    onChose = null,
    onMouseOver = null,
    onMouseOut = null;

  var cursorIsOver = function (cursor, block) {
    return cursor.x > block.left && cursor.x < block.right && cursor.y > block.top && cursor.y < block.bottom;
  };

  var getBoundRect = function (o) {
    var
      wasHidden = false,
      oldDisplayValue = '',
      toShow = false,
      rect = null,
      maxAvailableValue = 40,
      shift = maxAvailableValue >> 1,
      offsetBlock = null;

    wasHidden = ASC.TMTalk.style.get(o, 'display') === 'none';
    if (wasHidden) {
      oldDisplayValue = o.style.display;
      o.style.display = 'block';
    }
    offsetBlock = ASC.TMTalk.dom.offset(o);
    rect = {
      left : offsetBlock.x - (o.offsetWidth > maxAvailableValue ? 0 : shift),
      top : offsetBlock.y - (o.offsetHeight > maxAvailableValue ? 0 : shift),
      right : offsetBlock.x + (o.offsetWidth > maxAvailableValue ? o.offsetWidth : shift),
      bottom : offsetBlock.y + (o.offsetHeight > maxAvailableValue ? o.offsetHeight : shift)
    };
    if (wasHidden) {
      o.style.display = oldDisplayValue ? oldDisplayValue : '';
    }
    return rect;
  };

  var execEvent = function (eventType, thisArg, argsArray) {
    thisArg = thisArg || window;
    argsArray = argsArray || [];
    if (window.getSelection) {
        window.getSelection().removeAllRanges();
    } else {
        document.selection.empty();
    }
    switch (eventType.toLowerCase()) {
      case 'ondrag' :
        if (typeof onDrop === 'function') {
          onDrag.apply(thisArg, argsArray);
        }
        break;
      case 'ondrop' :
        if (typeof onDrop === 'function') {
          onDrop.apply(thisArg, argsArray);
        }
        break;
      case 'onchose' :
        if (typeof onChose === 'function') {
          onChose.apply(thisArg, argsArray);
        }
        break;
      case 'onmouseover' :
        if (typeof onMouseOver === 'function') {
          onMouseOver.apply(thisArg, argsArray);
        }
        break;
      case 'onmouseout' :
        if (typeof onMouseOut === 'function') {
          onMouseOut.apply(thisArg, argsArray);
        }
        break;
    }
  };

  var onDragStart = function () {
    return false;
  };

  var onSelectStart = function () {
    return false;
  };

  var onMouseMoveFix = function (evt) {
    evt = ASC.TMTalk.events.fix(evt);

    if (Math.abs(cursorStartPosition.x - evt.pageX) > cursorMaxShift || Math.abs(cursorStartPosition.y - evt.pageY) > cursorMaxShift) {
      ASC.TMTalk.events.remove(document, 'mousemove', onMouseMoveFix);
      ASC.TMTalk.events.remove(document, 'mouseup', onMouseUpFix);
      ASC.TMTalk.events.add(document, 'mousemove', onMouseMove);
      ASC.TMTalk.events.add(document, 'mouseup', onMouseUp);

      ASC.TMTalk.dom.addClass(selectedElement, 'selected');

      dragableElement.style.display = 'block';
      dragableElement.style.left = evt.pageX - cursorOffset.x + 'px';
      dragableElement.style.top = evt.pageY - cursorOffset.y + 'px';

      execEvent('ondrag', dragableElement, [selectedElement]);
    }
  };

  var onMouseMove = function (evt) {
    evt = ASC.TMTalk.events.fix(evt);

    dragableElement.style.left = evt.pageX - cursorOffset.x + 'px';
    dragableElement.style.top = evt.pageY - cursorOffset.y + 'px';

    var target = null;
    for (var i = 0, n = targets.length; i < n; i++) {
      target = targets[i];
      if (cursorIsOver({x : evt.pageX, y : evt.pageY}, getBoundRect(target.element))) {
        if (!target.mouseover) {
          target.mouseover = true;
          ASC.TMTalk.dom.addClass(target.element, 'mouseover');
          execEvent('onmouseover', target.element);
        }
      } else {
        if (target.mouseover) {
          target.mouseover = false;
          ASC.TMTalk.dom.removeClass(target.element, 'mouseover');
          execEvent('onmouseout', target.element);
        }
      }
    }
  };

  var onMouseUpFix = function (evt) {
    ASC.TMTalk.events.remove(document.body, 'selectstart', onSelectStart);
    ASC.TMTalk.events.remove(document, 'dragstart', onDragStart);
    ASC.TMTalk.events.remove(document, 'mousemove', onMouseMoveFix);
    ASC.TMTalk.events.remove(document, 'mouseup', onMouseUpFix);
  };

  var onMouseUp = function (evt) {
    evt = ASC.TMTalk.events.fix(evt);

    dragableElement.style.display = 'none';

    ASC.TMTalk.events.remove(document.body, 'selectstart', onSelectStart);
    ASC.TMTalk.events.remove(document, 'dragstart', onDragStart);
    ASC.TMTalk.events.remove(document, 'mousemove', onMouseMove);
    ASC.TMTalk.events.remove(document, 'mouseup', onMouseUp);

    ASC.TMTalk.dom.removeClass(selectedElement, 'selected');

    var
      selectedTargets = [],
      targetsInd = targets.length;
    while (targetsInd--) {
      if (ASC.TMTalk.dom.hasClass(targets[targetsInd].element, 'mouseover')) {
        selectedTargets.push(targets[targetsInd].element);
        ASC.TMTalk.dom.removeClass(targets[targetsInd].element, 'mouseover');
      }
    }

    execEvent('ondrop', dragableElement, [selectedElement]);
    execEvent('onchose', dragableElement, [selectedElement, selectedTargets]);
  };

  var create = function () {
    if (dragableElement === null) {
      var node = null, background = null;
      dragableElement = document.createElement('div');
      dragableElement.style.display = 'none';
      node = document.createElement('div');
      node.className = 'state';
      dragableElement.appendChild(node);
      node = document.createElement('div');
      node.className = 'title';
      dragableElement.appendChild(node);
      background = document.createElement('div');
      background.className = 'background';
      node = document.createElement('div');
      node.className = 'helper';
      background.appendChild(node);
      node = document.createElement('div');
      node.className = 'left-side';
      background.appendChild(node);
      node = document.createElement('div');
      node.className = 'right-side';
      background.appendChild(node);
      dragableElement.appendChild(background);
      document.body.appendChild(dragableElement);
    }
  };

  var start = function (evt, el, newtargets, properties, handler) {
    if (typeof el === 'string') {
      el = document.getElementById(el);
    }
    if (!el || typeof el !== 'object') {
      return undefined;
    }

    targets = [];
    if (newtargets instanceof Array) {
      var
        newtarget = null,
        newtargetsInd = newtargets.length;
      while (newtargetsInd--) {
        newtarget = newtargets[newtargetsInd];
        if (typeof newtarget === 'string') {
          newtarget = document.getElementById(newtarget);
        }
        if (!newtarget || typeof newtarget !== 'object') {
          continue;
        }
        targets.push({
          element   : newtarget,
          boundrect : getBoundRect(newtarget),
          mouseover : false
        });
      }
    }

    if (properties && typeof properties == 'object') {
      onDrag = typeof properties.onDrag === 'function' ? properties.onDrag : null;
      onDrop = typeof properties.onDrop === 'function' ? properties.onDrop : null;
      onChose = typeof properties.onChose === 'function' ? properties.onChose : null;
      onMouseOver = typeof properties.onMouseOver === 'function' ? properties.onMouseOver : null;
      onMouseOut = typeof properties.onMouseOut === 'function' ? properties.onMouseOut : null;
    }

    create();
    selectedElement = el;
    dragableElement.style.position = 'absolute';
    dragableElement.style.overflow = 'hidden';
    dragableElement.style.zIndex = '9001';

    if (typeof handler === 'function') {
      handler.apply(dragableElement, [selectedElement]);
    }

    cursorStartPosition = {
      x : evt.pageX,
      y : evt.pageY
    };

    cursorOffset = ASC.TMTalk.dom.offset(selectedElement);
    cursorOffset.x = evt.pageX - cursorOffset.x;
    cursorOffset.y = evt.pageY - cursorOffset.y;

    ASC.TMTalk.events.add(document.body, 'selectstart', onSelectStart);
    ASC.TMTalk.events.add(document, 'dragstart', onDragStart);
    ASC.TMTalk.events.add(document, 'mousemove', onMouseMoveFix);
    ASC.TMTalk.events.add(document, 'mouseup', onMouseUpFix);
  };

  return {
    start   : start
  };
})();

window.ASC.TMTalk.cookies = (function () {
  var get = function (name) {
    if (typeof name === 'undefined') {
      return '';
    }
    var
      start = 0,
      end = 0,
      value = '',
      search = ' ' + name + '=',
      cookie = ' ' + document.cookie;

	  if ((start = cookie.indexOf(search)) !== -1) {
	    start += search.length;
		  if ((end = cookie.indexOf(";", start)) === -1) {
  			end = cookie.length;
	  	}
		  value = cookie.substring(start, end);
	  }
    return decodeURI(value);
  };

  var set = function (name, value, expires, path, domain, secure) {
    if (typeof name === 'undefined' || typeof value === 'undefined') {
      return undefined;
    }
    expires = expires || 365;
    if (isFinite(+expires)) {
      var currentDate = new Date();
      currentDate.setTime(currentDate.getTime() + expires * 8640000);
      expires = currentDate.toUTCString();
    }
    expires = expires ? ';expires=' + expires : '';
    path    = path    ? ';path='    + path    : ';path=/';
    domain  = domain  ? ';domain='  + domain  : '';
    secure  = secure  ? ';secure='  + secure  : '';
    document.cookie = name + '=' + encodeURI(value) + expires + path + domain + secure;
    return value;
  };

  var remove = function (name, path, domain) {
    if (name && document.cookie.indexOf(name + '=')  != -1) {
      path    = path    ? ';path='    + path    : ';path=/';
      domain  = domain  ? ';domain='  + domain  : '';
      document.cookie = name + '=' + path + domain + ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
    }
    return true;
  };

  return {
    get     : get,
    set     : set,
    remove  : remove
  };
})();

window.ASC.TMTalk.dom = (function () {
  var
    browser = (function () {
      var
        ua = navigator.userAgent,
        version = (ua.match(/.+(?:rv|it|ra|ie|ox|me|on)[\/:\s]([\d.]+)/i)||[0,'0'])[1];
      return {
        version : isFinite(+version) ? +version : version,
        // browsers
        msie    : '\v' == 'v' || /msie/i.test(ua),
        opera   : window.opera ? true : false,
        chrome  : window.chrome ? true : false,
        safari  : /safari/i.test(ua) && !window.chrome,
        firefox : /firefox/i.test(ua),
        mozilla : /mozilla/i.test(ua) && !/(compatible|webkit)/.test(ua),
        // engine
        gecko   : /gecko/i.test(ua),
        webkit  : /webkit/i.test(ua)
      }
    })();

  var inArray = function (elem, array) {
	  for (var i = 0, n = array.length; i < n; i++) {
		  if (array[i] === elem) {
			  return i;
			}
    }
	  return -1;
  };

  var hasClass = function (o, className) {
    if (typeof o === 'string'){
	    o = document.getElementById(o);
	  }
    if (!o) {
      return false;
    }
    if (typeof className !== 'string' || !className) {
      return false;
    }

    if (o.nodeType === 1) {
      var currentClassName = o.className;
      return currentClassName && currentClassName.indexOf(className) !== -1 && inArray(className, currentClassName.split(/\s+/)) !== -1;
    }
    return false;
  };

  var addClass = function (o, className) {
    if (typeof o === 'string'){
	    o = document.getElementById(o);
	  }
    if (!o) {
      return null;
    }
    if (typeof className !== 'string' || !className) {
      return o;
    }
    
    if (o.nodeType === 1) {
      var currentClassName = o.className;
      if (!currentClassName) {
        o.className = className;
      } else {
        if (inArray(className, currentClassName.split(/\s+/)) === -1) {
          o.className += ' ' + className;
        }
      }
    }
    return o;
  };

  var removeClass = function (o, className) {
    if (typeof o === 'string'){
	    o = document.getElementById(o);
	  }
    if (!o) {
      return null;
    }
    if (typeof className !== 'string' || !className) {
      return o;
    }

    if (o.nodeType === 1) {
      var currentClassName = o.className;
      if (currentClassName && currentClassName.indexOf(className) !== -1) {
        var
          classPos = -1,
          classes = currentClassName.split(/\s+/);
        if ((classPos = inArray(className, classes)) !== -1) {
          classes.splice(classPos, 1);
          o.className = classes.join(' ');
        }
      }
    }
    return o;
  };

  var toggleClass = function (o, className) {
    if (typeof o === 'string'){
	    o = document.getElementById(o);
	  }
    if (!o) {
      return null;
    }
    if (typeof className !== 'string' || !className) {
      return o;
    }

    if (o.nodeType === 1) {
      var currentClassName = o.className;
      if (currentClassName && currentClassName.indexOf(className) !== -1) {
        var
          classPos = -1,
          classes = currentClassName.split(/\s+/);
        if ((classPos = inArray(className, classes)) !== -1) {
          classes.splice(classPos, 1);
          o.className = classes.join(' ');
        } else {
          o.className = currentClassName === ''? className : currentClassName + ' ' + className;
        }
      } else {
        o.className = currentClassName === ''? className : currentClassName + ' ' + className;
      }
    }
    return o;
  };

  var getElementsByClassName = (function () {
    if (typeof document.getElementsByClassName === 'function') {
      return function (o, className, tagName) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return [];
        }
        if (typeof tagName !== 'string') {
          return o.getElementsByClassName(className);
        }
			  var
          current = null,
          returnElements = [],
          elements = o.getElementsByClassName(className),
          nodeName = new RegExp('\\b' + tagName + '\\b', 'i');
        for (var i = 0, n = elements.length; i < n; i++) {
          current = elements[i];
          if(nodeName.test(current.nodeName)) {
            returnElements.push(current);
          }
        }
        return returnElements;
      };
    } else if (document.evaluate) {
      return function (o, className, tagName) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return [];
        }
        tagName = tagName || '*';
        var
          classes = className.split(' '),
          classesToCheck = '',
          xhtmlNamespace = 'http://www.w3.org/1999/xhtml',
          namespaceResolver = document.documentElement.namespaceURI === xhtmlNamespace ? xhtmlNamespace : null,
          returnElements = [],
          elements = null,
          node = null;
        for(var i = 0, n = classes.length; i < n; i++) {
          classesToCheck += '[contains(concat(" ", @class, " "), " ' + classes[i] + ' ")]';
        }
        try	{
          elements = document.evaluate(".//" + tagName + classesToCheck, o, namespaceResolver, 0, null);
        }
        catch (err) {
          elements = document.evaluate(".//" + tagName + classesToCheck, o, null, 0, null);
        }
        while ((node = elements.iterateNext())) {
          returnElements.push(node);
        }
        return returnElements;
      };
    }
    return function (o, className, tagName) {
      if (typeof o === 'string'){
	      o = document.getElementById(o);
	    }
      if (!o) {
        return [];
      }
      tagName = tagName || '*';
      var
        i = 0, j = 0, n = 0, m = 0,
        classes = className.split(' '),
        classesToCheck = [],
        elements = tagName === '*' && o.all ? o.all : o.getElementsByTagName(tagName),
        current = null,
        returnElements = [],
        match = false;
      for (i = 0, n = classes.length; i < n; i++) {
        classesToCheck.push(new RegExp('(^|\\s)' + classes[i] + '(\\s|$)'));
      }
      for (i = 0, n = elements.length; i < n; i++) {
        current = elements[i];
        match = false;
        for(j = 0, m = classesToCheck.length; j < m; j++){
					match = classesToCheck[j].test(current.className);
					if (!match) {
						break;
					}
				}
				if (match) {
					returnElements.push(current);
				}
			}
			return returnElements; 
    };
  })();

  var getContent = (function () {
    if (typeof document.createElement('div').textContent === 'string' && !browser.msie) {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return '';
        }
        return o.textContent;
      };
    } else if (typeof document.createElement('div').text === 'string') {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return '';
        }
        return o.text;
      };
    }
    return function (o) {
      if (typeof o === 'string'){
	      o = document.getElementById(o);
	    }
      if (!o) {
        return '';
      }
      result = '';
      var childs = o.childNodes;
      if (!childs) {
        return result;
      }
      for (var i = 0, n = childs.length; i < n; i++) {
        var child = childs.item(i);
        switch (child.nodeType) {
          case 1 :
          case 5 :
            result += arguments.callee(child);
            break;
          case 3 :
          case 2 :
          case 4 :
            result += child.nodeValue;
            break;
        }
      }
      return result;
    };
  })();

  var clear = function (o) {
    if (typeof o === 'string'){
	    o = document.getElementById(o);
	  }
    if (!o) {
      return null;
    }
	  while (o.firstChild) {
	    o.removeChild(o.firstChild);
	  }
	  return o;
  };

  var offset = (function () {
    if (typeof document.createElement('div').getBoundingClientRect !== 'undefined') {
      if (typeof document.documentElement === 'object') {
        return function (o) {
          if (typeof o === 'string'){
	          o = document.getElementById(o);
	        }
          if (!o) {
            return {
              x : 0,
              y : 0
            };
          }
          var box = o.getBoundingClientRect();
          return {
            x : Math.round(box.left + document.documentElement.scrollLeft - (document.documentElement.clientLeft || 0)),
            y : Math.round(box.top +  document.documentElement.scrollTop - (document.documentElement.clientTop || 0))
          };
        };
      }
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return {
            x : 0,
            y : 0
          };
        }
        var box = o.getBoundingClientRect();
        return {
          x : Math.round(box.left + document.body.scrollLeft - (document.body.clientLeft || 0)),
          y : Math.round(box.top +  document.body.scrollTop - (document.body.clientTop || 0))
        };
      };
    }
    return function (o) {
      if (typeof o === 'string'){
	      o = document.getElementById(o);
	    }
      if (!o) {
        return {
          x : 0,
          y : 0
        };
      }
      var  x = 0, y = 0;
      while(o) {
        y = y + parseInt(o.offsetTop, 10);
        x = x + parseInt(o.offsetLeft, 10);
        o = o.offsetParent;
      }
      return {
        x : x,
        y : y
      };
    };
  })();

  var maxScrollLeft = function (o) {
    if (typeof o === 'string'){
	    o = document.getElementById(o);
	  }
    if (!o) {
      return 0;
    }
    var origScrollLeft = o.scrollLeft, iter = 1000, scrollLeft = origScrollLeft;
    o.scrollLeft = scrollLeft += iter;
    while (o.scrollLeft === scrollLeft) {
      o.scrollLeft = scrollLeft += iter;
    }
    scrollLeft = o.scrollLeft;
    o.scrollLeft = origScrollLeft;
    return scrollLeft;
  };

  var maxScrollTop = function (o) {
    if (typeof o === 'string'){
	    o = document.getElementById(o);
	  }
    if (!o) {
      return 0;
    }
    var origScrollTop = o.scrollTop, iter = 1000, scrollTop = origScrollTop;
    o.scrollTop = scrollTop += iter;
    while (o.scrollTop === scrollTop) {
      o.scrollTop = scrollTop += iter;
    }
    scrollTop = o.scrollTop;
    o.scrollTop = origScrollTop;
    return scrollTop;
  };

  var prevElementSibling = (function () {
    if (typeof document.createElement('div').prevElementSibling === 'object') {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        return o.prevElementSibling;
      };
    } else {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        o = o.previousSibling;
        while(o && o.nodeType !== 1) {
          o = o.previousSibling;
        }
        return o && o.nodeType === 1 ? o : null;
      };
    }
  })();

  var nextElementSibling = (function () {
    if (typeof document.createElement('div').nextElementSibling === 'object') {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        return o.nextElementSibling;
      };
    } else {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        o = o.nextSibling;
        while(o && o.nodeType !== 1) {
          o = o.nextSibling;
        }
        return o && o.nodeType === 1 ? o : null;
      };
    }
  })();

  var firstElementChild = (function () {
    if (typeof document.createElement('div').firstElementChild === 'object') {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        return o.firstElementChild;
      };
    } else {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        o = o.firstChild;
        while(o && o.nodeType !== 1) {
          o = o.nextSibling;
        }
        return o && o.nodeType === 1 ? o : null;
      };
    }
  })();

  var lastElementChild = (function () {
    if (typeof document.createElement('div').lastElementChild === 'object') {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        return o.lastElementChild;
      };
    } else {
      return function (o) {
        if (typeof o === 'string'){
	        o = document.getElementById(o);
	      }
        if (!o) {
          return null;
        }
        o = o.lastChild;
        while(o && o.nodeType !== 1) {
          o = o.previousSibling;
        }
        return o && o.nodeType === 1 ? o : null;
      };
    }
  })();

  return {
    hasClass    : hasClass,
    addClass    : addClass,
    removeClass : removeClass,
    toggleClass : toggleClass,

    getElementsByClassName  : getElementsByClassName,

    getContent  : getContent,

    clear   : clear,
    offset  : offset,

    maxScrollLeft  : maxScrollLeft,
    maxScrollTop   : maxScrollTop,

    prevElementSibling  : prevElementSibling,
    nextElementSibling  : nextElementSibling,

    firstElementChild : firstElementChild,
    lastElementChild  : lastElementChild
  };
})();

window.ASC.TMTalk.notifications  = (function () {
  var isInit = false,
    propertyName = 'spnt',
    notifications = [],
    isDisabled = true,
    handlerIconPath = null,
    handlerNotifPath = null,
    supported = {
        current: window.Notification != null
    };

  var getNotificationsClickCallback = function (cid) {
      hWnd = null;
      try {hWnd = window.open('', window.name)} catch (err) {}
      try {hWnd.focus()} catch (err) {}
      try {ASC.TMTalk.contactsContainer.openItem(cid)} catch (err) {}
  };

  var init = function (iconpath, notifpath) {
    if (isInit === true) {
      return undefined;
    }
    isInit = true;
    // TODO:
    if (typeof iconpath === "string") {
      handlerIconPath = iconpath;
    }
    if (typeof notifpath === "string") {
      handlerNotifPath = notifpath;
    }

    if (supported.current === true && jq.notification.permissionLevel() !== "denied" && ASC.TMTalk.properties.item(propertyName) === "1") {
        isDisabled = false;
    }
  };

  var show = function (marker, title, content) {
      if (isDisabled) {
          return;
      }
      Teamlab.getProfile({}, marker.split("@")[0], {
          success: function (params, data) {
              jQuery.notification({
                  title: title,
                  body: content,
                  tag: marker,
                  timeout: 10000,
                  //iconUrl: window.ASC.TMTalk.TalkResource.iconTeamlabOffice32
                  iconUrl: location.origin + data.avatar
              }).then(function (notification) {
                  if (notification !== null) {
                      notifications.push({ marker: marker, handler: notification });
                      notification.onclick = function () {
                          getNotificationsClickCallback(marker);
                          notification.close();
                      };
                  }
              }, function () {
                  console.error('Rejected!');
              });
          }
      });
  };

  var hide = function (marker) {
      if (isDisabled) {
          return;
      }
      if (window.Notification) {
          var notificationsInd = notifications.length;
          while (notificationsInd-- > 0) {
              if (notifications[notificationsInd] && notifications[notificationsInd].tag === marker) {
                  notifications[notificationsInd].handler.close();
                  notifications.splice(notificationsInd, 1);
              }
          }
      }
  };
  var enable = function () {
      //Defer subscription
      if (jq('#talkStatusMenu').hasClass('processing')) {
          setTimeout(enable, 100);
          return;
      }
      if (window.Notification) {
          try {
              var messaging = window.firebase.messaging();
              messaging.requestPermission()
                  .then(function() {
                      if (Notification.permission != 'denied') {
                          isDisabled = false;
                          ASC.TMTalk.properties.item(propertyName, "1", true);
                          jq('#button-browser-notification').addClass('on').removeClass('off');
                      }
                      return messaging.getToken();
                  })
                  .then(function(token) {
                      var browser = getBrowser();
                      var username = ASC.TMTalk.connectionManager.getJID();
                      username = username.split('@')[0];
                      var endpoint = token;
                      ASC.TMTalk.connectionManager.savePushEndpoint(username, endpoint, browser);
                  })
                  .catch(function(err) {
                      console.log("Permission error:", err);
                  });
          } catch(exp) {

              var callback = function () {
                  if (Notification.permission === 'denied') {
                      return;
                  }
                  isDisabled = false;
                  ASC.TMTalk.properties.item(propertyName, "1", true);
                  jq('#button-browser-notification').addClass('on').removeClass('off');
              };

              try {
                  Notification.requestPermission().then(callback);
              } catch (error) {
                  if (error instanceof TypeError) {
                      Notification.requestPermission(callback);
                  } else {
                      throw error;
                  }
              }
          }
        }
    };

    var getBrowser = function() { 
       
        var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
        var is_explorer = navigator.userAgent.indexOf('MSIE') > -1;
        var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
        var is_safari = navigator.userAgent.indexOf("Safari") > -1;
        var is_opera = navigator.userAgent.toLowerCase().indexOf("opr") > -1;

        if ((is_chrome) && (is_safari) && (is_opera)) {
            return 'Opera';
        }
        else if ((is_chrome) && (is_safari)) {
            return 'Google Chrome';
        } else if ((is_safari)) {
            return 'Safari';
        } else if (is_firefox) {
            return 'Firefox';
        } else if (is_explorer) {
            return 'Internet Explorer';
        }
        
        return "Unknown browser";
    };
    
    var disable = function () {
        isDisabled = true;
        ASC.TMTalk.properties.item(propertyName, "0", true);
        if ('serviceWorker' in navigator) {

                navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
                    serviceWorkerRegistration.pushManager.getSubscription().then(
                        function (subscription) {
                            if (!subscription) {
                                return;
                            }
                            subscription.unsubscribe().then(function (successful) {

                            }).catch(function (e) {
                                console.log('Unsubscription error: ', e);
                            });
                        });
                });
        }
    };

    var initialiseFirebase = function (config) {
        if (typeof config === "object") {
            if ('serviceWorker' in navigator && !jQuery.browser.msie && !jQuery.browser.safari) {
                try {
                    window.firebase.initializeApp(config);
                } catch(e) {
                    console.log("initialize firebase error: ", e);
                }
            } else {
                return;
            }
            //Are service workers supported in this browser
            if ('serviceWorker' in navigator && !jQuery.browser.msie && !jQuery.browser.safari) {
                    navigator.serviceWorker.register('talk.notification.js')
                    .then(initialiseState);
            }
        } else {
            if ('serviceWorker' in navigator && !jQuery.browser.msie && !jQuery.browser.safari) {

                    navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
                        serviceWorkerRegistration.pushManager.getSubscription().then(
                            function (subscription) {
                                if (!subscription) {
                                    return;
                                }
                                subscription.unsubscribe().then(function (successful) {

                                }).catch(function (e) {
                                    console.log('Unsubscription error: ', e);
                                });
                            });
                    });
            }
    }
    };
 
    function initialiseState(registration) {
        var messaging = window.firebase.messaging();
        messaging.useServiceWorker(registration);
        if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
            return;
        }
        if (enabled()) setTimeout(enable, 500);
    }
 
  var enabled = function () {
    return !isDisabled;
  };

  return {
    init  : init,

    show  : show,
    hide  : hide,

    enable    : enable,
    disable   : disable,
    enabled   : enabled,
    supported : supported,

    initialiseFirebase: initialiseFirebase
  };
})();

window.ASC.TMTalk.iconManager  = (function () {
  var
    isInit = false,
    defaultIcon = null,
    currentIsDefault = false,
    browser = (function () {
      var
        ua = navigator.userAgent,
        version = (ua.match(/.+(?:rv|it|ra|ie|ox|me|on)[\/:\s]([\d.]+)/i)||[0,'0'])[1];
      return {
        version : isFinite(+version) ? +version : version,
        // browsers
        msie    : '\v' == 'v' || /msie/i.test(ua),
        opera   : window.opera ? true : false,
        chrome  : window.chrome ? true : false,
        safari  : /safari/i.test(ua) && !window.chrome,
        firefox : /firefox/i.test(ua),
        mozilla : /mozilla/i.test(ua) && !/(compatible|webkit)/.test(ua),
        // engine
        gecko   : /gecko/i.test(ua),
        webkit  : /webkit/i.test(ua)
      }
    })();

  var init = function (path) {
    if (isInit === true) {
      return undefined;
    }
    isInit = true;
    // TODO
    var
      linkInd = 0,
      links = null;
    links = document.getElementsByTagName('link');
    linkInd = links.length;
    while (linkInd--) {
      if (links[linkInd].getAttribute('rel') === 'icon') {
        defaultIcon = links[linkInd].getAttribute('href');
        currentIsDefault = true;
        break;
      }
    }
  };

  var set = (function () {
    if (browser.chrome) {
      return function (icon) {
        var
          links = null,
          linkInd = 0;
        links = document.getElementsByTagName('link');
        linkInd = links.length;
        while (linkInd--) {
          if (links[linkInd].getAttribute('rel') === 'icon') {
            links[linkInd].setAttribute('href', icon);
            break;
          }
        }
      };
    }
    if (browser.msie) {
      return function (icon) {
        
      };
    }
    if (browser.opera) {
      return function (icon) {
      };
    }
    return function (icon) {
      var
        link = null,
        links = null,
        linkInd = 0;
      links = document.getElementsByTagName('link');
      linkInd = links.length;
      while (linkInd--) {
        link = links[linkInd];
        if (link.getAttribute('rel') === 'icon') {
          link.parentNode.removeChild(link);
        }
      }

      link = document.createElement('link');
      link.setAttribute('href', icon);
      link.setAttribute('type', 'image/x-icon');
      link.setAttribute('rel', 'icon');

      var head = document.getElementsByTagName('head')[0];
      if (head) {
        head.appendChild(link);
      }
    };
  })();

  var reset = (function () {
    if (browser.chrome) {
      return function () {
        if (defaultIcon === null) {
          return undefined;
        }
        var
          linkInd = 0,
          links = null;
        links = document.getElementsByTagName('link');
        linkInd = links.length;
        while (linkInd--) {
          if (links[linkInd].getAttribute('rel') === 'icon') {
            links[linkInd].setAttribute('href', defaultIcon);
            break;
          }
        }
      };
    }
    if (browser.msie) {
      return function () {
        
      };
    }
    if (browser.opera) {
      return function (icon) {
      };
    }
    return function () {
      var
        link = null,
        links = null,
        linkInd = 0;
      links = document.getElementsByTagName('link');
      linkInd = links.length;
      while (linkInd--) {
        link = links[linkInd];
        if (link.getAttribute('rel') === 'icon') {
          link.parentNode.removeChild(link);
        }
      }

      link = document.createElement('link');
      link.setAttribute('href', defaultIcon);
      link.setAttribute('type', 'image/x-icon');
      link.setAttribute('rel', 'icon');

      var head = document.getElementsByTagName('head')[0];
      if (head) {
        head.appendChild(link);
      }
    };
  })();

  return {
    init  : init,

    set   : set,
    reset : reset
  };
})();

window.ASC.TMTalk.uniqueId = function (prefix) {
  return (typeof prefix !== 'undefined' ? prefix + '-' : '') + Math.floor(Math.random() * 1000000);
};

window.ASC.TMTalk.stringFormat = function () {
  if (arguments.length === 0) {
    return '';
  }
  var
    pos = -1,
    ind = [],
    reInd = /{(\d)}/g,
    message = arguments[0];
  while (ind = reInd.exec(message)) {
    pos = -1;
    while ((pos = message.indexOf(ind[0], pos + 1)) !== -1) {
      message = message.substring(0, pos) + (arguments[+ind[1] + 1] || '') + message.substring(pos + ind[0].length);
    }
  }
  return message;
};

window.ASC.TMTalk.getHash = function (value) {
  var i = 0, n = 0, hash = value.length;
  if (value.length === 1) {
    return hash ^= value.charCodeAt(0);
  }
  for (i = 0, n = value.length - 1; i < n; i += 2) {
    hash ^= +(value.charCodeAt(i).toString() + value.charCodeAt(i + 1).toString());
  }
  return hash;
};

window.ASC.TMTalk.trim = function (str) {
  if (typeof str !== 'string' || str.length === 0) {
    return '';
  }
  return str.replace(/^\s+|\s+$/g, '');
};


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/MediaViewer/imageviewer.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC.Files.ImageViewer = (function () {
    var scalingInProcess = false;
    var currentFileName;

    var isInit;

    var imgRef;
    var header;
    var zoomPercBox;

    var odimensions = {};
    var ndimensions = {};
    var oScale = 0;
    var cScale = 0;
    var nScale = 0;
    var scaleStep = 10;
    var rotateAngel = 0;
    var mouseOffset;
    var windowDimensions = {};
    var imageAreaDimensions = {};
    var centerArea = {};
    var onImageLoad;
    var onNextImage;
    var onError;
    var onLock;

    var options;
    var headerHeight;
    var controlsHeight;

    var zoomInBtn;
    var zoomOutBtn;
    var zoomToActualBtn;
    var rotateLeftBtn;
    var rotateRightBtn;

    var init = function (optionsParam, headerRef, headerH, controlsH, onLoad, nextImage, error, lockChange) {
        if (isInit || !optionsParam) {
            return;
        }
        isInit = true;

        options = optionsParam;
        header = headerRef;
        headerHeight = controlsH;
        controlsHeight = controlsH;
        onImageLoad = onLoad;
        onNextImage = nextImage;
        onError = error;
        onLock = lockChange;

        imgRef = jq("#imageViewerContainer");
        zoomPercBox = jq("#imageViewerInfo");

        zoomInBtn = jq("#imageZoomIn");
        zoomOutBtn = jq("#imageZoomOut");
        zoomToActualBtn = jq("#imageFullScale");
        rotateLeftBtn = jq("#imageRotateLeft");
        rotateRightBtn = jq("#imageRotateRight");

        return {
            getPreviewHash: getPreviewHash,

            setOptions: setOptions,
            showImage: showImage,

            closeImageViewer: closeImageViewer,
            resetWorkspace: resetWorkspace,

            rotateImage: rotateImage,
            zoomImage: zoomImage,
            zoomImageFull: zoomImageFull
        };
    };

    var setOptions = function (optionsParam) {
        if (!isInit || !optionsParam) {
            return;
        }

        options = optionsParam;
    };

    var getPreviewHash = function (fileId) {
        return "preview/" + fileId;
    };

    var prepareWorkspace = function () {
        imgRef.show();

        imgRef.on("dblclick", mouseDoubleClickEvent);
        imgRef.on("mousedown", mouseDownEvent);
        imgRef.on("touchmove", touchMoveEvent);
        imgRef.on("touchend", touchEndEvent);
        imgRef.on("load", imageOnLoad);
        imgRef.on("error", function () {
            onError(ASC.Files.FilesJSResource.PreviewError.format(currentFileName));
        });

        jq(window).bind("resize.ImageViewer", calculateDimensions);
        jq(document).bind("mousewheel.ImageViewer", mouseWheelEvent);
        jq(document).bind("touchmove.ImageViewer", multiTouchEvent);

        zoomInBtn.on("click", function () { zoomImage(true); });
        zoomOutBtn.on("click", function () { zoomImage(false); });
        zoomToActualBtn.on("click", function () { zoomImageFull(); });
        rotateLeftBtn.on("click", function () { rotateImage(true); });
        rotateRightBtn.on("click", function () { rotateImage(false); });
    };

    var resetWorkspace = function () {
        imgRef.hide();
        imgRef.removeAttr("src");

        scalingInProcess = false;
        onLock(false);

        jq(document).unbind("mousemove.ImageViewer");
        jq(document).unbind("mouseup.ImageViewer");

        imgRef.off("dblclick", mouseDoubleClickEvent);
        imgRef.off("mousedown", mouseDownEvent);
        imgRef.off("touchmove", touchMoveEvent);
        imgRef.off("touchend", touchEndEvent);
        imgRef.off("load", imageOnLoad);

        jq(window).unbind("resize.ImageViewer");
        jq(document).unbind("mousewheel.ImageViewer");
        jq(document).unbind("touchmove.ImageViewer");

        zoomInBtn.off("click");
        zoomOutBtn.off("click");
        zoomToActualBtn.off("click");
        rotateLeftBtn.off("click");
        rotateRightBtn.off("click");
    };

    var getnewSize = function (side, nvalue) {
        var otherside = (side == "w") ? "h" : "w";
        if (typeof nvalue == "undefined" || nvalue == null) {
            var newSize = ndimensions[otherside] * odimensions[side] / odimensions[otherside];
        } else {
            newSize = (/%/.test(nvalue)) ? parseInt(nvalue) / 100 * odimensions[side] : parseInt(nvalue);
        }
        ndimensions[side] = Math.round(newSize);
    };

    var setNewDimensions = function (setting, callbackHandle) {
        var sortbysize = (odimensions.w > odimensions.h) ? ["w", "h"] : ["h", "w"];
        setting[sortbysize[0]] = setting.ls;
        setting[sortbysize[1]] = null;

        var sortbyavail = (setting.w) ? ["w", "h"] : (setting.h) ? ["h", "w"] : [];

        var oldDimensions = { w: ndimensions.w, h: ndimensions.h };

        getnewSize(sortbyavail[0], setting[sortbyavail[0]]);
        getnewSize(sortbyavail[1], setting[sortbyavail[1]]);

        scalingInProcess = true;
        onLock(true);

        if (typeof callbackHandle == "undefined" || callbackHandle == null) {
            callbackHandle = function () {
                scalingInProcess = false;
                onLock(false);
                zoomPercBox.hide();
                cScale = nScale;

                var top = parseFloat(imgRef.css("top"));
                var left = parseFloat(imgRef.css("left"));

                if (left < -ndimensions.w || windowDimensions.w < left || top < -ndimensions.h || windowDimensions.h < top)
                    imgRef.css({
                        "left": centerArea.w - ndimensions.w / 2,
                        "top": centerArea.h - ndimensions.h / 2
                    });
            };
        }

        if (typeof setting.speed == "undefined" || setting.speed == null) {
            setting.speed = 250;
        }

        var getDimensionOffset = function (side) {
            if (setting.toPtr) {
                var diff = (ndimensions[side] - oldDimensions[side]) / 2 + (oldDimensions[side] / 2 - mouseOffset[side == "h" ? "y" : "x"]) * (1 - ndimensions[side] / oldDimensions[side]);
            } else if (setting.toCenter) {
                return centerArea[side] - (ndimensions[side] / 2);
            } else {
                diff = (ndimensions[side] - oldDimensions[side]) / 2;
            }

            if (diff > 0) {
                return "-=" + diff + "px";
            } else {
                return "+=" + (-diff) + "px";
            }
        };

        if (setting.speed != 0) {
            imgRef.animate({ width: ndimensions.w + "px", height: ndimensions.h + "px", left: getDimensionOffset("w"), top: getDimensionOffset("h") },
                {
                    duration: setting.speed,
                    easing: "linear",
                    complete: callbackHandle,
                    step: function (now, obj) {
                        jq("#imageViewerInfo span").text(cScale + Math.round((nScale - cScale) * obj.pos) + "%");
                    }
                });
        } else {
            imgRef.css({ width: ndimensions.w + "px", height: ndimensions.h + "px", left: getDimensionOffset("w"), top: getDimensionOffset("h") });
            callbackHandle();
        }
    };

    var imageOnLoad = function () {
        imgRef[0].style.cssText = "";

        var tempimg = jq("<img src=\"" + imgRef.attr("src") + "\" class=\"image-viewer-temp\" />").prependTo("body");

        odimensions = { w: tempimg.width(), h: tempimg.height() };

        if (odimensions.w == 0 && odimensions.h == 0) {
            odimensions.w = imgRef.attr("naturalWidth") || imgRef[0].naturalWidth;
            odimensions.h = imgRef.attr("naturalHeight") || imgRef[0].naturalHeight;
        }

        var similarityFactors = { w: odimensions.w / imageAreaDimensions.w, h: odimensions.h / imageAreaDimensions.h };
        var lsf = (similarityFactors.w > similarityFactors.h) ? "w" : "h";

        nScale = (similarityFactors[lsf] > 1) ?
            Math.round(imageAreaDimensions[lsf] * 100.0 / odimensions[lsf]) :
            100;

        nScale = Math.max(nScale, scaleStep);

        ndimensions = { w: 10, h: 10 };

        imgRef.css({
            "left": centerArea.w - ndimensions.w / 2,
            "top": centerArea.h - ndimensions.h / 2
        }).show();

        oScale = nScale;

        setNewDimensions({ speed: 0, ls: nScale + "%" });

        tempimg.remove();

        resetImageInfo();

        onImageLoad();
    };

    var resetImageInfo = function () {
        if (isImageLoadCompleted()) {
            var imageName = currentFileName;
            var text = "{0} ({1}x{2})".format(imageName, odimensions.w, odimensions.h);
            header.text(text);
        }
    };

    var isImageLoadCompleted = function () {
        return !jq.isEmptyObject(odimensions);
    };

    var showImage = function (ext, fileId, fileName) {
        odimensions = {};
        ndimensions = {};
        rotateAngel = 0;
        scalingInProcess = false;
        currentFileName = fileName;

        prepareWorkspace();
        calculateDimensions();

        imgRef.hide();

        var tiffreg = /^\.tif[f]?$/gi;

        if (tiffreg.test(ext)) {
            var xhr = new XMLHttpRequest();
            xhr.responseType = 'arraybuffer';
            xhr.open('GET', options.downloadAction(fileId));
            xhr.onload = function (e) {
                var tiff = new Tiff({ buffer: xhr.response });

                imgRef.attr("src", tiff.toDataURL());
            };
            xhr.send();
        }
        else {
            imgRef.attr("src", options.downloadAction(fileId));
        }
    };

    var mouseDownEvent = function (event) {
        if (scalingInProcess || event.which != 1) {
            return false;
        }

        mouseOffset = { x: event.pageX - imgRef.offset().left, y: event.pageY - imgRef.offset().top };

        jq(document).unbind("mouseup.ImageViewer");
        jq(document).bind("mouseup.ImageViewer", mouseUpEvent);

        jq(document).unbind("mousemove.ImageViewer");
        jq(document).bind("mousemove.ImageViewer", mouseMoveEvent);

        document.ondragstart = function () {
            return false;
        };
        document.body.onselectstart = function () {
            return false;
        };
        imgRef[0].ondragstart = function () {
            return false;
        };

        return false;
    };

    var mouseMoveEvent = function (event) {
        var x = event.pageX,
            y = event.pageY,
            w = windowDimensions.w,
            h = windowDimensions.h;

        x = x < 0 ? 0 : x > w ? w : x;
        y = y < 0 ? 0 : y > h ? h : y;

        imgRef.css({
            "cursor": "pointer",
            "left": x - mouseOffset.x,
            "top": y - mouseOffset.y
        });
    };


    var lastTouchY;
    var lastTouchX;
    var offsetTouchY;
    var offsetTouchX;
    var isTouchMoving;
    var startedTouch;

    var swipeDurationThreshold = 1000; // More time than this, and it isn't a swipe.
    var swipeHorizontalDistanceThreshold = 30; // Swipe horizontal displacement must be more than this.
    var swipeVerticalDistanceThreshold = 10; // Swipe vertical displacement must be less than this.

    var pinchZoomThreshold = 10; // Pinch zoom displacement must be more than this.

    var touchMoveEvent = function (e) {
        if (e.originalEvent.touches.length > 1)
        {
            e.originalEvent.preventDefault();
            return true;
        }

        var touchY = e.originalEvent.touches[0].clientY;
        var touchX = e.originalEvent.touches[0].clientX;

        if (!startedTouch) {
            lastTouchY = touchY;
            lastTouchX = touchX;
            startedTouch = (new Date()).getTime();
            return false;
        }

        offsetTouchY = lastTouchY - touchY;
        offsetTouchX = lastTouchX - touchX;

        lastTouchY = touchY;
        lastTouchX = touchX;

        imgRef.css({
            "left": parseFloat(imgRef.css("left")) - offsetTouchX,
            "top": parseFloat(imgRef.css("top")) - offsetTouchY
        });

        return false;
    };

    var multiTouchEvent = function (e) {
        if (e.originalEvent.touches.length <= 1) {
            return true;
        }

        e.stopPropagation();
        e.originalEvent.preventDefault();

        if (!lastTouchX) {
            lastTouchY = e.originalEvent.touches[0].clientY;
            lastTouchX = e.originalEvent.touches[0].clientX;
            offsetTouchY = e.originalEvent.touches[1].clientY;
            offsetTouchX = e.originalEvent.touches[1].clientX;
            return false;
        }

        var touchY = e.originalEvent.touches[0].clientY;
        var touchX = e.originalEvent.touches[0].clientX;
        var secondaryTouchY = e.originalEvent.touches[1].clientY;
        var secondaryTouchX = e.originalEvent.touches[1].clientX;

        function distance(x1, y1, x2, y2) {
            return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
        }

        var oldDistance = distance(lastTouchX, lastTouchY, offsetTouchX, offsetTouchY);
        var newDistance = distance(touchX, touchY, secondaryTouchX, secondaryTouchY);

        if (Math.abs(newDistance - oldDistance) > pinchZoomThreshold) {
            mouseOffset = { x: (touchX + secondaryTouchX) / 2 - imgRef.offset().left, y: (touchY + secondaryTouchY) / 2 - imgRef.offset().top };

            zoomImage(oldDistance < newDistance, true);

            lastTouchY = touchY;
            lastTouchX = touchX;
            offsetTouchY = secondaryTouchY;
            offsetTouchX = secondaryTouchX;
        }
        return false;
    }

    var touchEndEvent = function (e) {
        if (Math.abs(offsetTouchY) < swipeVerticalDistanceThreshold && Math.abs(offsetTouchX) > swipeHorizontalDistanceThreshold
            && (new Date()).getTime() - startedTouch < swipeDurationThreshold) {
            onNextImage(offsetTouchX > 0);
        }

        lastTouchY = 0;
        lastTouchX = 0;
        isTouchMoving = false;
        startedTouch = 0;
    };

    var mouseUpEvent = function () {
        imgRef.css("cursor", "move");
        jq(document).unbind("mouseup.ImageViewer");
        jq(document).unbind("mousemove.ImageViewer");

        imgRef[0].ondragstart = null;
        document.ondragstart = null;
        document.body.onselectstart = null;
    };

    var mouseWheelEvent = function (event, delta) {
        if (jq(".blockUI:visible").length) return true;

        if (scalingInProcess) {
            return false;
        }

        mouseOffset = { x: event.pageX - imgRef.offset().left, y: event.pageY - imgRef.offset().top };

        zoomImage(delta > 0, event.target.id == "imageViewerContainer");
        return false;
    };

    var mouseDoubleClickEvent = function (event) {
        if (scalingInProcess) {
            return;
        }

        mouseOffset = { x: event.pageX - imgRef.offset().left, y: event.pageY - imgRef.offset().top };

        nScale = oScale;
        zoomPercBox.show();
        setNewDimensions({ ls: nScale + "%", toPtr: true });
    };

    var calculateDimensions = function () {
        windowDimensions = { w: jq(window).width(), h: jq(window).height() };

        var centerAreaOx = windowDimensions.w / 2 + jq(window).scrollLeft();
        var centerAreaOy = windowDimensions.h / 2 + jq(window).scrollTop();

        centerArea = { w: centerAreaOx, h: centerAreaOy };

        imageAreaDimensions = { w: windowDimensions.w, h: windowDimensions.h - headerHeight - controlsHeight };

        zoomPercBox.css({
            "left": centerArea.w,
            "top": centerArea.h
        });
    };

    var rotateImage = function (toLeft) {
        if (scalingInProcess) {
            return;
        }

        rotateAngel += 90 * (toLeft ? -1 : 1);

        if (!jq.browser.msie) {
            var rotateCssAttr = "rotate({0}deg)".format(rotateAngel);

            imgRef.css({
                "-moz-transform": rotateCssAttr,
                "-o-transform": rotateCssAttr,
                "-webkit-transform": rotateCssAttr,
                "transform": rotateCssAttr
            });
        } else {
            var rad = (rotateAngel * Math.PI) / 180.0;
            var filter = "progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\"auto expand\", M11 = " + Math.cos(rad) + ", M12 = " + (-Math.sin(rad)) + ", M21 = " + Math.sin(rad) + ", M22 = " + Math.cos(rad) + ")";

            var imgOffset = imgRef.offset();

            imgRef.css(
                {
                    "-ms-filter": filter,
                    "filter": filter
                });

            var rotateOffset = { left: -Math.round((imgRef.width() - ndimensions.w) / 2), top: -Math.round((imgRef.height() - ndimensions.h) / 2) };

            imgRef.css(
                {
                    "left": imgOffset.left + rotateOffset.left,
                    "top": imgOffset.top + rotateOffset.top
                });

            ndimensions.w = imgRef.width();
            ndimensions.h = imgRef.height();
        }
    };

    var closeImageViewer = function () {
        resetWorkspace();
    };

    var zoomImage = function (directionIn, toPtr) {
        if (scalingInProcess) {
            return;
        }

        if ((!directionIn && nScale <= scaleStep) || (directionIn && nScale >= 1000)) {
            zoomPercBox.show();
            setTimeout(function () { zoomPercBox.hide(); }, 500);
            return;
        }

        if (nScale < 100) {
            var step = scaleStep * (directionIn ? 1 : -1);
        } else {
            step = scaleStep * Math.floor(nScale / 50) * (directionIn ? 1 : -1);
        }

        nScale += step;

        if (nScale > 1000) {
            nScale = 1000;
        }
        if (nScale < scaleStep) {
            nScale = scaleStep;
        }

        zoomPercBox.show();
        setNewDimensions({ ls: nScale + "%", toPtr: toPtr });
    };

    var zoomImageFull = function () {
        if (scalingInProcess || nScale == 100) {
            return;
        }

        nScale = 100;

        zoomPercBox.show();
        setNewDimensions({ ls: nScale + "%", toCenter: true });
    };

    return {
        init: init,
        getPreviewHash: getPreviewHash
    };
})();

<|start_filename|>module/ASC.VoipService/Twilio/TwilioResponseHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Core.Tenants;

using Twilio.TwiML;

namespace ASC.VoipService.Twilio
{
    public class TwilioResponseHelper
    {
        private readonly VoipSettings settings;
        private readonly string baseUrl;

        public TwilioResponseHelper(VoipSettings settings, string baseUrl)
        {
            this.settings = settings;
            this.baseUrl = baseUrl.TrimEnd('/') + "/twilio/";
        }

        public VoiceResponse Inbound(Tuple<Agent, bool> agentTuple)
        {
            var agent = agentTuple != null ? agentTuple.Item1 : null;
            var anyOnline = agentTuple != null ? agentTuple.Item2 : false;
            var response = new VoiceResponse();

            if (settings.WorkingHours != null && settings.WorkingHours.Enabled)
            {
                var now = TenantUtil.DateTimeFromUtc(DateTime.UtcNow);
                if (!(settings.WorkingHours.From <= now.TimeOfDay && settings.WorkingHours.To >= now.TimeOfDay))
                {
                    return AddVoiceMail(response);
                }
            }

            if (anyOnline)
            {
                if (!string.IsNullOrEmpty(settings.GreetingAudio))
                {
                    response.Play(Uri.EscapeUriString(settings.GreetingAudio));
                }

                response.Enqueue(settings.Queue.Name, GetEcho("Enqueue", agent != null), "POST",
                    GetEcho("Wait", agent != null), "POST");
            }

            return AddVoiceMail(response);
        }

        public VoiceResponse Outbound()
        {
            return !settings.Caller.AllowOutgoingCalls
                       ? new VoiceResponse()
                       : AddToResponse(new VoiceResponse(), settings.Caller);
        }

        public VoiceResponse Dial()
        {
            return new VoiceResponse();
        }

        public VoiceResponse Queue()
        {
            return new VoiceResponse();
        }

        public VoiceResponse Enqueue(string queueResult)
        {
            return queueResult == "leave" ? AddVoiceMail(new VoiceResponse()) : new VoiceResponse();
        }

        public VoiceResponse Dequeue()
        {
            return AddToResponse(new VoiceResponse(), settings.Caller);
        }

        public VoiceResponse Leave()
        {
            return AddVoiceMail(new VoiceResponse());
        }

        public VoiceResponse Wait(string queueId, string queueTime, string queueSize)
        {
            var response = new VoiceResponse();
            var queue = settings.Queue;

            if (Convert.ToInt32(queueTime) > queue.WaitTime || Convert.ToInt32(queueSize) > queue.Size) return response.Leave();

            if (!string.IsNullOrEmpty(queue.WaitUrl))
            {
                var gather = new Gather(method: "POST", action: GetEcho("gatherQueue"));
                gather.Play(Uri.EscapeUriString(queue.WaitUrl));
                response.Gather(gather);
            }
            else
            {
                response.Pause(queue.WaitTime);
            }

            return response;
        }

        public VoiceResponse GatherQueue(string digits, string number, List<Agent> availableOperators)
        {
            var response = new VoiceResponse();

            if (digits == "#") return AddVoiceMail(response);

            var oper = settings.Operators.Find(r => r.PostFix == digits && availableOperators.Contains(r)) ??
                settings.Operators.FirstOrDefault(r => availableOperators.Contains(r));

            return oper != null ? AddToResponse(response, oper) : response;
        }

        public VoiceResponse Redirect(string to)
        {
            if (to == "hold")
            {
                return new VoiceResponse().Play(Uri.EscapeUriString(settings.HoldAudio), 0);
            }

            Guid newCallerId;

            if (Guid.TryParse(to, out newCallerId))
            {
                SecurityContext.AuthenticateMe(newCallerId);
            }

            return new VoiceResponse().Enqueue(settings.Queue.Name, GetEcho("enqueue"), "POST",
                GetEcho("wait") + "&RedirectTo=" + to, "POST");
        }

        public VoiceResponse VoiceMail()
        {
            return new VoiceResponse();
        }

        private VoiceResponse AddToResponse(VoiceResponse response, Agent agent)
        {
            var dial = new Dial(method: "POST", action: GetEcho("dial"), timeout: agent.TimeOut, record: agent.Record ? "record-from-answer" : "do-not-record");

            switch (agent.Answer)
            {
                case AnswerType.Number:
                    response.Dial(dial.Number(agent.PhoneNumber, method: "POST", url: GetEcho("client")));
                    break;
                case AnswerType.Client:
                    response.Dial(dial.Client(agent.ClientID, "POST", GetEcho("client")));
                    break;
                case AnswerType.Sip:
                    response.Dial(dial.Sip(agent.ClientID, method: "POST", url: GetEcho("client")));
                    break;
            }

            return response;
        }


        private VoiceResponse AddVoiceMail(VoiceResponse response)
        {
            return string.IsNullOrEmpty(settings.VoiceMail)
                       ? response.Say("")
                       : response.Play(Uri.EscapeUriString(settings.VoiceMail)).Record(method: "POST", action: GetEcho("voiceMail"), maxLength: 30);
        }

        public string GetEcho(string action, bool user = true)
        {
            var result = baseUrl.TrimEnd('/');

            if (!string.IsNullOrEmpty(action))
            {
                result += "/" + action.TrimStart('/');
            }
            if (user)
            {
                result += "?CallerId=" + SecurityContext.CurrentAccount.ID;
            }

            return result;
        }
    }
}


<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/ProviderManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Core.Common.Configuration;
using ASC.FederatedLogin.Profile;

namespace ASC.FederatedLogin.LoginProviders
{
    public class ProviderManager
    {
        public static ILoginProvider GetLoginProvider(string providerType)
        {
            return providerType == ProviderConstants.OpenId
                ? new OpenIdLoginProvider()
                : ConsumerFactory.GetByName(providerType) as ILoginProvider;
        }

        public static LoginProfile Process(string providerType, HttpContext context, IDictionary<string, string> @params)
        {
            return GetLoginProvider(providerType).ProcessAuthoriztion(context, @params);
        }

        public static LoginProfile GetLoginProfile(string providerType, string accessToken)
        {
            var consumer = GetLoginProvider(providerType);
            if (consumer == null) throw new ArgumentException("Unknown provider type", "providerType");

            try
            {
                return consumer.GetLoginProfile(accessToken);
            }
            catch (Exception ex)
            {
                return LoginProfile.FromError(ex);
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Mail/MailApi.Autoreply.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Api.Attributes;
using ASC.Mail.Core.Engine;
using ASC.Mail.Data.Contracts;

namespace ASC.Api.Mail
{
    public partial class MailApi
    {
        /// <summary>
        /// This method needed for update or create autoreply.
        /// </summary>
        /// <param name="mailboxId">Id of updated mailbox.</param>
        /// <param name="turnOn">New autoreply status.</param>
        /// <param name="onlyContacts">If true then send autoreply only for contacts.</param>
        /// <param name="turnOnToDate">If true then field To is active.</param>
        /// <param name="fromDate">Start date of autoreply sending.</param>
        /// <param name="toDate">End date of autoreply sending.</param>
        /// <param name="subject">New autoreply subject.</param>
        /// <param name="html">New autoreply value.</param>
        [Create(@"autoreply/update/{mailboxId:[0-9]+}")]
        public MailAutoreplyData UpdateAutoreply(int mailboxId, bool turnOn, bool onlyContacts,
            bool turnOnToDate, DateTime fromDate, DateTime toDate, string subject, string html)
        {
            var result = MailEngineFactory
                .AutoreplyEngine
                .SaveAutoreply(mailboxId, turnOn, onlyContacts, turnOnToDate, fromDate, toDate, subject, html);

            CacheEngine.Clear(Username);

            return result;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/BookmarkRaitingUserControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.IO;
using System.Text;
using System.Web.UI;

using ASC.Bookmarking;
using ASC.Bookmarking.Common;
using ASC.Bookmarking.Pojo;
using ASC.Web.Community.Product;
using ASC.Web.UserControls.Bookmarking.Common;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;

namespace ASC.Web.UserControls.Bookmarking
{
    public partial class BookmarkRaitingUserControl : BookmarkInfoBase
    {

        private long _simpleModeRaiting;

        public long SimpleModeRaiting
        {
            get
            {
                return Bookmark == null ? _simpleModeRaiting : Raiting;
            }
            set
            {
                _simpleModeRaiting = value;
            }
        }

        /// <summary>
        /// ID of the div which contains raiting.
        /// This field is used to the copying raiting to the Add bookmark to Favourites panel.
        /// </summary>
        public string DivId { get; set; }

        public bool SimpleMode { get; set; }

        private string _singleBookmarkDivID;

        public string SingleBookmarkDivID
        {
            get
            {
                return _singleBookmarkDivID == null ? string.Empty : _singleBookmarkDivID;
            }
            set
            {
                _singleBookmarkDivID = value;
            }
        }

        public string GetUniqueIDFromSingleBookmark()
        {
            return GetUniqueIDFromSingleBookmark(SingleBookmarkDivID);
        }

        public bool FavouriteMode
        {
            get
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                return BookmarkDisplayMode.Favourites.Equals(displayMode);
            }
        }

        public string GetBookmarkRaiting(Bookmark b)
        {
            if (CommunitySecurity.IsOutsider()) return string.Empty;

            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                using (HtmlTextWriter textWriter = new HtmlTextWriter(sw))
                {
                    using (var c = LoadControl(BookmarkUserControlPath.BookmarkRaitingUserControlPath) as BookmarkRaitingUserControl)
                    {
                        c.SimpleModeRaiting = ServiceHelper.GetUserBookmarksCount(b);
                        c.SimpleMode = true;
                        c.Bookmark = b;
                        c.RenderControl(textWriter);
                    }
                }
            }
            return sb.ToString();
        }

        public string GetBookmarkRaiting(Bookmark b, string divID)
        {
            if (CommunitySecurity.IsOutsider()) return string.Empty;

            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                using (HtmlTextWriter textWriter = new HtmlTextWriter(sw))
                {
                    using (var c = LoadControl(BookmarkUserControlPath.BookmarkRaitingUserControlPath) as BookmarkRaitingUserControl)
                    {
                        c.Bookmark = b;
                        c.DivId = divID;
                        c.RenderControl(textWriter);
                    }
                }
            }
            return sb.ToString();
        }

        public string GetBookmarkRaiting(Bookmark b, string divID, string singleBookmarkDivID)
        {
            return GetBookmarkRaiting(b, null, divID, singleBookmarkDivID);
        }

        public string GetBookmarkRaiting(Bookmark b, UserBookmark ub, string divID, string singleBookmarkDivID)
        {
            if (CommunitySecurity.IsOutsider()) return string.Empty;

            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                using (HtmlTextWriter textWriter = new HtmlTextWriter(sw))
                {
                    using (var c = LoadControl(BookmarkUserControlPath.BookmarkRaitingUserControlPath) as BookmarkRaitingUserControl)
                    {
                        c.Bookmark = b;
                        c.UserBookmark = ub;
                        c.DivId = divID;
                        c.SingleBookmarkDivID = singleBookmarkDivID;
                        c.RenderControl(textWriter);
                    }
                }
            }
            return sb.ToString();
        }



        public override void InitUserControl() { }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Resources/MailScriptResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Mail.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class MailScriptResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal MailScriptResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Mail.Resources.MailScriptResource", typeof(MailScriptResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Account connection error..
        /// </summary>
        public static string AccountCreationErrorBodyHeader {
            get {
                return ResourceManager.GetString("AccountCreationErrorBodyHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to In case the error persists, please read the {0}FAQ section{1} to learn more about the problem..
        /// </summary>
        public static string AccountCreationErrorGmailFooter {
            get {
                return ResourceManager.GetString("AccountCreationErrorGmailFooter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Account connection error.
        /// </summary>
        public static string AccountCreationErrorHeader {
            get {
                return ResourceManager.GetString("AccountCreationErrorHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Account settings.
        /// </summary>
        public static string AccountEdit {
            get {
                return ResourceManager.GetString("AccountEdit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Google account was reconnected successfully.
        /// </summary>
        public static string AccountGoogleReconnectSuccess {
            get {
                return ResourceManager.GetString("AccountGoogleReconnectSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The account is connected using OAuth, editing is limited..
        /// </summary>
        public static string AccountNotificationText {
            get {
                return ResourceManager.GetString("AccountNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Accounts.
        /// </summary>
        public static string AccountsLabel {
            get {
                return ResourceManager.GetString("AccountsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Actions.
        /// </summary>
        public static string Actions {
            get {
                return ResourceManager.GetString("Actions", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to activate %1?.
        /// </summary>
        public static string ActivateAccountShure {
            get {
                return ResourceManager.GetString("ActivateAccountShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add Account.
        /// </summary>
        public static string AddAccountBtnLabel {
            get {
                return ResourceManager.GetString("AddAccountBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to add your first mail account right now?.
        /// </summary>
        public static string AddAccountInfoQuestion {
            get {
                return ResourceManager.GetString("AddAccountInfoQuestion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You haven&apos;t got any mail accounts connected to ONLYOFFICE™ Mail. Please add your mail account to start receiving and sending email messages..
        /// </summary>
        public static string AddAccountInfoText {
            get {
                return ResourceManager.GetString("AddAccountInfoText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add a new account to start using ONLYOFFICE™ Mail..
        /// </summary>
        public static string AddAccountInfoTitle {
            get {
                return ResourceManager.GetString("AddAccountInfoTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add condition.
        /// </summary>
        public static string AddFilterConditionBtnLabel {
            get {
                return ResourceManager.GetString("AddFilterConditionBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail Server.
        /// </summary>
        public static string AdministrationLabel {
            get {
                return ResourceManager.GetString("AdministrationLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to (Alias).
        /// </summary>
        public static string AliasLabel {
            get {
                return ResourceManager.GetString("AliasLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %mailbox_address% mailbox alias, edited in administration panel only.
        /// </summary>
        public static string AliasNotificationText {
            get {
                return ResourceManager.GetString("AliasNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All.
        /// </summary>
        public static string AllLabel {
            get {
                return ResourceManager.GetString("AllLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to and.
        /// </summary>
        public static string AndLabel {
            get {
                return ResourceManager.GetString("AndLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to matches all of the conditions.
        /// </summary>
        public static string ApplyMultiConditionsAllLabel {
            get {
                return ResourceManager.GetString("ApplyMultiConditionsAllLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to matches at least one of the conditions.
        /// </summary>
        public static string ApplyMultiConditionsAtLeastOneLabel {
            get {
                return ResourceManager.GetString("ApplyMultiConditionsAtLeastOneLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apply to.
        /// </summary>
        public static string ApplyToLabel {
            get {
                return ResourceManager.GetString("ApplyToLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apply to messages from.
        /// </summary>
        public static string ApplyToMessagesFromLabel {
            get {
                return ResourceManager.GetString("ApplyToMessagesFromLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Some input parameters are invalid..
        /// </summary>
        public static string AttachmentsBadInputParamsError {
            get {
                return ResourceManager.GetString("AttachmentsBadInputParamsError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Access to the document is denied..
        /// </summary>
        public static string AttachmentsDocumentAccessDeniedError {
            get {
                return ResourceManager.GetString("AttachmentsDocumentAccessDeniedError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Document could not be found or does not exist on the chosen storage..
        /// </summary>
        public static string AttachmentsDocumentNotFoundError {
            get {
                return ResourceManager.GetString("AttachmentsDocumentNotFoundError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Empty files are not supported..
        /// </summary>
        public static string AttachmentsEmptyFileNotSupportedError {
            get {
                return ResourceManager.GetString("AttachmentsEmptyFileNotSupportedError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to executable files may be not allowed by some services (e.g. Gmail).
        /// </summary>
        public static string AttachmentsExecutableWarning {
            get {
                return ResourceManager.GetString("AttachmentsExecutableWarning", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Note: the file size must not exceed %1 MB. The total size of all files should be no more than %2 MB..
        /// </summary>
        public static string AttachmentsLimitLabel {
            get {
                return ResourceManager.GetString("AttachmentsLimitLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message could not be found..
        /// </summary>
        public static string AttachmentsMessageNotFoundError {
            get {
                return ResourceManager.GetString("AttachmentsMessageNotFoundError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Total size of all attachments exceeds limit..
        /// </summary>
        public static string AttachmentsTotalLimitError {
            get {
                return ResourceManager.GetString("AttachmentsTotalLimitError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Some unexpected error has occurred. Please try again later..
        /// </summary>
        public static string AttachmentsUnknownError {
            get {
                return ResourceManager.GetString("AttachmentsUnknownError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The {0} mail account could not be connected for a long time and had to be disabled.{1} Please, check all the account settings you entered or sign in to the mail service you use and check the security settings. When you are sure all the issues with the account connection are resolved you can always enable it in your connected accounts list..
        /// </summary>
        public static string AuthErrorDisablePopupBody {
            get {
                return ResourceManager.GetString("AuthErrorDisablePopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The mail account has been disabled due to connection error..
        /// </summary>
        public static string AuthErrorDisablePopupBodyHeader {
            get {
                return ResourceManager.GetString("AuthErrorDisablePopupBodyHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail account disabled.
        /// </summary>
        public static string AuthErrorDisablePopupHeader {
            get {
                return ResourceManager.GetString("AuthErrorDisablePopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are problems with send and receive operations for the {0} mail account.{1} The reason might be that you changed your account password. Please, check all the account settings you entered or sign in to the mail service you use and check the security settings..
        /// </summary>
        public static string AuthErrorPopupBody {
            get {
                return ResourceManager.GetString("AuthErrorPopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to An error occurred while connecting to the account..
        /// </summary>
        public static string AuthErrorPopupBodyHeader {
            get {
                return ResourceManager.GetString("AuthErrorPopupBodyHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to disable.
        /// </summary>
        public static string AutoreplyDisable {
            get {
                return ResourceManager.GetString("AutoreplyDisable", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to B.
        /// </summary>
        public static string Bytes {
            get {
                return ResourceManager.GetString("Bytes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Agenda.
        /// </summary>
        public static string CalendarAgendaLabel {
            get {
                return ResourceManager.GetString("CalendarAgendaLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No later events.
        /// </summary>
        public static string CalendarAgendaNoEventsAfterLabel {
            get {
                return ResourceManager.GetString("CalendarAgendaNoEventsAfterLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No earlier events.
        /// </summary>
        public static string CalendarAgendaNoEventsBeforeLabel {
            get {
                return ResourceManager.GetString("CalendarAgendaNoEventsBeforeLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All day.
        /// </summary>
        public static string CalendarEventAllDayLabel {
            get {
                return ResourceManager.GetString("CalendarEventAllDayLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Prev day.
        /// </summary>
        public static string CalendarEventPrevDayLabel {
            get {
                return ResourceManager.GetString("CalendarEventPrevDayLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Calendar.
        /// </summary>
        public static string CalendarLabel {
            get {
                return ResourceManager.GetString("CalendarLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to map.
        /// </summary>
        public static string CalendarMapLabel {
            get {
                return ResourceManager.GetString("CalendarMapLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No location.
        /// </summary>
        public static string CalendarNoLocationLabel {
            get {
                return ResourceManager.GetString("CalendarNoLocationLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Organizer.
        /// </summary>
        public static string CalendarOrganizerLabel {
            get {
                return ResourceManager.GetString("CalendarOrganizerLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Participants.
        /// </summary>
        public static string CalendarParticipantsLabel {
            get {
                return ResourceManager.GetString("CalendarParticipantsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Recurrence.
        /// </summary>
        public static string CalendarRecurrenceLabel {
            get {
                return ResourceManager.GetString("CalendarRecurrenceLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reply.
        /// </summary>
        public static string CalendarReplyLabel {
            get {
                return ResourceManager.GetString("CalendarReplyLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Maybe.
        /// </summary>
        public static string CalendarReplyMaybeLabel {
            get {
                return ResourceManager.GetString("CalendarReplyMaybeLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No.
        /// </summary>
        public static string CalendarReplyNoLabel {
            get {
                return ResourceManager.GetString("CalendarReplyNoLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Yes.
        /// </summary>
        public static string CalendarReplyYesLabel {
            get {
                return ResourceManager.GetString("CalendarReplyYesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to When.
        /// </summary>
        public static string CalendarWhenLabel {
            get {
                return ResourceManager.GetString("CalendarWhenLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Where.
        /// </summary>
        public static string CalendarWhereLabel {
            get {
                return ResourceManager.GetString("CalendarWhereLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Who.
        /// </summary>
        public static string CalendarWhoLabel {
            get {
                return ResourceManager.GetString("CalendarWhoLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cancel.
        /// </summary>
        public static string CancelBtnLabel {
            get {
                return ResourceManager.GetString("CancelBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cc.
        /// </summary>
        public static string CcLabel {
            get {
                return ResourceManager.GetString("CcLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Change account settings.
        /// </summary>
        public static string ChangeAccountSettingsBtn {
            get {
                return ResourceManager.GetString("ChangeAccountSettingsBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose tag.
        /// </summary>
        public static string ChooseTag {
            get {
                return ResourceManager.GetString("ChooseTag", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close.
        /// </summary>
        public static string CloseBtnLabel {
            get {
                return ResourceManager.GetString("CloseBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Collapse all.
        /// </summary>
        public static string CollapseAllLabel {
            get {
                return ResourceManager.GetString("CollapseAllLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Common Settings.
        /// </summary>
        public static string CommonSettingsLabel {
            get {
                return ResourceManager.GetString("CommonSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to contains.
        /// </summary>
        public static string ContainsLabel {
            get {
                return ResourceManager.GetString("ContainsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This conversation contains collapsed messages which may include hidden images. Do you want to print it?.
        /// </summary>
        public static string ConversationCollapsedBlockedPopupBody {
            get {
                return ResourceManager.GetString("ConversationCollapsedBlockedPopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This conversation contains images that cannot be displayed at the moment. Do you want to print it?.
        /// </summary>
        public static string ConversationImagesBlockedPopupBody {
            get {
                return ResourceManager.GetString("ConversationImagesBlockedPopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Error occured while copying file.
        /// </summary>
        public static string CopyFileToMyDocumentsFolderErrorMsg {
            get {
                return ResourceManager.GetString("CopyFileToMyDocumentsFolderErrorMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Copying to &quot;My documents&quot; folder.
        /// </summary>
        public static string CopyingToMyDocumentsLabel {
            get {
                return ResourceManager.GetString("CopyingToMyDocumentsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create contact.
        /// </summary>
        public static string CreateContactButton {
            get {
                return ResourceManager.GetString("CreateContactButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create mailbox.
        /// </summary>
        public static string CreateMailboxBtn {
            get {
                return ResourceManager.GetString("CreateMailboxBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to We provide you with a ready-made free default domain so that you could create your new mailbox right away..
        /// </summary>
        public static string CreateMyMailboxPopupBody_1 {
            get {
                return ResourceManager.GetString("CreateMyMailboxPopupBody_1", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This domain is common for all portals, so it is recommended that your corporate domain is used for corporate email correspondence..
        /// </summary>
        public static string CreateMyMailboxPopupBody_2 {
            get {
                return ResourceManager.GetString("CreateMyMailboxPopupBody_2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create mailbox.
        /// </summary>
        public static string CreateMyMailboxPopupHeader {
            get {
                return ResourceManager.GetString("CreateMyMailboxPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new contact.
        /// </summary>
        public static string CreateNewContactLabel {
            get {
                return ResourceManager.GetString("CreateNewContactLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new CRM company.
        /// </summary>
        public static string CreateNewCRMCompany {
            get {
                return ResourceManager.GetString("CreateNewCRMCompany", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new CRM person.
        /// </summary>
        public static string CreateNewCRMPerson {
            get {
                return ResourceManager.GetString("CreateNewCRMPerson", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create personal contact.
        /// </summary>
        public static string CreatePersonalContact {
            get {
                return ResourceManager.GetString("CreatePersonalContact", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Company.
        /// </summary>
        public static string CRMCompany {
            get {
                return ResourceManager.GetString("CRMCompany", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to CRM Contacts.
        /// </summary>
        public static string CRMContactsLabel {
            get {
                return ResourceManager.GetString("CRMContactsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Date.
        /// </summary>
        public static string DateLabel {
            get {
                return ResourceManager.GetString("DateLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to deactivate %1?.
        /// </summary>
        public static string DeactivateAccountShure {
            get {
                return ResourceManager.GetString("DeactivateAccountShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Some of your accounts are not receiving mail..
        /// </summary>
        public static string DeactivatedAccountsNotification {
            get {
                return ResourceManager.GetString("DeactivatedAccountsNotification", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This account used to send the mail by default.
        /// </summary>
        public static string DefaultAccountText {
            get {
                return ResourceManager.GetString("DefaultAccountText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string Delete {
            get {
                return ResourceManager.GetString("Delete", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can reassign templates and drafts to another account..
        /// </summary>
        public static string DeleteAccountOptionHead {
            get {
                return ResourceManager.GetString("DeleteAccountOptionHead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to reassign to account.
        /// </summary>
        public static string DeleteAccountOptionText {
            get {
                return ResourceManager.GetString("DeleteAccountOptionText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete %1?.
        /// </summary>
        public static string DeleteAccountShure {
            get {
                return ResourceManager.GetString("DeleteAccountShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete the %1 tag?.
        /// </summary>
        public static string DeleteTagShure {
            get {
                return ResourceManager.GetString("DeleteTagShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete the &quot;{0}&quot; folder?.
        /// </summary>
        public static string DeleteUserFolderShure {
            get {
                return ResourceManager.GetString("DeleteUserFolderShure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deleting messages.
        /// </summary>
        public static string DeletionMessage {
            get {
                return ResourceManager.GetString("DeletionMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, check your message recipients addresses and message format.  If you are sure your message is correct, check all the {account_name} account settings, and, if everything is correct, sign in to the mail service you use and confirm any verification questions, in case there are some. After then try again..
        /// </summary>
        public static string DeliveryFailurePopupBody {
            get {
                return ResourceManager.GetString("DeliveryFailurePopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to In case the error persists, please read the {faq_link_open_tag}FAQ section{faq_link_close_tag} to learn more about the problem..
        /// </summary>
        public static string DeliveryFailurePopupBodyFooter {
            get {
                return ResourceManager.GetString("DeliveryFailurePopupBodyFooter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delivery failed for message &quot;{subject}&quot;..
        /// </summary>
        public static string DeliveryFailurePopupBodyHeader {
            get {
                return ResourceManager.GetString("DeliveryFailurePopupBodyHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message delivery failed..
        /// </summary>
        public static string DeliveryFailurePopupHeader {
            get {
                return ResourceManager.GetString("DeliveryFailurePopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail accounts have been disabled..
        /// </summary>
        public static string DisableAllMailboxesPopupBodyHeader {
            get {
                return ResourceManager.GetString("DisableAllMailboxesPopupBodyHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail accounts have been disabled.
        /// </summary>
        public static string DisableAllMailboxesPopupHeader {
            get {
                return ResourceManager.GetString("DisableAllMailboxesPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your portal has not been used for quite a long time, so your mail accounts connected to ONLYOFFICE™ Mail have been disabled. If you still want to use them go to your account page and enable them back again..
        /// </summary>
        public static string DisableAllMailboxesPopupText {
            get {
                return ResourceManager.GetString("DisableAllMailboxesPopupText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Done.
        /// </summary>
        public static string DoneLabel {
            get {
                return ResourceManager.GetString("DoneLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do not save.
        /// </summary>
        public static string DoNotSave {
            get {
                return ResourceManager.GetString("DoNotSave", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit contact.
        /// </summary>
        public static string EditContactcLabel {
            get {
                return ResourceManager.GetString("EditContactcLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uploading attachment to selected folder failed..
        /// </summary>
        public static string EmailInFailurePopupBodyHeader {
            get {
                return ResourceManager.GetString("EmailInFailurePopupBodyHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attachments Error.
        /// </summary>
        public static string EmailInFailurePopupHeader {
            get {
                return ResourceManager.GetString("EmailInFailurePopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The selected Attachments folder could not be accessed and was unlinked from your {account} mail account. Please check whether you have enough access rights for the selected folder and relink it back..
        /// </summary>
        public static string EmailInFolderAccessRightsFailurePopupText {
            get {
                return ResourceManager.GetString("EmailInFolderAccessRightsFailurePopupText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The selected Attachments folder could not be found and was unlinked from your {account} mail account. Please check whether the selected folder exists and relink it back..
        /// </summary>
        public static string EmailInFolderNotFoundFailurePopupText {
            get {
                return ResourceManager.GetString("EmailInFolderNotFoundFailurePopupText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Compose the first draft.
        /// </summary>
        public static string EmptyDraftsButton {
            get {
                return ResourceManager.GetString("EmptyDraftsButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The Draft section allows you to create and sort messages which you can send to different people later. Here you can tick the most important messages or delete the unnecessary ones..
        /// </summary>
        public static string EmptyDraftsDescription {
            get {
                return ResourceManager.GetString("EmptyDraftsDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages to be displayed in this folder.
        /// </summary>
        public static string EmptyDraftsHeader {
            get {
                return ResourceManager.GetString("EmptyDraftsHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Compose new message.
        /// </summary>
        public static string EmptyInboxButton {
            get {
                return ResourceManager.GetString("EmptyInboxButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The Inbox section allows you to manage the messages you receive. Here you can see the correspondence history, tick the most important messages, group emails by categories using tags or delete the unnecessary ones..
        /// </summary>
        public static string EmptyInboxDescription {
            get {
                return ResourceManager.GetString("EmptyInboxDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages received.
        /// </summary>
        public static string EmptyInboxHeader {
            get {
                return ResourceManager.GetString("EmptyInboxHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set up the first account.
        /// </summary>
        public static string EmptyScrAccountsButton {
            get {
                return ResourceManager.GetString("EmptyScrAccountsButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set up an account to send, receive, and keep your messages in order right on the portal. Get access to message history, contacts, and files through any browser anytime, anywhere. Sort messages using your own tags. Create a mailbox with the ready-made free default domain..
        /// </summary>
        public static string EmptyScrAccountsDescription {
            get {
                return ResourceManager.GetString("EmptyScrAccountsDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No account is set up yet.
        /// </summary>
        public static string EmptyScrAccountsHeader {
            get {
                return ResourceManager.GetString("EmptyScrAccountsHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to CRM.
        /// </summary>
        public static string EmptyScrCrmButton {
            get {
                return ResourceManager.GetString("EmptyScrCrmButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This contact list will contain all your clients from CRM.
        /// </summary>
        public static string EmptyScrCrmDescription {
            get {
                return ResourceManager.GetString("EmptyScrCrmDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The contact list is empty.
        /// </summary>
        public static string EmptyScrCrmHeader {
            get {
                return ResourceManager.GetString("EmptyScrCrmHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create filter.
        /// </summary>
        public static string EmptyScrFiltersButton {
            get {
                return ResourceManager.GetString("EmptyScrFiltersButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create filters to sort and manage all your mail.
        /// </summary>
        public static string EmptyScrFiltersDescription {
            get {
                return ResourceManager.GetString("EmptyScrFiltersDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No filters created.
        /// </summary>
        public static string EmptyScrFiltersHeader {
            get {
                return ResourceManager.GetString("EmptyScrFiltersHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This contact list will show all your personal contacts from the address book. You have not entered any contacts there yet..
        /// </summary>
        public static string EmptyScrMailContactsDescription {
            get {
                return ResourceManager.GetString("EmptyScrMailContactsDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create New Mail Tag.
        /// </summary>
        public static string EmptyScrTagsButton {
            get {
                return ResourceManager.GetString("EmptyScrTagsButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create tags to classify mail messages.
        /// </summary>
        public static string EmptyScrTagsDescription {
            get {
                return ResourceManager.GetString("EmptyScrTagsDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No tags created.
        /// </summary>
        public static string EmptyScrTagsHeader {
            get {
                return ResourceManager.GetString("EmptyScrTagsHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create folder.
        /// </summary>
        public static string EmptyScrUserFoldersButton {
            get {
                return ResourceManager.GetString("EmptyScrUserFoldersButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add folders to keep your emails organized.
        /// </summary>
        public static string EmptyScrUserFoldersDescription {
            get {
                return ResourceManager.GetString("EmptyScrUserFoldersDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No folders created.
        /// </summary>
        public static string EmptyScrUserFoldersHeader {
            get {
                return ResourceManager.GetString("EmptyScrUserFoldersHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Compose new message.
        /// </summary>
        public static string EmptySentButton {
            get {
                return ResourceManager.GetString("EmptySentButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The Sent section allows you to manage the messages you send. Here you can tick the most important messages, group emails by categories using tags or delete the unnecessary ones..
        /// </summary>
        public static string EmptySentDescription {
            get {
                return ResourceManager.GetString("EmptySentDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages have been sent yet.
        /// </summary>
        public static string EmptySentHeader {
            get {
                return ResourceManager.GetString("EmptySentHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The Spam folder contains messages that have been marked as spam either by you or by the system. Here you can mark a message as not spam, delete it permanently or empty the folder..
        /// </summary>
        public static string EmptySpamDescription {
            get {
                return ResourceManager.GetString("EmptySpamDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages to be displayed in this folder.
        /// </summary>
        public static string EmptySpamHeader {
            get {
                return ResourceManager.GetString("EmptySpamHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Compose the first template.
        /// </summary>
        public static string EmptyTemplatesButton {
            get {
                return ResourceManager.GetString("EmptyTemplatesButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can compose a message and save it as a template, then reuse it anytime you want it, adding new information if needed. Tick the most important messages or delete unnecessary ones.
        ///.
        /// </summary>
        public static string EmptyTemplatesDescription {
            get {
                return ResourceManager.GetString("EmptyTemplatesDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No templates to be displayed in this folder.
        /// </summary>
        public static string EmptyTemplatesHeader {
            get {
                return ResourceManager.GetString("EmptyTemplatesHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The Trash section contains messages which were deleted. Here you can recover some emails or delete them permanently..
        /// </summary>
        public static string EmptyTrashDescription {
            get {
                return ResourceManager.GetString("EmptyTrashDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages to be displayed in this folder.
        /// </summary>
        public static string EmptyTrashHeader {
            get {
                return ResourceManager.GetString("EmptyTrashHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This section allows you to manage the messages you move. Here you can see the correspondence history, tick the most important messages, group emails by categories using tags or delete the unnecessary ones..
        /// </summary>
        public static string EmptyUserFolderDescription {
            get {
                return ResourceManager.GetString("EmptyUserFolderDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages to be displayed in this folder.
        /// </summary>
        public static string EmptyUserFolderHeader {
            get {
                return ResourceManager.GetString("EmptyUserFolderHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail autoreply is enabled.
        /// </summary>
        public static string EnabledAutoreplyNotification {
            get {
                return ResourceManager.GetString("EnabledAutoreplyNotification", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This account already exists.
        /// </summary>
        public static string ErrorAccountAlreadyExists {
            get {
                return ResourceManager.GetString("ErrorAccountAlreadyExists", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Calendar is unreachable.
        /// </summary>
        public static string ErrorCalendarIsUnreachable {
            get {
                return ResourceManager.GetString("ErrorCalendarIsUnreachable", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to empty field.
        /// </summary>
        public static string ErrorEmptyField {
            get {
                return ResourceManager.GetString("ErrorEmptyField", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Empty &apos;To&apos; field.
        /// </summary>
        public static string ErrorEmptyToField {
            get {
                return ResourceManager.GetString("ErrorEmptyToField", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect address .
        /// </summary>
        public static string ErrorIncorrectAddress {
            get {
                return ResourceManager.GetString("ErrorIncorrectAddress", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Incorrect address .
        /// </summary>
        public static string ErrorIncorrectEmail {
            get {
                return ResourceManager.GetString("ErrorIncorrectEmail", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Lost internet connection.
        /// </summary>
        public static string ErrorLostInternetConnection {
            get {
                return ResourceManager.GetString("ErrorLostInternetConnection", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reduce size of body of letter to continue.
        /// </summary>
        public static string ErrorMailMessageSizeBody {
            get {
                return ResourceManager.GetString("ErrorMailMessageSizeBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message body exceeded limit ({0} KB).
        /// </summary>
        public static string ErrorMailMessageSizeHead {
            get {
                return ResourceManager.GetString("ErrorMailMessageSizeHead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to no mailbox selected.
        /// </summary>
        public static string ErrorNoMailboxSelectedField {
            get {
                return ResourceManager.GetString("ErrorNoMailboxSelectedField", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unknown error has occurred.
        /// </summary>
        public static string ErrorNotification {
            get {
                return ResourceManager.GetString("ErrorNotification", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to no user selected.
        /// </summary>
        public static string ErrorNoUserSelectedField {
            get {
                return ResourceManager.GetString("ErrorNoUserSelectedField", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to A problem has occurred while trying to open this message..
        /// </summary>
        public static string ErrorOpenMessage {
            get {
                return ResourceManager.GetString("ErrorOpenMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please refresh the page and try to open this message once again. In case the problem persists, please {0}contact our support team.{1}.
        /// </summary>
        public static string ErrorOpenMessageHelp {
            get {
                return ResourceManager.GetString("ErrorOpenMessageHelp", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Our apologies for the inconveniences but the mail message failed to load to ONLYOFFICE™ Mail. Use the copy of the original message added as an attachment to open it using any available mail client software or {0}contact our support team.{1}.
        /// </summary>
        public static string ErrorParseMessageHelp {
            get {
                return ResourceManager.GetString("ErrorParseMessageHelp", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This phone number already exists.
        /// </summary>
        public static string ErrorPhoneExist {
            get {
                return ResourceManager.GetString("ErrorPhoneExist", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The %1 tag already exists.
        /// </summary>
        public static string ErrorTagNameAlreadyExists {
            get {
                return ResourceManager.GetString("ErrorTagNameAlreadyExists", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unsupported file format.
        /// </summary>
        public static string ErrorUnsupportedFileFormat {
            get {
                return ResourceManager.GetString("ErrorUnsupportedFileFormat", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you want to reconnect this account, please remove it first from the list of your connected accounts at the &apos;Settings &gt; Accounts Management&apos; page..
        /// </summary>
        public static string ExistAccountText {
            get {
                return ResourceManager.GetString("ExistAccountText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Existing account.
        /// </summary>
        public static string ExistingAccountLabel {
            get {
                return ResourceManager.GetString("ExistingAccountLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Expand all.
        /// </summary>
        public static string ExpandAllLabel {
            get {
                return ResourceManager.GetString("ExpandAllLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Export message to CRM.
        /// </summary>
        public static string ExportConversationPopupHeader {
            get {
                return ResourceManager.GetString("ExportConversationPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail Export Error.
        /// </summary>
        public static string ExportFailurePopupHeader {
            get {
                return ResourceManager.GetString("ExportFailurePopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to An error occurred while exporting the message..
        /// </summary>
        public static string ExportFailurePopupName {
            get {
                return ResourceManager.GetString("ExportFailurePopupName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The message you are trying to export is already linked with the selected CRM item..
        /// </summary>
        public static string ExportFailurePopupText {
            get {
                return ResourceManager.GetString("ExportFailurePopupText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Export message to CRM contact history complete successfully.
        /// </summary>
        public static string ExportMessageText {
            get {
                return ResourceManager.GetString("ExportMessageText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete forever.
        /// </summary>
        public static string FilterActionDeleteLabel {
            get {
                return ResourceManager.GetString("FilterActionDeleteLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Take the following action.
        /// </summary>
        public static string FilterActionInfo {
            get {
                return ResourceManager.GetString("FilterActionInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as important.
        /// </summary>
        public static string FilterActionMarkAsImportantLabel {
            get {
                return ResourceManager.GetString("FilterActionMarkAsImportantLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as read.
        /// </summary>
        public static string FilterActionMarkAsReadLabel {
            get {
                return ResourceManager.GetString("FilterActionMarkAsReadLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add tag.
        /// </summary>
        public static string FilterActionMarkWithTagLabel {
            get {
                return ResourceManager.GetString("FilterActionMarkWithTagLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move to folder.
        /// </summary>
        public static string FilterActionMoveToLabel {
            get {
                return ResourceManager.GetString("FilterActionMoveToLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move to trash.
        /// </summary>
        public static string FilterActionMoveToTarshLabel {
            get {
                return ResourceManager.GetString("FilterActionMoveToTarshLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Advanced options.
        /// </summary>
        public static string FilterAdvancedInfo {
            get {
                return ResourceManager.GetString("FilterAdvancedInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other.
        /// </summary>
        public static string FilterAnotherGroup {
            get {
                return ResourceManager.GetString("FilterAnotherGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apply to all mailboxes.
        /// </summary>
        public static string FilterApplyToAllMailboxes {
            get {
                return ResourceManager.GetString("FilterApplyToAllMailboxes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apply if attachments are.
        /// </summary>
        public static string FilterApplyToAttachemnts {
            get {
                return ResourceManager.GetString("FilterApplyToAttachemnts", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to not present in the letter.
        /// </summary>
        public static string FilterApplyToAttachemntsNotPresent {
            get {
                return ResourceManager.GetString("FilterApplyToAttachemntsNotPresent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to present in the letter.
        /// </summary>
        public static string FilterApplyToAttachemntsPresent {
            get {
                return ResourceManager.GetString("FilterApplyToAttachemntsPresent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Temperature level.
        /// </summary>
        public static string FilterByContactStage {
            get {
                return ResourceManager.GetString("FilterByContactStage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Date.
        /// </summary>
        public static string FilterByDate {
            get {
                return ResourceManager.GetString("FilterByDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Custom period.
        /// </summary>
        public static string FilterByPeriod {
            get {
                return ResourceManager.GetString("FilterByPeriod", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Name.
        /// </summary>
        public static string FilterByTitle {
            get {
                return ResourceManager.GetString("FilterByTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose.
        /// </summary>
        public static string FilterChoose {
            get {
                return ResourceManager.GetString("FilterChoose", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Companies.
        /// </summary>
        public static string FilterCompany {
            get {
                return ResourceManager.GetString("FilterCompany", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Temperature level.
        /// </summary>
        public static string FilterContactStage {
            get {
                return ResourceManager.GetString("FilterContactStage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not specified.
        /// </summary>
        public static string FilterContactStageNotSpecified {
            get {
                return ResourceManager.GetString("FilterContactStageNotSpecified", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can also {0}enter a name{1} that will be displayed in the list of filters..
        /// </summary>
        public static string FilterEnterNameDescription {
            get {
                return ResourceManager.GetString("FilterEnterNameDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All the selected accounts have been deleted.
        /// </summary>
        public static string FilterErrorAllAccountsRemoved {
            get {
                return ResourceManager.GetString("FilterErrorAllAccountsRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Empty value of condition.
        /// </summary>
        public static string FilterErrorEmptyCondition {
            get {
                return ResourceManager.GetString("FilterErrorEmptyCondition", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No folder selected.
        /// </summary>
        public static string FilterErrorEmptyMoveToFolderValue {
            get {
                return ResourceManager.GetString("FilterErrorEmptyMoveToFolderValue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No tag selected.
        /// </summary>
        public static string FilterErrorEmptyTagValue {
            get {
                return ResourceManager.GetString("FilterErrorEmptyTagValue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The selected folder has been deleted.
        /// </summary>
        public static string FilterErrorFolderRemoved {
            get {
                return ResourceManager.GetString("FilterErrorFolderRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No action selected.
        /// </summary>
        public static string FilterErrorNoActionSelected {
            get {
                return ResourceManager.GetString("FilterErrorNoActionSelected", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No folder selected to apply filter.
        /// </summary>
        public static string FilterErrorNoApplyToFolderSelected {
            get {
                return ResourceManager.GetString("FilterErrorNoApplyToFolderSelected", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No mailbox selected to apply filter.
        /// </summary>
        public static string FilterErrorNoApplyToMailboxSelected {
            get {
                return ResourceManager.GetString("FilterErrorNoApplyToMailboxSelected", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The selected tag has been deleted.
        /// </summary>
        public static string FilterErrorTagRemoved {
            get {
                return ResourceManager.GetString("FilterErrorTagRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to From sender.
        /// </summary>
        public static string FilterFromSender {
            get {
                return ResourceManager.GetString("FilterFromSender", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ignore other filters.
        /// </summary>
        public static string FilterIgnoreOther {
            get {
                return ResourceManager.GetString("FilterIgnoreOther", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Important.
        /// </summary>
        public static string FilterImportant {
            get {
                return ResourceManager.GetString("FilterImportant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Filter name.
        /// </summary>
        public static string FilterName {
            get {
                return ResourceManager.GetString("FilterName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Custom period.
        /// </summary>
        public static string FilterPeriodCustom {
            get {
                return ResourceManager.GetString("FilterPeriodCustom", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to By period.
        /// </summary>
        public static string FilterPeriodGroup {
            get {
                return ResourceManager.GetString("FilterPeriodGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Last week.
        /// </summary>
        public static string FilterPeriodLastWeek {
            get {
                return ResourceManager.GetString("FilterPeriodLastWeek", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Today.
        /// </summary>
        public static string FilterPeriodToday {
            get {
                return ResourceManager.GetString("FilterPeriodToday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Yesterday.
        /// </summary>
        public static string FilterPeriodYesterday {
            get {
                return ResourceManager.GetString("FilterPeriodYesterday", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Persons.
        /// </summary>
        public static string FilterPerson {
            get {
                return ResourceManager.GetString("FilterPerson", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Read.
        /// </summary>
        public static string FilterRead {
            get {
                return ResourceManager.GetString("FilterRead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to select folder.
        /// </summary>
        public static string FilterSelectFolderLabel {
            get {
                return ResourceManager.GetString("FilterSelectFolderLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to select tag.
        /// </summary>
        public static string FilterSelectTagLabel {
            get {
                return ResourceManager.GetString("FilterSelectTagLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show.
        /// </summary>
        public static string FilterShowGroup {
            get {
                return ResourceManager.GetString("FilterShowGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Status.
        /// </summary>
        public static string FilterStatusGroup {
            get {
                return ResourceManager.GetString("FilterStatusGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To mail address.
        /// </summary>
        public static string FilterToMailAddress {
            get {
                return ResourceManager.GetString("FilterToMailAddress", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unread.
        /// </summary>
        public static string FilterUnread {
            get {
                return ResourceManager.GetString("FilterUnread", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to With attachments.
        /// </summary>
        public static string FilterWithAttachments {
            get {
                return ResourceManager.GetString("FilterWithAttachments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to With calendar.
        /// </summary>
        public static string FilterWithCalendar {
            get {
                return ResourceManager.GetString("FilterWithCalendar", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to With opportunities.
        /// </summary>
        public static string FilterWithOpportunity {
            get {
                return ResourceManager.GetString("FilterWithOpportunity", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to With tag.
        /// </summary>
        public static string FilterWithTags {
            get {
                return ResourceManager.GetString("FilterWithTags", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Fwd.
        /// </summary>
        public static string ForwardSubjectPrefix {
            get {
                return ResourceManager.GetString("ForwardSubjectPrefix", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Forwarded message.
        /// </summary>
        public static string ForwardTitle {
            get {
                return ResourceManager.GetString("ForwardTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to From.
        /// </summary>
        public static string FromLabel {
            get {
                return ResourceManager.GetString("FromLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can {0} or change it in {1}.
        /// </summary>
        public static string GoToAccountsForChangeAutoreply {
            get {
                return ResourceManager.GetString("GoToAccountsForChangeAutoreply", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to {0} to enable them..
        /// </summary>
        public static string GoToAccountsOnDeactivationText {
            get {
                return ResourceManager.GetString("GoToAccountsOnDeactivationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to Calendar.
        /// </summary>
        public static string GoToCalendarLink {
            get {
                return ResourceManager.GetString("GoToCalendarLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to Event.
        /// </summary>
        public static string GoToEventLink {
            get {
                return ResourceManager.GetString("GoToEventLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Group cannot be set as default mailbox.
        /// </summary>
        public static string GroupCouldNotSetAsDefault {
            get {
                return ResourceManager.GetString("GroupCouldNotSetAsDefault", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Help.
        /// </summary>
        public static string HelpCenterLabel {
            get {
                return ResourceManager.GetString("HelpCenterLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Always hide images from.
        /// </summary>
        public static string HideImagesLabel {
            get {
                return ResourceManager.GetString("HideImagesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Hide.
        /// </summary>
        public static string HidePasswordLinkLabel {
            get {
                return ResourceManager.GetString("HidePasswordLinkLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If.
        /// </summary>
        public static string IfLabel {
            get {
                return ResourceManager.GetString("IfLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The account is successfully connected..
        /// </summary>
        public static string ImportAccountHeader {
            get {
                return ResourceManager.GetString("ImportAccountHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All the mail for the last 30 days will be imported..
        /// </summary>
        public static string ImportAccountRestrictLabel {
            get {
                return ResourceManager.GetString("ImportAccountRestrictLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message importing is in progress. It can take some time. You can close this window and continue using the Mail or even close the browser. The importing will continue in background..
        /// </summary>
        public static string ImportAccountText {
            get {
                return ResourceManager.GetString("ImportAccountText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Important.
        /// </summary>
        public static string ImportantLabel {
            get {
                return ResourceManager.GetString("ImportantLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Some of the messages which have been received using other services earlier might be not imported. Please read the {0}FAQ section{1} for more details..
        /// </summary>
        public static string ImportGmailAttention {
            get {
                return ResourceManager.GetString("ImportGmailAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If an error occurs while importing the mail, please read the {0}FAQ section{1} for more details..
        /// </summary>
        public static string ImportProblemText {
            get {
                return ResourceManager.GetString("ImportProblemText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New folder &apos;{0}&apos; is created.
        /// </summary>
        public static string InfoCreateFolder {
            get {
                return ResourceManager.GetString("InfoCreateFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The folder &apos;{0}&apos; is moved into &apos;{1}&apos;.
        /// </summary>
        public static string InfoMoveFolder {
            get {
                return ResourceManager.GetString("InfoMoveFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The folder &apos;{0}&apos; is moved into the root folder.
        /// </summary>
        public static string InfoMoveFolderToRoot {
            get {
                return ResourceManager.GetString("InfoMoveFolderToRoot", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The folder &apos;{0}&apos; is deleted.
        /// </summary>
        public static string InfoRemoveFolder {
            get {
                return ResourceManager.GetString("InfoRemoveFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The folder &apos;{0}&apos; is renamed to &apos;{1}&apos;.
        /// </summary>
        public static string InfoRenameFolder {
            get {
                return ResourceManager.GetString("InfoRenameFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to conversation.
        /// </summary>
        public static string InfoSelectConversation {
            get {
                return ResourceManager.GetString("InfoSelectConversation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to conversations: {0}.
        /// </summary>
        public static string InfoSelectConversations {
            get {
                return ResourceManager.GetString("InfoSelectConversations", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to message.
        /// </summary>
        public static string InfoSelectMessage {
            get {
                return ResourceManager.GetString("InfoSelectMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to messages: {0}.
        /// </summary>
        public static string InfoSelectMessages {
            get {
                return ResourceManager.GetString("InfoSelectMessages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move {0}.
        /// </summary>
        public static string InfoSelectMove {
            get {
                return ResourceManager.GetString("InfoSelectMove", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Inserted via link.
        /// </summary>
        public static string InsertedViaLink {
            get {
                return ResourceManager.GetString("InsertedViaLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to KB.
        /// </summary>
        public static string Kilobytes {
            get {
                return ResourceManager.GetString("Kilobytes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Link conversation with CRM.
        /// </summary>
        public static string LinkConversationPopupHeader {
            get {
                return ResourceManager.GetString("LinkConversationPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Link conversation to CRM contact history complete successfully.
        /// </summary>
        public static string LinkConversationText {
            get {
                return ResourceManager.GetString("LinkConversationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Conversation Linking Error.
        /// </summary>
        public static string LinkFailurePopupHeader {
            get {
                return ResourceManager.GetString("LinkFailurePopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to An error occurred while linking the conversation to CRM..
        /// </summary>
        public static string LinkFailurePopupName {
            get {
                return ResourceManager.GetString("LinkFailurePopupName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The selected CRM item is no longer available, or the connection has been lost. Please, verify the selected CRM item location and check your network connection. In case the error persists, please contact your portal administrator..
        /// </summary>
        public static string LinkFailurePopupText {
            get {
                return ResourceManager.GetString("LinkFailurePopupText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to loading attachments....
        /// </summary>
        public static string LoadingAttachments {
            get {
                return ResourceManager.GetString("LoadingAttachments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to From.
        /// </summary>
        public static string MailAutoreplyFromDateLabel {
            get {
                return ResourceManager.GetString("MailAutoreplyFromDateLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail Autoreply.
        /// </summary>
        public static string MailAutoreplyLabel {
            get {
                return ResourceManager.GetString("MailAutoreplyLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To.
        /// </summary>
        public static string MailAutoreplyToDateLabel {
            get {
                return ResourceManager.GetString("MailAutoreplyToDateLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creating mailbox....
        /// </summary>
        public static string MailboxCreation {
            get {
                return ResourceManager.GetString("MailboxCreation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailbox update....
        /// </summary>
        public static string MailBoxUpdate {
            get {
                return ResourceManager.GetString("MailBoxUpdate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Drafts reassigned.
        /// </summary>
        public static string MailDraftsReassigned {
            get {
                return ResourceManager.GetString("MailDraftsReassigned", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Message filtering.
        /// </summary>
        public static string MailFilters {
            get {
                return ResourceManager.GetString("MailFilters", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Templates reassigned.
        /// </summary>
        public static string MailTemplatesReassigned {
            get {
                return ResourceManager.GetString("MailTemplatesReassigned", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Manage accounts.
        /// </summary>
        public static string ManageAccountsLabel {
            get {
                return ResourceManager.GetString("ManageAccountsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Manage signature.
        /// </summary>
        public static string ManageSignatureLabel {
            get {
                return ResourceManager.GetString("ManageSignatureLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark all recipient(s) mail.
        /// </summary>
        public static string MarkAllRecipientsLabel {
            get {
                return ResourceManager.GetString("MarkAllRecipientsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark all sender(s) mail.
        /// </summary>
        public static string MarkAllSendersLabel {
            get {
                return ResourceManager.GetString("MarkAllSendersLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as important.
        /// </summary>
        public static string MarkImportantLabel {
            get {
                return ResourceManager.GetString("MarkImportantLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as not important.
        /// </summary>
        public static string MarkNotImportantLabel {
            get {
                return ResourceManager.GetString("MarkNotImportantLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to matches.
        /// </summary>
        public static string MatchesLabel {
            get {
                return ResourceManager.GetString("MatchesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to MB.
        /// </summary>
        public static string Megabytes {
            get {
                return ResourceManager.GetString("Megabytes", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This message contains images that cannot be displayed at the moment. Do you want to continue?.
        /// </summary>
        public static string MessageImagesBlockedContinuePopupBody {
            get {
                return ResourceManager.GetString("MessageImagesBlockedContinuePopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Continue without images.
        /// </summary>
        public static string MessageImagesBlockedContinuePopupHeader {
            get {
                return ResourceManager.GetString("MessageImagesBlockedContinuePopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This message contains images that cannot be displayed at the moment. Do you want to print it?.
        /// </summary>
        public static string MessageImagesBlockedPopupBody {
            get {
                return ResourceManager.GetString("MessageImagesBlockedPopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Confirm printing without images.
        /// </summary>
        public static string MessageImagesBlockedPopupHeader {
            get {
                return ResourceManager.GetString("MessageImagesBlockedPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The message has not been sent. Are you sure you want to delete it?.
        /// </summary>
        public static string MessageNotSent {
            get {
                return ResourceManager.GetString("MessageNotSent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %1 more.
        /// </summary>
        public static string More {
            get {
                return ResourceManager.GetString("More", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to More Details.
        /// </summary>
        public static string MoreDetailsLabel {
            get {
                return ResourceManager.GetString("MoreDetailsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Moving messages.
        /// </summary>
        public static string MovingMessages {
            get {
                return ResourceManager.GetString("MovingMessages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add mail account.
        /// </summary>
        public static string NewAccount {
            get {
                return ResourceManager.GetString("NewAccount", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Message.
        /// </summary>
        public static string NewMessage {
            get {
                return ResourceManager.GetString("NewMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No further action is necessary..
        /// </summary>
        public static string NoActionText {
            get {
                return ResourceManager.GetString("NoActionText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages matching your filter can be displayed in this folder. Please select other filter options or clear filter to view all the messages in this folder..
        /// </summary>
        public static string NoLettersFilterDescription {
            get {
                return ResourceManager.GetString("NoLettersFilterDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No messages to be displayed for this filter here.
        /// </summary>
        public static string NoLettersFilterHeader {
            get {
                return ResourceManager.GetString("NoLettersFilterHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to None.
        /// </summary>
        public static string NoneLabel {
            get {
                return ResourceManager.GetString("NoneLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to no subject.
        /// </summary>
        public static string NoSubject {
            get {
                return ResourceManager.GetString("NoSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to doesn&apos;t contains.
        /// </summary>
        public static string NotContainsLabel {
            get {
                return ResourceManager.GetString("NotContainsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as important.
        /// </summary>
        public static string NotImportantLabel {
            get {
                return ResourceManager.GetString("NotImportantLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to doesn&apos;t match.
        /// </summary>
        public static string NotMatchesLabel {
            get {
                return ResourceManager.GetString("NotMatchesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not Spam.
        /// </summary>
        public static string NotSpamLabel {
            get {
                return ResourceManager.GetString("NotSpamLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Obtaining default domain settings ....
        /// </summary>
        public static string ObtainingDefaultDomainSettings {
            get {
                return ResourceManager.GetString("ObtainingDefaultDomainSettings", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to OK.
        /// </summary>
        public static string OkBtnLabel {
            get {
                return ResourceManager.GetString("OkBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to or.
        /// </summary>
        public static string OrLabel {
            get {
                return ResourceManager.GetString("OrLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Draft.
        /// </summary>
        public static string PageHeaderDraft {
            get {
                return ResourceManager.GetString("PageHeaderDraft", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Forward.
        /// </summary>
        public static string PageHeaderForward {
            get {
                return ResourceManager.GetString("PageHeaderForward", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reply.
        /// </summary>
        public static string PageHeaderReply {
            get {
                return ResourceManager.GetString("PageHeaderReply", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Template.
        /// </summary>
        public static string PageHeaderTemplate {
            get {
                return ResourceManager.GetString("PageHeaderTemplate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Personal Contacts.
        /// </summary>
        public static string PersonalContactsLabel {
            get {
                return ResourceManager.GetString("PersonalContactsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Print all.
        /// </summary>
        public static string PrintAllBtnLabel {
            get {
                return ResourceManager.GetString("PrintAllBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Print.
        /// </summary>
        public static string PrintBtnLabel {
            get {
                return ResourceManager.GetString("PrintBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The available disk storage space is exceeded on your portal. Not all messages can be loaded and no new messages can be sent. Please delete some messages from the Inbox or delete some files from the Documents module. You can also change the pricing plan to have more available disk space..
        /// </summary>
        public static string QuotaPopupBody {
            get {
                return ResourceManager.GetString("QuotaPopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The available disk storage is exceeded.
        /// </summary>
        public static string QuotaPopupHeader {
            get {
                return ResourceManager.GetString("QuotaPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to [Quoted text hidden].
        /// </summary>
        public static string QuotedTextHiddenMsg {
            get {
                return ResourceManager.GetString("QuotedTextHiddenMsg", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as read.
        /// </summary>
        public static string ReadLabel {
            get {
                return ResourceManager.GetString("ReadLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete all messages from Spam?.
        /// </summary>
        public static string RemoveSpamQuestion {
            get {
                return ResourceManager.GetString("RemoveSpamQuestion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete all messages from Trash?.
        /// </summary>
        public static string RemoveTrashQuestion {
            get {
                return ResourceManager.GetString("RemoveTrashQuestion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Re.
        /// </summary>
        public static string ReplySubjectPrefix {
            get {
                return ResourceManager.GetString("ReplySubjectPrefix", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reset of EMail-In folder was unsuccessful..
        /// </summary>
        public static string ResetAccountEMailInFolderFailure {
            get {
                return ResourceManager.GetString("ResetAccountEMailInFolderFailure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reset of EMail-In folder was successful..
        /// </summary>
        public static string ResetAccountEMailInFolderSuccess {
            get {
                return ResourceManager.GetString("ResetAccountEMailInFolderSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No CRM contacts matching your filter can be displayed on this page. Please select other filter options or clear filter to view all the CRM contacts..
        /// </summary>
        public static string ResetCrmContactsFilterDescription {
            get {
                return ResourceManager.GetString("ResetCrmContactsFilterDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No CRM contacts to be displayed for this filter here.
        /// </summary>
        public static string ResetCrmContactsFilterHeader {
            get {
                return ResourceManager.GetString("ResetCrmContactsFilterHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reset filter.
        /// </summary>
        public static string ResetFilterButton {
            get {
                return ResourceManager.GetString("ResetFilterButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No contacts matching the selected filter could be found. Please select another filter or clear this one to view all contacts..
        /// </summary>
        public static string ResetMailContactsFilterDescription {
            get {
                return ResourceManager.GetString("ResetMailContactsFilterDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no contacts matching this filter.
        /// </summary>
        public static string ResetMailContactsFilterHeader {
            get {
                return ResourceManager.GetString("ResetMailContactsFilterHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No portal contacts matching your filter can be displayed on this page. Please select other filter options or clear filter to view all the portal contacts..
        /// </summary>
        public static string ResetTlContactsFilterDescription {
            get {
                return ResourceManager.GetString("ResetTlContactsFilterDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No portal contacts to be displayed for this filter here.
        /// </summary>
        public static string ResetTlContactsFilterHeader {
            get {
                return ResourceManager.GetString("ResetTlContactsFilterHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Restore.
        /// </summary>
        public static string RestoreBtnLabel {
            get {
                return ResourceManager.GetString("RestoreBtnLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Restoring messages.
        /// </summary>
        public static string RestoringMessages {
            get {
                return ResourceManager.GetString("RestoringMessages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to It was successfully saved %real_count% from %count% in My documents..
        /// </summary>
        public static string SaveAllAttachmentsToMyDocsSuccess {
            get {
                return ResourceManager.GetString("SaveAllAttachmentsToMyDocsSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saving was unsuccessful..
        /// </summary>
        public static string SaveAttachmentsToDocumentsFailure {
            get {
                return ResourceManager.GetString("SaveAttachmentsToDocumentsFailure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to &apos;%file_name%&apos; is successfully saved in Calendar..
        /// </summary>
        public static string SaveAttachmentToCalendarSuccess {
            get {
                return ResourceManager.GetString("SaveAttachmentToCalendarSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to &apos;%file_name%&apos; is successfully saved in &apos;%folder_name%&apos;..
        /// </summary>
        public static string SaveAttachmentToDocsSuccess {
            get {
                return ResourceManager.GetString("SaveAttachmentToDocsSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save draft.
        /// </summary>
        public static string SaveDraft {
            get {
                return ResourceManager.GetString("SaveDraft", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save template.
        /// </summary>
        public static string SaveTemplate {
            get {
                return ResourceManager.GetString("SaveTemplate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save template changes?.
        /// </summary>
        public static string SaveTemplateChanges {
            get {
                return ResourceManager.GetString("SaveTemplateChanges", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have changed template but did not save it. If you close the page, all changes will be lost. Save changes?.
        /// </summary>
        public static string SaveTemplateText {
            get {
                return ResourceManager.GetString("SaveTemplateText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saving message.
        /// </summary>
        public static string SavingMessage {
            get {
                return ResourceManager.GetString("SavingMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select.
        /// </summary>
        public static string Select {
            get {
                return ResourceManager.GetString("Select", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This account has been deactivated. Please, activate this account or select another one..
        /// </summary>
        public static string SendFromDeactivateAccount {
            get {
                return ResourceManager.GetString("SendFromDeactivateAccount", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sending message.
        /// </summary>
        public static string SendingMessage {
            get {
                return ResourceManager.GetString("SendingMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Server.
        /// </summary>
        public static string ServerLabel {
            get {
                return ResourceManager.GetString("ServerLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Server mailbox, edited in administration panel only.
        /// </summary>
        public static string ServerMailboxNotificationText {
            get {
                return ResourceManager.GetString("ServerMailboxNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Setup of EMail-In folder was unsuccessful..
        /// </summary>
        public static string SetAccountEMailInFolderFailure {
            get {
                return ResourceManager.GetString("SetAccountEMailInFolderFailure", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Setup of EMail-In folder was successful..
        /// </summary>
        public static string SetAccountEMailInFolderSuccess {
            get {
                return ResourceManager.GetString("SetAccountEMailInFolderSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set as default and use to send the mail.
        /// </summary>
        public static string SetAsDefaultAccountText {
            get {
                return ResourceManager.GetString("SetAsDefaultAccountText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sharing setting for files.
        /// </summary>
        public static string SharingSettingForFiles {
            get {
                return ResourceManager.GetString("SharingSettingForFiles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show.
        /// </summary>
        public static string ShowPasswordLinkLabel {
            get {
                return ResourceManager.GetString("ShowPasswordLinkLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This signature will be appended at the end of all outgoing messages. You can add your contact information or a favorite quote.
        ///.
        /// </summary>
        public static string SignatureInformationText {
            get {
                return ResourceManager.GetString("SignatureInformationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Spam.
        /// </summary>
        public static string SpamLabel {
            get {
                return ResourceManager.GetString("SpamLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subject.
        /// </summary>
        public static string SubjectLabel {
            get {
                return ResourceManager.GetString("SubjectLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saving tag....
        /// </summary>
        public static string TagCreation {
            get {
                return ResourceManager.GetString("TagCreation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Imported from CRM. You cannot edit or delete this tag here..
        /// </summary>
        public static string TagNotificationText {
            get {
                return ResourceManager.GetString("TagNotificationText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tags.
        /// </summary>
        public static string Tags {
            get {
                return ResourceManager.GetString("Tags", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Portal Contacts.
        /// </summary>
        public static string TeamLabContactsLabel {
            get {
                return ResourceManager.GetString("TeamLabContactsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To.
        /// </summary>
        public static string ToLabel {
            get {
                return ResourceManager.GetString("ToLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To or Cc.
        /// </summary>
        public static string ToOrCcLabel {
            get {
                return ResourceManager.GetString("ToOrCcLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Total contacts:.
        /// </summary>
        public static string TotalContacts {
            get {
                return ResourceManager.GetString("TotalContacts", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Try again.
        /// </summary>
        public static string TryAgainButton {
            get {
                return ResourceManager.GetString("TryAgainButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unlink from CRM.
        /// </summary>
        public static string UnlinkFromCRMPopupHeader {
            get {
                return ResourceManager.GetString("UnlinkFromCRMPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mark as unread.
        /// </summary>
        public static string UnreadLabel {
            get {
                return ResourceManager.GetString("UnreadLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The filter was not found.
        /// </summary>
        public static string UserFilterNotFound {
            get {
                return ResourceManager.GetString("UserFilterNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to not selected.
        /// </summary>
        public static string UserFolderNoSelected {
            get {
                return ResourceManager.GetString("UserFolderNoSelected", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The required folder was not found.
        /// </summary>
        public static string UserFolderNotFoundError {
            get {
                return ResourceManager.GetString("UserFolderNotFoundError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folders.
        /// </summary>
        public static string UserFolders {
            get {
                return ResourceManager.GetString("UserFolders", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Parent folder:.
        /// </summary>
        public static string UserFolderSelectorLabel {
            get {
                return ResourceManager.GetString("UserFolderSelectorLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select the parent folder.
        /// </summary>
        public static string UserFolderSelectorLink {
            get {
                return ResourceManager.GetString("UserFolderSelectorLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Use signature.
        /// </summary>
        public static string UseSingatureLabel {
            get {
                return ResourceManager.GetString("UseSingatureLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Warning.
        /// </summary>
        public static string Warning {
            get {
                return ResourceManager.GetString("Warning", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to With attachments.
        /// </summary>
        public static string WithAttachments {
            get {
                return ResourceManager.GetString("WithAttachments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Without tags.
        /// </summary>
        public static string WithoutTags {
            get {
                return ResourceManager.GetString("WithoutTags", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to With tags.
        /// </summary>
        public static string WithTags {
            get {
                return ResourceManager.GetString("WithTags", resourceCulture);
            }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/UA/SIP_UA_Call_EventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.UA
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class provides data for <b>SIP_UA.IncomingCall</b> event.
    /// </summary>
    public class SIP_UA_Call_EventArgs : EventArgs
    {
        #region Members

        private readonly SIP_UA_Call m_pCall;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="call">SIP UA call.</param>
        /// <exception cref="ArgumentNullException">Is called when <b>call</b> is null reference.</exception>
        public SIP_UA_Call_EventArgs(SIP_UA_Call call)
        {
            if (call == null)
            {
                throw new ArgumentNullException("call");
            }

            m_pCall = call;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets call.
        /// </summary>
        public SIP_UA_Call Call
        {
            get { return m_pCall; }
        }

        #endregion
    }
}

<|start_filename|>web/core/ASC.Web.Core/WhiteLabel/AdditionalWhiteLabelSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;

namespace ASC.Web.Core.WhiteLabel
{
    [Serializable]
    [DataContract]
    public class AdditionalWhiteLabelSettings : BaseSettings<AdditionalWhiteLabelSettings>
    {
        [DataMember(Name = "StartDocsEnabled")]
        public bool StartDocsEnabled { get; set; }

        [DataMember(Name = "HelpCenterEnabled")]
        public bool HelpCenterEnabled { get; set; }

        [DataMember(Name = "FeedbackAndSupportEnabled")]
        public bool FeedbackAndSupportEnabled { get; set; }

        [DataMember(Name = "FeedbackAndSupportUrl")]
        public string FeedbackAndSupportUrl { get; set; }

        [DataMember(Name = "UserForumEnabled")]
        public bool UserForumEnabled { get; set; }

        [DataMember(Name = "UserForumUrl")]
        public string UserForumUrl { get; set; }

        [DataMember(Name = "VideoGuidesEnabled")]
        public bool VideoGuidesEnabled { get; set; }

        [DataMember(Name = "VideoGuidesUrl")]
        public string VideoGuidesUrl { get; set; }

        [DataMember(Name = "SalesEmail")]
        public string SalesEmail { get; set; }

        [DataMember(Name = "BuyUrl")]
        public string BuyUrl { get; set; }

        [DataMember(Name = "LicenseAgreementsEnabled")]
        public bool LicenseAgreementsEnabled { get; set; }

        [DataMember(Name = "LicenseAgreementsUrl")]
        public string LicenseAgreementsUrl { get; set; }

        public bool IsDefault
        {
            get
            {
                var defaultSettings = GetDefault() as AdditionalWhiteLabelSettings;

                if (defaultSettings == null) return false;

                return StartDocsEnabled == defaultSettings.StartDocsEnabled &&
                       HelpCenterEnabled == defaultSettings.HelpCenterEnabled &&
                       FeedbackAndSupportEnabled == defaultSettings.FeedbackAndSupportEnabled &&
                       FeedbackAndSupportUrl == defaultSettings.FeedbackAndSupportUrl &&
                       UserForumEnabled == defaultSettings.UserForumEnabled &&
                       UserForumUrl == defaultSettings.UserForumUrl &&
                       VideoGuidesEnabled == defaultSettings.VideoGuidesEnabled &&
                       VideoGuidesUrl == defaultSettings.VideoGuidesUrl &&
                       SalesEmail == defaultSettings.SalesEmail &&
                       BuyUrl == defaultSettings.BuyUrl &&
                       LicenseAgreementsEnabled == defaultSettings.LicenseAgreementsEnabled &&
                       LicenseAgreementsUrl == defaultSettings.LicenseAgreementsUrl;
            }
        }

        #region ISettings Members

        public override Guid ID
        {
            get { return new Guid("{0108422F-C05D-488E-B271-30C4032494DA}"); }
        }

        public override ISettings GetDefault()
        {
            return new AdditionalWhiteLabelSettings
            {
                StartDocsEnabled = true,
                HelpCenterEnabled = DefaultHelpCenterUrl != null,
                FeedbackAndSupportEnabled = DefaultFeedbackAndSupportUrl != null,
                FeedbackAndSupportUrl = DefaultFeedbackAndSupportUrl,
                UserForumEnabled = DefaultUserForumUrl != null,
                UserForumUrl = DefaultUserForumUrl,
                VideoGuidesEnabled = DefaultVideoGuidesUrl != null,
                VideoGuidesUrl = DefaultVideoGuidesUrl,
                SalesEmail = DefaultMailSalesEmail,
                BuyUrl = DefaultBuyUrl,
                LicenseAgreementsEnabled = true,
                LicenseAgreementsUrl = DefaultLicenseAgreements
            };
        }

        #endregion

        #region Default values

        public static string DefaultHelpCenterUrl
        {
            get
            {
                var url = ConfigurationManagerExtension.AppSettings["web.help-center"];
                return string.IsNullOrEmpty(url) ? null : url;
            }
        }

        public static string DefaultFeedbackAndSupportUrl
        {
            get
            {
                var url = ConfigurationManagerExtension.AppSettings["web.support-feedback"];
                return string.IsNullOrEmpty(url) ? null : url;
            }
        }

        public static string DefaultUserForumUrl
        {
            get
            {
                var url = ConfigurationManagerExtension.AppSettings["web.user-forum"];
                return string.IsNullOrEmpty(url) ? null : url;
            }
        }

        public static string DefaultVideoGuidesUrl
        {
            get
            {
                var url = DefaultHelpCenterUrl;
                return string.IsNullOrEmpty(url) ? null : url + "/video.aspx";
            }
        }

        public static string DefaultMailSalesEmail
        {
            get
            {
                var email = ConfigurationManagerExtension.AppSettings["web.payment.email"];
                return !string.IsNullOrEmpty(email) ? email : "<EMAIL>";
            }
        }

        public static string DefaultBuyUrl
        {
            get
            {
                var site = ConfigurationManagerExtension.AppSettings["web.teamlab-site"];
                return !string.IsNullOrEmpty(site) ? site + "/post.ashx?type=buyenterprise" : "";
            }
        }

        public static string DefaultLicenseAgreements
        {
            get
            {
                return "https://help.onlyoffice.com/Products/Files/doceditor.aspx?fileid=6795868&doc=RG5GaVN6azdUQW5kLzZQNzBXbHZ4Rm9QWVZuNjZKUmgya0prWnpCd2dGcz0_IjY3OTU4Njgi0";
            }
        }

        #endregion

        public static AdditionalWhiteLabelSettings Instance
        {
            get
            {
                return LoadForDefaultTenant();
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Utils/Import/CSV/ImportCSVSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ASC.Web.CRM.Core.Enums;

using Newtonsoft.Json.Linq;

namespace ASC.Web.CRM.Classes
{
    public class ImportCSVSettings
    {
        public ImportCSVSettings(String jsonStr)
        {
            var json = JObject.Parse(jsonStr);

            if (json == null) return;

            HasHeader = json["has_header"].Value<bool>();
            DelimiterCharacter = Convert.ToChar(json["delimiter_character"].Value<int>());
            Encoding = Encoding.GetEncoding(json["encoding"].Value<int>());
            QuoteType = Convert.ToChar(json["quote_character"].Value<int>());

            JToken columnMappingToken;

            if (json.TryGetValue("column_mapping", out columnMappingToken))
                ColumnMapping = (JObject)columnMappingToken;

            JToken duplicateRecordRuleToken;

            if (json.TryGetValue("removing_duplicates_behavior", out duplicateRecordRuleToken))
                DuplicateRecordRule = duplicateRecordRuleToken.Value<int>();

            JToken isPrivateToken;
            if (json.TryGetValue("is_private", out isPrivateToken))
            {
                IsPrivate = isPrivateToken.Value<bool>();
                AccessList = json["access_list"].Values<String>().Select(item => new Guid(item)).ToList();
            }

            JToken shareTypeToken;
            if (json.TryGetValue("share_type", out shareTypeToken))
            {
                ShareType = (ShareType)(shareTypeToken.Value<int>());
                ContactManagers = json["contact_managers"].Values<String>().Select(item => new Guid(item)).ToList();
            }

            if (json["tags"] != null)
            {
                Tags = json["tags"].Values<String>().ToList();
            }
        }

        public bool IsPrivate { get; set; }

        public ShareType ShareType { get; set; }

        public int DuplicateRecordRule { get; set; }

        public bool HasHeader { get; set; }

        public char DelimiterCharacter { get; set; }

        public char QuoteType { get; set; }

        public Encoding Encoding { get; set; }

        public List<Guid> AccessList { get; set; }

        public List<Guid> ContactManagers { get; set; }

        public JObject ColumnMapping { get; set; }

        public List<String> Tags { get; set; }
    }

}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/DocumentService/DocbuilderReportsUtility.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Web;

using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Core;
using ASC.Web.Files.Classes;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Files.Services.DocumentService
{
    public enum ReportOrigin
    {
        CRM,
        Projects,
        ProjectsAuto,
    }

    public enum ReportStatus
    {
        Queued,
        Started,
        Done,
        Failed
    }

    public class ReportState
    {
        public string Id { get; set; }
        public string FileName { get; set; }
        public int FileId { get; set; }
        public int ReportType { get; set; }

        public string Exception { get; set; }
        public ReportStatus Status { get; set; }
        public ReportOrigin Origin { get; set; }

        internal string BuilderKey { get; set; }
        internal string Script { get; set; }
        internal string TmpFileName { get; set; }
        internal Action<ReportState, string> SaveFileAction { get; set; }

        internal int TenantId { get; set; }
        internal Guid UserId { get; set; }
        internal string ContextUrl { get; set; }

        public object Obj { get; set; }

        protected DistributedTask TaskInfo { get; private set; }

        public ReportState(string fileName, string tmpFileName, string script, int reportType, ReportOrigin origin, Action<ReportState, string> saveFileAction, object obj)
        {
            Id = DocbuilderReportsUtility.GetCacheKey(origin);
            Origin = origin;
            FileName = fileName;
            TmpFileName = tmpFileName;
            Script = script;
            ReportType = reportType;
            SaveFileAction = saveFileAction;
            TaskInfo = new DistributedTask();
            TenantId = TenantProvider.CurrentTenantID;
            UserId = SecurityContext.CurrentAccount.ID;
            ContextUrl = HttpContext.Current != null ? HttpContext.Current.Request.GetUrlRewriter().ToString() : null;
            Obj = obj;
        }

        public static ReportState FromTask(DistributedTask task)
        {
            return new ReportState(
                task.GetProperty<string>("fileName"),
                task.GetProperty<string>("tmpFileName"),
                task.GetProperty<string>("script"),
                task.GetProperty<int>("reportType"),
                task.GetProperty<ReportOrigin>("reportOrigin"),
                null,
                null)
            {
                Id = task.GetProperty<string>("id"),
                FileId = task.GetProperty<int>("fileId"),
                Status = task.GetProperty<ReportStatus>("status"),
                Exception = task.GetProperty<string>("exception")
            };
        }

        public void GenerateReport(DistributedTask task, CancellationToken cancellationToken)
        {
            try
            {
                Status = ReportStatus.Started;
                PublishTaskInfo();

                if (HttpContext.Current == null && !WorkContext.IsMono && !string.IsNullOrEmpty(ContextUrl))
                {
                    HttpContext.Current = new HttpContext(
                        new HttpRequest("hack", ContextUrl, string.Empty),
                        new HttpResponse(new System.IO.StringWriter()));
                }

                CoreContext.TenantManager.SetCurrentTenant(TenantId);
                SecurityContext.AuthenticateMe(UserId);

                Dictionary<string, string> urls;
                BuilderKey = DocumentServiceConnector.DocbuilderRequest(null, Script, true, out urls);

                while (true)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        throw new OperationCanceledException();
                    }

                    Task.Delay(1500, cancellationToken).Wait(cancellationToken);
                    var builderKey = DocumentServiceConnector.DocbuilderRequest(BuilderKey, null, true, out urls);
                    if (builderKey == null)
                        throw new NullReferenceException();

                    if (urls != null && !urls.Any()) throw new Exception("Empty response");

                    if (urls != null && urls.ContainsKey(TmpFileName))
                        break;
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    throw new OperationCanceledException();
                }

                SaveFileAction(this, urls[TmpFileName]);

                Status = ReportStatus.Done;
            }
            catch (Exception e)
            {
                Global.Logger.Error("DocbuilderReportsUtility error", e);
                Exception = e.Message;
                Status = ReportStatus.Failed;
            }

            PublishTaskInfo();
        }

        public DistributedTask GetDistributedTask()
        {
            FillDistributedTask();
            return TaskInfo;
        }

        protected void PublishTaskInfo()
        {
            var tries = 3;
            while (tries-- > 0)
            {
                try
                {
                    FillDistributedTask();
                    TaskInfo.PublishChanges();
                    return;
                }
                catch (Exception e)
                {
                    LogManager.GetLogger("ASC").Error(" PublishTaskInfo DocbuilderReportsUtility", e);
                    if (tries == 0) throw;
                }
            }
        }

        protected void FillDistributedTask()
        {
            TaskInfo.SetProperty("id", Id);
            TaskInfo.SetProperty("fileName", FileName);
            TaskInfo.SetProperty("tmpFileName", TmpFileName);
            TaskInfo.SetProperty("reportType", ReportType);
            TaskInfo.SetProperty("fileId", FileId);
            TaskInfo.SetProperty("status", Status);
            TaskInfo.SetProperty("reportOrigin", Origin);
            TaskInfo.SetProperty("exception", Exception);
        }
    }

    public static class DocbuilderReportsUtility
    {
        private static readonly DistributedTaskQueue tasks;
        private static readonly object Locker;

        public static string TmpFileName
        {
            get
            {
                return string.Format("tmp{0}.xlsx", DateTime.UtcNow.Ticks);
            }
        }

        static DocbuilderReportsUtility()
        {
            tasks = new DistributedTaskQueue("DocbuilderReportsUtility", 10);
            Locker = new object();
        }

        public static void Enqueue(ReportState state)
        {
            lock (Locker)
            {
                tasks.QueueTask(state.GenerateReport, state.GetDistributedTask());
            }
        }

        public static void Terminate(ReportOrigin origin)
        {
            lock (Locker)
            {
                var result = tasks.GetTasks().Where(Predicate(origin));

                foreach (var t in result)
                {
                    tasks.CancelTask(t.Id);
                }
            }
        }

        public static ReportState Status(ReportOrigin origin)
        {
            lock (Locker)
            {
                var task = tasks.GetTasks().LastOrDefault(Predicate(origin));
                if (task == null) return null;

                var result = ReportState.FromTask(task);
                if ((int)result.Status > 1)
                {
                    tasks.RemoveTask(task.Id);
                }

                return result;
            }
        }

        private static Func<DistributedTask, bool> Predicate(ReportOrigin origin)
        {
            return t => t.GetProperty<string>("id") == GetCacheKey(origin);
        }

        internal static string GetCacheKey(ReportOrigin origin)
        {
            return string.Format("{0}_{1}_{2}", TenantProvider.CurrentTenantID, SecurityContext.CurrentAccount.ID, (int)origin);
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Billing/License/LicenseException.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Core.Billing
{
    [Serializable]
    public class LicenseException : BillingException
    {
        public LicenseException(string message, object debugInfo = null) : base(message, debugInfo)
        {
        }
    }

    [Serializable]
    public class LicenseExpiredException : LicenseException
    {
        public LicenseExpiredException(string message, object debugInfo = null) : base(message, debugInfo)
        {
        }
    }

    [Serializable]
    public class LicenseQuotaException : LicenseException
    {
        public LicenseQuotaException(string message, object debugInfo = null) : base(message, debugInfo)
        {
        }
    }

    [Serializable]
    public class LicensePortalException : LicenseException
    {
        public LicensePortalException(string message, object debugInfo = null) : base(message, debugInfo)
        {
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Controls/Common/PageNavigator.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using ASC.Web.Studio.PublicResources;

namespace ASC.Web.Studio.Controls.Common
{
    [Themeable(true)]
    [ToolboxData("<{0}:PageNavigator runat=server></{0}:PageNavigator>")]
    public class PageNavigator : WebControl, ICloneable
    {
        private string _jsObjName;

        public int CurrentPageNumber { get; set; }

        public int EntryCountOnPage { get; set; }

        public int EntryCount { get; set; }

        public bool VisibleOnePage { get; set; }

        public int VisiblePageCount { get; set; }

        public string PageUrl { get; set; }

        public string ParamName { get; set; }

        public bool AutoDetectCurrentPage { get; set; }

        public PageNavigator()
        {
            ParamName = "p";
            VisiblePageCount = 10;
            VisibleOnePage = false;
            AutoDetectCurrentPage = false;
            EntryCountOnPage = 1;
            PageUrl = "";
        }

        private int _page_amount;
        private int _start_page;
        private int _end_page;

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            _jsObjName = String.IsNullOrEmpty(ID) ? "pageNavigator" + UniqueID.Replace('$', '_') : ID;

            if (HttpContext.Current != null && HttpContext.Current.Request != null && AutoDetectCurrentPage)
            {
                if (!String.IsNullOrEmpty(HttpContext.Current.Request[this.ParamName]))
                {
                    try
                    {
                        CurrentPageNumber = Convert.ToInt32(HttpContext.Current.Request[this.ParamName]);
                    }
                    catch
                    {
                        CurrentPageNumber = 0;
                    }
                }
            }

            if (CurrentPageNumber <= 0)
                CurrentPageNumber = 1;

            var scriptNav = String.Format(@"window.{0} = new ASC.Controls.PageNavigator.init('{0}', 'body', '{1}', {2}, {3}, '{4}', '{5}');",
                                          _jsObjName,
                                          EntryCountOnPage,
                                          VisiblePageCount,
                                          CurrentPageNumber,
                                          UserControlsCommonResource.PreviousPage,
                                          UserControlsCommonResource.NextPage);

            Page.RegisterInlineScript(scriptNav, onReady: false);


            _page_amount = Convert.ToInt32(Math.Ceiling(EntryCount / (EntryCountOnPage * 1.0)));
            _start_page = CurrentPageNumber - 1 - VisiblePageCount / 2;

            if (_start_page + VisiblePageCount > _page_amount)
                _start_page = _page_amount - VisiblePageCount;

            if (_start_page < 0)
                _start_page = 0;

            _end_page = _start_page + VisiblePageCount;

            if (_end_page > _page_amount)
                _end_page = _page_amount;

            if ((_page_amount == 1 && VisibleOnePage) || _start_page >= _end_page || _end_page - _start_page <= 1)
                return;

            var spliter = "&";
            if (PageUrl.IndexOf("?") == -1)
            {
                spliter = "&";
            }

            var isFirst = (CurrentPageNumber == 1);
            var isLast = (CurrentPageNumber == _page_amount);

            var prevURL = PageUrl + spliter + ParamName + "=" + (CurrentPageNumber - 1).ToString();
            var nextURL = PageUrl + spliter + ParamName + "=" + (CurrentPageNumber + 1).ToString();

            var script = @"document.onkeydown = function(e)
                            {
                                var code;
                                if (!e) var e = window.event;
                                if (e.keyCode) code = e.keyCode;
                                else if (e.which) code = e.which;" +

                         ((!isFirst) ?
                              @"if ((code == 37) && (e.ctrlKey == true))
                                {
                                    window.open('" + prevURL + @"','_self');
                                }" : "") +

                         ((!isLast) ?
                              @"if ((code == 39) && (e.ctrlKey == true))
                                {
                                    window.open('" + nextURL + @"','_self');
                                }" : "") +
                         @"}; ";

            Page.RegisterInlineScript(script, onReady: false);
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            var sb = new StringBuilder();

            if (_page_amount == 1 && VisibleOnePage)
            {
                sb.Append("<div class='pagerNavigationLinkBox'>");
                sb.Append("<span class='pagerCurrentPosition'>");
                sb.Append(1);
                sb.Append("</span>");

                sb.Append("</div>");

                writer.Write(sb.ToString());
                return;
            }

            if (_start_page >= _end_page || _end_page - _start_page <= 1)
                return;

            sb.Append("<div class='pagerNavigationLinkBox'>");

            var spliter = "&";
            if (PageUrl.IndexOf("?") == -1)
            {
                spliter = "&";
            }
            string url = PageUrl;

            if (CurrentPageNumber != 1)
            {
                url = PageUrl + spliter + ParamName + "=" + Convert.ToString(CurrentPageNumber - 1);
                sb.Append("<a class='pagerPrevButtonCSSClass' href=\"" + url + "\">" + UserControlsCommonResource.PreviousPage + "</a>");
            }

            for (var i = _start_page; i < _end_page && _end_page - _start_page > 1; i++)
            {
                if (i == _start_page && i != 0)
                {
                    url = PageUrl + spliter + ParamName + "=" + Convert.ToString(1);
                    sb.Append("<a class='pagerNavigationLinkCSSClass' href=\"" + url + "\">1</a>");
                    if (i != 1)
                        sb.Append("<span class='splitter'>...</span>");
                }
                if ((CurrentPageNumber - 1) == i)
                {
                    sb.Append("<span class='pagerCurrentPosition'>");
                    sb.Append(CurrentPageNumber);
                    sb.Append("</span>");
                }
                else
                {
                    url = PageUrl + spliter + ParamName + "=" + Convert.ToString((i + 1));
                    sb.Append("<a class='pagerNavigationLinkCSSClass' href=\"" + url + "\">" + (i + 1) + "</a>");
                }
                if (i == _end_page - 1 && i != _page_amount - 1)
                {
                    url = PageUrl + spliter + ParamName + "=" + Convert.ToString((_page_amount));
                    if (i != _page_amount - 2)
                        sb.Append("<span class='splitter'>...</span>");
                    sb.Append("<a class='pagerNavigationLinkCSSClass' href=\"" + url + "\">" + _page_amount + "</a>");
                }
            }

            if (CurrentPageNumber != _page_amount && _page_amount != 1)
            {
                url = PageUrl + spliter + ParamName + "=" + Convert.ToString(CurrentPageNumber + 1);
                sb.Append("<a class='pagerNextButtonCSSClass' href=\"" + url + "\">" + UserControlsCommonResource.NextPage + "</a>");
            }

            sb.Append("</div>");
            writer.Write(sb.ToString());
        }

        #region ICloneable Members

        public object Clone()
        {
            return new PageNavigator
            {
                CurrentPageNumber = this.CurrentPageNumber,
                EntryCountOnPage = this.EntryCountOnPage,
                EntryCount = this.EntryCount,
                VisibleOnePage = this.VisibleOnePage,
                VisiblePageCount = this.VisiblePageCount,
                PageUrl = this.PageUrl,
                ParamName = this.ParamName,
            };
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Storage/MailStoragePathCombiner.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;

using ASC.Core;
using ASC.Mail.Data.Contracts;
using ASC.Security.Cryptography;
using ASC.Web.Core.Files;
using ASC.Web.Studio.Utility;

namespace ASC.Mail.Data.Storage
{
    public static class MailStoragePathCombiner
    {
        public const string BODY_FILE_NAME = "body.html";
        public const string EML_FILE_NAME = "message.eml";

        private static readonly Dictionary<char, string> Replacements = new Dictionary<char, string>
                {
                    {'+', "%2b"}, {'#', "%23"}, {'|', "_"}, {'<', "_"}, {'>', "_"}, {'"', "_"}, {':', "_"}, {'~', "_"}, {'?', "_"}
                };

        private const string BAD_CHARS_IN_PATH = "|<>:\"~?";

        private static string ComplexReplace(string str, string replacement)
        {
            return replacement.Aggregate(str, (current, badChar) => current.Replace(badChar.ToString(CultureInfo.InvariantCulture), Replacements[badChar]));
        }

        public static string PrepareAttachmentName(string name)
        {
            return ComplexReplace(name, BAD_CHARS_IN_PATH);
        }

        public static string GetPreSignedUri(int fileId, int tenant, string user, string stream, int fileNumber, string fileName)
        {
            //TODO: Move url to config;
            const string attachmentPath = "/addons/mail/httphandlers/download.ashx";

            var uriBuilder = new UriBuilder(CommonLinkUtility.GetFullAbsolutePath(attachmentPath));
            if (uriBuilder.Uri.IsLoopback)
            {
                uriBuilder.Host = Dns.GetHostName();
            }
            var query = uriBuilder.Query;

            query += "attachid=" + fileId + "&";
            query += "stream=" + stream + "&";
            query += FilesLinkUtility.AuthKey + "=" + EmailValidationKeyProvider.GetEmailKey(fileId + stream);

            var url = uriBuilder.Uri + "?" + query;

            return url;
        }

        public static string GetStoredUrl(Uri uri)
        {
            var url = uri.ToString();

            if (WorkContext.IsMono && uri.Scheme == Uri.UriSchemeFile)
            {
                if (url.StartsWith("file://"))
                    url = url.Substring(7);
            }

            return GetStoredUrl(url);
        }

        private static string GetStoredUrl(string fullUrl)
        {
            return ComplexReplace(fullUrl, "#");
        }

        public static string GetFileKey(string user, string stream, int fileNumber, string fileName)
        {
            return string.Format("{0}/{1}/attachments/{2}/{3}", user, stream, fileNumber, ComplexReplace(fileName, BAD_CHARS_IN_PATH));
        }

        public static string GetTempFileKey(string user, string stream, int fileNumber, string fileName)
        {
            return string.Format("temp/{0}/{1}/attachments/{2}/{3}", user, stream, fileNumber, ComplexReplace(fileName, BAD_CHARS_IN_PATH));
        }

        public static string GetBodyKey(string stream)
        {
            return string.Format("{0}/{1}", stream, BODY_FILE_NAME);
        }

        public static string GetBodyKey(string user, string stream)
        {
            return string.Format("{0}/{1}/{2}", user, stream, BODY_FILE_NAME);
        }

        public static string GetEmlKey(string user, string stream)
        {
            return string.Format("{0}/{1}/{2}", user, stream, EML_FILE_NAME);
        }

        public static string GerStoredFilePath(MailAttachmentData mailAttachmentData)
        {
            return GetFileKey(mailAttachmentData.user, mailAttachmentData.streamId, mailAttachmentData.fileNumber, mailAttachmentData.storedName);
        }

        public static string GetTempStoredFilePath(MailAttachmentData mailAttachmentData)
        {
            return GetTempFileKey(mailAttachmentData.user, mailAttachmentData.streamId, mailAttachmentData.fileNumber, mailAttachmentData.storedName);
        }

        public static string GetPreSignedUrl(MailAttachmentData mailAttachmentData)
        {
            return GetPreSignedUri(mailAttachmentData.fileId, mailAttachmentData.tenant, mailAttachmentData.user, mailAttachmentData.streamId, mailAttachmentData.fileNumber, mailAttachmentData.storedName);
        }

        public static string GerStoredSignatureImagePath(string user, int mailboxId, string storedName)
        {
            return String.Format("{0}/signatures/{1}/{2}", user, mailboxId, ComplexReplace(storedName, BAD_CHARS_IN_PATH));
        }

        public static string GetMessageDirectory(string user, string stream)
        {
            return String.Format("{0}/{1}", user, stream);
        }

        public static string GetUserMailsDirectory(string user)
        {
            return String.Format("{0}", user);
        }

        public static string GetEditorSmileBaseUrl()
        {
            return "/usercontrols/common/ckeditor/plugins/smiley/teamlab_images";
        }

        public static string GetEditorImagesBaseUrl()
        {
            return "/usercontrols/common/ckeditor/plugins/filetype/images";
        }

        public static string GetProxyHttpHandlerUrl()
        {
            return "/httphandlers/urlProxy.ashx";
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/ApiServer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Routing;

using ASC.Api.Batch;
using ASC.Api.Interfaces;
using ASC.Common.Logging;

using Autofac;

namespace ASC.Api
{
    public class ApiServer
    {
        private static bool? available = null;
        private readonly HttpContextBase _context;
        private readonly ApiBatchHttpHandler _batchHandler;
        private readonly IComponentContext container;


        public static bool Available
        {
            get
            {
                if (!available.HasValue)
                {
                    available = ApiSetup.Builder.IsRegistered<ILog>();
                }
                return available.Value;
            }
        }

        public ApiServer()
            : this(HttpContext.Current)
        {
        }

        public ApiServer(HttpContext context)
            : this(new HttpContextWrapper(context))
        { }

        public ApiServer(HttpContextBase context)
        {
            _context = context;
            container = ApiSetup.Builder;
            var config = container.Resolve<IApiConfiguration>();
            var route = RouteTable.Routes.OfType<Route>().First(r => r.Url.EndsWith(config.GetBasePath() + "batch"));
            if (route == null)
            {
                throw new ArgumentException("Couldn't resolve api");
            }
            var routeHandler = route.RouteHandler as ApiBatchRouteHandler;
            if (routeHandler == null)
            {
                throw new ArgumentException("Couldn't resolve api");
            }

            var requestContext = new RequestContext(context, new RouteData(new Route("batch", routeHandler), routeHandler));
            _batchHandler = routeHandler.GetHttpHandler(requestContext) as ApiBatchHttpHandler;
            if (_batchHandler == null)
            {
                throw new ArgumentException("Couldn't resolve api");
            }
        }

        public string GetApiResponse(string apiUrl)
        {
            return GetApiResponse(apiUrl, null);
        }

        public string GetApiResponse(string apiUrl, string httpMethod)
        {
            return GetApiResponse(apiUrl, httpMethod, null);
        }

        public string GetApiResponse(string apiUrl, string httpMethod, string body)
        {
            return GetApiResponse(new ApiBatchRequest() { Method = httpMethod, RelativeUrl = apiUrl, Body = body });
        }

        public string GetApiResponse(ApiBatchRequest request)
        {
            var response = CallApiMethod(request);
            return response != null ? response.Data : null;
        }

        public ApiBatchResponse CallApiMethod(string apiUrl)
        {
            return CallApiMethod(apiUrl, "GET");
        }

        public ApiBatchResponse CallApiMethod(string apiUrl, string httpMethod)
        {
            return CallApiMethod(apiUrl, httpMethod, null);
        }

        public ApiBatchResponse CallApiMethod(string apiUrl, string httpMethod, string body)
        {
            return CallApiMethod(new ApiBatchRequest { Method = httpMethod, RelativeUrl = apiUrl, Body = body });
        }

        public ApiBatchResponse CallApiMethod(ApiBatchRequest request)
        {
            return CallApiMethod(request, true);
        }

        public ApiBatchResponse CallApiMethod(ApiBatchRequest request, bool encode)
        {
            var response = _batchHandler.ProcessBatchRequest(_context, request);
            if (encode && response != null && response.Data != null)
                response.Data = Convert.ToBase64String(Encoding.UTF8.GetBytes(response.Data));
            return response;
        }


        public IEnumerable<ApiBatchResponse> CallApiMethods(IEnumerable<ApiBatchRequest> requests)
        {
            return requests.Select(request => CallApiMethod(request));
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Entities/DealMilestone.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Runtime.Serialization;

#endregion

namespace ASC.CRM.Core.Entities
{

    [DataContract]
    public class DealMilestone : DomainObject
    {
        [DataMember(Name = "title")]
        public String Title { get; set; }

        [DataMember(Name = "description")]
        public String Description { get; set; }

        [DataMember(Name = "color")]
        public String Color { get; set; }

        [DataMember(Name = "sort_order")]
        public int SortOrder { get; set; }

        [DataMember(Name = "probability")]
        public int Probability { get; set; }

        [DataMember(Name = "status")]
        public DealMilestoneStatus Status { get; set; }

    }
}

<|start_filename|>web/core/ASC.Web.Core/Client/ClientSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;

namespace ASC.Web.Core.Client
{
    public static class ClientSettings
    {
        private static bool? bundlesEnabled;
        private static bool? storeEnabled;
        private static bool? gzipEnabled;
        private static readonly string resetCacheKey = ConfigurationManagerExtension.AppSettings["web.client.cache.resetkey"] ?? DateTime.UtcNow.ToString("yyyyMMddhhmmss");


        public static bool BundlingEnabled
        {
            get { return bundlesEnabled ?? (bool)(bundlesEnabled = bool.Parse(ConfigurationManagerExtension.AppSettings["web.client.bundling"] ?? "false")); }
        }

        public static bool StoreBundles
        {
            get { return storeEnabled ?? (bool)(storeEnabled = bool.Parse(ConfigurationManagerExtension.AppSettings["web.client.store"] ?? "false")); }
        }

        public static bool GZipEnabled
        {
            get { return gzipEnabled ?? (bool)(gzipEnabled = bool.Parse(ConfigurationManagerExtension.AppSettings["web.client.store.gzip"] ?? "true")); }
        }

        public static string ResetCacheKey
        {
            get { return resetCacheKey; }
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Client/Bundling/CssTransform.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Hosting;
using System.Web.Optimization;

using dotless.Core;
using dotless.Core.configuration;

using Microsoft.Ajax.Utilities;

namespace ASC.Web.Core.Client.Bundling
{
    class CssTransform : IItemTransform, IBundleTransform
    {
        private readonly string bundlepath;
        private readonly bool minify;

        public CssTransform() : this("", false) { }

        public CssTransform(string bundlepath, bool minify = true)
        {
            this.bundlepath = bundlepath;
            this.minify = minify;
        }


        public string Process(string includedVirtualPath, string input)
        {
            if (VirtualPathUtility.GetExtension(includedVirtualPath) == ".less")
            {
                var cfg = DotlessConfiguration.GetDefaultWeb();
                cfg.Web = true;
                cfg.MinifyOutput = BundleTable.EnableOptimizations;
                cfg.MapPathsToWeb = true;
                cfg.CacheEnabled = false;

                var importRegex = new Regex(@"@import (.*?);", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
                input = importRegex.Replace(input, m => ResolveImportLessPath(includedVirtualPath, m));
                input = LessWeb.Parse(input, cfg);
            }

            var urlRegex = new Regex(@"url\((.*?)\)", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
            input = urlRegex.Replace(input, m => ResolveUrlPath(includedVirtualPath, m));
            return minify ? new Minifier().MinifyStyleSheet(input) : input;
        }

        private string ResolveImportLessPath(string virtualPath, Match m)
        {
            if (m.Success && m.Groups[1].Success)
            {
                var path = m.Groups[1].Value.Trim().Trim('\'', '"');
                var vpath = VirtualPathUtility.Combine(VirtualPathUtility.GetDirectory(virtualPath), path);
                return m.Value.Replace(m.Groups[1].Value, "\"" + vpath + "\"");
            }
            return m.Value;
        }

        private string ResolveUrlPath(string virtualPath, Match m)
        {
            if (m.Success && m.Groups[1].Success)
            {
                var path = m.Groups[1].Value.Trim().Trim('\'', '"');
                if (path.StartsWith("data:", StringComparison.InvariantCultureIgnoreCase))
                {
                    return m.Value;
                }
                if (Uri.IsWellFormedUriString(path, UriKind.Relative))
                {
                    path = VirtualPathUtility.Combine(VirtualPathUtility.GetDirectory(virtualPath), path);
                }
                else if (path.StartsWith(Uri.UriSchemeHttp))
                {
                    path = new Uri(path).PathAndQuery;
                }
                if (HostingEnvironment.ApplicationVirtualPath != "/" && path.StartsWith(HostingEnvironment.ApplicationVirtualPath))
                {
                    path = path.Substring(HostingEnvironment.ApplicationVirtualPath.Length);
                }
                if (path.StartsWith("/"))
                {
                    path = "~" + path;
                }
                path = VirtualPathUtility.MakeRelative(bundlepath, path);
                return m.Value.Replace(m.Groups[1].Value, "\"" + path + "\"");
            }
            return m.Value;
        }

        public void Process(BundleContext context, BundleResponse response)
        {
            response.ContentType = "text/css";
        }
    }
}

<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Core/Dao/AliasDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Server.Core.Dao.Interfaces;
using ASC.Mail.Server.Core.DbSchema;
using ASC.Mail.Server.Core.DbSchema.Interfaces;
using ASC.Mail.Server.Core.DbSchema.Tables;
using ASC.Mail.Server.Core.Entities;

namespace ASC.Mail.Server.Core.Dao
{
    public class AliasDao : BaseDao, IAliasDao
    {
        protected static ITable table = new MailServerTableFactory().Create<AliasTable>();

        public AliasDao(IDbManager dbManager)
            : base(table, dbManager)
        {
        }

        public int Save(Alias alias)
        {
            var query = new SqlInsert(AliasTable.TABLE_NAME, true)
                .InColumnValue(AliasTable.Columns.ADDRESS, alias.Address)
                .InColumnValue(AliasTable.Columns.GOTO, alias.GoTo)
                .InColumnValue(AliasTable.Columns.DOMAIN, alias.Domain)
                .InColumnValue(AliasTable.Columns.CREATED, alias.Created)
                .InColumnValue(AliasTable.Columns.MODIFIED, alias.Modified)
                .InColumnValue(AliasTable.Columns.ACTIVE, alias.IsActive)
                .InColumnValue(AliasTable.Columns.IS_GROUP, alias.IsGroup);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }

        public int Remove(string address)
        {
            var query = new SqlDelete(AliasTable.TABLE_NAME)
                .Where(AliasTable.Columns.ADDRESS, address);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }

        public int RemoveByDomain(string domain)
        {
            var query = new SqlDelete(AliasTable.TABLE_NAME)
                .Where(AliasTable.Columns.DOMAIN, domain);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }
    }
}

<|start_filename|>common/ASC.Common/Data/AdoProxy/DbConnectionProxy.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Data;
using System.Data.Common;

namespace ASC.Common.Data.AdoProxy
{
    class DbConnectionProxy : DbConnection
    {
        private readonly DbConnection connection;
        private readonly ProxyContext context;
        private bool disposed;


        public DbConnectionProxy(DbConnection connection, ProxyContext ctx)
        {
            if (connection == null) throw new ArgumentNullException("connection");
            if (ctx == null) throw new ArgumentNullException("ctx");

            this.connection = connection;
            context = ctx;
        }

        protected override System.Data.Common.DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
        {
            using (ExecuteHelper.Begin(dur => context.FireExecuteEvent(this, "BeginTransaction", dur)))
            {
                return new DbTransactionProxy(connection.BeginTransaction(), context);
            }
        }

        public override void ChangeDatabase(string databaseName)
        {
            connection.ChangeDatabase(databaseName);
        }

        public override void Close()
        {
            connection.Close();
        }

        public override string ConnectionString
        {
            get { return connection.ConnectionString; }
            set { connection.ConnectionString = value; }
        }

        public override int ConnectionTimeout
        {
            get { return connection.ConnectionTimeout; }
        }

        protected override DbCommand CreateDbCommand()
        {
            return new DbCommandProxy(connection.CreateCommand(), context);
        }

        public override string Database
        {
            get { return connection.Database; }
        }

        public override string DataSource
        {
            get { return connection.DataSource; }
        }

        public override void Open()
        {
            using (ExecuteHelper.Begin(dur => context.FireExecuteEvent(this, "Open", dur)))
            {
                connection.Open();
            }
        }

        public override string ServerVersion
        {
            get { return connection.ServerVersion; }
        }

        public override ConnectionState State
        {
            get { return connection.State; }
        }

        protected override void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    using (ExecuteHelper.Begin(dur => context.FireExecuteEvent(this, "Dispose", dur)))
                    {
                        connection.Dispose();
                    }
                }
                disposed = true;
            }
        }

        ~DbConnectionProxy()
        {
            Dispose(false);
        }
    }
}

<|start_filename|>common/ASC.ActiveDirectory/Novell/Data/NovellLdapObject.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.ActiveDirectory.Base;
using ASC.ActiveDirectory.Base.Data;
using ASC.ActiveDirectory.Novell.Extensions;
using ASC.Common.Logging;

using Novell.Directory.Ldap;

namespace ASC.ActiveDirectory.Novell.Data
{
    /// <summary>
    /// Novell LDAP object class
    /// </summary>
    public class NovellLdapObject : LdapObject
    {
        private readonly LdapEntry _ldapEntry;
        private readonly ILog _log;
        private readonly string _sid;
        private readonly string _sidAttribute;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="ldapEntry">init ldap entry</param>
        /// <param name="ldapUniqueIdAttribute"></param>
        public NovellLdapObject(LdapEntry ldapEntry, string ldapUniqueIdAttribute = null)
        {
            if (ldapEntry == null)
                throw new ArgumentNullException("ldapEntry");

            _ldapEntry = ldapEntry;

            if (string.IsNullOrEmpty(ldapUniqueIdAttribute))
                return;

            _log = LogManager.GetLogger("ASC");

            try
            {
                _sid = GetValue(ldapUniqueIdAttribute) as string;
                _sidAttribute = ldapUniqueIdAttribute;
            }
            catch (Exception e)
            {
                _log.ErrorFormat("Can't get LDAPObject Sid property. {0}", e);
            }
        }

        #region .Public

        public override string DistinguishedName
        {
            get { return _ldapEntry.DN; }
        }

        public override string Sid
        {
            get { return _sid; }
        }

        public override string SidAttribute
        {
            get { return _sidAttribute; }
        }

        public override bool IsDisabled
        {
            get
            {
                var userAccauntControl = LdapConstants.UserAccountControl.EMPTY;
                try
                {
                    var uac = Convert.ToInt32(GetValue(LdapConstants.ADSchemaAttributes.USER_ACCOUNT_CONTROL));
                    userAccauntControl = (LdapConstants.UserAccountControl)uac;
                }
                catch (Exception e)
                {
                    _log.ErrorFormat("Can't get LDAPUser UserAccauntControl property. {0}", e);
                }

                return (userAccauntControl & LdapConstants.UserAccountControl.ADS_UF_ACCOUNTDISABLE) > 0;
            }
        }

        #endregion

        /// <summary>
        /// Get property object
        /// </summary>
        /// <param name="propertyName">property name</param>
        /// <returns>value object</returns>
        public sealed override object GetValue(string propertyName, bool getBytes = false)
        {
            return _ldapEntry.GetAttributeValue(propertyName, getBytes);
        }

        /// <summary>
        /// Get property values
        /// </summary>
        /// <param name="propertyName">property name</param>
        /// <returns>list of values</returns>
        public override List<string> GetValues(string propertyName)
        {
            var propertyValueArray = _ldapEntry.GetAttributeArrayValue(propertyName);
            if (propertyValueArray == null)
            {
                return new List<string>();
            }

            var properties = propertyValueArray.ToList();
            return properties;
        }
    }
}


<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/MailModuleSpecifics.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

using ASC.Common.Logging;
using ASC.Data.Backup.Tasks.Data;
using ASC.Data.Storage;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal class MailModuleSpecifics : ModuleSpecificsBase
    {
        private readonly TableInfo[] _tables = new[]
            {
                new TableInfo("mail_attachment", "tenant", "id"),
                new TableInfo("mail_chain", "tenant") {UserIDColumns = new[] {"id_user"}},
                new TableInfo("mail_contacts", "tenant", "id") {UserIDColumns = new[] {"id_user"}},
                new TableInfo("mail_folder_counters", "tenant") {UserIDColumns = new[] {"id_user"}},
                new TableInfo("mail_mail", "tenant", "id")
                    {
                        UserIDColumns = new[] {"id_user"},
                        DateColumns = new Dictionary<string, bool> {{"date_received", false}, {"date_sent", false}, {"chain_date", false}}
                    },
                new TableInfo("mail_mailbox", "tenant", "id")
                    {
                        UserIDColumns = new[] {"id_user"},
                        DateColumns = new Dictionary<string, bool> {{"begin_date", false}}
                    },
                new TableInfo("mail_tag", "tenant", "id") {UserIDColumns = new[] {"id_user"}},
                new TableInfo("mail_tag_addresses", "tenant"),
                new TableInfo("mail_tag_mail", "tenant") {UserIDColumns = new[] {"id_user"}},
                new TableInfo("mail_chain_x_crm_entity", "id_tenant"),
                new TableInfo("mail_mailbox_signature", "tenant"),
                new TableInfo("mail_mailbox_autoreply", "tenant"),
                new TableInfo("mail_mailbox_autoreply_history", "tenant"),
                new TableInfo("mail_contact_info", "tenant", "id") {UserIDColumns = new[] {"id_user"}},
                new TableInfo("mail_mailbox_provider", idColumn: "id"),
                new TableInfo("mail_mailbox_domain", idColumn: "id"),
                new TableInfo("mail_mailbox_server", idColumn: "id")
            };

        private readonly RelationInfo[] _tableRelations = new[]
            {
                new RelationInfo("mail_mail", "id", "mail_attachment", "id_mail"),
                new RelationInfo("mail_mailbox", "id", "mail_chain", "id_mailbox"),
                new RelationInfo("mail_tag", "id", "mail_chain", "tags"),
                new RelationInfo("crm_tag", "id", "mail_chain", "tags", typeof(CrmModuleSpecifics)),
                new RelationInfo("mail_mailbox", "id", "mail_mail", "id_mailbox"),
                new RelationInfo("crm_tag", "id", "mail_tag", "crm_id", typeof(CrmModuleSpecifics)),
                new RelationInfo("mail_tag", "id", "mail_tag_addresses", "id_tag", x => Convert.ToInt32(x["id_tag"]) > 0),
                new RelationInfo("crm_tag", "id", "mail_tag_addresses", "id_tag", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["id_tag"]) < 0),
                new RelationInfo("mail_mail", "id", "mail_tag_mail", "id_mail"),
                new RelationInfo("mail_tag", "id", "mail_tag_mail", "id_tag", x => Convert.ToInt32(x["id_tag"]) > 0),
                new RelationInfo("crm_tag", "id", "mail_tag_mail", "id_tag", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["id_tag"]) < 0),
                new RelationInfo("mail_mailbox", "id", "mail_chain_x_crm_entity", "id_mailbox"),
                new RelationInfo("crm_contact", "id", "mail_chain_x_crm_entity", "entity_id", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["entity_type"]) == 1),
                new RelationInfo("crm_case", "id", "mail_chain_x_crm_entity", "entity_id", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["entity_type"]) == 2),
                new RelationInfo("crm_deal", "id", "mail_chain_x_crm_entity", "entity_id", typeof(CrmModuleSpecifics), x => Convert.ToInt32(x["entity_type"]) == 3),
                new RelationInfo("mail_mailbox", "id", "mail_mailbox_signature", "id_mailbox"),
                new RelationInfo("files_folder", "id", "mail_mailbox", "email_in_folder", typeof(FilesModuleSpecifics)),
                new RelationInfo("mail_mailbox", "id", "mail_mailbox_autoreply", "id_mailbox"),
                new RelationInfo("mail_mailbox", "id", "mail_mailbox_autoreply_history", "id_mailbox"),
                new RelationInfo("mail_contacts", "id", "mail_contact_info", "id_contact"),
                new RelationInfo("mail_mailbox_provider", "id", "mail_mailbox_domain", "id_provider"),
                new RelationInfo("mail_mailbox_server", "id", "mail_mailbox", "id_smtp_server"),
                new RelationInfo("mail_mailbox_server", "id", "mail_mailbox", "id_in_server")
            };

        public override ModuleName ModuleName
        {
            get { return ModuleName.Mail; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return _tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return _tableRelations; }
        }

        protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
        {
            //optimization: 1) do not include "deleted" rows, 2) backup mail only for the last 30 days
            switch (table.Name)
            {
                case "mail_mailbox_provider":
                    return string.Format("where t.id in " +
                                            "(select distinct t2.id_provider from mail_mailbox t1 " +
                                            "inner join mail_mailbox_server t2 on t2.id in (t1.id_in_server, t1.id_smtp_server) and t2.is_user_data = 1 " +
                                            "where t1.tenant = {0} and t1.is_removed = 0)", tenantId);

                // mail_mailbox_domain.id_provider not in index
                case "mail_mailbox_domain":
                    return string.Format("where t.id_provider in " +
                                            "(select distinct t2.id_provider from mail_mailbox t1 " +
                                            "inner join mail_mailbox_server t2 on t2.id in (t1.id_in_server, t1.id_smtp_server) and t2.is_user_data = 1 " +
                                            "where t1.tenant = {0} and t1.is_removed = 0)", tenantId);

                case "mail_mailbox_server":
                    return string.Format("where t.id in " +
                                            "(select distinct t2.id from mail_mailbox t1 " +
                                            "inner join mail_mailbox_server t2 on t2.id in (t1.id_in_server, t1.id_smtp_server) and t2.is_user_data = 1 " +
                                            "where t1.tenant = {0} and t1.is_removed = 0)", tenantId);

                case "mail_mailbox":
                    return string.Format("where t.is_removed = 0 and t.tenant = {0}", tenantId);

                //condition on chain_date because of Bug 18855 - transfer mail only for the last 30 days
                case "mail_mail":
                    return string.Format("inner join mail_mailbox t1 on t1.id = t.id_mailbox " +
                                         "where t.tenant = {0} and t1.tenant = {0} and t.is_removed = 0 and t1.is_removed = 0 and t.chain_date > '{1}'",
                                         tenantId,
                                         DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)).ToString("yyyy-MM-dd HH:mm:ss"));

                case "mail_attachment":
                case "mail_tag_mail":
                    return string.Format("inner join mail_mail as t1 on t1.id = t.id_mail " +
                                         "inner join mail_mailbox as t2 on t2.id = t1.id_mailbox " +
                                         "where t1.tenant = {0} and t2.tenant = {0} and t1.is_removed = 0 and t2.is_removed = 0 and t1.chain_date > '{1}'",
                                         tenantId,
                                         DateTime.UtcNow.Subtract(TimeSpan.FromDays(30)).ToString("yyyy-MM-dd HH:mm:ss"));

                case "mail_chain":
                    return string.Format("inner join mail_mailbox t1 on t1.id = t.id_mailbox " +
                                         "where t.tenant = {0} and t1.is_removed = 0",
                                         tenantId);

                default:
                    return base.GetSelectCommandConditionText(tenantId, table);
            }
        }

        protected override string GetDeleteCommandConditionText(int tenantId, TableInfo table)
        {
            //delete all rows regardless of whether there is is_removed = 1 or not
            return base.GetSelectCommandConditionText(tenantId, table);
        }

        public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
        {
            //todo: hack: will be changed later
            filePath = Regex.Replace(filePath, @"^[-\w]+(?=/)", match => dump ? match.Value : columnMapper.GetUserMapping(match.Value));
            return !filePath.StartsWith("/");
        }

        protected override bool TryPrepareRow(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, DataRowInfo row, out Dictionary<string, object> preparedRow)
        {
            if (table.Name == "mail_mailbox")
            {
                var boxType = row["is_server_mailbox"];
                if (boxType != null && Convert.ToBoolean(int.Parse(boxType.ToString())))
                {
                    preparedRow = null;
                    return false;
                }
            }
            return base.TryPrepareRow(dump, connection, columnMapper, table, row, out preparedRow);
        }

        protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
        {
            relations = relations.ToList();
            if (relations.All(x => x.ChildTable == "mail_chain" && x.ChildColumn == "tags"))
            {
                var mappedTags = new List<string>();

                foreach (var tag in value.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x)))
                {
                    object tagId;
                    if (tag > 0)
                    {
                        tagId = columnMapper.GetMapping("mail_tag", "id", tag);
                    }
                    else
                    {
                        tagId = columnMapper.GetMapping("crm_tag", "id", -tag);
                        if (tagId != null)
                        {
                            tagId = -Convert.ToInt32(tagId);
                        }
                    }
                    if (tagId != null)
                    {
                        mappedTags.Add(tagId.ToString());
                    }
                }

                value = string.Join(",", mappedTags.ToArray());
                return true;
            }

            return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relations, ref value);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
        {
            if (relation.ParentTable == "crm_tag" && relation.ChildColumn == "id_tag"
                && (relation.ChildTable == "mail_tag_mail" || relation.ChildTable == "mail_tag_addresses"))
            {
                var crmTagId = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, -Convert.ToInt32(value));
                if (crmTagId == null)
                    return false;

                value = -Convert.ToInt32(crmTagId);
                return true;
            }

            return base.TryPrepareValue(connection, columnMapper, relation, ref value);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
        {
            if (table.Name == "mail_mailbox" && (columnName == "smtp_password" || columnName == "pop3_password") && value != null)
            {
                try
                {
                    value = Helpers.CreateHash(value as string); // save original hash
                }
                catch (Exception err)
                {
                    LogManager.GetLogger("ASC").ErrorFormat("Can not prepare value {0}: {1}", value, err);
                    value = null;
                }
                return true;
            }
            return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
        }

        public override void PrepareData(DataTable data)
        {
            if (data.TableName == "mail_mailbox")
            {
                var address = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "address");
                var smtp = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "smtp_password");
                var pop3 = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "pop3_password");
                var token = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "token");
                for (var i = 0; i < data.Rows.Count; i++)
                {
                    var row = data.Rows[i];
                    try
                    {
                        row[smtp] = Helpers.CreateHash2(row[smtp] as string);
                        row[pop3] = Helpers.CreateHash2(row[pop3] as string);
                        row[token] = Helpers.CreateHash2(row[token] as string);
                    }
                    catch (Exception ex)
                    {
                        LogManager.GetLogger("ASC").ErrorFormat("Can not prepare data {0}: {1}", row[address] as string, ex);
                        data.Rows.Remove(row);
                        i--;
                    }
                }
            }
        }

        public override Stream PrepareData(string key, Stream stream, ColumnMapper columnMapper)
        {
            if (!key.EndsWith("body.html")) return stream;

            using (var streamReader = new StreamReader(stream, Encoding.UTF8, true, 1024, true))
            {
                var data = streamReader.ReadToEnd();
                data = Regex.Replace(data, @"(htmleditorfiles|aggregator)(\/0\/|\/[\d]+\/\d\d\/\d\d\/)([-\w]+(?=/))",
                    match => "/" + TenantPath.CreatePath(columnMapper.GetTenantMapping().ToString()) + "/" + columnMapper.GetUserMapping(match.Groups[3].Value));

                var content = Encoding.UTF8.GetBytes(data);

                stream.Position = 0;
                stream.Write(content, 0, content.Length);
            }

            return stream;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/js/common.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof jq === "undefined") {
    jq = jQuery.noConflict();
}

if (typeof ASC === "undefined") {
    ASC = {};
}

if (typeof ASC.Files === "undefined") {
    ASC.Files = (function () {
        return {};
    })();
}

if (typeof (ASC.Files.Constants) === 'undefined') {
    ASC.Files.Constants = {};
}

ASC.Files.Constants.REQUEST_STATUS_DELAY = 2000;
ASC.Files.Constants.REQUEST_CONVERT_DELAY = 2000;
ASC.Files.Constants.COUNT_ON_PAGE = 30,
ASC.Files.Constants.entryIdRegExpStr = "(\\d+|[a-z]+-\\d+(-.+)*)",
ASC.Files.Constants.storageKeyRecent = "TeamLabRecentDocuments",
ASC.Files.Constants.storageKeyCompactView = "TeamLabDocumentsCompactView",
ASC.Files.Constants.storageKeyUploaderCompactView = "TeamLabDocumentsUploaderCompactView";

ASC.Files.Common = (function () {

    var storeOriginal = false;

    var isCorrectId = function (id) {
        if (typeof id === "undefined") {
            return false;
        }
        if (id === null) {
            return false;
        }
        if (id === 0) {
            return false;
        }
        var regExp = new RegExp("^" + ASC.Files.Constants.entryIdRegExpStr);
        return regExp.test(id);
    };

    var getCorrectHash = function (anchor) {
        if (jq.browser.safari || jq.browser.mozilla) {
            return encodeURI(anchor);
        }
        return anchor;
    };

    var jsonToXml = function (o, parent) {
        var xml = "";

        if (typeof o === "object") {
            if (o === null) {
                if (typeof parent !== "undefined") {
                    xml += "<" + parent + "></" + parent + ">";
                }
            } else if (o.constructor.toString().indexOf("Array") !== -1) {
                var n;
                for (i = 0, n = o.length; i < n; i++) {
                    if (typeof parent !== "undefined") {
                        xml += "<" + parent + ">" + arguments.callee(o[i]) + "</" + parent + ">";
                    } else {
                        xml += arguments.callee(o[i]);
                    }
                }
            } else {
                for (var i in o) {
                    xml += arguments.callee(o[i], i);
                }
                if (typeof parent !== "undefined") {
                    xml = "<" + parent + ">" + xml + "</" + parent + ">";
                }
            }
        } else if (typeof o === "string") {
            xml = replaceInXml(o);
            if (typeof parent !== "undefined") {
                xml = "<" + parent + ">" + xml + "</" + parent + ">";
            }
        } else if (typeof o !== "undefined" && typeof o.toString !== "undefined") {
            xml = replaceInXml(o.toString());
            if (typeof parent !== "undefined") {
                xml = "<" + parent + ">" + xml + "</" + parent + ">";
            }
        }
        return xml;
    };

    var replaceInXml = function (str) {
        return str.replace(/&/gim, "&amp;").replace(/</gim, "&lt;").replace(/>/gim, "&gt;");
    };

    var getSitePath = function () {
        var sitePath = jq.url.attr("protocol");
        sitePath += "://";
        sitePath += jq.url.attr("host");
        if (jq.url.attr("port") != null) {
            sitePath += ":";
            sitePath += jq.url.attr("port");
        }
        return sitePath;
    };

    var cancelBubble = function (e) {
        if (!e) {
            e = window.event;
        }
        e.cancelBubble = true;
        if (e.stopPropagation) {
            e.stopPropagation();
        }
    };

    var characterString = "*+:\"<>?|\/";
    var characterRegExp = new RegExp("[\t*\+:\"<>?|\\\\/]", "gim");

    var replaceSpecCharacter = function (str) {
        return (str || "").trim().replace(ASC.Files.Common.characterRegExp, "_");
    };

    var keyCode = { enter: 13, ctrl: 17, esc: 27, spaceBar: 32, pageUP: 33, pageDown: 34, end: 35, home: 36, left: 37, up: 38, right: 39, down: 40, insertKey: 45, deleteKey: 46, A: 65, C: 67, F: 70, N: 78, F2: 113 };

    return {
        getSitePath: getSitePath,
        cancelBubble: cancelBubble,
        keyCode: keyCode,

        characterString: characterString,
        characterRegExp: characterRegExp,
        replaceSpecCharacter: replaceSpecCharacter,

        isCorrectId: isCorrectId,
        getCorrectHash: getCorrectHash,
        jsonToXml: jsonToXml,

        storeOriginal: storeOriginal,
    };
})();

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_IdentityInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;
    using System.Text;

    #endregion

    /// <summary>
    /// Implements SIP "Identity-Info" value. Defined in RFC 4474.
    /// </summary>
    /// <remarks>
    /// <code>
    /// RFC 4474 Syntax:
    ///     Identity-Info        = ident-info *( SEMI ident-info-params )
    ///     ident-info           = LAQUOT absoluteURI RAQUOT
    ///     ident-info-params    = ident-info-alg / ident-info-extension
    ///     ident-info-alg       = "alg" EQUAL token
    ///     ident-info-extension = generic-param
    /// </code>
    /// </remarks>
    public class SIP_t_IdentityInfo : SIP_t_ValueWithParams
    {
        #region Members

        private string m_Uri = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets URI value.
        /// </summary>
        /// <exception cref="ArgumentNullException">Is raised when null value is passed.</exception>
        /// <exception cref="ArgumentException">Is raised when invalid 'absoluteURI' value is passed.</exception>
        public string Uri
        {
            get { return m_Uri; }

            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("Uri");
                }
                if (value == "")
                {
                    throw new ArgumentException("Invalid Identity-Info 'absoluteURI' value !");
                }

                m_Uri = value;
            }
        }

        /// <summary>
        /// Gets or sets 'alg' parameter value. Value null means not specified.
        /// </summary>
        public string Alg
        {
            get
            {
                SIP_Parameter parameter = Parameters["alg"];
                if (parameter != null)
                {
                    return parameter.Value;
                }
                else
                {
                    return null;
                }
            }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    Parameters.Remove("alg");
                }
                else
                {
                    Parameters.Set("alg", value);
                }
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="value">SIP 'Identity-Info' value.</param>
        public SIP_t_IdentityInfo(string value)
        {
            Parse(value);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "Identity-Info" from specified value.
        /// </summary>
        /// <param name="value">SIP "Identity-Info" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>value</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "Identity-Info" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            /*
                Identity-Info        = ident-info *( SEMI ident-info-params )
                ident-info           = LAQUOT absoluteURI RAQUOT
                ident-info-params    = ident-info-alg / ident-info-extension
                ident-info-alg       = "alg" EQUAL token
                ident-info-extension = generic-param
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // absoluteURI
            try
            {
                string word = reader.ReadParenthesized();
                if (word == null)
                {
                    throw new SIP_ParseException("Invalid Identity-Info 'absoluteURI' value !");
                }
                m_Uri = word;
            }
            catch
            {
                throw new SIP_ParseException("Invalid Identity-Info 'absoluteURI' value !");
            }

            // Parse parameters
            ParseParameters(reader);
        }

        /// <summary>
        /// Converts this to valid "Identity-Info" value.
        /// </summary>
        /// <returns>Returns "Identity-Info" value.</returns>
        public override string ToStringValue()
        {
            /*
                Identity-Info        = ident-info *( SEMI ident-info-params )
                ident-info           = LAQUOT absoluteURI RAQUOT
                ident-info-params    = ident-info-alg / ident-info-extension
                ident-info-alg       = "alg" EQUAL token
                ident-info-extension = generic-param
            */

            StringBuilder retVal = new StringBuilder();

            // absoluteURI
            retVal.Append("<" + m_Uri + ">");

            // Add parameters
            retVal.Append(ParametersToString());

            return retVal.ToString();
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailSearchFilterData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using ASC.Mail.Enums;

namespace ASC.Mail.Data.Contracts
{
    [DataContract(Namespace = "")]
    public class MailSearchFilterData : ICloneable
    {
        [DataMember(Name = "PrimaryFolder")]
        public FolderType PrimaryFolder { get; set; }

        [DataMember(Name = "Unread")]
        public bool? Unread { get; set; }

        [DataMember(Name = "Attachments")]
        public bool? Attachments { get; set; }

        [DataMember(Name = "Period_from")]
        public long? PeriodFrom { get; set; }

        [DataMember(Name = "Period_to")]
        public long? PeriodTo { get; set; }

        [DataMember(Name = "Important")]
        public bool? Important { get; set; }

        [DataMember(Name = "FromAddress")]
        public string FromAddress { get; set; }

        [DataMember(Name = "ToAddress")]
        public string ToAddress { get; set; }

        [DataMember(Name = "MailboxId")]
        public int? MailboxId { get; set; }

        [DataMember(Name = "CustomLabels")]
        public List<int> CustomLabels { get; set; }

        [DataMember(Name = "Sort")]
        public string Sort { get; set; }

        [DataMember(Name = "SortOrder")]
        public string SortOrder { get; set; }

        [DataMember(Name = "SearchFilter")]
        public string SearchText { get; set; }

        [DataMember(Name = "Page")]
        public int? Page { get; set; }

        [DataMember(Name = "PageSize")]
        public int? PageSize { get; set; }

        public int? SetLabel { get; set; }

        [DataMember(Name = "WithCalendar")]
        public bool? WithCalendar { get; set; }

        [DataMember(Name = "UserFolderId")]
        public int? UserFolderId { get; set; }

        [DataMember(Name = "FromDate")]
        public DateTime? FromDate { get; set; }

        [DataMember(Name = "FromMessage")]
        public int? FromMessage { get; set; }

        [DataMember(Name = "PrevFlag")]
        public bool? PrevFlag { get; set; }

        public MailSearchFilterData()
        {
            CustomLabels = new List<int>();
        }

        public bool IsDefault()
        {
            return !Attachments.HasValue &&
                   !PeriodFrom.HasValue &&
                   !PeriodTo.HasValue &&
                   !Important.HasValue &&
                   string.IsNullOrEmpty(FromAddress) &&
                   string.IsNullOrEmpty(ToAddress) &&
                   !MailboxId.HasValue &&
                   (CustomLabels == null || !CustomLabels.Any()) &&
                   string.IsNullOrEmpty(SearchText) &&
                   !WithCalendar.HasValue &&
                   !Unread.HasValue;
        }

        public override int GetHashCode()
        {
            return PrimaryFolder.GetHashCode() ^ Unread.GetHashCode() ^ Attachments.GetHashCode() ^
                   PeriodFrom.GetHashCode() ^ PeriodTo.GetHashCode() ^ Important.GetHashCode() ^
                   FromAddress.GetHashCode() ^ MailboxId.GetHashCode() ^ CustomLabels.GetHashCode() ^
                   Sort.GetHashCode() ^ SortOrder.GetHashCode() ^ SearchText.GetHashCode() ^
                   Page.GetValueOrDefault() ^ PageSize.GetHashCode() ^ SetLabel.GetHashCode() ^
                   WithCalendar.GetHashCode() ^ UserFolderId.GetHashCode() ^ FromDate.GetHashCode() ^
                   FromMessage.GetHashCode() ^ PrevFlag.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            var searchFilterData = obj as MailSearchFilterData;
            return searchFilterData != null && searchFilterData.PrimaryFolder == PrimaryFolder &&
                   searchFilterData.Unread == Unread && searchFilterData.Attachments == Attachments &&
                   searchFilterData.PeriodFrom == PeriodFrom && searchFilterData.PeriodTo == PeriodTo &&
                   searchFilterData.Important == Important && searchFilterData.Sort == Sort &&
                   searchFilterData.SortOrder == SortOrder && searchFilterData.SearchText == SearchText &&
                   searchFilterData.Page == Page && searchFilterData.PageSize == PageSize &&
                   searchFilterData.SetLabel == SetLabel && searchFilterData.WithCalendar == WithCalendar &&
                   searchFilterData.WithCalendar == WithCalendar && searchFilterData.UserFolderId == UserFolderId &&
                   searchFilterData.FromDate == FromDate && searchFilterData.FromMessage == FromMessage &&
                   searchFilterData.PrevFlag == PrevFlag;
        }

        public object Clone()
        {
            return MemberwiseClone();
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Global.asax.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Runtime.Remoting.Messaging;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Tenants;
using ASC.Web.Core;
using ASC.Web.Core.Client;
using ASC.Web.Core.Helpers;
using ASC.Web.Core.Utility;
using ASC.Web.Core.Utility.Settings;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Backup;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio
{
    public class Global : HttpApplication
    {
        private static readonly object locker = new object();
        private static volatile bool applicationStarted;


        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            if (!applicationStarted)
            {
                lock (locker)
                {
                    if (!applicationStarted)
                    {
                        Startup.Configure();
                        applicationStarted = true;
                    }
                }
            }

            SecurityContext.Logout();
            var tenant = CoreContext.TenantManager.GetCurrentTenant(false);

            BlockNotFoundPortal(tenant);
            BlockRemovedOrSuspendedPortal(tenant);
            BlockTransferingOrRestoringPortal(tenant);
            BlockMigratingPortal(tenant);
            BlockPortalEncryption(tenant);
            BlockNotPaidPortal(tenant);
            TenantWhiteLabelSettings.Apply(tenant.TenantId);

            Authenticate();
            BlockIPSecurityPortal(tenant);
            ResolveUserCulture();
        }

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            CallContext.FreeNamedDataSlot(TenantManager.CURRENT_TENANT);
            SecurityContext.Logout();
        }

        protected void Application_AcquireRequestState(object sender, EventArgs e)
        {
            Authenticate();
            ResolveUserCulture();
        }

        protected void Session_Start(object sender, EventArgs e)
        {
            if (Request.GetUrlRewriter().Scheme == "https")
                Response.Cookies["ASP.NET_SessionId"].Secure = true;

            Response.Cookies["ASP.NET_SessionId"].HttpOnly = true;
        }

        public override string GetVaryByCustomString(HttpContext context, string custom)
        {
            if (String.IsNullOrEmpty(custom)) return base.GetVaryByCustomString(context, custom);
            if (custom == "cacheKey") return ClientSettings.ResetCacheKey;

            var result = String.Empty;

            foreach (Match match in Regex.Matches(custom.ToLower(), "(?<key>\\w+)(\\[(?<subkey>\\w+)\\])?;?", RegexOptions.Compiled))
            {
                var key = String.Empty;
                var subkey = String.Empty;

                if (match.Groups["key"].Success)
                    key = match.Groups["key"].Value;

                if (match.Groups["subkey"].Success)
                    subkey = match.Groups["subkey"].Value;

                var value = String.Empty;

                switch (key)
                {
                    case "relativeurl":
                        var appUrl = VirtualPathUtility.ToAbsolute("~/");
                        value = Request.GetUrlRewriter().AbsolutePath.Remove(0, appUrl.Length - 1);
                        break;
                    case "url":
                        value = Request.GetUrlRewriter().AbsoluteUri;
                        break;
                    case "page":
                        value = Request.GetUrlRewriter().AbsolutePath.Substring(Request.Url.AbsolutePath.LastIndexOfAny(new[] { '/', '\\' }) + 1);
                        break;
                    case "module":
                        var module = "common";
                        var matches = Regex.Match(Request.Url.AbsolutePath.ToLower(), "(products|addons)/(\\w+)/?", RegexOptions.Compiled);

                        if (matches.Success && matches.Groups.Count > 2 && matches.Groups[2].Success)
                            module = matches.Groups[2].Value;

                        value = module;

                        break;
                    case "culture":
                        value = Thread.CurrentThread.CurrentUICulture.Name;
                        break;
                    case "theme":
                        value = ColorThemesSettings.GetColorThemesSettings();
                        break;
                    case "whitelabel":
                        var whiteLabelSettings = TenantWhiteLabelSettings.Load();
                        value = whiteLabelSettings.LogoText ?? string.Empty;
                        break;
                }

                if (!(String.Compare((value ?? "").ToLower(), subkey, StringComparison.Ordinal) == 0
                      || String.IsNullOrEmpty(subkey))) continue;

                result += "|" + value;

            }

            if (!string.IsNullOrEmpty(result)) return String.Join("|", ClientSettings.ResetCacheKey, result);

            return base.GetVaryByCustomString(context, custom);
        }

        public static bool Authenticate()
        {
            if (SecurityContext.IsAuthenticated)
            {
                return true;
            }

            var authenticated = false;
            var tenant = CoreContext.TenantManager.GetCurrentTenant(false);
            if (tenant != null)
            {
                if (HttpContext.Current != null)
                {
                    string cookie;
                    if (AuthorizationHelper.ProcessBasicAuthorization(HttpContext.Current, out cookie))
                    {
                        CookiesManager.SetCookies(CookiesType.AuthKey, cookie);
                        authenticated = true;
                    }
                }
                if (!authenticated)
                {
                    var cookie = CookiesManager.GetCookies(CookiesType.AuthKey);
                    if (!string.IsNullOrEmpty(cookie))
                    {
                        authenticated = SecurityContext.AuthenticateMe(cookie);

                        if (!authenticated)
                        {
                            Auth.ProcessLogout();
                            return false;
                        }
                    }
                }

                var accessSettings = TenantAccessSettings.Load();
                if (authenticated && SecurityContext.CurrentAccount.ID == ASC.Core.Users.Constants.OutsideUser.ID && !accessSettings.Anyone)
                {
                    Auth.ProcessLogout();
                    authenticated = false;
                }
            }
            return authenticated;
        }

        private static void ResolveUserCulture()
        {
            CultureInfo culture = null;

            var tenant = CoreContext.TenantManager.GetCurrentTenant(false);
            if (tenant != null)
            {
                culture = tenant.GetCulture();
            }

            var user = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
            if (!string.IsNullOrEmpty(user.CultureName))
            {
                culture = CultureInfo.GetCultureInfo(user.CultureName);
            }

            if (culture != null && !Equals(Thread.CurrentThread.CurrentCulture, culture))
            {
                Thread.CurrentThread.CurrentCulture = culture;
            }
            if (culture != null && !Equals(Thread.CurrentThread.CurrentUICulture, culture))
            {
                Thread.CurrentThread.CurrentUICulture = culture;
            }
        }

        private void BlockNotFoundPortal(Tenant tenant)
        {
            if (tenant == null)
            {
                if (string.IsNullOrEmpty(SetupInfo.NoTenantRedirectURL))
                {
                    Response.StatusCode = (int)HttpStatusCode.NotFound;
                    Response.End();
                }
                else
                {
                    var redirectUrl = string.Format("{0}?url={1}", SetupInfo.NoTenantRedirectURL, Request.GetUrlRewriter().Host);
                    ResponseRedirect(redirectUrl, HttpStatusCode.NotFound);
                }
            }
        }

        private void BlockRemovedOrSuspendedPortal(Tenant tenant)
        {
            if (tenant.Status != TenantStatus.RemovePending && tenant.Status != TenantStatus.Suspended)
            {
                return;
            }

            var passthroughtRequestEndings = new[] { ".js", ".css", ".less", "confirm.aspx", "capabilities.json" };
            if (tenant.Status == TenantStatus.Suspended && passthroughtRequestEndings.Any(path => Request.Url.AbsolutePath.EndsWith(path, StringComparison.InvariantCultureIgnoreCase)))
            {
                return;
            }

            if (string.IsNullOrEmpty(SetupInfo.NoTenantRedirectURL))
            {
                Response.StatusCode = (int)HttpStatusCode.NotFound;
                Response.End();
            }
            else
            {
                var redirectUrl = string.Format("{0}?url={1}", SetupInfo.NoTenantRedirectURL, Request.GetUrlRewriter().Host);
                ResponseRedirect(redirectUrl, HttpStatusCode.NotFound);
            }
        }

        private void BlockTransferingOrRestoringPortal(Tenant tenant)
        {
            if (tenant.Status != TenantStatus.Restoring && tenant.Status != TenantStatus.Transfering)
            {
                return;
            }

            // allow requests to backup handler to get access to the GetRestoreStatus method
            var handlerType = typeof(BackupAjaxHandler);
            var backupHandler = handlerType.FullName + "," + handlerType.Assembly.GetName().Name + ".ashx";

            var passthroughtRequestEndings = new[] { ".js", ".css", ".less", ".ico", ".png", backupHandler, "PreparationPortal.aspx", "TenantLogo.ashx", "portal/getrestoreprogress.json", "capabilities.json" };
            if (passthroughtRequestEndings.Any(path => Request.Url.AbsolutePath.EndsWith(path, StringComparison.InvariantCultureIgnoreCase)))
            {
                return;
            }

            ResponseRedirect("~/PreparationPortal.aspx?type=" + (tenant.Status == TenantStatus.Transfering ? "0" : "1"), HttpStatusCode.ServiceUnavailable);
        }

        private void BlockMigratingPortal(Tenant tenant)
        {
            if (tenant.Status != TenantStatus.Migrating)
            {
                return;
            }

            var passthroughtRequestEndings = new[] { ".js", ".css", ".less", ".ico", ".png", "MigrationPortal.aspx", "TenantLogo.ashx", "settings/storage/progress.json", "capabilities.json" };
            if (passthroughtRequestEndings.Any(path => Request.Url.AbsolutePath.EndsWith(path, StringComparison.InvariantCultureIgnoreCase)))
            {
                return;
            }

            ResponseRedirect("~/MigrationPortal.aspx", HttpStatusCode.ServiceUnavailable);
        }

        private void BlockPortalEncryption(Tenant tenant)
        {
            if (tenant.Status != TenantStatus.Encryption)
            {
                return;
            }

            var passthroughtRequestEndings = new[] { ".js", ".css", ".less", ".ico", ".png", "PortalEncryption.aspx", "TenantLogo.ashx", "settings/encryption/progress.json", "capabilities.json" };
            if (passthroughtRequestEndings.Any(path => Request.Url.AbsolutePath.EndsWith(path, StringComparison.InvariantCultureIgnoreCase)))
            {
                return;
            }

            ResponseRedirect("~/PortalEncryption.aspx", HttpStatusCode.ServiceUnavailable);
        }

        private void BlockNotPaidPortal(Tenant tenant)
        {
            if (tenant == null) return;

            var passthroughtRequestEndings = new[] { ".htm", ".ashx", ".png", ".ico", ".less", ".css", ".js", "capabilities.json" };
            if (passthroughtRequestEndings.Any(path => Request.Url.AbsolutePath.EndsWith(path, StringComparison.InvariantCultureIgnoreCase)))
            {
                return;
            }

            if (!TenantExtra.EnableTariffSettings && TenantExtra.GetCurrentTariff().State >= TariffState.NotPaid)
            {
                if (string.IsNullOrEmpty(AdditionalWhiteLabelSettings.Instance.BuyUrl)
                    || AdditionalWhiteLabelSettings.Instance.BuyUrl == AdditionalWhiteLabelSettings.DefaultBuyUrl)
                {
                    LogManager.GetLogger("ASC").WarnFormat("Tenant {0} is not paid", tenant.TenantId);
                    Response.StatusCode = (int)HttpStatusCode.PaymentRequired;
                    Response.End();
                }
                else if (!Request.Url.AbsolutePath.EndsWith(CommonLinkUtility.ToAbsolute(PaymentRequired.Location)))
                {
                    ResponseRedirect(PaymentRequired.Location, HttpStatusCode.PaymentRequired);
                }
            }
        }

        private void BlockIPSecurityPortal(Tenant tenant)
        {
            if (tenant == null) return;

            var settings = IPRestrictionsSettings.LoadForTenant(tenant.TenantId);
            if (settings.Enable && SecurityContext.IsAuthenticated && !IPSecurity.IPSecurity.Verify(tenant))
            {
                Auth.ProcessLogout();

                ResponseRedirect("~/Auth.aspx?error=ipsecurity", HttpStatusCode.Forbidden);
            }
        }

        private void ResponseRedirect(string url, HttpStatusCode httpStatusCode)
        {
            if (Request.Url.AbsolutePath.StartsWith(SetupInfo.WebApiBaseUrl, StringComparison.InvariantCultureIgnoreCase) ||
                Request.Url.AbsolutePath.EndsWith(".svc", StringComparison.InvariantCultureIgnoreCase) ||
                Request.Url.AbsolutePath.EndsWith(".ashx", StringComparison.InvariantCultureIgnoreCase))
            {
                // we shouldn't redirect
                Response.StatusCode = (int)httpStatusCode;
                Response.End();
            }

            Response.Redirect(url, true);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileOperations/FileMoveCopyOperation.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

using ASC.Files.Core;
using ASC.MessagingSystem;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Helpers;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Utils;

namespace ASC.Web.Files.Services.WCFService.FileOperations
{
    class FileMoveCopyOperation : FileOperation
    {
        private readonly string _toFolderId;
        private readonly bool _copy;
        private readonly FileConflictResolveType _resolveType;
        private readonly List<FileEntry> _needToMark = new List<FileEntry>();

        private readonly Dictionary<string, string> _headers;

        public override FileOperationType OperationType
        {
            get { return _copy ? FileOperationType.Copy : FileOperationType.Move; }
        }

        public FileMoveCopyOperation(List<object> folders, List<object> files, string toFolderId, bool copy, FileConflictResolveType resolveType, bool holdResult = true, Dictionary<string, string> headers = null)
            : base(folders, files, holdResult)
        {
            _toFolderId = toFolderId;
            _copy = copy;
            _resolveType = resolveType;
            _headers = headers;
        }

        protected override void Do()
        {
            Status += string.Format("folder_{0}{1}", _toFolderId, SPLIT_CHAR);

            //TODO: check on each iteration?
            var toFolder = FolderDao.GetFolder(_toFolderId);
            if (toFolder == null) return;
            if (!FilesSecurity.CanCreate(toFolder)) throw new System.Security.SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create);

            if (FolderDao.GetParentFolders(toFolder.ID).Any(parent => Folders.Contains(parent.ID.ToString())))
            {
                Error = FilesCommonResource.ErrorMassage_FolderCopyError;
                return;
            }

            if (_copy)
            {
                Folder rootFrom = null;
                if (0 < Folders.Count) rootFrom = FolderDao.GetRootFolder(Folders[0]);
                if (0 < Files.Count) rootFrom = FolderDao.GetRootFolderByFile(Files[0]);
                if (rootFrom != null && rootFrom.FolderType == FolderType.TRASH) throw new InvalidOperationException("Can not copy from Trash.");
                if (toFolder.RootFolderType == FolderType.TRASH) throw new InvalidOperationException("Can not copy to Trash.");
            }

            MoveOrCopyFolders(Folders, toFolder, _copy);
            MoveOrCopyFiles(Files, toFolder, _copy);

            _needToMark.Distinct().ToList().ForEach(x => FileMarker.MarkAsNew(x));
        }

        private void MoveOrCopyFolders(ICollection folderIds, Folder toFolder, bool copy)
        {
            if (folderIds.Count == 0) return;

            var toFolderId = toFolder.ID;
            var isToFolder = Equals(toFolderId.ToString(), _toFolderId);

            foreach (var folderId in folderIds)
            {
                CancellationToken.ThrowIfCancellationRequested();

                var folder = FolderDao.GetFolder(folderId);
                if (folder == null)
                {
                    Error = FilesCommonResource.ErrorMassage_FolderNotFound;
                }
                else if (!FilesSecurity.CanRead(folder))
                {
                    Error = FilesCommonResource.ErrorMassage_SecurityException_ReadFolder;
                }
                else if (folder.RootFolderType == FolderType.Privacy
                    && (copy || toFolder.RootFolderType != FolderType.Privacy))
                {
                    Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
                }
                else if (!Equals((folder.ParentFolderID ?? string.Empty).ToString(), toFolderId.ToString()) || _resolveType == FileConflictResolveType.Duplicate)
                {
                    try
                    {
                        //if destination folder contains folder with same name then merge folders
                        var conflictFolder = folder.RootFolderType == FolderType.Privacy
                            ? null
                            : FolderDao.GetFolder(folder.Title, toFolderId);
                        Folder newFolder;

                        if (copy || conflictFolder != null)
                        {
                            if (conflictFolder != null)
                            {
                                newFolder = conflictFolder;

                                if (isToFolder)
                                    _needToMark.Add(conflictFolder);
                            }
                            else
                            {
                                newFolder = FolderDao.CopyFolder(folder.ID, toFolderId, CancellationToken);
                                FilesMessageService.Send(newFolder, toFolder, _headers, MessageAction.FolderCopied, newFolder.Title, toFolder.Title);

                                if (isToFolder)
                                    _needToMark.Add(newFolder);

                                if (ProcessedFolder(folderId))
                                {
                                    Status += string.Format("folder_{0}{1}", newFolder.ID, SPLIT_CHAR);
                                }
                            }

                            if (toFolder.ProviderId == folder.ProviderId // crossDao operation is always recursive
                                && FolderDao.UseRecursiveOperation(folder.ID, toFolderId))
                            {
                                MoveOrCopyFiles(FileDao.GetFiles(folder.ID), newFolder, copy);
                                MoveOrCopyFolders(FolderDao.GetFolders(folder.ID).Select(f => f.ID).ToList(), newFolder, copy);

                                if (!copy)
                                {
                                    if (!FilesSecurity.CanDelete(folder))
                                    {
                                        Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
                                    }
                                    else if (FolderDao.IsEmpty(folder.ID))
                                    {
                                        FolderDao.DeleteFolder(folder.ID);
                                        if (ProcessedFolder(folderId))
                                        {
                                            Status += string.Format("folder_{0}{1}", newFolder.ID, SPLIT_CHAR);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (conflictFolder != null)
                                {
                                    string tmpError;
                                    object newFolderId;
                                    if (copy)
                                    {
                                        newFolder = FolderDao.CopyFolder(folder.ID, toFolderId, CancellationToken);
                                        newFolderId = newFolder.ID;
                                        FilesMessageService.Send(newFolder, toFolder, _headers, MessageAction.FolderCopiedWithOverwriting, newFolder.Title, toFolder.Title);

                                        if (isToFolder)
                                            _needToMark.Add(newFolder);

                                        if (ProcessedFolder(folderId))
                                        {
                                            Status += string.Format("folder_{0}{1}", newFolderId, SPLIT_CHAR);
                                        }
                                    }
                                    else if (!FilesSecurity.CanDelete(folder))
                                    {
                                        Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
                                    }
                                    else if (WithError(FileDao.GetFiles(folder.ID, new OrderBy(SortedByType.AZ, true), FilterType.FilesOnly, false, Guid.Empty, string.Empty, false, true), out tmpError))
                                    {
                                        Error = tmpError;
                                    }
                                    else
                                    {
                                        FileMarker.RemoveMarkAsNewForAll(folder);

                                        newFolderId = FolderDao.MoveFolder(folder.ID, toFolderId, CancellationToken);
                                        newFolder = FolderDao.GetFolder(newFolderId);
                                        FilesMessageService.Send(folder.RootFolderType != FolderType.USER ? folder : newFolder, toFolder, _headers, MessageAction.FolderMovedWithOverwriting, folder.Title, toFolder.Title);

                                        if (isToFolder)
                                            _needToMark.Add(newFolder);

                                        if (ProcessedFolder(folderId))
                                        {
                                            Status += string.Format("folder_{0}{1}", newFolderId, SPLIT_CHAR);
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            string tmpError;
                            if (!FilesSecurity.CanDelete(folder))
                            {
                                Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFolder;
                            }
                            else if (WithError(FileDao.GetFiles(folder.ID, new OrderBy(SortedByType.AZ, true), FilterType.FilesOnly, false, Guid.Empty, string.Empty, false, true), out tmpError))
                            {
                                Error = tmpError;
                            }
                            else
                            {
                                FileMarker.RemoveMarkAsNewForAll(folder);

                                var newFolderId = FolderDao.MoveFolder(folder.ID, toFolderId, CancellationToken);
                                newFolder = FolderDao.GetFolder(newFolderId);
                                FilesMessageService.Send(folder.RootFolderType != FolderType.USER ? folder : newFolder, toFolder, _headers, MessageAction.FolderMoved, folder.Title, toFolder.Title);

                                if (isToFolder)
                                    _needToMark.Add(newFolder);

                                if (ProcessedFolder(folderId))
                                {
                                    Status += string.Format("folder_{0}{1}", newFolderId, SPLIT_CHAR);
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Error = ex.Message;

                        Logger.Error(Error, ex);
                    }
                }
                ProgressStep(FolderDao.CanCalculateSubitems(folderId) ? null : folderId);
            }
        }

        private void MoveOrCopyFiles(ICollection fileIds, Folder toFolder, bool copy)
        {
            if (fileIds.Count == 0) return;

            var toFolderId = toFolder.ID;
            foreach (var fileId in fileIds)
            {
                CancellationToken.ThrowIfCancellationRequested();

                var file = FileDao.GetFile(fileId);
                if (file == null)
                {
                    Error = FilesCommonResource.ErrorMassage_FileNotFound;
                }
                else if (!FilesSecurity.CanRead(file))
                {
                    Error = FilesCommonResource.ErrorMassage_SecurityException_ReadFile;
                }
                else if (file.RootFolderType == FolderType.Privacy
                    && (copy || toFolder.RootFolderType != FolderType.Privacy))
                {
                    Error = FilesCommonResource.ErrorMassage_SecurityException_MoveFile;
                }
                else if (Global.EnableUploadFilter
                         && !FileUtility.ExtsUploadable.Contains(FileUtility.GetFileExtension(file.Title)))
                {
                    Error = FilesCommonResource.ErrorMassage_NotSupportedFormat;
                }
                else
                {
                    var parentFolder = FolderDao.GetFolder(file.FolderID);
                    try
                    {
                        var conflict = _resolveType == FileConflictResolveType.Duplicate
                            || file.RootFolderType == FolderType.Privacy
                                           ? null
                                           : FileDao.GetFile(toFolderId, file.Title);
                        if (conflict == null)
                        {
                            File newFile = null;
                            if (copy)
                            {
                                try
                                {
                                    newFile = FileDao.CopyFile(file.ID, toFolderId); //Stream copy will occur inside dao
                                    FilesMessageService.Send(newFile, toFolder, _headers, MessageAction.FileCopied, newFile.Title, parentFolder.Title, toFolder.Title);

                                    if (Equals(newFile.FolderID.ToString(), _toFolderId))
                                    {
                                        _needToMark.Add(newFile);
                                    }

                                    if (ProcessedFile(fileId))
                                    {
                                        Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR);
                                    }
                                }
                                catch
                                {
                                    if (newFile != null)
                                    {
                                        FileDao.DeleteFile(newFile.ID);
                                    }
                                    throw;
                                }
                            }
                            else
                            {
                                string tmpError;
                                if (WithError(new[] { file }, out tmpError))
                                {
                                    Error = tmpError;
                                }
                                else
                                {
                                    FileMarker.RemoveMarkAsNewForAll(file);

                                    var newFileId = FileDao.MoveFile(file.ID, toFolderId);
                                    newFile = FileDao.GetFile(newFileId);
                                    FilesMessageService.Send(file.RootFolderType != FolderType.USER ? file : newFile, toFolder, _headers, MessageAction.FileMoved, file.Title, parentFolder.Title, toFolder.Title);

                                    if (file.RootFolderType == FolderType.TRASH
                                        && newFile.ThumbnailStatus == Thumbnail.NotRequired)
                                    {
                                        newFile.ThumbnailStatus = Thumbnail.Waiting;
                                        FileDao.SaveThumbnail(newFile, null);
                                    }

                                    if (Equals(toFolderId.ToString(), _toFolderId))
                                    {
                                        _needToMark.Add(newFile);
                                    }

                                    if (ProcessedFile(fileId))
                                    {
                                        Status += string.Format("file_{0}{1}", newFileId, SPLIT_CHAR);
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (_resolveType == FileConflictResolveType.Overwrite)
                            {
                                if (!FilesSecurity.CanEdit(conflict))
                                {
                                    Error = FilesCommonResource.ErrorMassage_SecurityException;
                                }
                                else if (EntryManager.FileLockedForMe(conflict.ID))
                                {
                                    Error = FilesCommonResource.ErrorMassage_LockedFile;
                                }
                                else if (FileTracker.IsEditing(conflict.ID))
                                {
                                    Error = FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile;
                                }
                                else
                                {
                                    var newFile = conflict;
                                    newFile.Version++;
                                    newFile.VersionGroup++;
                                    newFile.PureTitle = file.PureTitle;
                                    newFile.ConvertedType = file.ConvertedType;
                                    newFile.Comment = FilesCommonResource.CommentOverwrite;
                                    newFile.Encrypted = file.Encrypted;
                                    newFile.ThumbnailStatus = Thumbnail.Waiting;

                                    using (var stream = FileDao.GetFileStream(file))
                                    {
                                        newFile.ContentLength = stream.CanSeek ? stream.Length : file.ContentLength;

                                        newFile = FileDao.SaveFile(newFile, stream);
                                    }

                                    if (file.ThumbnailStatus == Thumbnail.Created)
                                    {
                                        using (var thumbnail = FileDao.GetThumbnail(file))
                                        {
                                            FileDao.SaveThumbnail(newFile, thumbnail);
                                        }
                                        newFile.ThumbnailStatus = Thumbnail.Created;
                                    }

                                    _needToMark.Add(newFile);

                                    if (copy)
                                    {
                                        FilesMessageService.Send(newFile, toFolder, _headers, MessageAction.FileCopiedWithOverwriting, newFile.Title, parentFolder.Title, toFolder.Title);
                                        if (ProcessedFile(fileId))
                                        {
                                            Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR);
                                        }
                                    }
                                    else
                                    {
                                        if (Equals(file.FolderID.ToString(), toFolderId.ToString()))
                                        {
                                            if (ProcessedFile(fileId))
                                            {
                                                Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR);
                                            }
                                        }
                                        else
                                        {
                                            string tmpError;
                                            if (WithError(new[] { file }, out tmpError))
                                            {
                                                Error = tmpError;
                                            }
                                            else
                                            {
                                                FileDao.DeleteFile(file.ID);

                                                FilesMessageService.Send(file.RootFolderType != FolderType.USER ? file : newFile, toFolder, _headers, MessageAction.FileMovedWithOverwriting, file.Title, parentFolder.Title, toFolder.Title);

                                                if (ProcessedFile(fileId))
                                                {
                                                    Status += string.Format("file_{0}{1}", newFile.ID, SPLIT_CHAR);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            else if (_resolveType == FileConflictResolveType.Skip)
                            {
                                //nothing
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Error = ex.Message;
                        Logger.Error(Error, ex);
                    }
                }
                ProgressStep(fileId: FolderDao.CanCalculateSubitems(fileId) ? null : fileId);
            }
        }

        private bool WithError(IEnumerable<File> files, out string error)
        {
            error = null;
            foreach (var file in files)
            {
                if (!FilesSecurity.CanDelete(file))
                {
                    error = FilesCommonResource.ErrorMassage_SecurityException_MoveFile;
                    return true;
                }
                if (EntryManager.FileLockedForMe(file.ID))
                {
                    error = FilesCommonResource.ErrorMassage_LockedFile;
                    return true;
                }
                if (FileTracker.IsEditing(file.ID))
                {
                    error = FilesCommonResource.ErrorMassage_SecurityException_UpdateEditingFile;
                    return true;
                }
            }
            return false;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Settings.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;

using ASC.Web.Core.Client;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Projects.Classes;
using ASC.Web.Projects.Resources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Projects
{
    public partial class Settings : BasePage
    {
        protected override bool CheckSecurity { get { return ProjectSecurity.IsProjectsEnabled(); } }

        protected override void PageLoad()
        {
            Title = HeaderStringHelper.GetPageTitle(ProjectsCommonResource.CommonSettings);
            Page.RegisterStyle(
                PathProvider.GetFileStaticRelativePath("settings.less"),
                "~/Products/Files/Controls/FileSelector/fileselector.css",
                "~/Products/Files/Controls/ThirdParty/thirdparty.css",
                "~/Products/Files/Controls/ContentList/contentlist.css",
                "~/Products/Files/Controls/EmptyFolder/emptyfolder.css",
                "~/Products/Files/Controls/Tree/tree.css")
                .RegisterBodyScripts(
                PathProvider.GetFileStaticRelativePath("settings.js"),
                    "~/Products/Files/Controls/Tree/tree.js",
                    "~/Products/Files/Controls/EmptyFolder/emptyfolder.js",
                    "~/Products/Files/Controls/FileSelector/fileselector.js",
                    "~/Products/Files/js/common.js",
                    "~/Products/Files/js/templatemanager.js",
                    "~/Products/Files/js/servicemanager.js",
                    "~/Products/Files/js/ui.js",
                    "~/Products/Files/js/eventhandler.js");

            FolderSelectorHolder.Controls.Add(LoadControl(CommonLinkUtility.ToAbsolute("~/Products/Files/Controls/FileSelector/FileSelector.ascx")));

            Page.RegisterClientScript(new ClientSettingsResources());
        }
    }

    public class ClientSettingsResources : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Projects.Master.Settings"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            var icons = new[]
                        {
                            "/skins/default/images/svg/projects/timetrack.svg",
                            "/skins/default/images/svg/projects/inbox.svg",
                            "/skins/default/images/svg/projects/pause.svg",
                            "/skins/default/images/svg/projects/milstones.svg",
                            "/skins/default/images/svg/projects/check_tick.svg",
                            "/skins/default/images/svg/projects/documents.svg",
                            "/skins/default/images/svg/projects/bookmark.svg",
                            "/skins/default/images/svg/projects/discussions.svg",
                            "/skins/default/images/svg/projects/projects.svg",
                            "/skins/default/images/svg/calendar/up.svg"
                        }
            .Select(r => HttpContext.Current.Server.MapPath(r))
            .Select(r => File.ReadAllText(r))
            .Select(r => Convert.ToBase64String(Encoding.UTF8.GetBytes(r)))
            .ToList();

            return new List<KeyValuePair<string, object>>(1)
            {
                RegisterObject(
                    new
                    {
                        icons,
                        colors = new[]
                        {
                            "#f48454",
                            "#ffb45e",
                            "#ffd267",
                            "#b7d269",
                            "#6bbd72",
                            "#77cf9a",
                            "#6ac6dd",
                            "#4682b6",
                            "#6a9ad2",
                            "#8a98d8",
                            "#7e6eb2",
                            "#b58fd6",
                            "#d28cc8",
                            "#e795c1",
                            "#f2a9be",
                            "#df7895"
                        }
                    })
            };
        }

        protected override string GetCacheHash()
        {
            return ClientSettings.ResetCacheKey;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Resources/ProjectsEnumResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Projects.Core.Model.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class ProjectsEnumResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal ProjectsEnumResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Projects.Core.Model.Resources.ProjectsEnumResource", typeof(ProjectsEnumResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comment.
        /// </summary>
        public static string EntityType_Comment {
            get {
                return ResourceManager.GetString("EntityType_Comment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to File.
        /// </summary>
        public static string EntityType_File {
            get {
                return ResourceManager.GetString("EntityType_File", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Discussion.
        /// </summary>
        public static string EntityType_Message {
            get {
                return ResourceManager.GetString("EntityType_Message", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone.
        /// </summary>
        public static string EntityType_Milestone {
            get {
                return ResourceManager.GetString("EntityType_Milestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Project.
        /// </summary>
        public static string EntityType_Project {
            get {
                return ResourceManager.GetString("EntityType_Project", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subtask.
        /// </summary>
        public static string EntityType_SubTask {
            get {
                return ResourceManager.GetString("EntityType_SubTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task.
        /// </summary>
        public static string EntityType_Task {
            get {
                return ResourceManager.GetString("EntityType_Task", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Team.
        /// </summary>
        public static string EntityType_Team {
            get {
                return ResourceManager.GetString("EntityType_Team", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Time.
        /// </summary>
        public static string EntityType_TimeSpend {
            get {
                return ResourceManager.GetString("EntityType_TimeSpend", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string MilestoneStatus_Closed {
            get {
                return ResourceManager.GetString("MilestoneStatus_Closed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Active.
        /// </summary>
        public static string MilestoneStatus_Open {
            get {
                return ResourceManager.GetString("MilestoneStatus_Open", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Billed.
        /// </summary>
        public static string PaymentStatus_Billed {
            get {
                return ResourceManager.GetString("PaymentStatus_Billed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not Billed.
        /// </summary>
        public static string PaymentStatus_NotBilled {
            get {
                return ResourceManager.GetString("PaymentStatus_NotBilled", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not Chargeable.
        /// </summary>
        public static string PaymentStatus_NotChargeable {
            get {
                return ResourceManager.GetString("PaymentStatus_NotChargeable", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string ProjectStatus_Closed {
            get {
                return ResourceManager.GetString("ProjectStatus_Closed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Active.
        /// </summary>
        public static string ProjectStatus_Open {
            get {
                return ResourceManager.GetString("ProjectStatus_Open", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Paused.
        /// </summary>
        public static string ProjectStatus_Paused {
            get {
                return ResourceManager.GetString("ProjectStatus_Paused", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to High.
        /// </summary>
        public static string TaskPriority_High {
            get {
                return ResourceManager.GetString("TaskPriority_High", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Low.
        /// </summary>
        public static string TaskPriority_Low {
            get {
                return ResourceManager.GetString("TaskPriority_Low", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Normal.
        /// </summary>
        public static string TaskPriority_Normal {
            get {
                return ResourceManager.GetString("TaskPriority_Normal", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string TaskStatus_Closed {
            get {
                return ResourceManager.GetString("TaskStatus_Closed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string TaskStatus_Open {
            get {
                return ResourceManager.GetString("TaskStatus_Open", resourceCulture);
            }
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Interfaces/IFilterDao.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao.Interfaces
{
    public interface IFilterDao
    {
        /// <summary>
        ///     Get a list of filters
        /// </summary>
        List<Filter> GetList();

        /// <summary>
        ///     Get filter by id.
        /// </summary>
        /// <param name="id">id</param>
        Filter Get(int id);

        /// <summary>
        ///     Save or update filter
        /// </summary>
        /// <param name="filter"></param>
        int Save(Filter filter);

        /// <summary>
        ///     Delete filter
        /// </summary>
        /// <param name="id">id</param>
        int Delete(int id);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Core/Dao/Interfaces/IFileDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace ASC.Files.Core
{
    /// <summary>
    ///    Interface encapsulates access toFolderId files
    /// </summary>
    public interface IFileDao : IDisposable
    {
        /// <summary>
        ///     Clear the application cache for the specific file
        /// </summary>
        void InvalidateCache(object fileId);

        /// <summary>
        ///     Receive file
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <returns></returns>
        File GetFile(object fileId);

        /// <summary>
        ///     Receive file
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <param name="fileVersion">file version</param>
        /// <returns></returns>
        File GetFile(object fileId, int fileVersion);

        /// <summary>
        ///     Receive file
        /// </summary>
        /// <param name="parentId">folder id</param>
        /// <param name="title">file name</param>
        /// <returns>
        ///   file
        /// </returns>
        File GetFile(object parentId, String title);

        /// <summary>
        ///     Receive last file without forcesave
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <param name="fileVersion"></param>
        /// <returns></returns>
        File GetFileStable(object fileId, int fileVersion = -1);

        /// <summary>
        ///  Returns all versions of the file
        /// </summary>
        /// <param name="fileId"></param>
        /// <returns></returns>
        List<File> GetFileHistory(object fileId);

        /// <summary>
        ///     Gets the file (s) by ID (s)
        /// </summary>
        /// <param name="fileIds">id file</param>
        /// <returns></returns>
        List<File> GetFiles(object[] fileIds);

        /// <summary>
        ///     Gets the file (s) by ID (s) for share
        /// </summary>
        /// <param name="fileIds">id file</param>
        /// <param name="filterType"></param>
        /// <param name="subjectGroup"></param>
        /// <param name="subjectID"></param>
        /// <param name="searchText"></param>
        /// <param name="searchInContent"></param>
        /// <returns></returns>
        List<File> GetFilesFiltered(object[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parentId"></param>
        /// <returns></returns>
        List<object> GetFiles(object parentId);

        /// <summary>
        ///     Get files in folder
        /// </summary>
        /// <param name="parentId">folder id</param>
        /// <param name="orderBy"></param>
        /// <param name="filterType">filterType type</param>
        /// <param name="subjectGroup"></param>
        /// <param name="subjectID"></param>
        /// <param name="searchText"> </param>
        /// <param name="searchInContent"></param>
        /// <param name="withSubfolders"> </param>
        /// <returns>list of files</returns>
        /// <remarks>
        ///    Return only the latest versions of files of a folder
        /// </remarks>
        List<File> GetFiles(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent, bool withSubfolders = false);

        /// <summary>
        /// Get stream of file
        /// </summary>
        /// <param name="file"></param>
        /// <returns>Stream</returns>
        Stream GetFileStream(File file);

        Task<Stream> GetFileStreamAsync(File file);

        /// <summary>
        /// Get stream of file
        /// </summary>
        /// <param name="file"></param>
        /// <param name="offset"></param>
        /// <returns>Stream</returns>
        Stream GetFileStream(File file, long offset);

        /// <summary>
        /// Get presigned uri
        /// </summary>
        /// <param name="file"></param>
        /// <param name="expires"></param>
        /// <returns>Stream uri</returns>
        Uri GetPreSignedUri(File file, TimeSpan expires);

        /// <summary>
        ///  Check is supported PreSignedUri
        /// </summary>
        /// <param name="file"></param>
        /// <returns>Stream uri</returns>
        bool IsSupportedPreSignedUri(File file);

        /// <summary>
        ///  Saves / updates the version of the file
        ///  and save stream of file
        /// </summary>
        /// <param name="file"></param>
        /// <param name="fileStream"> </param>
        /// <returns></returns>
        /// <remarks>
        /// Updates the file if:
        /// - The file comes with the given id
        /// - The file with that name in the folder / container exists
        ///
        /// Save in all other cases
        /// </remarks>
        File SaveFile(File file, Stream fileStream);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="file"></param>
        /// <param name="fileStream"></param>
        /// <returns></returns>
        File ReplaceFileVersion(File file, Stream fileStream);

        /// <summary>
        ///   Deletes a file including all previous versions
        /// </summary>
        /// <param name="fileId">file id</param>
        void DeleteFile(object fileId);

        /// <summary>
        ///     Checks whether or not file
        /// </summary>
        /// <param name="title">file name</param>
        /// <param name="folderId">folder id</param>
        /// <returns>Returns true if the file exists, otherwise false</returns>
        bool IsExist(String title, object folderId);

        /// <summary>
        ///   Moves a file or set of files in a folder
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <param name="toFolderId">The ID of the destination folder</param>
        object MoveFile(object fileId, object toFolderId);

        /// <summary>
        ///  Copy the files in a folder
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <param name="toFolderId">The ID of the destination folder</param>
        File CopyFile(object fileId, object toFolderId);

        /// <summary>
        ///   Rename file
        /// </summary>
        /// <param name="file"></param>
        /// <param name="newTitle">new name</param>
        object FileRename(File file, string newTitle);

        /// <summary>
        ///   Update comment file
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <param name="fileVersion">file version</param>
        /// <param name="comment">new comment</param>
        string UpdateComment(object fileId, int fileVersion, String comment);

        /// <summary>
        ///   Complete file version
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <param name="fileVersion">file version</param>
        void CompleteVersion(object fileId, int fileVersion);

        /// <summary>
        ///   Continue file version
        /// </summary>
        /// <param name="fileId">file id</param>
        /// <param name="fileVersion">file version</param>
        void ContinueVersion(object fileId, int fileVersion);

        /// <summary>
        /// Check the need to use the trash before removing
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        bool UseTrashForRemove(File file);

        #region chunking

        ChunkedUploadSession CreateUploadSession(File file, long contentLength);

        File UploadChunk(ChunkedUploadSession uploadSession, Stream chunkStream, long chunkLength);

        void AbortUploadSession(ChunkedUploadSession uploadSession);

        #endregion

        #region Only in TMFileDao

        /// <summary>
        /// Set created by
        /// </summary>
        /// <param name="fileIds"></param>
        /// <param name="newOwnerId"></param>
        void ReassignFiles(object[] fileIds, Guid newOwnerId);

        /// <summary>
        /// Search files in SharedWithMe & Projects
        /// </summary>
        /// <param name="parentIds"></param>
        /// <param name="filterType"></param>
        /// <param name="subjectGroup"></param>
        /// <param name="subjectID"></param>
        /// <param name="searchText"></param>
        /// <param name="searchInContent"></param>
        /// <returns></returns>
        List<File> GetFiles(object[] parentIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);

        /// <summary>
        /// Search the list of files containing text
        /// Only in TMFileDao
        /// </summary>
        /// <param name="text">search text</param>
        /// <param name="bunch"></param>
        /// <returns>list of files</returns>
        IEnumerable<File> Search(String text, bool bunch = false);

        /// <summary>
        ///   Checks whether file exists on storage
        /// </summary>
        /// <param name="file">file</param>
        /// <returns></returns>
        bool IsExistOnStorage(File file);

        Task<bool> IsExistOnStorageAsync(File file);

        void SaveEditHistory(File file, string changes, Stream differenceStream);

        List<EditHistory> GetEditHistory(object fileId, int fileVersion = 0);

        Stream GetDifferenceStream(File file);

        bool ContainChanges(object fileId, int fileVersion);

        void SaveThumbnail(File file, Stream thumbnail);

        Stream GetThumbnail(File file);

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/CommentEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Projects.Core.Services.NotifyService;
using ASC.Web.Projects.Core.Search;

namespace ASC.Projects.Engine
{
    public class CommentEngine
    {
        public bool DisableNotifications { get; set; }

        public IDaoFactory DaoFactory { get; set; }
        public EngineFactory EngineFactory { get; set; }
        public ProjectSecurity ProjectSecurity { get; set; }

        public TaskEngine TaskEngine { get { return EngineFactory.TaskEngine; } }
        public MessageEngine MessageEngine { get { return EngineFactory.MessageEngine; } }

        public CommentEngine(bool disableNotifications)
        {
            DisableNotifications = disableNotifications;
        }

        public List<Comment> GetComments(DomainObject<int> targetObject)
        {
            return targetObject != null ? DaoFactory.CommentDao.GetAll(targetObject) : new List<Comment>();
        }

        public Comment GetByID(Guid id)
        {
            return DaoFactory.CommentDao.GetById(id);
        }

        public int Count(DomainObject<int> targetObject)
        {
            return targetObject == null ? 0 : DaoFactory.CommentDao.Count(targetObject);
        }

        public List<int> Count(List<ProjectEntity> targets)
        {
            return DaoFactory.CommentDao.Count(targets);
        }

        public int Count(ProjectEntity target)
        {
            return DaoFactory.CommentDao.Count(target);
        }

        public void SaveOrUpdate(Comment comment)
        {
            if (comment == null) throw new ArgumentNullException("comment");

            if (comment.CreateBy == default(Guid)) comment.CreateBy = SecurityContext.CurrentAccount.ID;

            var now = TenantUtil.DateTimeNow();
            if (comment.CreateOn == default(DateTime)) comment.CreateOn = now;

            DaoFactory.CommentDao.Save(comment);

            if (!comment.Inactive)
            {
                FactoryIndexer<CommentsWrapper>.IndexAsync(comment);
            }
            else
            {
                FactoryIndexer<CommentsWrapper>.DeleteAsync(comment);
            }
        }

        public ProjectEntity GetEntityByTargetUniqId(Comment comment)
        {
            var engine = GetProjectEntityEngine(comment);
            if (engine == null) return null;

            return engine.GetEntityByID(comment.TargetID);
        }

        public Comment SaveOrUpdateComment(ProjectEntity entity, Comment comment)
        {
            var isNew = comment.OldGuidId.Equals(Guid.Empty);

            if (isNew)
            {
                ProjectSecurity.DemandCreateComment(entity);
            }
            else
            {
                var message = entity as Message;
                if (message != null)
                {
                    ProjectSecurity.DemandEditComment(message, comment);
                }
                else
                {
                    ProjectSecurity.DemandEditComment(entity.Project, comment);
                }
            }

            SaveOrUpdate(comment);

            NotifyNewComment(entity, comment, isNew);

            GetProjectEntityEngine(comment).Subscribe(entity, SecurityContext.CurrentAccount.ID);

            return comment;
        }

        private void NotifyNewComment(ProjectEntity entity, Comment comment, bool isNew)
        {
            if (DisableNotifications) return;

            var senders = GetProjectEntityEngine(comment).GetSubscribers(entity);

            NotifyClient.Instance.SendNewComment(senders, entity, comment, isNew);
        }

        private ProjectEntityEngine GetProjectEntityEngine(Comment comment)
        {
            switch (comment.TargetType)
            {
                case "Task":
                    return TaskEngine;
                case "Message":
                    return MessageEngine;
                default:
                    return null;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Domain/Reports/ReportTimeInterval.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Projects.Core.Domain.Reports
{
    public enum ReportTimeInterval
    {
        Absolute,
        Relative,

        Today,
        Yesterday,
        Tomorrow,

        CurrWeek,
        PrevWeek,
        NextWeek,

        CurrMonth,
        PrevMonth,
        NextMonth,

        CurrYear,
        PrevYear,
        NextYear,
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/MIME/MIME_Message.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.MIME
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.IO;
    using IO;

    #endregion

    /// <summary>
    /// Represents a MIME message. Defined in RFC 2045 2.3.
    /// </summary>
    public class MIME_Message : MIME_Entity
    {
        #region Members

        private bool m_IsDisposed = false;

        #endregion

        #region Properties

        /// <summary>
        /// Gets all MIME entities as list.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is disposed and this property is accessed.</exception>
        public MIME_Entity[] AllEntities
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                List<MIME_Entity> retVal = new List<MIME_Entity>();
                Queue<MIME_Entity> entitiesQueue = new Queue<MIME_Entity>();
                entitiesQueue.Enqueue(this);

                while (entitiesQueue.Count > 0)
                {
                    MIME_Entity currentEntity = entitiesQueue.Dequeue();

                    // Current entity is multipart entity, add it's body-parts for processing.
                    if (Body != null && currentEntity.Body.GetType().IsSubclassOf(typeof (MIME_b_Multipart)))
                    {
                        foreach (MIME_Entity bodypart in ((MIME_b_Multipart) currentEntity.Body).BodyParts)
                        {
                            entitiesQueue.Enqueue(bodypart);
                        }
                    }

                    retVal.Add(currentEntity);
                }

                return retVal.ToArray();
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses MIME message from the specified file.
        /// </summary>
        /// <param name="file">File name with path from where to parse MIME message.</param>
        /// <returns>Returns parsed MIME message.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>file</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public static MIME_Message ParseFromFile(string file)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }
            if (file == "")
            {
                throw new ArgumentException("Argument 'file' value must be specified.");
            }

            return ParseFromStream(File.OpenRead(file));
        }

        /// <summary>
        /// Parses MIME message from the specified stream.
        /// </summary>
        /// <param name="stream">Stream from where to parse MIME message. Parsing starts from current stream position.</param>
        /// <returns>Returns parsed MIME message.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null.</exception>
        public static MIME_Message ParseFromStream(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            MIME_Message retVal = new MIME_Message();
            retVal.Parse(new SmartStream(stream, false), new MIME_h_ContentType("text/plain"));

            return retVal;
        }

        /// <summary>
        /// Creates attachment entity.
        /// </summary>
        /// <param name="file">File name with optional path.</param>
        /// <returns>Returns created attachment entity.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>file</b> is null reference.</exception>
        public static MIME_Entity CreateAttachment(string file)
        {
            if (file == null)
            {
                throw new ArgumentNullException("file");
            }

            MIME_Entity retVal = new MIME_Entity();
            MIME_b_Application body = new MIME_b_Application(MIME_MediaTypes.Application.octet_stream);
            retVal.Body = body;
            body.SetBodyDataFromFile(file, MIME_TransferEncodings.Base64);
            retVal.ContentType.Param_Name = Path.GetFileName(file);

            FileInfo fileInfo = new FileInfo(file);
            MIME_h_ContentDisposition disposition =
                new MIME_h_ContentDisposition(MIME_DispositionTypes.Attachment);
            disposition.Param_FileName = Path.GetFileName(file);
            disposition.Param_Size = fileInfo.Length;
            disposition.Param_CreationDate = fileInfo.CreationTime;
            disposition.Param_ModificationDate = fileInfo.LastWriteTime;
            disposition.Param_ReadDate = fileInfo.LastAccessTime;
            retVal.ContentDisposition = disposition;

            return retVal;
        }

        /// <summary>
        /// Gets MIME entity with the specified Content-ID. Returns null if no such entity.
        /// </summary>
        /// <param name="cid">Content ID.</param>
        /// <returns>Returns MIME entity with the specified Content-ID or null if no such entity.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this class is disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>cid</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public MIME_Entity GetEntityByCID(string cid)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (cid == null)
            {
                throw new ArgumentNullException("cid");
            }
            if (cid == "")
            {
                throw new ArgumentException("Argument 'cid' value must be specified.", "cid");
            }

            foreach (MIME_Entity entity in AllEntities)
            {
                if (entity.ContentID == cid)
                {
                    return entity;
                }
            }

            return null;
        }

        #endregion

        // TODO:
        //public MIME_Entity GetEntityByPartsSpecifier(string partsSpecifier)
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IO/ReadLineEventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Text;

namespace LumiSoft.Net.IO
{
    /// <summary>
    /// This class provides data to <see cref="SmartStream.ReadLine">SmartStream.ReadLine</see> method.
    /// </summary>
    /// <remarks>This class can be reused on multiple calls of <see cref="SmartStream.ReadLine">SmartStream.ReadLine</see> method.</remarks>
    public class ReadLineEventArgs : EventArgs
    {
        private bool               m_IsDisposed     = false;
        private bool               m_IsCompleted    = false;
        private byte[]             m_pBuffer        = null;
        private SizeExceededAction m_ExceededAction = SizeExceededAction.JunkAndThrowException;
        private bool               m_CRLFLinesOnly  = false;
        private int                m_BytesInBuffer  = 0;
        private Exception          m_pException     = null;

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="buffer">Line buffer.</param>
        /// <param name="exceededAction">Specifies how line-reader behaves when maximum line size exceeded.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null reference.</exception>
        public ReadLineEventArgs(byte[] buffer,SizeExceededAction exceededAction)
        {
            if(buffer == null){
                throw new ArgumentNullException("buffer");
            }

            m_pBuffer        = buffer;
            m_ExceededAction = exceededAction;
        }


        #region method Start 

        internal bool Start(SmartStream stream)
        {   
            // TODO: Clear old data, if any.
            m_IsCompleted   = false;
            m_BytesInBuffer = 0;
            m_pException    = null;
   
            return DoLineReading();
        }

        #endregion

        #region method Buffering_Completed

        /// <summary>
        /// Is called when asynchronous read buffer buffering has completed.
        /// </summary>
        /// <param name="x">Exception that occured during async operation.</param>
        private void Buffering_Completed(Exception x)
        {
            /*
            if(x != null){
                m_pException = x;
                Completed();
            }
            // We reached end of stream, no more data.
            else if(m_pOwner.BytesInReadBuffer == 0){
                Completed();
            }
            // Continue line reading.
            else{
                DoLineReading();
            }*/
        }

        #endregion

        #region method DoLineReading

        /// <summary>
        /// Starts/continues line reading.
        /// </summary>
        /// <returns>Returns true if line reading completed.</returns>
        private bool DoLineReading()
        {
            try{
                while(true){
                    /*
                    // Read buffer empty, buff next data block.
                    if(m_pOwner.BytesInReadBuffer == 0){
                        // Buffering started asynchronously.
                        if(m_pOwner.BufferRead(true,this.Buffering_Completed)){
                            return;
                        }
                        // Buffering completed synchronously, continue processing.
                        else{
                            // We reached end of stream, no more data.
                            if(m_pOwner.BytesInReadBuffer == 0){
                                Completed();
                                return;
                            }
                        }
                    }*/

                    byte b = 1; //m_pOwner.m_pReadBuffer[m_pOwner.m_ReadBufferOffset++];
                    //m_BytesInBuffer++;

                    // TODO: Check for room, Store byte.

                    // We have LF line.
                    if(b == '\n'){
                        // TODO:
                        // m_CRLFLinesOnly
                    }
                }
            }
            catch(Exception x){
                m_pException = x;
                OnCompleted();
            }

            return true;
        }

        #endregion


        #region Properties implementation

        /// <summary>
        /// Gets if this object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get{ return m_IsDisposed; }
        }

        /// <summary>
        /// Gets if asynchronous operation has completed.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public bool IsCompleted
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }

                return m_IsCompleted; 
            }
        }

        /// <summary>
        /// Gets line buffer.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public byte[] Buffer
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }

                return m_pBuffer; 
            }
        }

        /// <summary>
        /// Gets number of bytes stored in the buffer. Line feed characters not included.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public int BytesInBuffer
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }

                return m_BytesInBuffer; 
            }
        }

        /// <summary>
        /// Gets line as ASCII string.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public string LineAscii
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }

                return Encoding.ASCII.GetString(m_pBuffer,0,m_BytesInBuffer); 
            }
        }

        /// <summary>
        /// Gets line as UTF-8 string.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public string LineUtf8
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }

                return Encoding.UTF8.GetString(m_pBuffer,0,m_BytesInBuffer);
            }
        }

        /// <summary>
        /// Gets error occured during asynchronous operation. Value null means no error.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public Exception Error
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException(this.GetType().Name);
                }

                return m_pException; 
            }
        }

        #endregion

        #region Events implementation

        /// <summary>
        /// Is raised when asynchronous operation has completed.
        /// </summary>
        public event EventHandler<ReadLineEventArgs> Completed = null;

        #region method OnCompleted

        /// <summary>
        /// Raises <b>Completed</b> event.
        /// </summary>
        private void OnCompleted()
        {
            if(this.Completed != null){
                this.Completed(this,this);
            }
        }

        #endregion

        #endregion
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/GreetingSettings/js/greetinglogosettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var GreetingLogoSettingsManager = new function () {

    var _bindAjaxProOnLoading = function () {
        AjaxPro.onLoading = function (b) {
            if (b) {
                LoadingBanner.showLoaderBtn("#studio_greetingLogoSettings");
            } else {
                LoadingBanner.hideLoaderBtn("#studio_greetingLogoSettings");
            }
        };
    };

    var _saveGreetingLogoOptions = function () {
        _bindAjaxProOnLoading();
        GreetingLogoSettingsController.SaveGreetingLogoSettings(jq('#studio_greetingLogoPath').val(),
                                                function (result) {
                                                    //clean logo path input
                                                    jq('#studio_greetingLogoPath').val('');
                                                    LoadingBanner.showMesInfoBtn("#studio_greetingLogoSettings", result.value.Message, result.value.Status == 1 ? "success" : "error");
                                                });
      };

    var _restoreGreetingLogoOptions = function () {
        _bindAjaxProOnLoading();
        GreetingLogoSettingsController.RestoreGreetingLogoSettings(function (result) {
            //clean logo path input
            jq('#studio_greetingLogoPath').val('');

            if (result.value.Status == 1) {
                jq('#studio_greetingLogo').attr('src', result.value.LogoPath);
            }
            LoadingBanner.showMesInfoBtn("#studio_greetingLogoSettings", result.value.Message, result.value.Status == 1 ? "success" : "error");
        });
    };

    var _uploadCompleteGreetingLogo = function (file, response) {
        LoadingBanner.hideLoaderBtn("#studio_greetingLogoSettings");

        var result = eval("(" + response + ")");

        if (result.Success) {
            jq('#studio_greetingLogo').attr('src', result.Message);
            jq('#studio_greetingLogoPath').val(result.Message);
        } else {
            LoadingBanner.showMesInfoBtn("#studio_greetingLogoSettings", result.Message, "error");
        }
    };

    this.Init = function () {
        jq('#saveGreetLogoSettingsBtn').on("click", _saveGreetingLogoOptions);
        jq('#restoreGreetLogoSettingsBtn').on("click", _restoreGreetingLogoOptions);

        if (jq('#studio_logoUploader').length > 0) {
            new AjaxUpload('studio_logoUploader', {
                action: 'ajaxupload.ashx?type=ASC.Web.Studio.UserControls.Management.LogoUploader,ASC.Web.Studio',
                onChange: function (file, ext) {
                    LoadingBanner.showLoaderBtn("#studio_greetingLogoSettings");
                },
                onComplete: _uploadCompleteGreetingLogo
            });
        }

    }
};


jq(function () {
    GreetingLogoSettingsManager.Init();
});

<|start_filename|>common/ASC.Common/Utils/ConfigurationManagerExtension.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Concurrent;
using System.Collections.Specialized;

namespace System.Configuration
{
    //mono:hack
    public static class ConfigurationManagerExtension
    {
        private static ConcurrentDictionary<string, object> Sections { get; set; }

        static ConfigurationManagerExtension()
        {
            Sections = new ConcurrentDictionary<string, object>();
        }

        public static NameValueCollection AppSettings
        {
            get
            {
                var section = GetSection("appSettings");
                if (section == null || !(section is NameValueCollection))
                {
                    throw new ConfigurationErrorsException("config exception");
                }

                return (NameValueCollection)section;
            }
        }

        public static object GetSection(string sectionName)
        {
            return Sections.GetOrAdd(sectionName, ConfigurationManager.GetSection(sectionName));
        }

        public static ConnectionStringSettingsCollection ConnectionStrings
        {
            get
            {
                var section = GetSection("connectionStrings");
                if (section == null || section.GetType() != typeof(ConnectionStringsSection))
                {
                    throw new ConfigurationErrorsException("Config_connectionstrings_declaration_invalid");
                }

                var connectionStringsSection = (ConnectionStringsSection)section;
                return connectionStringsSection.ConnectionStrings;
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/MailService/js/mailservice.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined")
    ASC = {};

if (typeof ASC.Settings === "undefined")
    ASC.Settings = {};

ASC.Settings.MailService = (function () {

    var ip;
    var sqlip;
    var database;
    var user;
    var password;
    var token;
    var host;

    var init = function () {
        jq(".settings-switcher-btn").click(function () {
            jq(".settings-switcher-btn, .settings-switcher-content").toggleClass("display-none");
        });

        jq("#mailServiceConnectBtn").click(function () {
            if (jq(this).hasClass("disable")) return;
            connect();
        });
        
        jq("#mailServiceSaveBtn").click(function () {
            if (jq(this).hasClass("disable")) return;
            save();
        });
    };

    var connect = function () {

        var serverIp = jq("#mailServiceIp").val().trim();
        var sqlIp = jq("#mailServiceSqlIp").val().trim();
        var db = jq("#mailServiceDatabase").val().trim();
        var usr = jq("#mailServiceUser").val().trim();
        var pwd = jq("#mailServicePassword").val().trim();
        var valid = true;

        if (!serverIp) {
            jq("#mailServiceIp").parent().addClass("requiredFieldError");
            valid = false;
        } else {
            jq("#mailServiceIp").parent().removeClass("requiredFieldError");
        }

        if (!db) {
            jq("#mailServiceDatabase").parent().addClass("requiredFieldError");
            valid = false;
        } else {
            jq("#mailServiceDatabase").parent().removeClass("requiredFieldError");
        }

        if (!usr) {
            jq("#mailServiceUser").parent().addClass("requiredFieldError");
            valid = false;
        } else {
            jq("#mailServiceUser").parent().removeClass("requiredFieldError");
        }

        if (!pwd) {
            jq("#mailServicePassword").parent().addClass("requiredFieldError");
            valid = false;
        } else {
            jq("#mailServicePassword").parent().removeClass("requiredFieldError");
        }

        if (!valid) return;

        Teamlab.connectMailServerInfo(null, serverIp, sqlIp || serverIp, db, usr, pwd, {
            before: function() {
                jq("#mailServiceBlock input").prop("disabled", true);
                LoadingBanner.showLoaderBtn("#mailServiceBlock");
            },
            success: function (params, res) {
                LoadingBanner.showMesInfoBtn("#mailServiceBlock", res.message, res.status);
                if (res.status == "success") {
                    ip = res.ip;
                    sqlip = res.sqlip;
                    database = res.database;
                    user = res.user;
                    password = <PASSWORD>;
                    token = res.token;
                    host = res.host;
                    jq("#mailServiceSaveBtn").removeClass("disable");
                } else {
                    ip = null;
                    sqlip = null;
                    database = null;
                    user = null;
                    password = <PASSWORD>;
                    token = null;
                    host = null;
                    jq("#mailServiceSaveBtn").addClass("disable");
                }
            },
            error: function (params, error) {
                LoadingBanner.showMesInfoBtn("#mailServiceBlock", error[0], "error");
            },
            after: function() {
                jq("#mailServiceBlock input").prop("disabled", false);
                LoadingBanner.hideLoaderBtn("#mailServiceBlock");
            }
        });
    };

    var save = function () {

        if (!ip || !database || !user || !password || !token || !host) return;

        Teamlab.saveMailServerInfo(null, ip, sqlip || ip, database, user, password, token, host, {
            before: function () {
                jq("#mailServiceBlock input").prop("disabled", true);
                LoadingBanner.showLoaderBtn("#mailServiceBlock");
            },
            success: function (params, res) {
                LoadingBanner.showMesInfoBtn("#mailServiceBlock", res.message, res.status);
                if (res.status == "success") {
                    jq("#mailServiceLink").removeClass("display-none");
                } else {
                    jq("#mailServiceLink").addClass("display-none");
                }
            },
            error: function (params, error) {
                LoadingBanner.showMesInfoBtn("#mailServiceBlock", error[0], "error");
            },
            after: function () {
                jq("#mailServiceBlock input").prop("disabled", false);
                LoadingBanner.hideLoaderBtn("#mailServiceBlock");
            }
        });
    };

    return {

        init: init
        
    };
})();

jq(function () {
    ASC.Settings.MailService.init();
});

<|start_filename|>common/ASC.Core.Common/Core/ITenantService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Core.Tenants;

namespace ASC.Core
{
    public interface ITenantService
    {
        void ValidateDomain(string domain);

        IEnumerable<Tenant> GetTenants(DateTime from, bool active = true);

        IEnumerable<Tenant> GetTenants(string login, string passwordHash);

        Tenant GetTenant(int id);

        Tenant GetTenant(string domain);

        Tenant GetTenantForStandaloneWithoutAlias(string ip);

        Tenant SaveTenant(Tenant tenant);

        void RemoveTenant(int id, bool auto = false);

        byte[] GetTenantSettings(int tenant, string key);

        void SetTenantSettings(int tenant, string key, byte[] data);

        IEnumerable<TenantVersion> GetTenantVersions();
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.Feed/FeedApi.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.Impl;
using ASC.Api.Interfaces;
using ASC.Common.Caching;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Feed;
using ASC.Feed.Data;
using ASC.Specific;

namespace ASC.Api.Feed
{
    public class FeedApi : IApiEntryPoint
    {
        private const string newFeedsCountCacheKey = "newfeedscount";
        private readonly ICache newFeedsCountCache = AscCache.Memory;

        private static string GetNewFeedsCountKey()
        {
            return newFeedsCountCacheKey + SecurityContext.CurrentAccount.ID;
        }

        private readonly ApiContext context;

        public string Name
        {
            get { return "feed"; }
        }

        public FeedApi(ApiContext context)
        {
            this.context = context;
        }

        [Update("/read")]
        public void Read()
        {
            new FeedReadedDataProvider().SetTimeReaded(SecurityContext.CurrentAccount.ID);
            newFeedsCountCache.Remove(GetNewFeedsCountKey());
        }

        [Read("/filter")]
        public object GetFeed(
            string product,
            ApiDateTime from,
            ApiDateTime to,
            Guid? author,
            bool? onlyNew,
            ApiDateTime timeReaded)
        {
            var filter = new FeedApiFilter
            {
                Product = product,
                Offset = (int)context.StartIndex,
                Max = (int)context.Count - 1,
                Author = author ?? Guid.Empty,
                SearchKeys = context.FilterValues,
                OnlyNew = onlyNew.HasValue && onlyNew.Value
            };

            if (from != null && to != null)
            {
                var f = TenantUtil.DateTimeFromUtc(from.UtcTime);
                filter.From = new DateTime(f.Year, f.Month, f.Day, 0, 0, 0);

                var t = TenantUtil.DateTimeFromUtc(to.UtcTime);
                filter.To = new DateTime(t.Year, t.Month, t.Day, 23, 59, 59);
            }
            else
            {
                filter.From = from != null ? from.UtcTime : DateTime.MinValue;
                filter.To = to != null ? to.UtcTime : DateTime.MaxValue;
            }

            var feedReadedProvider = new FeedReadedDataProvider();
            var lastTimeReaded = feedReadedProvider.GetTimeReaded();

            var readedDate = timeReaded != null ? (ApiDateTime)timeReaded.UtcTime : (ApiDateTime)lastTimeReaded;

            if (filter.OnlyNew)
            {
                filter.From = (ApiDateTime)lastTimeReaded;
                filter.Max = 100;
            }
            else if (timeReaded == null)
            {
                feedReadedProvider.SetTimeReaded();
                newFeedsCountCache.Remove(GetNewFeedsCountKey());
            }

            var feeds = FeedAggregateDataProvider
                .GetFeeds(filter)
                .GroupBy(n => n.GroupId,
                         n => new FeedWrapper(n),
                         (n, group) =>
                             {
                                 var firstFeed = group.First();
                                 firstFeed.GroupedFeeds = group.Skip(1);
                                 return firstFeed;
                             })
                .ToList();

            context.SetDataPaginated();
            return new { feeds, readedDate };
        }

        [Read("/newfeedscount")]
        public object GetFreshNewsCount()
        {
            var cacheKey = GetNewFeedsCountKey();
            var resultfromCache = newFeedsCountCache.Get<String>(cacheKey);
            int result;
            if (!int.TryParse(resultfromCache, out result))
            {
                var lastTimeReaded = new FeedReadedDataProvider().GetTimeReaded();
                result = FeedAggregateDataProvider.GetNewFeedsCount(lastTimeReaded);
                newFeedsCountCache.Insert(cacheKey, result.ToString(), DateTime.UtcNow.AddMinutes(3));
            }
            return result;
        }
    }
}

<|start_filename|>module/ASC.AuditTrail/Mappers/AuditActionMapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.MessagingSystem;

namespace ASC.AuditTrail.Mappers
{
    public class AuditActionMapper
    {
        private static readonly Dictionary<MessageAction, MessageMaps> actions;

        static AuditActionMapper()
        {
            actions = new Dictionary<MessageAction, MessageMaps>();

            actions = actions
                .Union(LoginActionsMapper.GetMaps())
                .Union(ProjectsActionsMapper.GetMaps())
                .Union(CrmActionMapper.GetMaps())
                .Union(PeopleActionMapper.GetMaps())
                .Union(DocumentsActionMapper.GetMaps())
                .Union(SettingsActionsMapper.GetMaps())
                .Union(OthersActionsMapper.GetMaps())
                .ToDictionary(x => x.Key, x => x.Value);
        }

        public static string GetActionText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            if (!actions.ContainsKey(action))
            {
                //log.Error(string.Format("There is no action text for \"{0}\" type of event", action));
                return string.Empty;
            }

            try
            {
                var actionText = actions[(MessageAction)evt.Action].GetActionText();

                if (evt.Description == null || !evt.Description.Any()) return actionText;

                var description = evt.Description
                                     .Select(t => t.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                                     .Select(split => string.Join(", ", split.Select(ToLimitedText))).ToArray();


                return string.Format(actionText, description);
            }
            catch
            {
                //log.Error(string.Format("Error while building action text for \"{0}\" type of event", action));
                return string.Empty;
            }
        }

        public static string GetActionText(LoginEvent evt)
        {
            var action = (MessageAction)evt.Action;
            if (!actions.ContainsKey(action))
            {
                //log.Error(string.Format("There is no action text for \"{0}\" type of event", action));
                return string.Empty;
            }

            try
            {
                var actionText = actions[(MessageAction)evt.Action].GetActionText();

                if (evt.Description == null || !evt.Description.Any()) return actionText;

                var description = evt.Description
                                     .Select(t => t.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
                                     .Select(split => string.Join(", ", split.Select(ToLimitedText))).ToArray();

                return string.Format(actionText, description);
            }
            catch
            {
                //log.Error(string.Format("Error while building action text for \"{0}\" type of event", action));
                return string.Empty;
            }
        }

        public static string GetActionTypeText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            return !actions.ContainsKey(action)
                       ? string.Empty
                       : actions[(MessageAction)evt.Action].GetActionTypeText();
        }

        public static string GetProductText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            return !actions.ContainsKey(action)
                       ? string.Empty
                       : actions[(MessageAction)evt.Action].GetProduct();
        }

        public static string GetModuleText(AuditEvent evt)
        {
            var action = (MessageAction)evt.Action;
            return !actions.ContainsKey(action)
                       ? string.Empty
                       : actions[(MessageAction)evt.Action].GetModule();
        }

        private static string ToLimitedText(string text)
        {
            if (text == null) return null;
            return text.Length < 50 ? text : string.Format("{0}...", text.Substring(0, 47));
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/CommonPhotoManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;

namespace ASC.Web.Core
{
    public class CommonPhotoManager
    {

        public static Image DoThumbnail(Image image, Size size, bool crop, bool transparent, bool rectangle)
        {
            var width = size.Width;
            var height = size.Height;
            var realWidth = image.Width;
            var realHeight = image.Height;

            var thumbnail = new Bitmap(width, height);

            var maxSide = realWidth > realHeight ? realWidth : realHeight;
            var minSide = realWidth < realHeight ? realWidth : realHeight;

            var alignWidth = true;
            if (crop) alignWidth = (minSide == realWidth);
            else alignWidth = (maxSide == realWidth);

            double scaleFactor = (alignWidth) ? (realWidth / (1.0 * width)) : (realHeight / (1.0 * height));

            if (scaleFactor < 1) scaleFactor = 1;

            int locationX, locationY;
            int finalWidth, finalHeigth;

            finalWidth = (int)(realWidth / scaleFactor);
            finalHeigth = (int)(realHeight / scaleFactor);


            if (rectangle)
            {
                locationY = (int)((height / 2.0) - (finalHeigth / 2.0));
                locationX = (int)((width / 2.0) - (finalWidth / 2.0));

                var rect = new Rectangle(locationX, locationY, finalWidth, finalHeigth);

                using (var graphic = Graphics.FromImage(thumbnail))
                {
                    if (!transparent)
                    {
                        graphic.Clear(Color.White);
                        graphic.SmoothingMode = SmoothingMode.HighQuality;
                    }
                    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;

                    using (ImageAttributes wrapMode = new ImageAttributes())
                    {
                        wrapMode.SetWrapMode(WrapMode.TileFlipXY);
                        graphic.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
                    }

                    //graphic.DrawImage(image, rect);
                }
            }
            else
            {
                thumbnail = new Bitmap(finalWidth, finalHeigth);

                using (var graphic = Graphics.FromImage(thumbnail))
                {
                    if (!transparent)
                    {
                        graphic.Clear(Color.White);
                        graphic.SmoothingMode = SmoothingMode.HighQuality;
                    }
                    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    graphic.DrawImage(image, 0, 0, finalWidth, finalHeigth);
                }
            }

            return thumbnail;
        }

        public static byte[] SaveToBytes(Image img)
        {
            using (var memoryStream = new MemoryStream())
            {
                img.Save(memoryStream, ImageFormat.Png);
                return memoryStream.ToArray();
            }
        }

        public static byte[] SaveToBytes(Image img, String formatName)
        {
            byte[] data;
            using (var memoryStream = new MemoryStream())
            {
                var encParams = new EncoderParameters(1);
                encParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)100);
                img.Save(memoryStream, GetCodecInfo(formatName), encParams);
                data = memoryStream.ToArray();
            }
            return data;
        }

        public static ImageCodecInfo GetCodecInfo(String formatName)
        {
            var mimeType = string.Format("image/{0}", formatName);
            if (mimeType == "image/jpg") mimeType = "image/jpeg";
            var encoders = ImageCodecInfo.GetImageEncoders();
            foreach (var e in
                encoders.Where(e => e.MimeType.Equals(mimeType, StringComparison.InvariantCultureIgnoreCase)))
            {
                return e;
            }
            return 0 < encoders.Length ? encoders[0] : null;
        }

        public static string GetImgFormatName(ImageFormat format)
        {
            if (format.Equals(ImageFormat.Bmp)) return "bmp";
            if (format.Equals(ImageFormat.Emf)) return "emf";
            if (format.Equals(ImageFormat.Exif)) return "exif";
            if (format.Equals(ImageFormat.Gif)) return "gif";
            if (format.Equals(ImageFormat.Icon)) return "icon";
            if (format.Equals(ImageFormat.Jpeg)) return "jpeg";
            if (format.Equals(ImageFormat.Png)) return "png";
            if (format.Equals(ImageFormat.Tiff)) return "tiff";
            if (format.Equals(ImageFormat.Wmf)) return "wmf";
            return "jpg";
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Resources/MailAdministrationResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Mail.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class MailAdministrationResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal MailAdministrationResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Mail.Resources.MailAdministrationResource", typeof(MailAdministrationResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add.
        /// </summary>
        public static string AddButton {
            get {
                return ResourceManager.GetString("AddButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add new mailbox.
        /// </summary>
        public static string AddMailboxLabel {
            get {
                return ResourceManager.GetString("AddMailboxLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add mailboxes to start using the new domain..
        /// </summary>
        public static string AddMailboxToNewDomainInfo {
            get {
                return ResourceManager.GetString("AddMailboxToNewDomainInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add new mail group.
        /// </summary>
        public static string AddMailgroupLabel {
            get {
                return ResourceManager.GetString("AddMailgroupLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add your own domain.
        /// </summary>
        public static string AddNewDomainButton {
            get {
                return ResourceManager.GetString("AddNewDomainButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Aliases.
        /// </summary>
        public static string AliasesLabel {
            get {
                return ResourceManager.GetString("AliasesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Alias.
        /// </summary>
        public static string AliasLabel {
            get {
                return ResourceManager.GetString("AliasLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter a new password.
        /// </summary>
        public static string ChangeMailboxPasswordPopupInfo {
            get {
                return ResourceManager.GetString("ChangeMailboxPasswordPopupInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new mailbox.
        /// </summary>
        public static string CreateMailboxHeaderInfo {
            get {
                return ResourceManager.GetString("CreateMailboxHeaderInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You need to enter the mailbox address and choose the user you want to create the mailbox for..
        /// </summary>
        public static string CreateMailboxPopupHeader {
            get {
                return ResourceManager.GetString("CreateMailboxPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new mail group.
        /// </summary>
        public static string CreateMailgroupHeaderInfo {
            get {
                return ResourceManager.GetString("CreateMailgroupHeaderInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You need to enter the mail group address and choose mailboxes that will be included in this mailgroup..
        /// </summary>
        public static string CreateMailgroupPopupHeader {
            get {
                return ResourceManager.GetString("CreateMailgroupPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete domain.
        /// </summary>
        public static string DeleteDomain {
            get {
                return ResourceManager.GetString("DeleteDomain", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you delete your domain all mailboxes and groups with this domain will also be removed..
        /// </summary>
        public static string DeleteDomainAttention {
            get {
                return ResourceManager.GetString("DeleteDomainAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail group deletion will not affect the mailboxes within it in any way.
        /// </summary>
        public static string DeleteGroupAttention {
            get {
                return ResourceManager.GetString("DeleteGroupAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete mail group.
        /// </summary>
        public static string DeleteGroupLabel {
            get {
                return ResourceManager.GetString("DeleteGroupLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you delete server mailbox all the letters will be removed from the mailbox..
        /// </summary>
        public static string DeleteMailboxAttention {
            get {
                return ResourceManager.GetString("DeleteMailboxAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete mailbox.
        /// </summary>
        public static string DeleteMailboxLabel {
            get {
                return ResourceManager.GetString("DeleteMailboxLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Do you want to delete %1?.
        /// </summary>
        public static string DeleteShureText {
            get {
                return ResourceManager.GetString("DeleteShureText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to DNS settings.
        /// </summary>
        public static string DNSSettingsLabel {
            get {
                return ResourceManager.GetString("DNSSettingsLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Domain has been added.
        /// </summary>
        public static string DomainAddedPopupHeader {
            get {
                return ResourceManager.GetString("DomainAddedPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %1 domain settings.
        /// </summary>
        public static string DomainDnsSettingsPopupHeader {
            get {
                return ResourceManager.GetString("DomainDnsSettingsPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Now you need to add %1-record in the control panel of your own domain..
        /// </summary>
        public static string DomainWizardAddRecord {
            get {
                return ResourceManager.GetString("DomainWizardAddRecord", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Complete.
        /// </summary>
        public static string DomainWizardCompleteBtn {
            get {
                return ResourceManager.GetString("DomainWizardCompleteBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Just open the control panel of your domain in another browser tab and simply copy the bold text into the appropriate fields or select the most suitable variant from the available ones:.
        /// </summary>
        public static string DomainWizardCopyInfo {
            get {
                return ResourceManager.GetString("DomainWizardCopyInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to DKIM (DomainKeys Identified Mail) record.
        /// </summary>
        public static string DomainWizardDKIMRecord {
            get {
                return ResourceManager.GetString("DomainWizardDKIMRecord", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Domain &quot;{0}&quot; is already in use..
        /// </summary>
        public static string DomainWizardDomainAlreadyExists {
            get {
                return ResourceManager.GetString("DomainWizardDomainAlreadyExists", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to In some cases, the DNS management service does not allow using &apos;@&apos; as a domain/subdomain name. Use your domain name with the &apos;.&apos; at the end, e.g.: &apos;%1.&apos;.
        /// </summary>
        public static string DomainWizardDomainNameSymbolInfo {
            get {
                return ResourceManager.GetString("DomainWizardDomainNameSymbolInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Domain &quot;{0}&quot; is not verified..
        /// </summary>
        public static string DomainWizardDomainNotVerified {
            get {
                return ResourceManager.GetString("DomainWizardDomainNotVerified", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you have already done that, just go to the next step..
        /// </summary>
        public static string DomainWizardGoNextStep {
            get {
                return ResourceManager.GetString("DomainWizardGoNextStep", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to MX (Mail Exchange) record.
        /// </summary>
        public static string DomainWizardMXRecord {
            get {
                return ResourceManager.GetString("DomainWizardMXRecord", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Name:.
        /// </summary>
        public static string DomainWizardName {
            get {
                return ResourceManager.GetString("DomainWizardName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Next.
        /// </summary>
        public static string DomainWizardNextBtn {
            get {
                return ResourceManager.GetString("DomainWizardNextBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your domain ownership record.
        /// </summary>
        public static string DomainWizardOwnershpCheckRecord {
            get {
                return ResourceManager.GetString("DomainWizardOwnershpCheckRecord", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add domain.
        /// </summary>
        public static string DomainWizardPopupHeader {
            get {
                return ResourceManager.GetString("DomainWizardPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Previous.
        /// </summary>
        public static string DomainWizardPrevBtn {
            get {
                return ResourceManager.GetString("DomainWizardPrevBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Priority:.
        /// </summary>
        public static string DomainWizardPriority {
            get {
                return ResourceManager.GetString("DomainWizardPriority", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Before you can start creating your corporate email addresses, you need to add a TXT record in the control panel of your own domain in order to prove your domain ownership..
        /// </summary>
        public static string DomainWizardProveDomainOwnershipInfo {
            get {
                return ResourceManager.GetString("DomainWizardProveDomainOwnershipInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to SPF (Sender Policy Framework) record.
        /// </summary>
        public static string DomainWizardSPFRecord {
            get {
                return ResourceManager.GetString("DomainWizardSPFRecord", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to step %1 of %2.
        /// </summary>
        public static string DomainWizardStep {
            get {
                return ResourceManager.GetString("DomainWizardStep", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Text/Value:.
        /// </summary>
        public static string DomainWizardTextOrValue {
            get {
                return ResourceManager.GetString("DomainWizardTextOrValue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can also read the {0}FAQ{1} for step-by-step instructions for most popular hosting services..
        /// </summary>
        public static string DomainWizardToFAQ {
            get {
                return ResourceManager.GetString("DomainWizardToFAQ", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Type:.
        /// </summary>
        public static string DomainWizardType {
            get {
                return ResourceManager.GetString("DomainWizardType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please note: DNS record update can take from several minutes to several hours. Please wait some time, if you changed the record not long ago..
        /// </summary>
        public static string DomainWizardWaitDNSrefrashInfo {
            get {
                return ResourceManager.GetString("DomainWizardWaitDNSrefrashInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Write your company domain name in the field below:.
        /// </summary>
        public static string DomainWizardWriteDomainName {
            get {
                return ResourceManager.GetString("DomainWizardWriteDomainName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit mail group addresses.
        /// </summary>
        public static string EditGroupAddressesLabel {
            get {
                return ResourceManager.GetString("EditGroupAddressesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit mailbox.
        /// </summary>
        public static string EditMailboxLabel {
            get {
                return ResourceManager.GetString("EditMailboxLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Email.
        /// </summary>
        public static string EmailLabel {
            get {
                return ResourceManager.GetString("EmailLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Group.
        /// </summary>
        public static string GroupLabel {
            get {
                return ResourceManager.GetString("GroupLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailbox address.
        /// </summary>
        public static string MailboxAddressLabel {
            get {
                return ResourceManager.GetString("MailboxAddressLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailbox alias.
        /// </summary>
        public static string MailboxAliasLabel {
            get {
                return ResourceManager.GetString("MailboxAliasLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailbox user.
        /// </summary>
        public static string MailboxUserLabel {
            get {
                return ResourceManager.GetString("MailboxUserLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail group address.
        /// </summary>
        public static string MailgroupAddressLabel {
            get {
                return ResourceManager.GetString("MailgroupAddressLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail group mailboxes.
        /// </summary>
        public static string MailgroupMailboxesLabel {
            get {
                return ResourceManager.GetString("MailgroupMailboxesLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Migrate from MS Exchange.
        /// </summary>
        public static string MigrateFromMSExchangeButton {
            get {
                return ResourceManager.GetString("MigrateFromMSExchangeButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The mailboxes previously existing on this domain cannot be automatically transferred to the portal. You need to add them anew..
        /// </summary>
        public static string NewDomainAttention {
            get {
                return ResourceManager.GetString("NewDomainAttention", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set up the first domain.
        /// </summary>
        public static string NoDomainSetUpButton {
            get {
                return ResourceManager.GetString("NoDomainSetUpButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set up your own domain to create and manage corporate mailboxes like <EMAIL>. You can create mailboxes for your employees, and they will see them in their ONLYOFFICE Mail clients..
        /// </summary>
        public static string NoDomainSetUpDescription {
            get {
                return ResourceManager.GetString("NoDomainSetUpDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No domain is set up yet.
        /// </summary>
        public static string NoDomainSetUpHeader {
            get {
                return ResourceManager.GetString("NoDomainSetUpHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to not in group.
        /// </summary>
        public static string NotInGroupLabel {
            get {
                return ResourceManager.GetString("NotInGroupLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sender name.
        /// </summary>
        public static string SenderNameLabel {
            get {
                return ResourceManager.GetString("SenderNameLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Now you can create mailboxes like {0}..
        /// </summary>
        public static string UnverifiedDomainAddedPopupBody {
            get {
                return ResourceManager.GetString("UnverifiedDomainAddedPopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your domain has been added successfully..
        /// </summary>
        public static string UnverifiedDomainAddedPopupHeader {
            get {
                return ResourceManager.GetString("UnverifiedDomainAddedPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please check.
        /// </summary>
        public static string UnverifiedDomainRecordExplain {
            get {
                return ResourceManager.GetString("UnverifiedDomainRecordExplain", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The settings of one or several DNS records for your domain are incorrect. Please go to your domain settings panel and check the presence of the below records there..
        /// </summary>
        public static string UnverifiedDomainRecordWarning {
            get {
                return ResourceManager.GetString("UnverifiedDomainRecordWarning", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to User.
        /// </summary>
        public static string UserLabel {
            get {
                return ResourceManager.GetString("UserLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to We have added your domain to the mail domain list, but you cannot use it right now to create your mailboxes. The reason might be that the necessary time has not passed yet. Please wait for a little, some servers can take up to 24 hours to update DNS information..
        /// </summary>
        public static string VerifiedDomainAddedPopupBody {
            get {
                return ResourceManager.GetString("VerifiedDomainAddedPopupBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to We will send you an email message to your {0} address when your domain is ready to be used..
        /// </summary>
        public static string VerifiedDomainAddedPopupFooter {
            get {
                return ResourceManager.GetString("VerifiedDomainAddedPopupFooter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your domain has been added successfully, but you will be able to use it later..
        /// </summary>
        public static string VerifiedDomainAddedPopupHeader {
            get {
                return ResourceManager.GetString("VerifiedDomainAddedPopupHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Verify.
        /// </summary>
        public static string VerifyButton {
            get {
                return ResourceManager.GetString("VerifyButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connection settings.
        /// </summary>
        public static string ViewMailboxConnectionSettingsPopupInfo {
            get {
                return ResourceManager.GetString("ViewMailboxConnectionSettingsPopupInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Domain.
        /// </summary>
        public static string WebDomainLabel {
            get {
                return ResourceManager.GetString("WebDomainLabel", resourceCulture);
            }
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Interfaces/ICrmLinkDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Data.Contracts;

namespace ASC.Mail.Core.Dao.Interfaces
{
    public interface ICrmLinkDao
    {
        List<CrmContactData> GetLinkedCrmContactEntities(string chainId, int mailboxId);

        int SaveCrmLinks(string chainId, int mailboxId, IEnumerable<CrmContactData> crmContactEntities);

        int UpdateCrmLinkedMailboxId(string chainId, int oldMailboxId, int newMailboxId);

        int UpdateCrmLinkedChainId(string chainId, int mailboxId, string newChainId);

        void RemoveCrmLinks(string chainId, int mailboxId, IEnumerable<CrmContactData> crmContactEntities);

        int RemoveCrmLinks(int mailboxId);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Sample/js/script.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof ASC === "undefined") {
    ASC = {};
}
if (typeof ASC.Sample === "undefined") {
    ASC.Sample = (function () { return {}; })();
}

ASC.Sample.PageScript = (function () {
    var isInit = false,
        userId = null;

    var initAdvansedFilter = function () {

        jq("#peopleFilter").advansedFilter({
            maxfilters: -1,
            anykey: false,
            store: false,
            hintDefaultDisable: true,
            sorters:
            [
                {
                    id: "by-name",
                    title: "Name",
                    dsc: false,
                    def: true
                }
            ],
            filters: 
            [
                {
                    type: "combobox",
                    id: "admin",
                    title: "Admin",
                    filtertitle: "Type label",
                    group: "User Type Title",
                    groupby: "user-type",
                    options: [
                        { value: 1, classname: "admin", title: "Admin", def: true },
                        { value: 0, classname: "user", title: "User or Guest" }
                    ],
                    hashmask: "type/{0}"
                },
                {
                    type: "combobox",
                    id: "user",
                    title: "User or Guest",
                    filtertitle: "Type label",
                    group: "User Type Title",
                    groupby: "user-type",
                    options: [
                        { value: 1, classname: "admin", title: "Admin" },
                        { value: 0, classname: "user", title: "User or Guest", def: true }
                    ],
                    hashmask: "type/{0}"
                },
                {
                    type: "group",
                    id: "user-group",
                    title: "Department label",
                    group: "Department Title",
                    hashmask: "group/{0}"
                }
            ]
        })
        .bind("setfilter", function (evt, $container, filter, filterparams, filters) {
            renderFilterContent(filters);
        })
        .bind("resetfilter", function (evt, $container, filter, filters) {
            renderFilterContent(filters);
        })
        .bind("resetallfilters", function () {
            jq("#peopleFilterContent").html("");
        });
    };

    function renderFilterContent(filters) {
        jq("#peopleFilterContent").html("");

        var asc = null;
        var text = null;
        var status = null;
        var group = null;

        filters.forEach(function (item) {
            switch (item.id) {
                case "sorter":
                    asc = item.params.sortOrder == "ascending";
                    break;
                case "text":
                    text = item.params.value.toLowerCase();
                    break;
                case "admin":
                    status = item.params.value;
                    break;
                case "user":
                    status = item.params.value;
                    break;
                case "user-group":
                    group = item.params.value;
                    break;
            }
        });

        var activeUsers = ASC.Resources.Master.ApiResponses_ActiveProfiles.response;

        var users = jq.grep(activeUsers, function (user) {

            if (group != null) {
                var groups = jq.map(user.groups, function (item) {
                    return item.id;
                });
                if (!groups.includes(group))
                    return false;
            }

            if (status != null) {
                if (user.isAdmin != status)
                    return false;
            }

            if (text != null) {
                if (user.displayName.toLowerCase().indexOf(text) == -1)
                    return false;
            }

            return true;
        });

        users.sort(function (a, b) {
            var res = ((a.displayName < b.displayName) ? -1 : ((a.displayName > b.displayName) ? 1 : 0));
            return asc ? res : res * (-1);
        });

        users.forEach(function (user) {
            jq("#peopleFilterContent").append(
                jq("<a/>").attr("href", user.profileUrl).append(
                    jq("<img/>").attr("src", user.avatarSmall).attr("title", user.displayName)
                ));
        });
    }

    function initElementsPage() {
        if (!jq("#select").length) return;
        
        jq("#select").tlCombobox({ "align": "left"});

        jq.dropdownToggle({
            switcherSelector: "#dropdownBtn",
            dropdownID: "dropdownPanel",
            addTop: 10,
            addLeft: 0,
            rightPos: false
        });

        jq("#dropdownPanel").on("click", ".dropdown-item", function () {
            jq("#dropdownBtn span").text(jq(this).text());
            jq("#dropdownPanel").hide();
        });

        jq("#popupBtn").on("click", function () {
            window.StudioBlockUIManager.blockUI("#popupDialog", 500);
        });

        jq("#popupDialog").on("click", ".close-popup", function () {
            window.LoadingBanner.hideLoaderBtn("#popupDialog");
            window.PopupKeyUpActionProvider.CloseDialog();
        });

        jq("#popupDialog").on("click", ".show-loading", function () {
            window.LoadingBanner.showLoaderBtn("#popupDialog");
        });

        jq("#popupDialog").on("click", ".show-success", function () {
            window.LoadingBanner.hideLoaderBtn("#popupDialog");
            window.LoadingBanner.showMesInfoBtn("#popupDialog", "success message", "success");
        });

        jq("#popupDialog").on("click", ".show-error", function () {
            window.LoadingBanner.hideLoaderBtn("#popupDialog");
            window.LoadingBanner.showMesInfoBtn("#popupDialog", "error message", "error");
        });
    }
    
    function initControlsPage() {
        if (!jq("#userSelector").length) return;
        
        var userSelector = jq("#userSelector");

        userSelector.useradvancedSelector({
            itemsChoose: [],
            itemsDisabledIds: [],
            canadd: false,
            showGroups: true,
            onechosen: true,
            withGuests: false
        }).on("showList", function (event, item) {
            jq(this).html(item.title + " (id: " + item.id + ")");
        });

        jq("#emailSelector").AdvancedEmailSelector("init", {
            isInPopup: false,
            items: [
                '"test.ru" <<EMAIL>>;',
                '"BROKEN" <<EMAIL>.>;',
                '<<EMAIL>>;',
                'NOT VALID',
                { name: "test.com", email: "<EMAIL>", isValid: true }
            ],
            maxCount: 20,
            onChangeCallback: function () {
                console.log("changed");
            }
        });

        initAdvansedFilter(); 
    }
    
    function initApiPage() {
        if (!jq("#addBtn").length) return;
        
        jq("#addBtn").on("click", function () {
            jq("#itemValue").val("");
            jq("#itemId").val("");
            window.StudioBlockUIManager.blockUI("#itemDialog", 230);
        });

        jq("#itemsTbl").on("click", ".editBtn", function () {
            var id = jq(this).attr("data-id");
            jq("#itemValue").val(jq("#itemValue_" + id).text().trim());
            jq("#itemId").val(id);
            window.StudioBlockUIManager.blockUI("#itemDialog", 230);
        });

        jq("#itemsTbl").on("click", ".deleteBtn", function () {
            var btn = jq(this);
            jq.ajax({
                url: "/api/2.0/sample/delete/" + btn.attr("data-id") + ".json",
                type: "DELETE"
            }).done(function () {
                btn.parents("tr:first").remove();
            });
        });

        window.LoadingBanner.displayLoading(true);
        jq.get("/api/2.0/sample/read.json", function (data) {
            if (data && data.response && data.response.length) {
                jq.each(data.response, function (index, item) {
                    jq("#itemTmpl").tmpl(item).appendTo("#itemsTbl tbody");
                });
            }
            
        }).always(function () {
            window.LoadingBanner.hideLoading();
        });

        jq("#itemDialog").on("click", ".close-popup", function () {
            window.PopupKeyUpActionProvider.CloseDialog();
        });

        jq("#itemDialog").on("click", ".save-popup", function () {
            var id = jq("#itemId").val();
            var value = jq("#itemValue").val();

            if (id) {
                jq.ajax({
                    type: "PUT",
                    url: "/api/2.0/sample/update.json",
                    data: { id: id, value: value }
                }).done(function () {
                    jq("#itemValue_" + id).text(value);
                    window.PopupKeyUpActionProvider.CloseDialog();
                });
            } else {
                jq.ajax({
                    type: "POST",
                    url: "/api/2.0/sample/create.json",
                    data: { value: value }
                }).done(function (data) {
                    jq("#itemTmpl").tmpl({ id: data.response.id, value: data.response.value }).appendTo("#itemsTbl tbody");
                    window.PopupKeyUpActionProvider.CloseDialog();
                });
            }
        });
    }

    var init = function(id) {
        if (isInit) {
            return;
        }

        isInit = true;
        userId = id;

        initElementsPage();

        initControlsPage();

        initApiPage();
    };

    return {
        init: init
    };
})(jQuery);

<|start_filename|>module/ASC.Mail/Services/ASC.Mail.Watchdog.Service/Program.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.ServiceProcess;

using ASC.Common.Logging;

namespace ASC.Mail.Watchdog.Service
{
    partial class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main(params string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

            if (Environment.UserInteractive || (args.Any()))
            {
                var service = new Watchdog();
                service.StartConsole();
            }
            else
            {
                ServiceBase.Run(new Watchdog());
            }
        }

        private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var log = LogManager.GetLogger("ASC.Mail.Watchdog");
            log.FatalFormat("Unhandled exception: {0}", e.ExceptionObject.ToString());
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Core/DIHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.Data;
using ASC.Common.DependencyInjection;

using Autofac;

namespace ASC.Web.Files.Core
{
    public static class DIHelper
    {
        internal static IContainer Builder { get; set; }
        private static bool isRegistered;
        private static readonly object Locker = new object();

        public static void Register()
        {
            if (isRegistered) return;

            lock (Locker)
            {
                if (isRegistered) return;

                var container = AutofacConfigLoader.Load("files");

                container.Register(c => DbManager.FromHttpContext("default"))
                         .AsSelf()
                         .As<IDbManager>()
                         .InstancePerRequest();

                Builder = container.Build();
                isRegistered = true;
            }
        }

        public static ILifetimeScope Resolve()
        {
            Register();

            var scope = Builder.BeginLifetimeScope(Autofac.Core.Lifetime.MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
            scope.Resolve<IDbManager>();

            return scope;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Resources/ProjectsJSResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Projects.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class ProjectsJSResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal ProjectsJSResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Projects.Resources.ProjectsJSResource", typeof(ProjectsJSResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new milestone.
        /// </summary>
        public static string AddMilestone {
            get {
                return ResourceManager.GetString("AddMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apply.
        /// </summary>
        public static string ApplyBtn {
            get {
                return ResourceManager.GetString("ApplyBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose Responsible.
        /// </summary>
        public static string ChooseResponsible {
            get {
                return ResourceManager.GetString("ChooseResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Contacts.
        /// </summary>
        public static string ContactsModule {
            get {
                return ResourceManager.GetString("ContactsModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new task.
        /// </summary>
        public static string CreateNewTask {
            get {
                return ResourceManager.GetString("CreateNewTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Company Name.
        /// </summary>
        public static string CRMCompanyName {
            get {
                return ResourceManager.GetString("CRMCompanyName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Find a company or a person by name....
        /// </summary>
        public static string CRMDescrForSelector {
            get {
                return ResourceManager.GetString("CRMDescrForSelector", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to First Name.
        /// </summary>
        public static string CRMFirstName {
            get {
                return ResourceManager.GetString("CRMFirstName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Last Name.
        /// </summary>
        public static string CRMLastName {
            get {
                return ResourceManager.GetString("CRMLastName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to day.
        /// </summary>
        public static string DelayDay {
            get {
                return ResourceManager.GetString("DelayDay", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to days.
        /// </summary>
        public static string DelayDays {
            get {
                return ResourceManager.GetString("DelayDays", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Discussion could not be found.
        /// </summary>
        public static string DiscussionNotFound {
            get {
                return ResourceManager.GetString("DiscussionNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Discussions.
        /// </summary>
        public static string DiscussionsModule {
            get {
                return ResourceManager.GetString("DiscussionsModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Documents.
        /// </summary>
        public static string DocumentsModule {
            get {
                return ResourceManager.GetString("DocumentsModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit Milestone.
        /// </summary>
        public static string EditMilestone {
            get {
                return ResourceManager.GetString("EditMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit task.
        /// </summary>
        public static string EditThisTask {
            get {
                return ResourceManager.GetString("EditThisTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each message must have a title.
        /// </summary>
        public static string EmptyMessageTitle {
            get {
                return ResourceManager.GetString("EmptyMessageTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each project must have a manager.
        /// </summary>
        public static string EmptyProjectManager {
            get {
                return ResourceManager.GetString("EmptyProjectManager", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each project must have a title.
        /// </summary>
        public static string EmptyProjectTitle {
            get {
                return ResourceManager.GetString("EmptyProjectTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to active tasks.
        /// </summary>
        public static string GanttActiveTasksPrjDesc {
            get {
                return ResourceManager.GetString("GanttActiveTasksPrjDesc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Collapse task list below milestones.
        /// </summary>
        public static string GanttCollapse {
            get {
                return ResourceManager.GetString("GanttCollapse", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to d.
        /// </summary>
        public static string GanttDayShort {
            get {
                return ResourceManager.GetString("GanttDayShort", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Expand task list below milestones.
        /// </summary>
        public static string GanttExpand {
            get {
                return ResourceManager.GetString("GanttExpand", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to add.
        /// </summary>
        public static string GanttLeftPanelAddDate {
            get {
                return ResourceManager.GetString("GanttLeftPanelAddDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Start Date.
        /// </summary>
        public static string GanttLeftPanelBeginDate {
            get {
                return ResourceManager.GetString("GanttLeftPanelBeginDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to closed.
        /// </summary>
        public static string GanttLeftPanelCloseStatus {
            get {
                return ResourceManager.GetString("GanttLeftPanelCloseStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to End Date.
        /// </summary>
        public static string GanttLeftPanelEndDate {
            get {
                return ResourceManager.GetString("GanttLeftPanelEndDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to high.
        /// </summary>
        public static string GanttLeftPanelHighPriority {
            get {
                return ResourceManager.GetString("GanttLeftPanelHighPriority", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to open.
        /// </summary>
        public static string GanttLeftPanelOpenStatus {
            get {
                return ResourceManager.GetString("GanttLeftPanelOpenStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Priority.
        /// </summary>
        public static string GanttLeftPanelPriority {
            get {
                return ResourceManager.GetString("GanttLeftPanelPriority", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Responsible.
        /// </summary>
        public static string GanttLeftPanelResponsibles {
            get {
                return ResourceManager.GetString("GanttLeftPanelResponsibles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Status.
        /// </summary>
        public static string GanttLeftPanelStatus {
            get {
                return ResourceManager.GetString("GanttLeftPanelStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to milestones.
        /// </summary>
        public static string GanttMilestonesPrjDesc {
            get {
                return ResourceManager.GetString("GanttMilestonesPrjDesc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Milestone.
        /// </summary>
        public static string GanttNewMilestone {
            get {
                return ResourceManager.GetString("GanttNewMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New task.
        /// </summary>
        public static string GanttNewTask {
            get {
                return ResourceManager.GetString("GanttNewTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no tasks available for link creation.
        /// </summary>
        public static string GanttNotAvailableTaskLink {
            get {
                return ResourceManager.GetString("GanttNotAvailableTaskLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The recent changes you made may be not saved if you leave this page right now..
        /// </summary>
        public static string GanttOnBeforeUnloadMessage {
            get {
                return ResourceManager.GetString("GanttOnBeforeUnloadMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} responsible users.
        /// </summary>
        public static string GanttResponsibles {
            get {
                return ResourceManager.GetString("GanttResponsibles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to subtasks.
        /// </summary>
        public static string GanttSubtasksTaskDesc {
            get {
                return ResourceManager.GetString("GanttSubtasksTaskDesc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to subtask.
        /// </summary>
        public static string GanttSubtaskTaskDesc {
            get {
                return ResourceManager.GetString("GanttSubtaskTaskDesc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Details.
        /// </summary>
        public static string GanttTaskDetails {
            get {
                return ResourceManager.GetString("GanttTaskDetails", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task is {0} days overdue.
        /// </summary>
        public static string GanttTaskOverdue {
            get {
                return ResourceManager.GetString("GanttTaskOverdue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to tasks.
        /// </summary>
        public static string GanttTasksMilDesc {
            get {
                return ResourceManager.GetString("GanttTasksMilDesc", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks without milestones.
        /// </summary>
        public static string GanttTaskWithoutMilestones {
            get {
                return ResourceManager.GetString("GanttTaskWithoutMilestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to week.
        /// </summary>
        public static string GanttWeekShort {
            get {
                return ResourceManager.GetString("GanttWeekShort", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to year.
        /// </summary>
        public static string GanttYear {
            get {
                return ResourceManager.GetString("GanttYear", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to selected.
        /// </summary>
        public static string GroupMenuSelectedItems {
            get {
                return ResourceManager.GetString("GroupMenuSelectedItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The date format is invalid.
        /// </summary>
        public static string IncorrectDate {
            get {
                return ResourceManager.GetString("IncorrectDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invalid time format.
        /// </summary>
        public static string InvalidTime {
            get {
                return ResourceManager.GetString("InvalidTime", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone Added.
        /// </summary>
        public static string MilestoneAdded {
            get {
                return ResourceManager.GetString("MilestoneAdded", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone Removed.
        /// </summary>
        public static string MilestoneRemoved {
            get {
                return ResourceManager.GetString("MilestoneRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestones.
        /// </summary>
        public static string MilestonesModule {
            get {
                return ResourceManager.GetString("MilestonesModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestones Removed.
        /// </summary>
        public static string MilestonesRemoved {
            get {
                return ResourceManager.GetString("MilestonesRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone Edited.
        /// </summary>
        public static string MilestoneUpdated {
            get {
                return ResourceManager.GetString("MilestoneUpdated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move.
        /// </summary>
        public static string Move {
            get {
                return ResourceManager.GetString("Move", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Next.
        /// </summary>
        public static string NextPage {
            get {
                return ResourceManager.GetString("NextPage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no active participants.
        /// </summary>
        public static string NoActiveParticipantsNote {
            get {
                return ResourceManager.GetString("NoActiveParticipantsNote", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No milestone.
        /// </summary>
        public static string NoMilestone {
            get {
                return ResourceManager.GetString("NoMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Overview.
        /// </summary>
        public static string OverviewModule {
            get {
                return ResourceManager.GetString("OverviewModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Previous.
        /// </summary>
        public static string PreviousPage {
            get {
                return ResourceManager.GetString("PreviousPage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects.
        /// </summary>
        public static string ProductName {
            get {
                return ResourceManager.GetString("ProductName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Project could not be found.
        /// </summary>
        public static string ProjectNotFound {
            get {
                return ResourceManager.GetString("ProjectNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects.
        /// </summary>
        public static string ProjectsModule {
            get {
                return ResourceManager.GetString("ProjectsModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Projects Removed.
        /// </summary>
        public static string ProjectsRemoved {
            get {
                return ResourceManager.GetString("ProjectsRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to end-end.
        /// </summary>
        public static string RelatedLinkTypeEE {
            get {
                return ResourceManager.GetString("RelatedLinkTypeEE", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to end-start.
        /// </summary>
        public static string RelatedLinkTypeES {
            get {
                return ResourceManager.GetString("RelatedLinkTypeES", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to start-end.
        /// </summary>
        public static string RelatedLinkTypeSE {
            get {
                return ResourceManager.GetString("RelatedLinkTypeSE", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to start-start.
        /// </summary>
        public static string RelatedLinkTypeSS {
            get {
                return ResourceManager.GetString("RelatedLinkTypeSS", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Report building.
        /// </summary>
        public static string ReportBuilding {
            get {
                return ResourceManager.GetString("ReportBuilding", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can always see, download, edit, or delete all the generated reports in {0}Documents/My documents{1}.
        /// </summary>
        public static string ReportBuildingInfo {
            get {
                return ResourceManager.GetString("ReportBuildingInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Report building ({0}% complete).
        /// </summary>
        public static string ReportBuildingProgress {
            get {
                return ResourceManager.GetString("ReportBuildingProgress", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Template could not be found.
        /// </summary>
        public static string ReportTmplNotFound {
            get {
                return ResourceManager.GetString("ReportTmplNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string StatusClosedMilestone {
            get {
                return ResourceManager.GetString("StatusClosedMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string StatusClosedProject {
            get {
                return ResourceManager.GetString("StatusClosedProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string StatusOpenMilestone {
            get {
                return ResourceManager.GetString("StatusOpenMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string StatusOpenProject {
            get {
                return ResourceManager.GetString("StatusOpenProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Paused.
        /// </summary>
        public static string StatusSuspendProject {
            get {
                return ResourceManager.GetString("StatusSuspendProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Successfully added.
        /// </summary>
        public static string SuccessfullyAdded {
            get {
                return ResourceManager.GetString("SuccessfullyAdded", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create new tag.
        /// </summary>
        public static string TagsSelectorAddText {
            get {
                return ResourceManager.GetString("TagsSelectorAddText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No tags in this list.
        /// </summary>
        public static string TagsSelectorEmptyList {
            get {
                return ResourceManager.GetString("TagsSelectorEmptyList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Each tag must have a title.
        /// </summary>
        public static string TagsSelectorEmptyTitleError {
            get {
                return ResourceManager.GetString("TagsSelectorEmptyTitleError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No tags in this group.
        /// </summary>
        public static string TagsSelectorNoItems {
            get {
                return ResourceManager.GetString("TagsSelectorNoItems", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No such tag.
        /// </summary>
        public static string TagsSelectorNoResult {
            get {
                return ResourceManager.GetString("TagsSelectorNoResult", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string TagsSelectorTitle {
            get {
                return ResourceManager.GetString("TagsSelectorTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task Added.
        /// </summary>
        public static string TaskAdded {
            get {
                return ResourceManager.GetString("TaskAdded", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task could not be found.
        /// </summary>
        public static string TaskNotFound {
            get {
                return ResourceManager.GetString("TaskNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task Removed.
        /// </summary>
        public static string TaskRemoved {
            get {
                return ResourceManager.GetString("TaskRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks.
        /// </summary>
        public static string TasksModule {
            get {
                return ResourceManager.GetString("TasksModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks Removed.
        /// </summary>
        public static string TasksRemoved {
            get {
                return ResourceManager.GetString("TasksRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks Updated.
        /// </summary>
        public static string TasksUpdated {
            get {
                return ResourceManager.GetString("TasksUpdated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Task Updated.
        /// </summary>
        public static string TaskUpdated {
            get {
                return ResourceManager.GetString("TaskUpdated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Team.
        /// </summary>
        public static string TeamModule {
            get {
                return ResourceManager.GetString("TeamModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Template saved.
        /// </summary>
        public static string TemplateSaved {
            get {
                return ResourceManager.GetString("TemplateSaved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Time Removed.
        /// </summary>
        public static string TimeRemoved {
            get {
                return ResourceManager.GetString("TimeRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No Data.
        /// </summary>
        public static string TimerNoData {
            get {
                return ResourceManager.GetString("TimerNoData", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Times Removed.
        /// </summary>
        public static string TimesRemoved {
            get {
                return ResourceManager.GetString("TimesRemoved", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Time Tracking.
        /// </summary>
        public static string TimeTrackingModule {
            get {
                return ResourceManager.GetString("TimeTrackingModule", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Time Updated.
        /// </summary>
        public static string TimeUpdated {
            get {
                return ResourceManager.GetString("TimeUpdated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To the task list.
        /// </summary>
        public static string ToTaskList {
            get {
                return ResourceManager.GetString("ToTaskList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to View all open tasks.
        /// </summary>
        public static string ViewAllOpenTasks {
            get {
                return ResourceManager.GetString("ViewAllOpenTasks", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Core/Entries/OrderBy.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Diagnostics;
using System.Runtime.Serialization;

namespace ASC.Files.Core
{
    [DataContract(Name = "sorted_by_type", Namespace = "")]
    public enum SortedByType
    {
        [EnumMember] DateAndTime,

        [EnumMember] AZ,

        [EnumMember] Size,

        [EnumMember] Author,

        [EnumMember] Type,

        [EnumMember] New,

        [EnumMember] DateAndTimeCreation

    }

    [DataContract(Name = "orderBy", IsReference = true, Namespace = "")]
    [DebuggerDisplay("{SortedBy} {IsAsc}")]
    public class OrderBy
    {
        [DataMember(Name = "is_asc")]
        public bool IsAsc { get; set; }

        [DataMember(Name = "property")]
        public SortedByType SortedBy { get; set; }

        public OrderBy(SortedByType sortedByType, bool isAsc)
        {
            SortedBy = sortedByType;
            IsAsc = isAsc;
        }
    }
}

<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Extensions/StringExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Server.Extensions
{
    public static class StringExtensions
    {
        public static string Prefix(this string str, string prefix)
        {
            return string.IsNullOrEmpty(prefix) ? str : string.Format("{0}.{1}", prefix, str);
        }

        public static string Alias(this string str, string alias)
        {
            return string.IsNullOrEmpty(alias) ? str : string.Format("{0} {1}", str, alias);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Controls/FileUploader/HttpModule/UploadProgressHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using AjaxPro;

using ASC.Common.Web;

namespace ASC.Web.Studio.Controls.FileUploader.HttpModule
{
    public abstract class FileUploadHandler
    {
        public class FileUploadResult
        {
            public bool Success { get; set; }
            public string FileName { get; set; }
            public string FileURL { get; set; }
            public object Data { get; set; }
            public string Message { get; set; }
        }

        public virtual string GetFileName(string path)
        {
            if (string.IsNullOrEmpty(path)) return string.Empty;

            var ind = path.LastIndexOf('\\');
            return ind != -1 ? path.Substring(ind + 1) : path;
        }

        public abstract FileUploadResult ProcessUpload(HttpContext context);
    }

    public class UploadProgressHandler : AbstractHttpAsyncHandler
    {
        public override void OnProcessRequest(HttpContext context)
        {
            if (!string.IsNullOrEmpty(context.Request["submit"]))
            {
                FileUploadHandler.FileUploadResult result;
                try
                {
                    var uploadHandler = (FileUploadHandler)Activator.CreateInstance(Type.GetType(context.Request["submit"], true));
                    result = uploadHandler.ProcessUpload(context);
                }
                catch (Exception ex)
                {
                    result = new FileUploadHandler.FileUploadResult
                    {
                        Success = false,
                        Message = ex.Message.HtmlEncode(),
                    };
                }

                //NOTE: Don't set content type. ie cant parse it
                context.Response.StatusCode = 200;
                context.Response.Write(JavaScriptSerializer.Serialize(result));
            }
            else
            {
                context.Response.StatusCode = 400;
                context.Response.Write("Not found submit parameter.");
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/HttpHandlers/OrganisationLogoHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.CRM.Core;
using ASC.Web.Core.Files;
using ASC.Web.Core.Utility;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.Controls.FileUploader;
using ASC.Web.Studio.Core;


namespace ASC.Web.CRM.Classes
{
    public class OrganisationLogoHandler : IFileUploadHandler
    {
        public FileUploadResult ProcessUpload(HttpContext context)
        {
            if (!CRMSecurity.IsAdmin)
                throw CRMSecurity.CreateSecurityException();

            var fileUploadResult = new FileUploadResult();

            if (!FileToUpload.HasFilesToUpload(context)) return fileUploadResult;

            var file = new FileToUpload(context);

            if (String.IsNullOrEmpty(file.FileName) || file.ContentLength == 0)
                throw new InvalidOperationException(CRMErrorsResource.InvalidFile);

            if (0 < SetupInfo.MaxImageUploadSize && SetupInfo.MaxImageUploadSize < file.ContentLength)
            {
                fileUploadResult.Success = false;
                fileUploadResult.Message = FileSizeComment.GetFileImageSizeNote(CRMCommonResource.ErrorMessage_UploadFileSize, false).HtmlEncode();
                return fileUploadResult;
            }

            if (FileUtility.GetFileTypeByFileName(file.FileName) != FileType.Image)
            {
                fileUploadResult.Success = false;
                fileUploadResult.Message = CRMJSResource.ErrorMessage_NotImageSupportFormat.HtmlEncode();
                return fileUploadResult;
            }

            try
            {
                var imageData = Global.ToByteArray(file.InputStream);
                var imageFormat = ContactPhotoManager.CheckImgFormat(imageData);
                var photoUri = OrganisationLogoManager.UploadLogo(imageData, imageFormat);

                fileUploadResult.Success = true;
                fileUploadResult.Data = photoUri;
                return fileUploadResult;
            }
            catch (Exception exception)
            {
                fileUploadResult.Success = false;
                fileUploadResult.Message = exception.Message.HtmlEncode();
                return fileUploadResult;
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_ParameterCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;
    using System.Collections;
    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// This class represents SIP value parameters collection.
    /// </summary>
    public class SIP_ParameterCollection : IEnumerable
    {
        #region Members

        private readonly List<SIP_Parameter> m_pCollection;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public SIP_ParameterCollection()
        {
            m_pCollection = new List<SIP_Parameter>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets parameters count in the collection.
        /// </summary>
        public int Count
        {
            get { return m_pCollection.Count; }
        }

        /// <summary>
        /// Gets specified parameter from collection. Returns null if parameter with specified name doesn't exist.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        /// <returns>Returns parameter with specified name or null if not found.</returns>
        public SIP_Parameter this[string name]
        {
            get
            {
                foreach (SIP_Parameter parameter in m_pCollection)
                {
                    if (parameter.Name.ToLower() == name.ToLower())
                    {
                        return parameter;
                    }
                }

                return null;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Adds new parameter to the collection.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        /// <param name="value">Parameter value.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>name</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when 'name' is '' or parameter with specified name 
        /// already exists in the collection.</exception>
        public void Add(string name, string value)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (Contains(name))
            {
                throw new ArgumentException(
                    "Prameter '' with specified name already exists in the collection !");
            }

            m_pCollection.Add(new SIP_Parameter(name, value));
        }

        /// <summary>
        /// Adds or updates specified parameter value.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        /// <param name="value">Parameter value.</param>
        public void Set(string name, string value)
        {
            if (Contains(name))
            {
                this[name].Value = value;
            }
            else
            {
                Add(name, value);
            }
        }

        /// <summary>
        /// Removes all parameters from the collection.
        /// </summary>
        public void Clear()
        {
            m_pCollection.Clear();
        }

        /// <summary>
        /// Removes specified parameter from the collection.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        public void Remove(string name)
        {
            SIP_Parameter parameter = this[name];
            if (parameter != null)
            {
                m_pCollection.Remove(parameter);
            }
        }

        /// <summary>
        /// Checks if the collection contains parameter with the specified name.
        /// </summary>
        /// <param name="name">Parameter name.</param>
        /// <returns>Returns true if collection contains specified parameter.</returns>
        public bool Contains(string name)
        {
            SIP_Parameter parameter = this[name];
            if (parameter != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Gets enumerator.
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            return m_pCollection.GetEnumerator();
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/PublicResources/UserControlsCommonResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Studio.PublicResources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class UserControlsCommonResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal UserControlsCommonResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Studio.PublicResources.UserControlsCommonResource", typeof(UserControlsCommonResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The active users are the portal members with the exception of guests and users with the &quot;disabled&quot; status.
        /// </summary>
        public static string ActiveUserDescr {
            get {
                return ResourceManager.GetString("ActiveUserDescr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add poll choice.
        /// </summary>
        public static string AddAnswerVariantButton {
            get {
                return ResourceManager.GetString("AddAnswerVariantButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add {!Users}.
        /// </summary>
        public static string AddEmployees {
            get {
                return ResourceManager.GetString("AddEmployees", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add a new social profile.
        /// </summary>
        public static string AddNewSocialProfile {
            get {
                return ResourceManager.GetString("AddNewSocialProfile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add message.
        /// </summary>
        public static string AddShareMessage {
            get {
                return ResourceManager.GetString("AddShareMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Admin.
        /// </summary>
        public static string Admin {
            get {
                return ResourceManager.GetString("Admin", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Total number of votes.
        /// </summary>
        public static string AllVoting {
            get {
                return ResourceManager.GetString("AllVoting", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Poll Choices.
        /// </summary>
        public static string AnswerVariants {
            get {
                return ResourceManager.GetString("AnswerVariants", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attach Files.
        /// </summary>
        public static string AttachFiles {
            get {
                return ResourceManager.GetString("AttachFiles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attach file from Documents.
        /// </summary>
        public static string AttachFromDocuments {
            get {
                return ResourceManager.GetString("AttachFromDocuments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Attach a file from project documents.
        /// </summary>
        public static string AttachOfProjectDocuments {
            get {
                return ResourceManager.GetString("AttachOfProjectDocuments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Shorten portal invitation links and links for shared documents using Bitly.
        /// </summary>
        public static string BannerBitly {
            get {
                return ResourceManager.GetString("BannerBitly", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Log in to the portal using your social accounts and search for contacts.
        /// </summary>
        public static string BannerSocial {
            get {
                return ResourceManager.GetString("BannerSocial", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connect your favorite cloud storage services and store all your files in one place.
        /// </summary>
        public static string BannerStorage {
            get {
                return ResourceManager.GetString("BannerStorage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Call your customers directly from the CRM thanks to {0}ONLYOFFICE Twilio{1} integration.
        /// </summary>
        public static string BannerTwilio2 {
            get {
                return ResourceManager.GetString("BannerTwilio2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to ....
        /// </summary>
        public static string BtnHiddenFilter {
            get {
                return ResourceManager.GetString("BtnHiddenFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create Presentation.
        /// </summary>
        public static string ButtonCreatePresentation {
            get {
                return ResourceManager.GetString("ButtonCreatePresentation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create Spreadsheet.
        /// </summary>
        public static string ButtonCreateSpreadsheet {
            get {
                return ResourceManager.GetString("ButtonCreateSpreadsheet", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create Document.
        /// </summary>
        public static string ButtonCreateText {
            get {
                return ResourceManager.GetString("ButtonCreateText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Learn more....
        /// </summary>
        public static string ButtonLearnMore {
            get {
                return ResourceManager.GetString("ButtonLearnMore", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cancel.
        /// </summary>
        public static string CancelButton {
            get {
                return ResourceManager.GetString("CancelButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can change the domain name later using the portal &apos;Settings&apos; section..
        /// </summary>
        public static string ChangeAliasHelper {
            get {
                return ResourceManager.GetString("ChangeAliasHelper", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Company Size.
        /// </summary>
        public static string CompanySizeTitle {
            get {
                return ResourceManager.GetString("CompanySizeTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Company.
        /// </summary>
        public static string CompanyTitle {
            get {
                return ResourceManager.GetString("CompanyTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save the file copy in the original format as well.
        /// </summary>
        public static string ConfirmStoreOriginalUploadCbxLabelTextAC {
            get {
                return ResourceManager.GetString("ConfirmStoreOriginalUploadCbxLabelTextAC", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All the documents you upload will be converted to the Office Open XML format for faster editing..
        /// </summary>
        public static string ConfirmStoreOriginalUploadTitleAC {
            get {
                return ResourceManager.GetString("ConfirmStoreOriginalUploadTitleAC", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Contact support.
        /// </summary>
        public static string ContactSupportBtn {
            get {
                return ResourceManager.GetString("ContactSupportBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete File.
        /// </summary>
        public static string DeleteFile {
            get {
                return ResourceManager.GetString("DeleteFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Download File.
        /// </summary>
        public static string DownloadFile {
            get {
                return ResourceManager.GetString("DownloadFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Edit File.
        /// </summary>
        public static string EditFile {
            get {
                return ResourceManager.GetString("EditFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Create{1} files right on your portal or {2}upload{3} them here to be able to {4}open{5} and {6}edit{7} them using the ONLYOFFICE™ portal editor..
        /// </summary>
        public static string EmptyListDocumentsDescr {
            get {
                return ResourceManager.GetString("EmptyListDocumentsDescr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {2}Upload{3} files right on your portal..
        /// </summary>
        public static string EmptyListDocumentsDescrPoor {
            get {
                return ResourceManager.GetString("EmptyListDocumentsDescrPoor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The list of documents is empty.
        /// </summary>
        public static string EmptyListDocumentsHead {
            get {
                return ResourceManager.GetString("EmptyListDocumentsHead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter your poll question.
        /// </summary>
        public static string EmptyQuestion {
            get {
                return ResourceManager.GetString("EmptyQuestion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select poll choice.
        /// </summary>
        public static string EmptySelect {
            get {
                return ResourceManager.GetString("EmptySelect", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title cannot contain any of the following characters:.
        /// </summary>
        public static string ErrorMassage_SpecCharacter {
            get {
                return ResourceManager.GetString("ErrorMassage_SpecCharacter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Everyone.
        /// </summary>
        public static string Everyone {
            get {
                return ResourceManager.GetString("Everyone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add post.
        /// </summary>
        public static string FeedBlogsModuleLink {
            get {
                return ResourceManager.GetString("FeedBlogsModuleLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add bookmark.
        /// </summary>
        public static string FeedBookmarkModuleLink {
            get {
                return ResourceManager.GetString("FeedBookmarkModuleLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to Documents.
        /// </summary>
        public static string FeedButtonGotoDocuments {
            get {
                return ResourceManager.GetString("FeedButtonGotoDocuments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Documents.
        /// </summary>
        public static string FeedCorporateFiles {
            get {
                return ResourceManager.GetString("FeedCorporateFiles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create a new company.
        /// </summary>
        public static string FeedCreateFirstCompany {
            get {
                return ResourceManager.GetString("FeedCreateFirstCompany", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create a new person.
        /// </summary>
        public static string FeedCreateFirstPerson {
            get {
                return ResourceManager.GetString("FeedCreateFirstPerson", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Create a new project.
        /// </summary>
        public static string FeedCreateFirstProject {
            get {
                return ResourceManager.GetString("FeedCreateFirstProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Anything added to the Community module will be shown here. Users can share interesting information, thoughts and experiences with others, express their opinions, get feedback from the others&apos; comments..
        /// </summary>
        public static string FeedEmptyCommunityDescription {
            get {
                return ResourceManager.GetString("FeedEmptyCommunityDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No events have been added yet.
        /// </summary>
        public static string FeedEmptyCommunityHeader {
            get {
                return ResourceManager.GetString("FeedEmptyCommunityHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The events for the CRM module available to you will be shown here. New companies and persons added or the existing edited, new cases, opportunities and tasks created - everything concerning CRM will go to this tab..
        /// </summary>
        public static string FeedEmptyContactListDescription {
            get {
                return ResourceManager.GetString("FeedEmptyContactListDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No CRM events have added yet.
        /// </summary>
        public static string FeedEmptyContactListHeader {
            get {
                return ResourceManager.GetString("FeedEmptyContactListHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The changes in the Projects module available to you will be shown here. The projects which you are a member or a follower of, your new tasks or changes to the existing ones will help you not to miss anything..
        /// </summary>
        public static string FeedEmptyListProjDescribe {
            get {
                return ResourceManager.GetString("FeedEmptyListProjDescribe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No projects have been added yet.
        /// </summary>
        public static string FeedEmptyListProjHeader {
            get {
                return ResourceManager.GetString("FeedEmptyListProjHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The changes to the portal documents available to you will be shown here. New documents shared with you, changes to the existing documents that you have access to, documents common for all portal users are all displayed here..
        /// </summary>
        public static string FeedEmptyScreenDescrCorporate {
            get {
                return ResourceManager.GetString("FeedEmptyScreenDescrCorporate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add event.
        /// </summary>
        public static string FeedEventsModuleLink {
            get {
                return ResourceManager.GetString("FeedEventsModuleLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Feed.
        /// </summary>
        public static string FeedTitle {
            get {
                return ResourceManager.GetString("FeedTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Allow multiple choices for this poll question.
        /// </summary>
        public static string FewAnswerVariant {
            get {
                return ResourceManager.GetString("FewAnswerVariant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no news matching this filter.
        /// </summary>
        public static string FilterNoNews {
            get {
                return ResourceManager.GetString("FilterNoNews", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No news matching your filter can be displayed in this section..
        /// </summary>
        public static string FilterNoNewsDescription {
            get {
                return ResourceManager.GetString("FilterNoNewsDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There are no calls matching this filter.
        /// </summary>
        public static string FilterNoVoipCalls {
            get {
                return ResourceManager.GetString("FilterNoVoipCalls", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No calls matching your filter can be displayed in this section..
        /// </summary>
        public static string FilterNoVoipCallsDescription {
            get {
                return ResourceManager.GetString("FilterNoVoipCallsDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Link for portal users.
        /// </summary>
        public static string GetPortalLink {
            get {
                return ResourceManager.GetString("GetPortalLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you want to pay for your ONLYOFFICE portal, click the Buy Now button..
        /// </summary>
        public static string HostedBuyDescr {
            get {
                return ResourceManager.GetString("HostedBuyDescr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please pay for your ONLYOFFICE and get:.
        /// </summary>
        public static string HostedPayAndGet {
            get {
                return ResourceManager.GetString("HostedPayAndGet", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Filter:.
        /// </summary>
        public static string LblFilter {
            get {
                return ResourceManager.GetString("LblFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to enter your query.
        /// </summary>
        public static string LblFilterPlaceholder {
            get {
                return ResourceManager.GetString("LblFilterPlaceholder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to From.
        /// </summary>
        public static string LblFrom {
            get {
                return ResourceManager.GetString("LblFrom", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select.
        /// </summary>
        public static string LblSelect {
            get {
                return ResourceManager.GetString("LblSelect", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sort by.
        /// </summary>
        public static string LblSort {
            get {
                return ResourceManager.GetString("LblSort", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To.
        /// </summary>
        public static string LblTo {
            get {
                return ResourceManager.GetString("LblTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Renew subscription to get:.
        /// </summary>
        public static string LicenseActivateAndGetV11 {
            get {
                return ResourceManager.GetString("LicenseActivateAndGetV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Activate.
        /// </summary>
        public static string LicenseActivateButtonV11 {
            get {
                return ResourceManager.GetString("LicenseActivateButtonV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to If you have already purchased the renewal, upload the license file and press Activate..
        /// </summary>
        public static string LicenseActivateDescrV11 {
            get {
                return ResourceManager.GetString("LicenseActivateDescrV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to By checking this box you accept the terms of the {0}License Agreements{1}.
        /// </summary>
        public static string LicenseAgreements {
            get {
                return ResourceManager.GetString("LicenseAgreements", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to This software is licensed under {0}Apache License, Version 2.0{1}.
        /// </summary>
        public static string LicensedUnderApache {
            get {
                return ResourceManager.GetString("LicensedUnderApache", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to License expired or user quota does not match the license.
        /// </summary>
        public static string LicenseException {
            get {
                return ResourceManager.GetString("LicenseException", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Purchase the renewal now. Note that you will be redirected to Avangate..
        /// </summary>
        public static string LicenseKeyBuyDescrV11 {
            get {
                return ResourceManager.GetString("LicenseKeyBuyDescrV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Buy license.
        /// </summary>
        public static string LicenseKeyBuyLabelV11 {
            get {
                return ResourceManager.GetString("LicenseKeyBuyLabelV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to License Activation File.
        /// </summary>
        public static string LicenseKeyHeader {
            get {
                return ResourceManager.GetString("LicenseKeyHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upload License.
        /// </summary>
        public static string LicenseKeyLabelV11 {
            get {
                return ResourceManager.GetString("LicenseKeyLabelV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to License key is not correct.
        /// </summary>
        public static string LicenseKeyNotCorrect {
            get {
                return ResourceManager.GetString("LicenseKeyNotCorrect", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You must enter a license key.
        /// </summary>
        public static string LicenseKeyNotFound {
            get {
                return ResourceManager.GetString("LicenseKeyNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to ONLYOFFICE Modules and Tools:.
        /// </summary>
        public static string LicenseModules {
            get {
                return ResourceManager.GetString("LicenseModules", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Online Documents Editors{1}{0}Document Management{1}{0}Mail{1}{0}Projects{1}{0}CRM{1}{0}Calendar{1}{0}Community{1}.
        /// </summary>
        public static string LicenseModulesList {
            get {
                return ResourceManager.GetString("LicenseModulesList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to mobile web editors,.
        /// </summary>
        public static string LicenseModulesMobileV11 {
            get {
                return ResourceManager.GetString("LicenseModulesMobileV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Private Room for encrypted collaboration,.
        /// </summary>
        public static string LicenseModulesPrivateV11 {
            get {
                return ResourceManager.GetString("LicenseModulesPrivateV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to ONLYOFFICE editors with pro features,.
        /// </summary>
        public static string LicenseModulesProV11 {
            get {
                return ResourceManager.GetString("LicenseModulesProV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 1 year of professional tech support service..
        /// </summary>
        public static string LicenseModulesSupportV11 {
            get {
                return ResourceManager.GetString("LicenseModulesSupportV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to regular functionality and security updates during 1 year,.
        /// </summary>
        public static string LicenseModulesUpdatesV11 {
            get {
                return ResourceManager.GetString("LicenseModulesUpdatesV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} - {1} active users.
        /// </summary>
        public static string LicenseRequestQuota {
            get {
                return ResourceManager.GetString("LicenseRequestQuota", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}+ active users.
        /// </summary>
        public static string LicenseRequestQuotaMore {
            get {
                return ResourceManager.GetString("LicenseRequestQuotaMore", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sign Out.
        /// </summary>
        public static string LogoutButton {
            get {
                return ResourceManager.GetString("LogoutButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Actual Size.
        /// </summary>
        public static string MediaViewerActualSize {
            get {
                return ResourceManager.GetString("MediaViewerActualSize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Close.
        /// </summary>
        public static string MediaViewerClose {
            get {
                return ResourceManager.GetString("MediaViewerClose", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Fullscreen.
        /// </summary>
        public static string MediaViewerFullscreen {
            get {
                return ResourceManager.GetString("MediaViewerFullscreen", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mute.
        /// </summary>
        public static string MediaViewerMute {
            get {
                return ResourceManager.GetString("MediaViewerMute", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Next.
        /// </summary>
        public static string MediaViewerNext {
            get {
                return ResourceManager.GetString("MediaViewerNext", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Play.
        /// </summary>
        public static string MediaViewerPlay {
            get {
                return ResourceManager.GetString("MediaViewerPlay", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Previous.
        /// </summary>
        public static string MediaViewerPrevious {
            get {
                return ResourceManager.GetString("MediaViewerPrevious", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Rotate Left.
        /// </summary>
        public static string MediaViewerRotateLeft {
            get {
                return ResourceManager.GetString("MediaViewerRotateLeft", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Rotate Right.
        /// </summary>
        public static string MediaViewerRotateRight {
            get {
                return ResourceManager.GetString("MediaViewerRotateRight", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Zoom In.
        /// </summary>
        public static string MediaViewerZoomIn {
            get {
                return ResourceManager.GetString("MediaViewerZoomIn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Zoom Out.
        /// </summary>
        public static string MediaViewerZoomOut {
            get {
                return ResourceManager.GetString("MediaViewerZoomOut", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter number.
        /// </summary>
        public static string MobileChangeButton {
            get {
                return ResourceManager.GetString("MobileChangeButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to An SMS with the portal access code has been sent to your {0}{1}{2} mobile phone number.{5}Please enter the code and click the &quot;{3}&quot; button. If no message is received for more than 3 minutes, click the &quot;{4}&quot; button..
        /// </summary>
        public static string MobileCodeDescription {
            get {
                return ResourceManager.GetString("MobileCodeDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your current mobile phone number: {0}.
        /// </summary>
        public static string MobileCurrentNumber {
            get {
                return ResourceManager.GetString("MobileCurrentNumber", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter mobile phone number.
        /// </summary>
        public static string MobilePhoneCaption {
            get {
                return ResourceManager.GetString("MobilePhoneCaption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The two-factor authentication is enabled to provide additional portal security. Enter your mobile phone number to continue work on the portal. Mobile phone number must be entered using an international format with country code..
        /// </summary>
        public static string MobilePhoneDescription {
            get {
                return ResourceManager.GetString("MobilePhoneDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to More.
        /// </summary>
        public static string More {
            get {
                return ResourceManager.GetString("More", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Document.
        /// </summary>
        public static string NewDocument {
            get {
                return ResourceManager.GetString("NewDocument", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New file.
        /// </summary>
        public static string NewFile {
            get {
                return ResourceManager.GetString("NewFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There is nothing to be displayed here.
        /// </summary>
        public static string NewsNotFound {
            get {
                return ResourceManager.GetString("NewsNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All the portal activities are displayed here in this section. Right now there are no events on the portal to be displayed. Start using your portal, fill it with the content and all the news will be shown at this page..
        /// </summary>
        public static string NewsNotFoundDescription {
            get {
                return ResourceManager.GetString("NewsNotFoundDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Next.
        /// </summary>
        public static string NextPage {
            get {
                return ResourceManager.GetString("NextPage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No comments.
        /// </summary>
        public static string NoComments {
            get {
                return ResourceManager.GetString("NoComments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Note: this action cannot be undone..
        /// </summary>
        public static string NotBeUndone {
            get {
                return ResourceManager.GetString("NotBeUndone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To play the media you will need to update your browser to a recent version..
        /// </summary>
        public static string NotSupportedBrowser {
            get {
                return ResourceManager.GetString("NotSupportedBrowser", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Allow only one choice for this poll question.
        /// </summary>
        public static string OneAnswerVariant {
            get {
                return ResourceManager.GetString("OneAnswerVariant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The file could not be added as you have exceeded your storage space quota. Please delete the outdated files or contact our support team for more information..
        /// </summary>
        public static string PersonalStorageLimitExceededBody {
            get {
                return ResourceManager.GetString("PersonalStorageLimitExceededBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Quota exceeded.
        /// </summary>
        public static string PersonalStorageLimitExceededHeader {
            get {
                return ResourceManager.GetString("PersonalStorageLimitExceededHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Storage space quota exceeded.
        /// </summary>
        public static string PersonalStorageLimitExceededSubHeader {
            get {
                return ResourceManager.GetString("PersonalStorageLimitExceededSubHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Poll Question.
        /// </summary>
        public static string PollQuestion {
            get {
                return ResourceManager.GetString("PollQuestion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Poll Type.
        /// </summary>
        public static string PollType {
            get {
                return ResourceManager.GetString("PollType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Previous.
        /// </summary>
        public static string PreviousPage {
            get {
                return ResourceManager.GetString("PreviousPage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to delete this file?.
        /// </summary>
        public static string QuestionDeleteFile {
            get {
                return ResourceManager.GetString("QuestionDeleteFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Delete.
        /// </summary>
        public static string QuickLinksDeleteLink {
            get {
                return ResourceManager.GetString("QuickLinksDeleteLink", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Read about non-profit usage.
        /// </summary>
        public static string ReadAboutNonProfitUsage {
            get {
                return ResourceManager.GetString("ReadAboutNonProfitUsage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Remove from this list.
        /// </summary>
        public static string RemoveFromList {
            get {
                return ResourceManager.GetString("RemoveFromList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Remove message.
        /// </summary>
        public static string RemoveShareMessage {
            get {
                return ResourceManager.GetString("RemoveShareMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reset filter.
        /// </summary>
        public static string ResetFilter {
            get {
                return ResourceManager.GetString("ResetFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Back to plans.
        /// </summary>
        public static string SaasTariffBackButton {
            get {
                return ResourceManager.GetString("SaasTariffBackButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Benefits.
        /// </summary>
        public static string SaasTariffBenefits {
            get {
                return ResourceManager.GetString("SaasTariffBenefits", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Business.
        /// </summary>
        public static string SaasTariffBusiness {
            get {
                return ResourceManager.GetString("SaasTariffBusiness", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} user/month.
        /// </summary>
        public static string SaasTariffBusinessCost {
            get {
                return ResourceManager.GetString("SaasTariffBusinessCost", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Up to 1000 users per portal.
        /// </summary>
        public static string SaasTariffBusinessFeature1 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature1", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 100 Gb per teammate.
        /// </summary>
        public static string SaasTariffBusinessFeature2 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unlimited number of simultaneous connections.
        /// </summary>
        public static string SaasTariffBusinessFeature3 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature3", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Branding &amp; customization.
        /// </summary>
        public static string SaasTariffBusinessFeature4 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature4", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to LDAP/SSO.
        /// </summary>
        public static string SaasTariffBusinessFeature5 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature5", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Data backups &amp; recovery.
        /// </summary>
        public static string SaasTariffBusinessFeature6 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature6", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tracking users logins &amp; actions.
        /// </summary>
        public static string SaasTariffBusinessFeature7 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature7", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Pro integrations: Twilio, DocuSign.
        /// </summary>
        public static string SaasTariffBusinessFeature8 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature8", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail Server.
        /// </summary>
        public static string SaasTariffBusinessFeature9 {
            get {
                return ResourceManager.GetString("SaasTariffBusinessFeature9", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Renew subscription to ONLYOFFICE Business cloud.
        /// </summary>
        public static string SaasTariffBuyBusinessSubscriptionHeaderBusiness {
            get {
                return ResourceManager.GetString("SaasTariffBuyBusinessSubscriptionHeaderBusiness", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Re-activate business plan?.
        /// </summary>
        public static string SaasTariffBuyBusinessSubscriptionHeaderStartup {
            get {
                return ResourceManager.GetString("SaasTariffBuyBusinessSubscriptionHeaderStartup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Buy ONLYOFFICE Business cloud subscription.
        /// </summary>
        public static string SaasTariffBuyBusinessSubscriptionHeaderTrial {
            get {
                return ResourceManager.GetString("SaasTariffBuyBusinessSubscriptionHeaderTrial", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to From {0} per user/month.
        /// </summary>
        public static string SaasTariffBuyBusinessSubscriptionSubHeader {
            get {
                return ResourceManager.GetString("SaasTariffBuyBusinessSubscriptionSubHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Change plan.
        /// </summary>
        public static string SaasTariffChangePlanBtn {
            get {
                return ResourceManager.GetString("SaasTariffChangePlanBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose the plan that suits your team.
        /// </summary>
        public static string SaasTariffChoosePlan {
            get {
                return ResourceManager.GetString("SaasTariffChoosePlan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Contact sales.
        /// </summary>
        public static string SaasTariffContactSales {
            get {
                return ResourceManager.GetString("SaasTariffContactSales", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have {0} active users. To buy less please disable users in {1}People module{2}.
        /// </summary>
        public static string SaasTariffError {
            get {
                return ResourceManager.GetString("SaasTariffError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The number of admins should not exceed {0}..
        /// </summary>
        public static string SaasTariffErrorAdmins {
            get {
                return ResourceManager.GetString("SaasTariffErrorAdmins", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, disable automatic backups..
        /// </summary>
        public static string SaasTariffErrorAutoBackup {
            get {
                return ResourceManager.GetString("SaasTariffErrorAutoBackup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, disable DNS in the Portal settings..
        /// </summary>
        public static string SaasTariffErrorDomain {
            get {
                return ResourceManager.GetString("SaasTariffErrorDomain", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have {0} active users. To buy less please {1}contact sales{2}.
        /// </summary>
        public static string SaasTariffErrorExpired {
            get {
                return ResourceManager.GetString("SaasTariffErrorExpired", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The number of guests should not exceed {0}..
        /// </summary>
        public static string SaasTariffErrorGuests {
            get {
                return ResourceManager.GetString("SaasTariffErrorGuests", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invalid number of active users..
        /// </summary>
        public static string SaasTariffErrorInvalidNumberOfActiveUsers {
            get {
                return ResourceManager.GetString("SaasTariffErrorInvalidNumberOfActiveUsers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, disable LDAP..
        /// </summary>
        public static string SaasTariffErrorLdap {
            get {
                return ResourceManager.GetString("SaasTariffErrorLdap", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please select the number of active users from {0} to {1}..
        /// </summary>
        public static string SaasTariffErrorMinMax {
            get {
                return ResourceManager.GetString("SaasTariffErrorMinMax", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The month tariff not found..
        /// </summary>
        public static string SaasTariffErrorMonthTariffNotFound {
            get {
                return ResourceManager.GetString("SaasTariffErrorMonthTariffNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, disconnect all social networks..
        /// </summary>
        public static string SaasTariffErrorOauth {
            get {
                return ResourceManager.GetString("SaasTariffErrorOauth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Region not found..
        /// </summary>
        public static string SaasTariffErrorRegionNotFound {
            get {
                return ResourceManager.GetString("SaasTariffErrorRegionNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, disable SSO..
        /// </summary>
        public static string SaasTariffErrorSso {
            get {
                return ResourceManager.GetString("SaasTariffErrorSso", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The startup tariff not found..
        /// </summary>
        public static string SaasTariffErrorStartupTariffNotFound {
            get {
                return ResourceManager.GetString("SaasTariffErrorStartupTariffNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The used storage size should not exceed {0}..
        /// </summary>
        public static string SaasTariffErrorStorage {
            get {
                return ResourceManager.GetString("SaasTariffErrorStorage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tariff not found..
        /// </summary>
        public static string SaasTariffErrorTariffNotFound {
            get {
                return ResourceManager.GetString("SaasTariffErrorTariffNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please, disable all 3rd party services..
        /// </summary>
        public static string SaasTariffErrorThirparty {
            get {
                return ResourceManager.GetString("SaasTariffErrorThirparty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The 3-year tariff not found..
        /// </summary>
        public static string SaasTariffErrorThreeYearsTariffNotFound {
            get {
                return ResourceManager.GetString("SaasTariffErrorThreeYearsTariffNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Only the trial tariff can be changed to the startup tariff..
        /// </summary>
        public static string SaasTariffErrorTrial {
            get {
                return ResourceManager.GetString("SaasTariffErrorTrial", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The number of active users should not exceed {0}..
        /// </summary>
        public static string SaasTariffErrorUsers {
            get {
                return ResourceManager.GetString("SaasTariffErrorUsers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to White Label settings should be set by default..
        /// </summary>
        public static string SaasTariffErrorWhiteLabel {
            get {
                return ResourceManager.GetString("SaasTariffErrorWhiteLabel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The year tariff not found..
        /// </summary>
        public static string SaasTariffErrorYearTariffNotFound {
            get {
                return ResourceManager.GetString("SaasTariffErrorYearTariffNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subscription expires on {0}..
        /// </summary>
        public static string SaasTariffInfoExpiresOnDate {
            get {
                return ResourceManager.GetString("SaasTariffInfoExpiresOnDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Free days left.
        /// </summary>
        public static string SaasTariffInfoFreeDaysLeft {
            get {
                return ResourceManager.GetString("SaasTariffInfoFreeDaysLeft", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Storage space.
        /// </summary>
        public static string SaasTariffInfoStorageSpace {
            get {
                return ResourceManager.GetString("SaasTariffInfoStorageSpace", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Used storage space.
        /// </summary>
        public static string SaasTariffInfoStorageSpaceTitle {
            get {
                return ResourceManager.GetString("SaasTariffInfoStorageSpaceTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} ({1}% full).
        /// </summary>
        public static string SaasTariffInfoStorageSpaceValue {
            get {
                return ResourceManager.GetString("SaasTariffInfoStorageSpaceValue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Users.
        /// </summary>
        public static string SaasTariffInfoUsersCount {
            get {
                return ResourceManager.GetString("SaasTariffInfoUsersCount", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Number of active users / paid users.
        /// </summary>
        public static string SaasTariffInfoUsersCountTitle {
            get {
                return ResourceManager.GetString("SaasTariffInfoUsersCountTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You’re using ONLYOFFICE Business cloud.
        /// </summary>
        public static string SaasTariffMainHeaderBusiness {
            get {
                return ResourceManager.GetString("SaasTariffMainHeaderBusiness", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your Business plan has expired.
        /// </summary>
        public static string SaasTariffMainHeaderBusinessExpired {
            get {
                return ResourceManager.GetString("SaasTariffMainHeaderBusinessExpired", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You’re using free Startup plan.
        /// </summary>
        public static string SaasTariffMainHeaderStartup {
            get {
                return ResourceManager.GetString("SaasTariffMainHeaderStartup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have 30 days of ONLYOFFICE business cloud for free.
        /// </summary>
        public static string SaasTariffMainHeaderTrial {
            get {
                return ResourceManager.GetString("SaasTariffMainHeaderTrial", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your trial for ONLYOFFICE Business cloud has expired.
        /// </summary>
        public static string SaasTariffMainHeaderTrialExpired {
            get {
                return ResourceManager.GetString("SaasTariffMainHeaderTrialExpired", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 1 month.
        /// </summary>
        public static string SaasTariffOneMonth {
            get {
                return ResourceManager.GetString("SaasTariffOneMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 1 year.
        /// </summary>
        public static string SaasTariffOneYear {
            get {
                return ResourceManager.GetString("SaasTariffOneYear", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Re-activate business.
        /// </summary>
        public static string SaasTariffReActivateBusiness {
            get {
                return ResourceManager.GetString("SaasTariffReActivateBusiness", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save {0}%.
        /// </summary>
        public static string SaasTariffSale {
            get {
                return ResourceManager.GetString("SaasTariffSale", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your tariff details.
        /// </summary>
        public static string SaasTariffSelectedTariffDetails {
            get {
                return ResourceManager.GetString("SaasTariffSelectedTariffDetails", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Billing cycle.
        /// </summary>
        public static string SaasTariffSelectedTariffLength {
            get {
                return ResourceManager.GetString("SaasTariffSelectedTariffLength", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Price per user.
        /// </summary>
        public static string SaasTariffSelectedTariffPrice {
            get {
                return ResourceManager.GetString("SaasTariffSelectedTariffPrice", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} per month.
        /// </summary>
        public static string SaasTariffSelectedTariffPriceValue {
            get {
                return ResourceManager.GetString("SaasTariffSelectedTariffPriceValue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select the number of users.
        /// </summary>
        public static string SaasTariffSelectNumberOfUsers {
            get {
                return ResourceManager.GetString("SaasTariffSelectNumberOfUsers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Startup.
        /// </summary>
        public static string SaasTariffStartup {
            get {
                return ResourceManager.GetString("SaasTariffStartup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} user/month.
        /// </summary>
        public static string SaasTariffStartupCost {
            get {
                return ResourceManager.GetString("SaasTariffStartupCost", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 5 users max.
        /// </summary>
        public static string SaasTariffStartupFeature1 {
            get {
                return ResourceManager.GetString("SaasTariffStartupFeature1", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 2 Gb per portal.
        /// </summary>
        public static string SaasTariffStartupFeature2 {
            get {
                return ResourceManager.GetString("SaasTariffStartupFeature2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 10 simultaneous connections.
        /// </summary>
        public static string SaasTariffStartupFeature3 {
            get {
                return ResourceManager.GetString("SaasTariffStartupFeature3", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Manual backups.
        /// </summary>
        public static string SaasTariffStartupFeature4 {
            get {
                return ResourceManager.GetString("SaasTariffStartupFeature4", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail aggregator.
        /// </summary>
        public static string SaasTariffStartupFeature5 {
            get {
                return ResourceManager.GetString("SaasTariffStartupFeature5", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to For trial extension and sales questions, contact us at {0}{1}{2}.
        /// </summary>
        public static string SaasTariffTContactSupport {
            get {
                return ResourceManager.GetString("SaasTariffTContactSupport", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Have questions? {0}Contact us{1}.
        /// </summary>
        public static string SaasTariffTContactUs {
            get {
                return ResourceManager.GetString("SaasTariffTContactUs", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 3 years.
        /// </summary>
        public static string SaasTariffThreeYears {
            get {
                return ResourceManager.GetString("SaasTariffThreeYears", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Total.
        /// </summary>
        public static string SaasTariffTotalPrice {
            get {
                return ResourceManager.GetString("SaasTariffTotalPrice", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to For any purchase questions, contact us at {0}.
        /// </summary>
        public static string SalesQuestionsV11 {
            get {
                return ResourceManager.GetString("SalesQuestionsV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string SaveButton {
            get {
                return ResourceManager.GetString("SaveButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to search.
        /// </summary>
        public static string SearchHld {
            get {
                return ResourceManager.GetString("SearchHld", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Search in module.
        /// </summary>
        public static string SeeInModulesHdr {
            get {
                return ResourceManager.GetString("SeeInModulesHdr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select all.
        /// </summary>
        public static string SelectAll {
            get {
                return ResourceManager.GetString("SelectAll", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Send notification.
        /// </summary>
        public static string SendShareNotify {
            get {
                return ResourceManager.GetString("SendShareNotify", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add users or groups and give them the appropriate access rights.
        ///.
        /// </summary>
        public static string SharingSettingsEmpty {
            get {
                return ResourceManager.GetString("SharingSettingsEmpty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sharing Settings.
        /// </summary>
        public static string SharingSettingsTitle {
            get {
                return ResourceManager.GetString("SharingSettingsTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show next news.
        /// </summary>
        public static string ShowNextNews {
            get {
                return ResourceManager.GetString("ShowNextNews", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Website.
        /// </summary>
        public static string SiteTitle {
            get {
                return ResourceManager.GetString("SiteTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Source code is availible on {0}GitHub{1}.
        /// </summary>
        public static string SourceCode {
            get {
                return ResourceManager.GetString("SourceCode", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to I want to subscribe to the ONLYOFFICE newsletter.
        /// </summary>
        public static string SubscribeSite {
            get {
                return ResourceManager.GetString("SubscribeSite", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to For solving technical issues, use {0}.
        /// </summary>
        public static string SupportQuestionsV11 {
            get {
                return ResourceManager.GetString("SupportQuestionsV11", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Basic price.
        /// </summary>
        public static string TariffBasicPrice {
            get {
                return ResourceManager.GetString("TariffBasicPrice", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to See Avangate for the full list of currencies.
        /// </summary>
        public static string TariffCurrencyHelp {
            get {
                return ResourceManager.GetString("TariffCurrencyHelp", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your pricing plan has major restrictions for the file size..
        /// </summary>
        public static string TariffFileSizeLimitReason {
            get {
                return ResourceManager.GetString("TariffFileSizeLimitReason", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Large file size.
        /// </summary>
        public static string TariffFileSizeLimitTitle {
            get {
                return ResourceManager.GetString("TariffFileSizeLimitTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Free.
        /// </summary>
        public static string TariffFree {
            get {
                return ResourceManager.GetString("TariffFree", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open full price list.
        /// </summary>
        public static string TariffFullPrice {
            get {
                return ResourceManager.GetString("TariffFullPrice", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Would you like to choose a new pricing plan?.
        /// </summary>
        public static string TariffLimitDecision {
            get {
                return ResourceManager.GetString("TariffLimitDecision", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Time limited offer.
        /// </summary>
        public static string TariffLimitedPrice {
            get {
                return ResourceManager.GetString("TariffLimitedPrice", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Yes, upgrade plan.
        /// </summary>
        public static string TariffLimitOkButton {
            get {
                return ResourceManager.GetString("TariffLimitOkButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}1 Month{2}{1} Subscription.
        /// </summary>
        public static string TariffNameSMonth {
            get {
                return ResourceManager.GetString("TariffNameSMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}1 Year{2}{1} Subscription.
        /// </summary>
        public static string TariffNameSYear {
            get {
                return ResourceManager.GetString("TariffNameSYear", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}3 Year{1} Subscription.
        /// </summary>
        public static string TariffNameSYear3 {
            get {
                return ResourceManager.GetString("TariffNameSYear3", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using a plan for nonprofit organization..
        /// </summary>
        public static string TariffNonProfit {
            get {
                return ResourceManager.GetString("TariffNonProfit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using ONLYOFFICE Enterprise Edition. {0}Support and updates are no longer available for your license{1}..
        /// </summary>
        public static string TariffNotPaidStandalone2 {
            get {
                return ResourceManager.GetString("TariffNotPaidStandalone2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using ONLYOFFICE Enterprise Edition. {0}Support is no longer available for your license{1}..
        /// </summary>
        public static string TariffNotPaidStandaloneSupport {
            get {
                return ResourceManager.GetString("TariffNotPaidStandaloneSupport", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}The portal payment is overdue.{1} {2}To continue using ONLYOFFICE collaboration features, {2}prolong the existing pricing plan or select another one..
        /// </summary>
        public static string TariffOverdueDesktop {
            get {
                return ResourceManager.GetString("TariffOverdueDesktop", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Your portal payment has expired..
        /// </summary>
        public static string TariffOverdueHosted {
            get {
                return ResourceManager.GetString("TariffOverdueHosted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using {0} - {1} active users plan. {2}The payment is overdue.{3}{4} To continue using ONLYOFFICE, prolong the existing plan or change it using the table below..
        /// </summary>
        public static string TariffOverduePlan {
            get {
                return ResourceManager.GetString("TariffOverduePlan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using ONLYOFFICE Enterprise Edition. {0}Support and updates are no longer available for your license since {2}{1}..
        /// </summary>
        public static string TariffOverdueStandalone2 {
            get {
                return ResourceManager.GetString("TariffOverdueStandalone2", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using ONLYOFFICE Enterprise Edition. {0}Support is no longer available for your license since {2}{1}..
        /// </summary>
        public static string TariffOverdueStandaloneSupport {
            get {
                return ResourceManager.GetString("TariffOverdueStandaloneSupport", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using {0} - {1} active users plan..
        /// </summary>
        public static string TariffPaidPlan {
            get {
                return ResourceManager.GetString("TariffPaidPlan", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using ONLYOFFICE Enterprise Edition..
        /// </summary>
        public static string TariffPaidStandalone {
            get {
                return ResourceManager.GetString("TariffPaidStandalone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to month.
        /// </summary>
        public static string TariffPerMonth {
            get {
                return ResourceManager.GetString("TariffPerMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to year.
        /// </summary>
        public static string TariffPerYear {
            get {
                return ResourceManager.GetString("TariffPerYear", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to 3 year.
        /// </summary>
        public static string TariffPerYear3 {
            get {
                return ResourceManager.GetString("TariffPerYear3", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The offer is available for annual subscribers only. .
        /// </summary>
        public static string TariffPerYearOnly {
            get {
                return ResourceManager.GetString("TariffPerYearOnly", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Most Popular Subscription.
        /// </summary>
        public static string TariffPop {
            get {
                return ResourceManager.GetString("TariffPop", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Adding a new portal will exceed the maximum number of portals allowed by your current pricing plan..
        /// </summary>
        public static string TariffPortalLimitHeaer {
            get {
                return ResourceManager.GetString("TariffPortalLimitHeaer", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save {0}.
        /// </summary>
        public static string TariffPriceOffer {
            get {
                return ResourceManager.GetString("TariffPriceOffer", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} per user/mo.
        /// </summary>
        public static string TariffPricePer {
            get {
                return ResourceManager.GetString("TariffPricePer", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Send your request.
        /// </summary>
        public static string TariffRequestBtn {
            get {
                return ResourceManager.GetString("TariffRequestBtn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Request contents.
        /// </summary>
        public static string TariffRequestContent {
            get {
                return ResourceManager.GetString("TariffRequestContent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please describe your request details here.
        /// </summary>
        public static string TariffRequestContentHolder {
            get {
                return ResourceManager.GetString("TariffRequestContentHolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please type your message here.
        /// </summary>
        public static string TariffRequestHeader {
            get {
                return ResourceManager.GetString("TariffRequestHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The portal storage space is exceeded.
        /// </summary>
        public static string TariffStorageLimitHeader {
            get {
                return ResourceManager.GetString("TariffStorageLimitHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please delete all the outdated content from the portal or change the current pricing plan to one with larger storage space..
        /// </summary>
        public static string TariffStorageLimitReason {
            get {
                return ResourceManager.GetString("TariffStorageLimitReason", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not enough free storage space.
        /// </summary>
        public static string TariffStorageLimitTitle {
            get {
                return ResourceManager.GetString("TariffStorageLimitTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are using ONLYOFFICE Enterprise Edition. {0}The current installation has been updated without a proper license provided.{1}{2} Please upload the updated license to continue using ONLYOFFICE Enterprise Edition..
        /// </summary>
        public static string TariffUpdateWithoutLicense {
            get {
                return ResourceManager.GetString("TariffUpdateWithoutLicense", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choose the number of your teammates.
        /// </summary>
        public static string TariffUserChoose {
            get {
                return ResourceManager.GetString("TariffUserChoose", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to How many users do you need?.
        /// </summary>
        public static string TariffUserChooseQuestion {
            get {
                return ResourceManager.GetString("TariffUserChooseQuestion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The plan that fits your team is {0}{2} - {3} active users{7} + {4}{1} Disk Storage.
        /// </summary>
        public static string TariffUserDescr {
            get {
                return ResourceManager.GetString("TariffUserDescr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cannot add new users.
        /// </summary>
        public static string TariffUserLimitHeader {
            get {
                return ResourceManager.GetString("TariffUserLimitHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Adding new users will exceed the maximum number of portal members allowed by your current pricing plan..
        /// </summary>
        public static string TariffUserLimitReason {
            get {
                return ResourceManager.GetString("TariffUserLimitReason", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Adding new users.
        /// </summary>
        public static string TariffUserLimitTitle {
            get {
                return ResourceManager.GetString("TariffUserLimitTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The pricing plans with more than {0} active users{1} are available upon request only..
        /// </summary>
        public static string TariffUserRequestDescr {
            get {
                return ResourceManager.GetString("TariffUserRequestDescr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You cannot downgrade a pricing plan..
        /// </summary>
        public static string TariffUserWarnDescr {
            get {
                return ResourceManager.GetString("TariffUserWarnDescr", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to read more.
        /// </summary>
        public static string TariffUserWarnRead {
            get {
                return ResourceManager.GetString("TariffUserWarnRead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Adding new guest will exceed the maximum number of portal guests allowed by your current pricing plan..
        /// </summary>
        public static string TariffVisitorLimitReason {
            get {
                return ResourceManager.GetString("TariffVisitorLimitReason", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter 6-digit generated code from your application. If you don&apos;t have access to your phone you can use your backup codes..
        /// </summary>
        public static string TfaAppAuthDescription {
            get {
                return ResourceManager.GetString("TfaAppAuthDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Configure your authenticator application.
        /// </summary>
        public static string TfaAppCaption {
            get {
                return ResourceManager.GetString("TfaAppCaption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connect app.
        /// </summary>
        public static string TfaAppConnctButton {
            get {
                return ResourceManager.GetString("TfaAppConnctButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The two-factor authentication is enabled to provide additional portal security. Configure your authenticator application to continue work on the portal. For example you could use {0} for {1} and {2} or {3} for {4}..
        /// </summary>
        public static string TfaAppDescription {
            get {
                return ResourceManager.GetString("TfaAppDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to To connect your apllication scan the QR code or manually enter your secret key {0} then enter 6-digit code from your application in the field below..
        /// </summary>
        public static string TfaAppHowTo {
            get {
                return ResourceManager.GetString("TfaAppHowTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can create documents ({0}), spreadsheets ({1}), presentations ({2}) and download them to most popular formats..
        /// </summary>
        public static string TooltipCreate {
            get {
                return ResourceManager.GetString("TooltipCreate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can edit the following files: {0}..
        /// </summary>
        public static string TooltipEdit {
            get {
                return ResourceManager.GetString("TooltipEdit", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can open the files with the following extentions: {0}..
        /// </summary>
        public static string TooltipOpen {
            get {
                return ResourceManager.GetString("TooltipOpen", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You can upload any files you want to the Documents..
        /// </summary>
        public static string TooltipUpload {
            get {
                return ResourceManager.GetString("TooltipUpload", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to First Name.
        /// </summary>
        public static string UnknownFirstName {
            get {
                return ResourceManager.GetString("UnknownFirstName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Last Name.
        /// </summary>
        public static string UnknownLastName {
            get {
                return ResourceManager.GetString("UnknownLastName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upgrade pricing plan.
        /// </summary>
        public static string UpgradeButton {
            get {
                return ResourceManager.GetString("UpgradeButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upload file.
        /// </summary>
        public static string UploadFile {
            get {
                return ResourceManager.GetString("UploadFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Choice.
        /// </summary>
        public static string Variant {
            get {
                return ResourceManager.GetString("Variant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to ver..
        /// </summary>
        public static string Version {
            get {
                return ResourceManager.GetString("Version", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There is nothing to be displayed here.
        /// </summary>
        public static string VoipCallsNotFound {
            get {
                return ResourceManager.GetString("VoipCallsNotFound", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to There is nothing to be displayed here.
        /// </summary>
        public static string VoipCallsNotFoundDescription {
            get {
                return ResourceManager.GetString("VoipCallsNotFoundDescription", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Vote.
        /// </summary>
        public static string VoteButton {
            get {
                return ResourceManager.GetString("VoteButton", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Apps you need for productive work.
        /// </summary>
        public static string WelcomeDashboardApps {
            get {
                return ResourceManager.GetString("WelcomeDashboardApps", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Use ONLYOFFICE Mail Server{1} to create corporate mailboxes, add aliases/mail groups..
        /// </summary>
        public static string WelcomeDashboardAppsFirstLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardAppsFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Sign docs with DocuSign{1}. Send docs for electronic signature right from your portal, and receive signed PDF files..
        /// </summary>
        public static string WelcomeDashboardAppsSecondLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardAppsSecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Call your clients with Twilio{1}. Make and receive calls right from a web browser using virtual numbers..
        /// </summary>
        public static string WelcomeDashboardAppsThirdLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardAppsThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Back up ONLYOFFICE.
        /// </summary>
        public static string WelcomeDashboardBackUp {
            get {
                return ResourceManager.GetString("WelcomeDashboardBackUp", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connect now.
        /// </summary>
        public static string WelcomeDashboardConnectNow {
            get {
                return ResourceManager.GetString("WelcomeDashboardConnectNow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Customize now.
        /// </summary>
        public static string WelcomeDashboardCustomizeNow {
            get {
                return ResourceManager.GetString("WelcomeDashboardCustomizeNow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enable now.
        /// </summary>
        public static string WelcomeDashboardEnableNow {
            get {
                return ResourceManager.GetString("WelcomeDashboardEnableNow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Go to DNS settings.
        /// </summary>
        public static string WelcomeDashboardGoToDns {
            get {
                return ResourceManager.GetString("WelcomeDashboardGoToDns", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Welcome to ONLYOFFICE Business cloud.
        /// </summary>
        public static string WelcomeDashboardHeader {
            get {
                return ResourceManager.GetString("WelcomeDashboardHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Import now.
        /// </summary>
        public static string WelcomeDashboardImportNow {
            get {
                return ResourceManager.GetString("WelcomeDashboardImportNow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Easy integration with your infrastructure.
        /// </summary>
        public static string WelcomeDashboardIntegration {
            get {
                return ResourceManager.GetString("WelcomeDashboardIntegration", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Use LDAP to easily import users{1} and groups from your server (e.g. OpenLDAP Server or Microsoft Active Directory)..
        /// </summary>
        public static string WelcomeDashboardIntegrationFirstLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardIntegrationFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Enable SSO authentication{1} to let users login with existing credentials..
        /// </summary>
        public static string WelcomeDashboardIntegrationSecondLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardIntegrationSecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Use your own domain name{1} as your portal address..
        /// </summary>
        public static string WelcomeDashboardIntegrationThirdLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardIntegrationThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Invite users.
        /// </summary>
        public static string WelcomeDashboardInviteUsers {
            get {
                return ResourceManager.GetString("WelcomeDashboardInviteUsers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Set up now.
        /// </summary>
        public static string WelcomeDashboardSetUpNow {
            get {
                return ResourceManager.GetString("WelcomeDashboardSetUpNow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Start editing.
        /// </summary>
        public static string WelcomeDashboardStartEditing {
            get {
                return ResourceManager.GetString("WelcomeDashboardStartEditing", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cloud tailored to your needs.
        /// </summary>
        public static string WelcomeDashboardTailoredCloud {
            get {
                return ResourceManager.GetString("WelcomeDashboardTailoredCloud", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Choose how many users{1} you need, appoint any number of admins..
        /// </summary>
        public static string WelcomeDashboardTailoredCloudFirstLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardTailoredCloudFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Customize your online office{1} style to match your branding..
        /// </summary>
        public static string WelcomeDashboardTailoredCloudSecondLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardTailoredCloudSecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Edit unlimited number of docs{1}, sheets, and slides simultaneously..
        /// </summary>
        public static string WelcomeDashboardTailoredCloudThirdLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardTailoredCloudThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Track now.
        /// </summary>
        public static string WelcomeDashboardTrackNow {
            get {
                return ResourceManager.GetString("WelcomeDashboardTrackNow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Ultimate security.
        /// </summary>
        public static string WelcomeDashboardUltimateSecurity {
            get {
                return ResourceManager.GetString("WelcomeDashboardUltimateSecurity", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Enable 2FA{1}, set password criteria, choose trusted IPs and mail domains..
        /// </summary>
        public static string WelcomeDashboardUltimateSecurityFirstLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardUltimateSecurityFirstLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Configure automatic backups{1} and perform manual ones..
        /// </summary>
        public static string WelcomeDashboardUltimateSecuritySecondLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardUltimateSecuritySecondLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}Track user logins{1} and other actions..
        /// </summary>
        public static string WelcomeDashboardUltimateSecurityThirdLine {
            get {
                return ResourceManager.GetString("WelcomeDashboardUltimateSecurityThirdLine", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Сonfigure now.
        /// </summary>
        public static string WelcomeDashboardСonfigureNow {
            get {
                return ResourceManager.GetString("WelcomeDashboardСonfigureNow", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to What&apos;s New.
        /// </summary>
        public static string WhatsNew {
            get {
                return ResourceManager.GetString("WhatsNew", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/HttpHandlers/OpenContactHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;
using System.Xml.Linq;

using ASC.Web.Core.Jabber;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Talk.HttpHandlers
{
    public class OpenContactHandler : IHttpHandler
    {
        private const string FROM = "from";
        private const string TO = "to";
        private const string FROM_TENANT = "fromtenant";
        private static readonly TalkConfiguration cfg = new TalkConfiguration();

        public bool IsReusable
        {
            // To enable pooling, return true here.
            // This keeps the handler in memory.
            get { return false; }
        }

        private readonly static JabberServiceClient _jabberServiceClient = new JabberServiceClient();

        public void ProcessRequest(HttpContext context)
        {
            var response = String.Empty;
            if (context.Request.Url != null && !string.IsNullOrEmpty(context.Request.Url.Query))
            {
                bool fromTenant = false;
                var to = string.Empty;
                var from = string.Empty;
                foreach (var query in context.Request.Url.Query.Trim().Trim('?').Split('&'))
                {
                    var el = query.Split('=');
                    switch (el[0].ToLower())
                    {
                        case FROM:
                            from = el[1];
                            break;
                        case TO:
                            to = el[1];
                            break;
                        case FROM_TENANT:
                            fromTenant = Convert.ToBoolean(el[1]);
                            break;
                    }
                }

                if (!String.IsNullOrEmpty(to) && !String.IsNullOrEmpty(from))
                {
                    if (cfg.ReplaceDomain && from != null && from.EndsWith(cfg.ReplaceToDomain))
                    {
                        int place = from.LastIndexOf(cfg.ReplaceToDomain);
                        if (place >= 0)
                        {
                            from = from.Remove(place, cfg.ReplaceToDomain.Length).Insert(place, cfg.ReplaceFromDomain);
                        }
                    }
                    if (cfg.ReplaceDomain && to != null && to.EndsWith(cfg.ReplaceToDomain))
                    {
                        int place = to.LastIndexOf(cfg.ReplaceToDomain);
                        if (place >= 0)
                        {
                            to = to.Remove(place, cfg.ReplaceToDomain.Length).Insert(place, cfg.ReplaceFromDomain);
                        }
                    }
                    try
                    {
                        _jabberServiceClient.SendCommand(TenantProvider.CurrentTenantID, from, to, "open", fromTenant);
                    }
                    catch (Exception ex)
                    {
                        response = ex.Message;
                    }
                }
                else
                {
                    response = "Invalid param";
                }
            }

            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.ContentType = "application/xml";
            context.Response.Charset = Encoding.UTF8.WebName;
            var xml = new XDocument(new XElement("response", response)).ToString();
            context.Response.Write(Encoding.UTF8.GetString(Encoding.Convert(Encoding.Unicode, Encoding.UTF8, Encoding.Unicode.GetBytes(xml))));
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/ContactCardDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Expressions.Contact;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Enums;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class ContactCardDao : IContactCardDao
    {
        public IDbManager Db { get; private set; }
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ContactCardDao(IDbManager dbManager, int tenant, string user)
        {
            Db = dbManager;
            Tenant = tenant;
            User = user;
        }

        private const string MAIL_CONTACTS = "mc";
        private const string CONTACT_INFO = "ci";

        public ContactCard GetContactCard(int id)
        {
            var query = new SqlQuery(ContactsTable.TABLE_NAME.Alias(MAIL_CONTACTS))
                .Select(ContactsTable.Columns.Id.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.User.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Tenant.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.ContactName.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Address.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Description.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Type.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.HasPhoto.Prefix(MAIL_CONTACTS))
                .Where(ContactsTable.Columns.Tenant.Prefix(MAIL_CONTACTS), Tenant)
                .Where(ContactsTable.Columns.User.Prefix(MAIL_CONTACTS), User)
                .Where(ContactsTable.Columns.Id.Prefix(MAIL_CONTACTS), id);

            var contacts = Db.ExecuteList(query)
                .ConvertAll(ToContact);

            query = new SqlQuery(ContactInfoTable.TABLE_NAME.Alias(CONTACT_INFO))
                .Select(ContactInfoTable.Columns.Id.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.Tenant.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.User.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.ContactId.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.Data.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.Type.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.IsPrimary.Prefix(CONTACT_INFO))
                .Where(ContactInfoTable.Columns.ContactId.Prefix(CONTACT_INFO), id);

            var contactInfos = Db.ExecuteList(query)
                .ConvertAll(ToContactInfo);

            return ToContactCardList(contacts, contactInfos).SingleOrDefault();
        }

        public List<ContactCard> GetContactCards(IContactsExp exp)
        {
            var query = new SqlQuery(ContactsTable.TABLE_NAME.Alias(MAIL_CONTACTS))
                .Select(ContactsTable.Columns.Id.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.User.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Tenant.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.ContactName.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Address.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Description.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.Type.Prefix(MAIL_CONTACTS),
                    ContactsTable.Columns.HasPhoto.Prefix(MAIL_CONTACTS))
                .Where(exp.GetExpression());

            if (exp.OrderAsc.HasValue)
            {
                query.OrderBy(ContactsTable.Columns.ContactName.Prefix(MAIL_CONTACTS), exp.OrderAsc.HasValue);
            }

            if (exp.StartIndex.HasValue)
            {
                query.SetFirstResult(exp.StartIndex.Value);
            }

            if (exp.Limit.HasValue)
            {
                query.SetMaxResults(exp.Limit.Value);
            }

            var contacts = Db.ExecuteList(query)
                .ConvertAll(ToContact);

            var ids = contacts.Select(c => c.Id).ToList();

            query = new SqlQuery(ContactInfoTable.TABLE_NAME.Alias(CONTACT_INFO))
                .Select(ContactInfoTable.Columns.Id.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.Tenant.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.User.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.ContactId.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.Data.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.Type.Prefix(CONTACT_INFO),
                    ContactInfoTable.Columns.IsPrimary.Prefix(CONTACT_INFO))
                .Where(Exp.In(ContactInfoTable.Columns.ContactId.Prefix(CONTACT_INFO), ids));

            var contactInfos = Db.ExecuteList(query)
                .ConvertAll(ToContactInfo);

            return ToContactCardList(contacts, contactInfos);
        }

        public int GetContactCardsCount(IContactsExp exp)
        {
            var query = new SqlQuery(ContactsTable.TABLE_NAME.Alias(MAIL_CONTACTS))
                .SelectCount("distinct " + ContactsTable.Columns.Id.Prefix(MAIL_CONTACTS))
                .LeftOuterJoin(ContactInfoTable.TABLE_NAME.Alias(CONTACT_INFO),
                    Exp.EqColumns(ContactsTable.Columns.Id.Prefix(MAIL_CONTACTS),
                        ContactInfoTable.Columns.ContactId.Prefix(CONTACT_INFO)))
                .Where(exp.GetExpression());

            var result = Db.ExecuteScalar<int>(query);

            return result;
        }

        protected List<ContactCard> ToContactCardList(List<Contact> contacts, List<ContactInfo> contactInfos)
        {
            return
                contacts.Select(
                    contact => new ContactCard(contact, contactInfos.Where(ci => ci.ContactId == contact.Id).ToList()))
                    .ToList();
        }

        protected Contact ToContact(object[] r)
        {
            var c = new Contact
            {
                Id = Convert.ToInt32(r[0]),
                User = Convert.ToString(r[1]),
                Tenant = Convert.ToInt32(r[2]),
                ContactName = Convert.ToString(r[3]),
                Address = Convert.ToString(r[4]),
                Description = Convert.ToString(r[5]),
                Type = (ContactType)Convert.ToInt32(r[6]),
                HasPhoto = Convert.ToBoolean(r[7])
            };

            return c;
        }

        protected ContactInfo ToContactInfo(object[] r)
        {
            var c = new ContactInfo
            {
                Id = Convert.ToInt32(r[0]),
                Tenant = Convert.ToInt32(r[1]),
                User = Convert.ToString(r[2]),
                ContactId = Convert.ToInt32(r[3]),
                Data = Convert.ToString(r[4]),
                Type = Convert.ToInt32(r[5]),
                IsPrimary = Convert.ToBoolean(r[6])
            };

            return c;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Clients/MailClientEventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Logging;
using ASC.Mail.Data.Contracts;

namespace ASC.Mail.Clients
{
    /// <summary>Authenticated event arguments.</summary>
    /// <remarks>
    /// Some servers, such as GMail IMAP, will send some free-form text in
    /// the response to a successful login.
    /// </remarks>
    public class MailClientEventArgs : EventArgs
    {
        /// <summary>Get the free-form text sent by the server.</summary>
        /// <remarks>Gets the free-form text sent by the server.</remarks>
        /// <value>The free-form text sent by the server.</value>
        public string Message { get; private set; }

        public MailBoxData Mailbox { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="T:MailClientEventArgs" /> class.
        /// </summary>
        /// <remarks>
        /// Creates a new <see cref="T:MailKit.AuthenticatedEventArgs" />.
        /// </remarks>
        /// <param name="message">The free-form text.</param>
        /// <param name="mailBoxData"></param>
        public MailClientEventArgs(string message, MailBoxData mailBoxData)
        {
            Message = message;
            Mailbox = mailBoxData;
        }
    }

    public class MailClientMessageEventArgs : EventArgs
    {
        public MimeKit.MimeMessage Message { get; private set; }

        public MailBoxData Mailbox { get; private set; }

        public bool Unread { get; private set; }

        public MailFolder Folder { get; private set; }

        public string MessageUid { get; private set; }

        public ILog Logger { get; private set; }

        public MailClientMessageEventArgs(MimeKit.MimeMessage message, string messageUid, bool uread, MailFolder folder,
            MailBoxData mailBoxData, ILog logger)
        {
            Message = message;
            Unread = uread;
            Folder = folder;
            Mailbox = mailBoxData;
            MessageUid = messageUid;
            Logger = logger;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/HttpHandlers/ContactPhotoHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.CRM.Core.Entities;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Core.Files;
using ASC.Web.Core.Utility;
using ASC.Web.CRM.Configuration;
using ASC.Web.CRM.Core;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.Controls.FileUploader;
using ASC.Web.Studio.Core;

using Autofac;


namespace ASC.Web.CRM.Classes
{
    public class ContactPhotoHandler : IFileUploadHandler
    {
        public FileUploadResult ProcessUpload(HttpContext context)
        {
            if (!WebItemSecurity.IsAvailableForMe(ProductEntryPoint.ID))
                throw CRMSecurity.CreateSecurityException();

            var contactId = Convert.ToInt32(context.Request["contactID"]);
            Contact contact = null;
            if (contactId != 0)
            {
                using (var scope = DIHelper.Resolve())
                {
                    contact = scope.Resolve<DaoFactory>().ContactDao.GetByID(contactId);
                    if (!CRMSecurity.CanEdit(contact))
                        throw CRMSecurity.CreateSecurityException();
                }
            }

            var fileUploadResult = new FileUploadResult();

            if (!FileToUpload.HasFilesToUpload(context)) return fileUploadResult;

            var file = new FileToUpload(context);

            if (String.IsNullOrEmpty(file.FileName) || file.ContentLength == 0)
                throw new InvalidOperationException(CRMErrorsResource.InvalidFile);

            if (0 < SetupInfo.MaxImageUploadSize && SetupInfo.MaxImageUploadSize < file.ContentLength)
            {
                fileUploadResult.Success = false;
                fileUploadResult.Message = FileSizeComment.GetFileImageSizeNote(CRMCommonResource.ErrorMessage_UploadFileSize, false).HtmlEncode();
                return fileUploadResult;
            }

            if (FileUtility.GetFileTypeByFileName(file.FileName) != FileType.Image)
            {
                fileUploadResult.Success = false;
                fileUploadResult.Message = CRMJSResource.ErrorMessage_NotImageSupportFormat.HtmlEncode();
                return fileUploadResult;
            }

            var uploadOnly = Convert.ToBoolean(context.Request["uploadOnly"]);
            var tmpDirName = Convert.ToString(context.Request["tmpDirName"]);

            try
            {
                ContactPhotoManager.PhotoData photoData;
                if (contactId != 0)
                {
                    photoData = ContactPhotoManager.UploadPhoto(file.InputStream, contactId, uploadOnly);
                }
                else
                {
                    if (String.IsNullOrEmpty(tmpDirName) || tmpDirName == "null")
                    {
                        tmpDirName = Guid.NewGuid().ToString();
                    }
                    photoData = ContactPhotoManager.UploadPhotoToTemp(file.InputStream, tmpDirName);
                }

                fileUploadResult.Success = true;
                fileUploadResult.Data = photoData;
            }
            catch (Exception e)
            {
                fileUploadResult.Success = false;
                fileUploadResult.Message = e.Message.HtmlEncode();
                return fileUploadResult;
            }

            if (contact != null)
            {
                var messageAction = contact is Company ? MessageAction.CompanyUpdatedPhoto : MessageAction.PersonUpdatedPhoto;
                MessageService.Send(context.Request, messageAction, MessageTarget.Create(contact.ID), contact.GetTitle());
            }

            return fileUploadResult;
        }
    }
}

<|start_filename|>common/ASC.Data.Storage/CrossModuleTransferUtility.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;

using ASC.Common;
using ASC.Common.Logging;
using ASC.Core.ChunkedUploader;

namespace ASC.Data.Storage
{
    public class CrossModuleTransferUtility
    {
        private static readonly ILog Log = LogManager.GetLogger("ASC.CrossModuleTransferUtility");
        private readonly IDataStore source;
        private readonly IDataStore destination;
        private readonly long maxChunkUploadSize;
        private readonly int chunksize;

        public CrossModuleTransferUtility(IDataStore source, IDataStore destination)
        {
            if (source == null) throw new ArgumentNullException("source");
            if (destination == null) throw new ArgumentNullException("destination");

            this.source = source;
            this.destination = destination;
            maxChunkUploadSize = 10 * 1024 * 1024;
            chunksize = 5 * 1024 * 1024;
        }

        public void CopyFile(string srcDomain, string srcPath, string destDomain, string destPath)
        {
            if (srcDomain == null) throw new ArgumentNullException("srcDomain");
            if (srcPath == null) throw new ArgumentNullException("srcPath");
            if (destDomain == null) throw new ArgumentNullException("destDomain");
            if (destPath == null) throw new ArgumentNullException("destPath");

            using (var stream = source.GetReadStream(srcDomain, srcPath))
            {
                if (stream.Length < maxChunkUploadSize)
                {
                    destination.Save(destDomain, destPath, stream);
                }
                else
                {
                    var session = new CommonChunkedUploadSession(stream.Length);
                    var holder = new CommonChunkedUploadSessionHolder(destination, destDomain);
                    holder.Init(session);
                    try
                    {
                        Stream memstream = null;
                        try
                        {
                            while (GetStream(stream, out memstream))
                            {
                                memstream.Seek(0, SeekOrigin.Begin);
                                holder.UploadChunk(session, memstream, chunksize);
                                memstream.Dispose();
                                memstream = null;
                            }
                        }
                        finally
                        {
                            if (memstream != null)
                            {
                                memstream.Dispose();
                            }
                        }

                        holder.Finalize(session);
                        destination.Move(destDomain, session.TempPath, destDomain, destPath);
                    }
                    catch (Exception ex)
                    {
                        Log.Error("Copy File", ex);
                        holder.Abort(session);
                    }
                }
            }
        }

        private bool GetStream(Stream stream, out Stream memstream)
        {
            memstream = TempStream.Create();
            var total = 0;
            int readed;
            const int portion = 2048;
            var buffer = new byte[portion];

            while ((readed = stream.Read(buffer, 0, portion)) > 0)
            {
                memstream.Write(buffer, 0, readed);
                total += readed;
                if (total >= chunksize) break;
            }

            return total > 0;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/URI/UriSchemes.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net
{
    /// <summary>
    /// This class represents well known URI schemes.
    /// </summary>
    public class UriSchemes
    {
        #region Constants

        /// <summary>
        /// HTTP Extensions for Distributed Authoring (WebDAV).
        /// </summary>
        public const string dav = "dav";

        /// <summary>
        /// Addressing files on local or network file systems.
        /// </summary>
        public const string file = "file";

        /// <summary>
        /// FTP resources.
        /// </summary>
        public const string ftp = "ftp";

        /// <summary>
        /// HTTP resources.
        /// </summary>
        public const string http = "http";

        /// <summary>
        /// HTTP connections secured using SSL/TLS.
        /// </summary>
        public const string https = "https";

        /// <summary>
        /// SMTP e-mail addresses and default content.
        /// </summary>
        public const string mailto = "mailto";

        /// <summary>
        /// Session Initiation Protocol (SIP).
        /// </summary>
        public const string sip = "sip";

        /// <summary>
        /// Session Initiation Protocol (SIP) using TLS.
        /// </summary>
        public const string sips = "sips";

        /// <summary>
        /// Telephone numbers.
        /// </summary>
        public const string tel = "tel";

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/App_Themes/default/css/reportsprint.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


.generated-report-filter-container #generateNewReport, .generated-report-buttons {
    visibility: hidden;
}
.generated-report-container.borderBase {
    border: none;
}
.generated-report-container a 
{
	color:#000000 !important;
	font-size:12px;
	font-weight:normal;
	text-decoration : none !important;
}

.sortable
{
	border-collapse: collapse;
	width: 100%;
}
.sortable thead th
{
	cursor: pointer;
	color: #000000;
	font-size: 12px;
}
.generated-report-container .sortable tbody td
{
	text-align: left;
	border-left: none;
	border-right: none;
	vertical-align: middle;
}

.generated-report-container .sortable tr:last-child td,
.generated-report-container .pm-tablebase tr:last-child td {
    border-bottom: medium none;
}

.report-tableColumnHeader
{
	border-bottom: none;
	color: #333;
	text-decoration:none;
}

/********heders**********/
a.report-big-header,
a.report-middle-header,
a.report-small-header,
a.report-big-header:visited,
a.report-middle-header:visited,
a.report-small-header:visited, 
a.report-big-header:hover,
a.report-middle-header:hover,
a.report-small-header:hover,
a.report-big-header:active,
a.report-middle-header:active,
a.report-small-header:active   {
    font-weight: bold;
    color: #333;
    text-decoration:none;
}

a.report-big-header:hover,
a.report-middle-header:hover,
a.report-small-header:hover {
    text-decoration: underline;
}

a.report-big-header {
    font-size: 16px;
}
a.report-middle-header {
    font-size: 14px;
}
/*----*/

.borderBase 
{
	border:1px solid #333;
}

.mainContainerClass
{
    border: none !important;
}
.mainPageLayout
{
    margin: 0 !important;
    width: 100% !important;
}
.gray-text, .red-text
{
	color:#333 !important;
}




<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Proxy/SIP_ProxyCore.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Proxy
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Net;
    using AUTH;
    using Message;
    using Stack;

    #endregion

    #region Delegates

    /// <summary>
    /// Represents the method that will handle the SIP_ProxyCore.IsLocalUri event.
    /// </summary>
    /// <param name="uri">Request URI.</param>
    /// <returns>Returns true if server local URI, otherwise false.</returns>
    public delegate bool SIP_IsLocalUriEventHandler(string uri);

    /// <summary>
    /// Represents the method that will handle the SIP_ProxyCore.Authenticate event.
    /// </summary>
    public delegate void SIP_AuthenticateEventHandler(SIP_AuthenticateEventArgs e);

    /// <summary>
    /// Represents the method that will handle the SIP_ProxyCore.AddressExists event.
    /// </summary>
    /// <param name="address">SIP address to check.</param>
    /// <returns>Returns true if specified address exists, otherwise false.</returns>
    public delegate bool SIP_AddressExistsEventHandler(string address);

    /// <summary>
    /// Represents the method that will handle the SIP_ProxyCore.GetGateways event.
    /// </summary>
    /// <param name="e">Event data.</param>
    public delegate void SIP_GetGatewaysEventHandler(SIP_GatewayEventArgs e);

    #endregion

    /// <summary>
    /// Implements SIP registrar,statefull and stateless proxy.
    /// </summary>
    public class SIP_ProxyCore : IDisposable
    {
        #region Events

        /// <summary>
        /// This event is raised when SIP proxy needs to know if specified local server address exists.
        /// </summary>
        public event SIP_AddressExistsEventHandler AddressExists = null;

        /// <summary>
        /// This event is raised when SIP proxy or registrar server needs to authenticate user.
        /// </summary>
        public event SIP_AuthenticateEventHandler Authenticate = null;

        /// <summary>
        /// This event is raised when SIP proxy needs to get gateways for non-SIP URI.
        /// </summary>
        public event SIP_GetGatewaysEventHandler GetGateways = null;

        /// <summary>
        /// This event is raised when SIP proxy needs to know if specified request URI is local URI or remote URI.
        /// </summary>
        public event SIP_IsLocalUriEventHandler IsLocalUri = null;

        #endregion

        #region Members

        private readonly string m_Opaque = "";

        private SIP_ForkingMode m_ForkingMode = SIP_ForkingMode.Parallel;
        private bool m_IsDisposed;
        private SIP_B2BUA m_pB2BUA;
        internal List<SIP_ProxyContext> m_pProxyContexts;
        private SIP_Registrar m_pRegistrar;
        private SIP_ProxyMode m_ProxyMode = SIP_ProxyMode.Registrar | SIP_ProxyMode.Statefull;
        private SIP_Stack m_pStack;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get { return m_IsDisposed; }
        }

        /// <summary>
        /// Gets owner SIP stack.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public SIP_Stack Stack
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pStack;
            }
        }

        /// <summary>
        /// Gets or sets proxy mode.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        /// <exception cref="ArgumentException">Is raised when invalid combination modes passed.</exception>
        public SIP_ProxyMode ProxyMode
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_ProxyMode;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                // Check for invalid mode ()
                if ((value & SIP_ProxyMode.Statefull) != 0 && (value & SIP_ProxyMode.Stateless) != 0)
                {
                    throw new ArgumentException("Proxy can't be at Statefull and Stateless at same time !");
                }

                m_ProxyMode = value;
            }
        }

        /// <summary>
        /// Gets or sets how proxy handle forking. This property applies for statefull proxy only.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public SIP_ForkingMode ForkingMode
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_ForkingMode;
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                m_ForkingMode = value;
            }
        }

        /// <summary>
        /// Gets SIP registrar server.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public SIP_Registrar Registrar
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pRegistrar;
            }
        }

        /// <summary>
        /// Gets SIP B2BUA server.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public SIP_B2BUA B2BUA
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pB2BUA;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stack">Reference to SIP stack.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>sipStack</b> is null.</exception>
        public SIP_ProxyCore(SIP_Stack stack)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }

            m_pStack = stack;
            m_pStack.RequestReceived += m_pStack_RequestReceived;
            m_pStack.ResponseReceived += m_pStack_ResponseReceived;

            m_pRegistrar = new SIP_Registrar(this);
            m_pB2BUA = new SIP_B2BUA(this);
            m_Opaque = Auth_HttpDigest.CreateOpaque();
            m_pProxyContexts = new List<SIP_ProxyContext>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            m_IsDisposed = true;

            if (m_pStack != null)
            {
                m_pStack.Dispose();
                m_pStack = null;
            }
            m_pRegistrar = null;
            m_pB2BUA = null;
            m_pProxyContexts = null;
        }

        #endregion

        #region Event handlers

        /// <summary>
        /// This method is called when SIP stack receives new request.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pStack_RequestReceived(object sender, SIP_RequestReceivedEventArgs e)
        {
            OnRequestReceived(e);
        }

        /// <summary>
        /// This method is called when SIP stack receives new response.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pStack_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            OnResponseReceived(e);
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// This method is called when new request is received.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        private void OnRequestReceived(SIP_RequestReceivedEventArgs e)
        {
            /* RFC 3261 16.12. ????????? Forward does all thse steps.
                1. The proxy will inspect the Request-URI.  If it indicates a
                   resource owned by this proxy, the proxy will replace it with
                   the results of running a location service.  Otherwise, the
                   proxy will not change the Request-URI.

                2. The proxy will inspect the URI in the topmost Route header
                   field value.  If it indicates this proxy, the proxy removes it
                   from the Route header field (this route node has been reached).

                3. The proxy will forward the request to the resource indicated
                   by the URI in the topmost Route header field value or in the
                   Request-URI if no Route header field is present.  The proxy
                   determines the address, port and transport to use when
                   forwarding the request by applying the procedures in [4] to that URI.
            */

            SIP_Request request = e.Request;
            try
            {
                #region Registrar

                // Registrar
                if ((m_ProxyMode & SIP_ProxyMode.Registrar) != 0 &&
                    request.RequestLine.Method == SIP_Methods.REGISTER)
                {
                    m_pRegistrar.Register(e);
                }

                    #endregion

                    #region Presence
                    /*
                // Presence
                else if((m_ProxyMode & SIP_ProxyMode.Presence) != 0 && (request.Method == "SUBSCRIBE" || request.Method == "NOTIFY")){

                }
*/
                    #endregion

                    #region Statefull

                    // Statefull
                else if ((m_ProxyMode & SIP_ProxyMode.Statefull) != 0)
                {
                    // Statefull proxy is transaction statefull proxy only, 
                    // what don't create dialogs and keep dialog state.

                    /* RFC 3261 16.10.
                        StateFull proxy:
	                        If a matching response context is found, the element MUST
	                        immediately return a 200 (OK) response to the CANCEL request. 

	                        If a response context is not found, the element does not have any
	                        knowledge of the request to apply the CANCEL to.  It MUST statelessly
	                        forward the CANCEL request (it may have statelessly forwarded the
	                        associated request previously).
                    */
                    if (e.Request.RequestLine.Method == SIP_Methods.CANCEL)
                    {
                        // Don't do server transaction before we get CANCEL matching transaction.
                        SIP_ServerTransaction trToCancel =
                            m_pStack.TransactionLayer.MatchCancelToTransaction(e.Request);
                        if (trToCancel != null)
                        {
                            trToCancel.Cancel();
                            e.ServerTransaction.SendResponse(m_pStack.CreateResponse(
                                                                 SIP_ResponseCodes.x200_Ok, request));
                        }
                        else
                        {
                            ForwardRequest(false, e);
                        }
                    }
                        // ACK never creates transaction, it's always passed directly to transport layer.
                    else if (e.Request.RequestLine.Method == SIP_Methods.ACK)
                    {
                        ForwardRequest(false, e);
                    }
                    else
                    {
                        ForwardRequest(true, e);
                    }
                }

                    #endregion
                
                    #region B2BUA
                
                    // B2BUA
                else if ((m_ProxyMode & SIP_ProxyMode.B2BUA) != 0)
                {
                    m_pB2BUA.OnRequestReceived(e);
                }

                    #endregion

                    #region Stateless

                    // Stateless
                else if ((m_ProxyMode & SIP_ProxyMode.Stateless) != 0)
                {
                    // Stateless proxy don't do transaction, just forwards all.
                    ForwardRequest(false, e);
                }

                    #endregion

                    #region Proxy won't accept command

                else
                {
                    e.ServerTransaction.SendResponse(
                        m_pStack.CreateResponse(SIP_ResponseCodes.x501_Not_Implemented, request));
                }

                #endregion
            }
            catch (Exception x)
            {
                try
                {
                    m_pStack.TransportLayer.SendResponse(
                        m_pStack.CreateResponse(
                            SIP_ResponseCodes.x500_Server_Internal_Error + ": " + x.Message, e.Request));
                }
                catch
                {
                    // Skip transport layer exception if send fails.
                }

                // Don't raise OnError for transport errors.
                if (!(x is SIP_TransportException))
                {
                    m_pStack.OnError(x);
                }
            }
        }

        /// <summary>
        /// This method is called when new response is received.
        /// </summary>
        /// <param name="e">Response event arguments.</param>
        private void OnResponseReceived(SIP_ResponseReceivedEventArgs e)
        {
            if ((m_ProxyMode & SIP_ProxyMode.B2BUA) != 0)
            {
                m_pB2BUA.OnResponseReceived(e);
            }
            else
            {
                /* This method is called when stateless proxy gets response or statefull proxy
                   has no matching server transaction.
                */

                /* RFC 3261 16.11.
                    When a response arrives at a stateless proxy, the proxy MUST inspect the sent-by 
                    value in the first (topmost) Via header field value. If that address matches the proxy,
                    (it equals a value this proxy has inserted into previous requests) the proxy MUST 
                    remove that header field value from the response and forward the result to the 
                    location indicated in the next Via header field value.
                */
                // Just remove topmost Via:, sent-by check is done in transport layer.
                e.Response.Via.RemoveTopMostValue();

                if ((m_ProxyMode & SIP_ProxyMode.Statefull) != 0)
                {
                    // We should not reach here. This happens when no matching client transaction found.
                    // RFC 3161 18.1.2 orders to forward them statelessly.
                    m_pStack.TransportLayer.SendResponse(e.Response);
                }
                else if ((m_ProxyMode & SIP_ProxyMode.Stateless) != 0)
                {
                    m_pStack.TransportLayer.SendResponse(e.Response);
                }
            }
        }

        /// <summary>
        /// Forwards specified request to destination recipient.
        /// </summary>
        /// <param name="statefull">Specifies if request is sent statefully or statelessly.</param>
        /// <param name="e">Request event arguments.</param>
        private void ForwardRequest(bool statefull, SIP_RequestReceivedEventArgs e)
        {
            ForwardRequest(statefull, e, e.Request, true);
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Forwards specified request to target recipient.
        /// </summary>
        /// <param name="statefull">Specifies if request is sent statefully or statelessly.</param>
        /// <param name="e">Request event arguments.</param>
        /// <param name="request">SIP request to forward.</param>
        /// <param name="addRecordRoute">Specifies if Record-Route header filed is added.</param>
        internal void ForwardRequest(bool statefull,
                                     SIP_RequestReceivedEventArgs e,
                                     SIP_Request request,
                                     bool addRecordRoute)
        {
            List<SIP_ProxyTarget> targetSet = new List<SIP_ProxyTarget>();
            List<NetworkCredential> credentials = new List<NetworkCredential>();
            SIP_Uri route = null;

            /* RFC 3261 16.
                1. Validate the request (Section 16.3)
                    1. Reasonable Syntax
                    2. URI scheme
                    3. Max-Forwards
                    4. (Optional) Loop Detection
                    5. Proxy-Require
                    6. Proxy-Authorization
                2. Preprocess routing information (Section 16.4)
                3. Determine target(s) for the request (Section 16.5)
                4. Forward the request (Section 16.6)
            */

            #region 1. Validate the request (Section 16.3)

            // 1.1 Reasonable Syntax.
            //      SIP_Message will do it.

            // 1.2 URI scheme check.
            if (!SIP_Utils.IsSipOrSipsUri(request.RequestLine.Uri.ToString()))
            {
                // TODO:
                SIP_GatewayEventArgs eArgs = OnGetGateways("uriScheme", "userName");
                // No suitable gateway or authenticated user has no access.
                if (eArgs.Gateways.Count == 0)
                {
                    e.ServerTransaction.SendResponse(
                        m_pStack.CreateResponse(SIP_ResponseCodes.x416_Unsupported_URI_Scheme, e.Request));
                    return;
                }
            }

            // 1.3 Max-Forwards.
            if (request.MaxForwards <= 0)
            {
                e.ServerTransaction.SendResponse(m_pStack.CreateResponse(
                                                     SIP_ResponseCodes.x483_Too_Many_Hops, request));
                return;
            }

            // 1.4 (Optional) Loop Detection.
            //      Skip.

            // 1.5 Proxy-Require.
            //      TODO:

            // 1.6 Proxy-Authorization.
            // We need to auth all foreign calls.            
            if (!SIP_Utils.IsSipOrSipsUri(request.RequestLine.Uri.ToString()) ||
                !OnIsLocalUri(((SIP_Uri) request.RequestLine.Uri).Host))
            {
                // We need to pass-through ACK.
                if (request.RequestLine.Method == SIP_Methods.ACK) {}
                else if (!AuthenticateRequest(e))
                {
                    return;
                }
            }

            #endregion

            #region 2. Preprocess routing information (Section 16.4).

            /*
                The proxy MUST inspect the Request-URI of the request.  If the
                Request-URI of the request contains a value this proxy previously
                placed into a Record-Route header field (see Section 16.6 item 4),
                the proxy MUST replace the Request-URI in the request with the last
                value from the Route header field, and remove that value from the
                Route header field.  The proxy MUST then proceed as if it received
                this modified request.
             
                If the first value in the Route header field indicates this proxy,
                the proxy MUST remove that value from the request.
            */

            // Strict route.
            if (SIP_Utils.IsSipOrSipsUri(request.RequestLine.Uri.ToString()) &&
                IsLocalRoute(((SIP_Uri) request.RequestLine.Uri)))
            {
                request.RequestLine.Uri =
                    request.Route.GetAllValues()[request.Route.GetAllValues().Length - 1].Address.Uri;
                SIP_t_AddressParam[] routes = request.Route.GetAllValues();
                route = (SIP_Uri) routes[routes.Length - 1].Address.Uri;
                request.Route.RemoveLastValue();
            }
                // Loose route.
            else if (request.Route.GetAllValues().Length > 0 &&
                     IsLocalRoute(SIP_Uri.Parse(request.Route.GetTopMostValue().Address.Uri.ToString())))
            {
                route = (SIP_Uri) request.Route.GetTopMostValue().Address.Uri;
                request.Route.RemoveTopMostValue();
            }

            #endregion

            #region 3. Determine target(s) for the request (Section 16.5)

            /* 3. Determine target(s) for the request (Section 16.5)
                    Next, the proxy calculates the target(s) of the request.  The set of
                    targets will either be predetermined by the contents of the request
                    or will be obtained from an abstract location service.  Each target
                    in the set is represented as a URI.
             
                    If the domain of the Request-URI indicates a domain this element is
                    not responsible for, the Request-URI MUST be placed into the target
                    set as the only target, and the element MUST proceed to the task of
                    Request Forwarding (Section 16.6).
              
                    If the target set for the request has not been predetermined as
                    described above, this implies that the element is responsible for the
                    domain in the Request-URI, and the element MAY use whatever mechanism
                    it desires to determine where to send the request.  Any of these
                    mechanisms can be modeled as accessing an abstract Location Service.
                    This may consist of obtaining information from a location service
                    created by a SIP Registrar, reading a database, consulting a presence
                    server, utilizing other protocols, or simply performing an
                    algorithmic substitution on the Request-URI.  When accessing the
                    location service constructed by a registrar, the Request-URI MUST
                    first be canonicalized as described in Section 10.3 before being used
                    as an index.  The output of these mechanisms is used to construct the
                    target set.
            */

            // Non-SIP
            // Foreign SIP
            // Local SIP

            // FIX ME: we may have tel: here
            SIP_Uri requestUri = (SIP_Uri) e.Request.RequestLine.Uri;

            // Proxy is not responsible for the domain in the Request-URI.
            if (!OnIsLocalUri(requestUri.Host))
            {
                /* NAT traversal.
                    When we do record routing, store request sender flow info and request target flow info.
                    Now the tricky part, how proxy later which flow is target (because both sides can send requests).
                      Sender-flow will store from-tag to flow and target-flow will store flowID only (Because we don't know to-tag).
                      Later if request to-tag matches(incoming request), use that flow, otherwise(outgoing request) other flow.
                 
                    flowInfo: sender-flow "/" target-flow
                              sender-flow = from-tag ":" flowID
                              target-flow = flowID                        
                */

                SIP_Flow targetFlow = null;
                string flowInfo = (route != null && route.Parameters["flowInfo"] != null)
                                      ? route.Parameters["flowInfo"].Value
                                      : null;
                if (flowInfo != null && request.To.Tag != null)
                {
                    string flow1Tag = flowInfo.Substring(0, flowInfo.IndexOf(':'));
                    string flow1ID = flowInfo.Substring(flowInfo.IndexOf(':') + 1,
                                                        flowInfo.IndexOf('/') - flowInfo.IndexOf(':') - 1);
                    string flow2ID = flowInfo.Substring(flowInfo.IndexOf('/') + 1);

                    if (flow1Tag == request.To.Tag)
                    {
                        targetFlow = m_pStack.TransportLayer.GetFlow(flow1ID);
                    }
                    else
                    {
                        ;
                        targetFlow = m_pStack.TransportLayer.GetFlow(flow2ID);
                    }
                }

                targetSet.Add(new SIP_ProxyTarget(requestUri, targetFlow));
            }
                // Proxy is responsible for the domain in the Request-URI.
            else
            {
                // TODO: tel:
                //SIP_Uri requestUri = SIP_Uri.Parse(e.Request.Uri);

                // Try to get AOR from registrar.
                SIP_Registration registration = m_pRegistrar.GetRegistration(requestUri.Address);

                // We have AOR specified in request-URI in registrar server.
                if (registration != null)
                {
                    // Add all AOR SIP contacts to target set.
                    foreach (SIP_RegistrationBinding binding in registration.Bindings)
                    {
                        if (binding.ContactURI is SIP_Uri && binding.TTL > 0)
                        {
                            targetSet.Add(new SIP_ProxyTarget((SIP_Uri) binding.ContactURI, binding.Flow));
                        }
                    }
                }
                    // We don't have AOR specified in request-URI in registrar server.
                else
                {
                    // If the Request-URI indicates a resource at this proxy that does not
                    // exist, the proxy MUST return a 404 (Not Found) response.                    
                    if (!OnAddressExists(requestUri.Address))
                    {
                        e.ServerTransaction.SendResponse(
                            m_pStack.CreateResponse(SIP_ResponseCodes.x404_Not_Found, e.Request));
                        return;
                    }
                }
            }

            // If the target set remains empty after applying all of the above, the proxy MUST return an error response, 
            // which SHOULD be the 480 (Temporarily Unavailable) response.
            if (targetSet.Count == 0)
            {
                e.ServerTransaction.SendResponse(
                    m_pStack.CreateResponse(SIP_ResponseCodes.x480_Temporarily_Unavailable, e.Request));
                return;
            }

            #endregion

            #region 4. Forward the request (Section 16.6)

            #region Statefull

            if (statefull)
            {
                // Create proxy context that will be responsible for forwarding request.
                SIP_ProxyContext proxyContext = new SIP_ProxyContext(this,
                                                                     e.ServerTransaction,
                                                                     request,
                                                                     addRecordRoute,
                                                                     m_ForkingMode,
                                                                     (ProxyMode & SIP_ProxyMode.B2BUA) != 0,
                                                                     false,
                                                                     false,
                                                                     targetSet.ToArray(),
                                                                     credentials.ToArray());
                m_pProxyContexts.Add(proxyContext);
                proxyContext.Start();
            }

                #endregion

                #region Stateless

            else
            {
                /* RFC 3261 16.6 Request Forwarding.
                For each target, the proxy forwards the request following these steps:
                    1.  Make a copy of the received request
                    2.  Update the Request-URI
                    3.  Update the Max-Forwards header field
                    4.  Optionally add a Record-route header field value
                    5.  Optionally add additional header fields
                    6.  Postprocess routing information
                    7.  Determine the next-hop address, port, and transport
                    8.  Add a Via header field value
                    9.  Add a Content-Length header field if necessary
                    10. Forward the new request
                */

                /* RFC 3261 16.11 Stateless Proxy.                 
                    o  A stateless proxy MUST choose one and only one target from the target set. This choice 
                       MUST only rely on fields in the message and time-invariant properties of the server. In
                       particular, a retransmitted request MUST be forwarded to the same destination each time 
                       it is processed. Furthermore, CANCEL and non-Routed ACK requests MUST generate the same
                       choice as their associated INVITE.
                 
                    However, a stateless proxy cannot simply use a random number generator to compute
                    the first component of the branch ID, as described in Section 16.6 bullet 8.
                    This is because retransmissions of a request need to have the same value, and 
                    a stateless proxy cannot tell a retransmission from the original request.
                
                    We just use: "z9hG4bK-" + md5(topmost branch)                
                */

                bool isStrictRoute = false;
                SIP_Hop[] hops = null;

                #region 1.  Make a copy of the received request

                SIP_Request forwardRequest = request.Copy();

                #endregion

                #region 2.  Update the Request-URI

                forwardRequest.RequestLine.Uri = targetSet[0].TargetUri;

                #endregion

                #region 3.  Update the Max-Forwards header field

                forwardRequest.MaxForwards--;

                #endregion

                #region 4.  Optionally add a Record-route header field value

                #endregion

                #region 5.  Optionally add additional header fields

                #endregion

                #region 6.  Postprocess routing information

                /* 6. Postprocess routing information.
             
                    If the copy contains a Route header field, the proxy MUST inspect the URI in its first value.  
                    If that URI does not contain an lr parameter, the proxy MUST modify the copy as follows:             
                        - The proxy MUST place the Request-URI into the Route header
                          field as the last value.
             
                        - The proxy MUST then place the first Route header field value
                          into the Request-URI and remove that value from the Route header field.
                */
                if (forwardRequest.Route.GetAllValues().Length > 0 &&
                    !forwardRequest.Route.GetTopMostValue().Parameters.Contains("lr"))
                {
                    forwardRequest.Route.Add(forwardRequest.RequestLine.Uri.ToString());

                    forwardRequest.RequestLine.Uri =
                        SIP_Utils.UriToRequestUri(forwardRequest.Route.GetTopMostValue().Address.Uri);
                    forwardRequest.Route.RemoveTopMostValue();

                    isStrictRoute = true;
                }

                #endregion

                #region 7.  Determine the next-hop address, port, and transport

                /* 7. Determine the next-hop address, port, and transport.
                      The proxy MAY have a local policy to send the request to a
                      specific IP address, port, and transport, independent of the
                      values of the Route and Request-URI.  Such a policy MUST NOT be
                      used if the proxy is not certain that the IP address, port, and
                      transport correspond to a server that is a loose router.
                      However, this mechanism for sending the request through a
                      specific next hop is NOT RECOMMENDED; instead a Route header
                      field should be used for that purpose as described above.
             
                      In the absence of such an overriding mechanism, the proxy
                      applies the procedures listed in [4] as follows to determine
                      where to send the request.  If the proxy has reformatted the
                      request to send to a strict-routing element as described in
                      step 6 above, the proxy MUST apply those procedures to the
                      Request-URI of the request.  Otherwise, the proxy MUST apply
                      the procedures to the first value in the Route header field, if
                      present, else the Request-URI.  The procedures will produce an
                      ordered set of (address, port, transport) tuples.
                      Independently of which URI is being used as input to the
                      procedures of [4], if the Request-URI specifies a SIPS
                      resource, the proxy MUST follow the procedures of [4] as if the
                      input URI were a SIPS URI.

                      As described in [4], the proxy MUST attempt to deliver the
                      message to the first tuple in that set, and proceed through the
                      set in order until the delivery attempt succeeds.

                      For each tuple attempted, the proxy MUST format the message as
                      appropriate for the tuple and send the request using a new
                      client transaction as detailed in steps 8 through 10.
             
                      Since each attempt uses a new client transaction, it represents
                      a new branch.  Thus, the branch parameter provided with the Via
                      header field inserted in step 8 MUST be different for each
                      attempt.

                      If the client transaction reports failure to send the request
                      or a timeout from its state machine, the proxy continues to the
                      next address in that ordered set.  If the ordered set is
                      exhausted, the request cannot be forwarded to this element in
                      the target set.  The proxy does not need to place anything in
                      the response context, but otherwise acts as if this element of
                      the target set returned a 408 (Request Timeout) final response.
                */
                SIP_Uri uri = null;
                if (isStrictRoute)
                {
                    uri = (SIP_Uri) forwardRequest.RequestLine.Uri;
                }
                else if (forwardRequest.Route.GetTopMostValue() != null)
                {
                    uri = (SIP_Uri) forwardRequest.Route.GetTopMostValue().Address.Uri;
                }
                else
                {
                    uri = (SIP_Uri) forwardRequest.RequestLine.Uri;
                }

                hops = m_pStack.GetHops(uri,
                                        forwardRequest.ToByteData().Length,
                                        ((SIP_Uri) forwardRequest.RequestLine.Uri).IsSecure);

                if (hops.Length == 0)
                {
                    if (forwardRequest.RequestLine.Method != SIP_Methods.ACK)
                    {
                        e.ServerTransaction.SendResponse(
                            m_pStack.CreateResponse(
                                SIP_ResponseCodes.x503_Service_Unavailable + ": No hop(s) for target.",
                                forwardRequest));
                    }

                    return;
                }

                #endregion

                #region 8.  Add a Via header field value

                forwardRequest.Via.AddToTop(
                    "SIP/2.0/transport-tl-addign sentBy-tl-assign-it;branch=z9hG4bK-" +
                    Core.ComputeMd5(request.Via.GetTopMostValue().Branch, true));

                // Add 'flowID' what received request, you should use the same flow to send response back.
                // For more info see RFC 3261 18.2.2.
                forwardRequest.Via.GetTopMostValue().Parameters.Add("flowID", request.Flow.ID);

                #endregion

                #region 9.  Add a Content-Length header field if necessary

                // Skip, our SIP_Message class is smart and do it when ever it's needed.

                #endregion

                #region 10. Forward the new request

                try
                {
                    try
                    {
                        if (targetSet[0].Flow != null)
                        {
                            m_pStack.TransportLayer.SendRequest(targetSet[0].Flow, request);

                            return;
                        }
                    }
                    catch
                    {
                        m_pStack.TransportLayer.SendRequest(request, null, hops[0]);
                    }
                }
                catch (SIP_TransportException x)
                {
                    string dummy = x.Message;

                    if (forwardRequest.RequestLine.Method != SIP_Methods.ACK)
                    {
                        /* RFC 3261 16.9 Handling Transport Errors
                            If the transport layer notifies a proxy of an error when it tries to
                            forward a request (see Section 18.4), the proxy MUST behave as if the
                            forwarded request received a 503 (Service Unavailable) response.
                        */
                        e.ServerTransaction.SendResponse(
                            m_pStack.CreateResponse(
                                SIP_ResponseCodes.x503_Service_Unavailable + ": Transport error.",
                                forwardRequest));
                    }
                }

                #endregion
            }

            #endregion

            #endregion
        }

        /// <summary>
        /// Authenticates SIP request. This method also sends all needed replys to request sender.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        /// <returns>Returns true if request was authenticated.</returns>
        internal bool AuthenticateRequest(SIP_RequestReceivedEventArgs e)
        {
            string userName = null;
            return AuthenticateRequest(e, out userName);
        }

        /// <summary>
        /// Authenticates SIP request. This method also sends all needed replys to request sender.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        /// <param name="userName">If authentication sucessful, then authenticated user name is stored to this variable.</param>
        /// <returns>Returns true if request was authenticated.</returns>
        internal bool AuthenticateRequest(SIP_RequestReceivedEventArgs e, out string userName)
        {
            userName = null;

            SIP_t_Credentials credentials = SIP_Utils.GetCredentials(e.Request, m_pStack.Realm);
            // No credentials for our realm.
            if (credentials == null)
            {
                SIP_Response notAuthenticatedResponse =
                    m_pStack.CreateResponse(SIP_ResponseCodes.x407_Proxy_Authentication_Required, e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(
                    new Auth_HttpDigest(m_pStack.Realm, m_pStack.DigestNonceManager.CreateNonce(), m_Opaque).
                        ToChallange());

                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }

            Auth_HttpDigest auth = new Auth_HttpDigest(credentials.AuthData, e.Request.RequestLine.Method);
            // Check opaque validity.
            if (auth.Opaque != m_Opaque)
            {
                SIP_Response notAuthenticatedResponse =
                    m_pStack.CreateResponse(
                        SIP_ResponseCodes.x407_Proxy_Authentication_Required + ": Opaque value won't match !",
                        e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(
                    new Auth_HttpDigest(m_pStack.Realm, m_pStack.DigestNonceManager.CreateNonce(), m_Opaque).
                        ToChallange());

                // Send response
                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }
            // Check nonce validity.
            if (!m_pStack.DigestNonceManager.NonceExists(auth.Nonce))
            {
                SIP_Response notAuthenticatedResponse =
                    m_pStack.CreateResponse(
                        SIP_ResponseCodes.x407_Proxy_Authentication_Required + ": Invalid nonce value !",
                        e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(
                    new Auth_HttpDigest(m_pStack.Realm, m_pStack.DigestNonceManager.CreateNonce(), m_Opaque).
                        ToChallange());

                // Send response
                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }
                // Valid nonce, consume it so that nonce can't be used any more. 
            else
            {
                m_pStack.DigestNonceManager.RemoveNonce(auth.Nonce);
            }

            SIP_AuthenticateEventArgs eArgs = OnAuthenticate(auth);
            // Authenticate failed.
            if (!eArgs.Authenticated)
            {
                SIP_Response notAuthenticatedResponse =
                    m_pStack.CreateResponse(
                        SIP_ResponseCodes.x407_Proxy_Authentication_Required + ": Authentication failed.",
                        e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(
                    new Auth_HttpDigest(m_pStack.Realm, m_pStack.DigestNonceManager.CreateNonce(), m_Opaque).
                        ToChallange());

                // Send response
                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }

            userName = auth.UserName;

            return true;
        }

        /// <summary>
        /// Gets if this proxy server is responsible for specified route.
        /// </summary>
        /// <param name="uri">Route value to check.</param>
        /// <returns>Returns trues if server route, otherwise false.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>uri</b> is null reference.</exception>
        internal bool IsLocalRoute(SIP_Uri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }

            // Not a route.
            if (uri.User != null)
            {
                return false;
            }

            // Consider any IP address as local route, because if server behind NAT we can't do IP check.
            if (Net_Utils.IsIPAddress(uri.Host))
            {
                return true;
            }
            else
            {
                foreach (IPBindInfo bind in m_pStack.BindInfo)
                {
                    if (uri.Host.ToLower() == bind.HostName.ToLower())
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        // REMOVE ME:

        /*
        /// <summary>
        /// Creates new Contact header field for b2bua forward request.
        /// </summary>
        /// <param name="address">Address.</param>
        /// <returns>Returns new Contact value.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>address</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        internal SIP_t_NameAddress CreateContactX(SIP_t_NameAddress address)
        {
            if(address == null){
                throw new ArgumentNullException("address");
            }

            if(address.IsSipOrSipsUri){
                SIP_Uri uri = SIP_Uri.Parse(address.Uri.ToString());
                uri.Host = m_pStack.TransportLayer.GetEndPoint(address.Uri);
                uri.Port = -1;

                SIP_t_NameAddress contact = new SIP_t_NameAddress();
                contact.Uri = uri;

                return contact;
            }
            else{
                throw new ArgumentException("Not SIP URI !");
            }
        }*/

        /// <summary>
        /// Raises 'IsLocalUri' event.
        /// </summary>
        /// <param name="uri">Request URI.</param>
        /// <returns>Returns true if server local URI, otherwise false.</returns>
        internal bool OnIsLocalUri(string uri)
        {
            if (IsLocalUri != null)
            {
                return IsLocalUri(uri);
            }

            return true;
        }

        /// <summary>
        /// Is called by SIP proxy or registrar server when it needs to authenticate user.
        /// </summary>
        /// <param name="auth">Authentication context.</param>
        /// <returns></returns>
        internal SIP_AuthenticateEventArgs OnAuthenticate(Auth_HttpDigest auth)
        {
            SIP_AuthenticateEventArgs eArgs = new SIP_AuthenticateEventArgs(auth);
            if (Authenticate != null)
            {
                Authenticate(eArgs);
            }

            return eArgs;
        }

        /// <summary>
        /// Is called by SIP proxy if it needs to check if specified address exists.
        /// </summary>
        /// <param name="address">SIP address to check.</param>
        /// <returns>Returns true if specified address exists, otherwise false.</returns>
        internal bool OnAddressExists(string address)
        {
            if (AddressExists != null)
            {
                return AddressExists(address);
            }

            return false;
        }

        #endregion

        /// <summary>
        /// Is called by SIP proxy when SIP proxy needs to get gateways for non-SIP URI.
        /// </summary>
        /// <param name="uriScheme">Non-SIP URI scheme which gateways to get.</param>
        /// <param name="userName">Authenticated user name.</param>
        /// <returns>Returns event data.</returns>
        protected SIP_GatewayEventArgs OnGetGateways(string uriScheme, string userName)
        {
            SIP_GatewayEventArgs e = new SIP_GatewayEventArgs(uriScheme, userName);
            if (GetGateways != null)
            {
                GetGateways(e);
            }
            return e;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Classes/ContactPhotoManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;

using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Threading.Workers;
using ASC.Data.Storage;
using ASC.Web.Core;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.CRM.Configuration;
using ASC.Web.CRM.Resources;

namespace ASC.Web.CRM.Classes
{
    public class ResizeWorkerItem
    {
        public int ContactID { get; set; }

        public bool UploadOnly { get; set; }

        public String TmpDirName { get; set; }

        public Size[] RequireFotoSize { get; set; }

        public byte[] ImageData { get; set; }

        public IDataStore DataStore { get; set; }

        public override bool Equals(object obj)
        {
            if (!(obj is ResizeWorkerItem)) return false;

            var item = (ResizeWorkerItem)obj;

            return item.ContactID.Equals(ContactID) && RequireFotoSize.Equals(item.RequireFotoSize) && ImageData.Length == item.ImageData.Length;
        }

        public override int GetHashCode()
        {
            return ContactID ^ RequireFotoSize.GetHashCode() ^ ImageData.Length;
        }
    }

    public static class ContactPhotoManager
    {
        #region Members

        private const string PhotosBaseDirName = "photos";
        private const string PhotosDefaultTmpDirName = "temp";

        private static readonly Dictionary<int, IDictionary<Size, string>> _photoCache = new Dictionary<int, IDictionary<Size, string>>();

        private static readonly WorkerQueue<ResizeWorkerItem> ResizeQueue = new WorkerQueue<ResizeWorkerItem>(2, TimeSpan.FromSeconds(30), 1, true);
        private static readonly ICacheNotify cachyNotify;

        private static readonly Size _oldBigSize = new Size(145, 145);

        private static readonly Size _bigSize = new Size(200, 200);
        private static readonly Size _mediumSize = new Size(82, 82);
        private static readonly Size _smallSize = new Size(40, 40);

        private static readonly object locker = new object();

        #endregion

        #region Cache and DataStore Methods

        static ContactPhotoManager()
        {
            cachyNotify = AscCache.Notify;
            cachyNotify.Subscribe<KeyValuePair<int, KeyValuePair<Size, string>>>(
                (item, action) =>
                {
                    var contactID = item.Key;
                    var sizeUriPair = item.Value;

                    switch (action)
                    {
                        case CacheNotifyAction.InsertOrUpdate:
                            ToPrivateCache(contactID, sizeUriPair.Value, sizeUriPair.Key);
                            break;
                        case CacheNotifyAction.Remove:
                            RemoveFromPrivateCache(contactID);
                            break;
                    }
                });
        }

        private static String FromCache(int contactID, Size photoSize)
        {
            lock (locker)
            {
                if (_photoCache.ContainsKey(contactID))
                {
                    if (_photoCache[contactID].ContainsKey(photoSize))
                    {
                        return _photoCache[contactID][photoSize];
                    }
                    if (photoSize == _bigSize && _photoCache[contactID].ContainsKey(_oldBigSize))
                    {
                        return _photoCache[contactID][_oldBigSize];
                    }
                }
            }
            return String.Empty;
        }

        private static void RemoveFromCache(int contactID)
        {
            cachyNotify.Publish(CreateCacheItem(contactID, "", Size.Empty), CacheNotifyAction.Remove);
        }

        private static void RemoveFromPrivateCache(int contactID)
        {
            lock (locker)
            {
                _photoCache.Remove(contactID);
            }
        }

        private static void ToCache(int contactID, String photoUri, Size photoSize)
        {
            cachyNotify.Publish(CreateCacheItem(contactID, photoUri, photoSize), CacheNotifyAction.InsertOrUpdate);
        }

        private static void ToPrivateCache(int contactID, String photoUri, Size photoSize)
        {
            lock (locker)
            {
                if (_photoCache.ContainsKey(contactID))
                    if (_photoCache[contactID].ContainsKey(photoSize))
                        _photoCache[contactID][photoSize] = photoUri;
                    else
                        _photoCache[contactID].Add(photoSize, photoUri);
                else
                    _photoCache.Add(contactID, new Dictionary<Size, string> { { photoSize, photoUri } });
            }
        }

        private static KeyValuePair<int, KeyValuePair<Size, string>> CreateCacheItem(int contactID, String photoUri, Size photoSize)
        {
            var sizeUriPair = new KeyValuePair<Size, string>(photoSize, photoUri);
            return new KeyValuePair<int, KeyValuePair<Size, string>>(contactID, sizeUriPair);
        }

        private static String FromDataStore(int contactID, Size photoSize)
        {
            return FromDataStore(contactID, photoSize, false, null);
        }

        private static String FromDataStore(int contactID, Size photoSize, Boolean isTmpDir, String tmpDirName)
        {
            var directoryPath = !isTmpDir
                                    ? BuildFileDirectory(contactID)
                                    : (String.IsNullOrEmpty(tmpDirName) ? BuildFileTmpDirectory(contactID) : BuildFileTmpDirectory(tmpDirName));

            var filesURI = Global.GetStore().ListFiles(directoryPath, BuildFileName(contactID, photoSize) + "*", false);

            if (filesURI.Length == 0 && photoSize == _bigSize)
            {
                filesURI = Global.GetStore().ListFiles(directoryPath, BuildFileName(contactID, _oldBigSize) + "*", false);
            }

            if (filesURI.Length == 0)
            {
                return String.Empty;
            }

            return filesURI[0].ToString();
        }

        private static String FromDataStoreRelative(int contactID, Size photoSize, Boolean isTmpDir, String tmpDirName)
        {
            var directoryPath = !isTmpDir
                                    ? BuildFileDirectory(contactID)
                                    : (String.IsNullOrEmpty(tmpDirName) ? BuildFileTmpDirectory(contactID) : BuildFileTmpDirectory(tmpDirName));

            var filesPaths = Global.GetStore().ListFilesRelative("", directoryPath, BuildFileName(contactID, photoSize) + "*", false);

            if (filesPaths.Length == 0 && photoSize == _bigSize)
            {
                filesPaths = Global.GetStore().ListFilesRelative("", directoryPath, BuildFileName(contactID, _oldBigSize) + "*", false);
            }

            if (filesPaths.Length == 0)
            {
                return String.Empty;
            }

            return Path.Combine(directoryPath, filesPaths[0]);
        }

        private static PhotoData FromDataStore(Size photoSize, String tmpDirName)
        {
            var directoryPath = BuildFileTmpDirectory(tmpDirName);

            if (!Global.GetStore().IsDirectory(directoryPath))
                return null;

            var filesURI = Global.GetStore().ListFiles(directoryPath, BuildFileName(0, photoSize) + "*", false);

            if (filesURI.Length == 0) return null;

            return new PhotoData { Url = filesURI[0].ToString(), Path = tmpDirName };
        }

        #endregion

        #region Private Methods

        private static String GetPhotoUri(int contactID, bool isCompany, Size photoSize)
        {
            var photoUri = FromCache(contactID, photoSize);

            if (!String.IsNullOrEmpty(photoUri)) return photoUri;

            photoUri = FromDataStore(contactID, photoSize);

            if (String.IsNullOrEmpty(photoUri))
                photoUri = GetDefaultPhoto(isCompany, photoSize);

            ToCache(contactID, photoUri, photoSize);

            return photoUri;
        }

        private static String BuildFileDirectory(int contactID)
        {
            var s = contactID.ToString("000000");

            return String.Concat(PhotosBaseDirName, "/", s.Substring(0, 2), "/",
                                 s.Substring(2, 2), "/",
                                 s.Substring(4), "/");
        }

        private static String BuildFileTmpDirectory(int contactID)
        {
            return String.Concat(BuildFileDirectory(contactID), PhotosDefaultTmpDirName, "/");
        }

        private static String BuildFileTmpDirectory(string tmpDirName)
        {
            return String.Concat(PhotosBaseDirName, "/", tmpDirName.TrimEnd('/'), "/");
        }

        private static String BuildFileName(int contactID, Size photoSize)
        {
            return String.Format("contact_{0}_{1}_{2}", contactID, photoSize.Width, photoSize.Height);
        }

        private static String BuildFilePath(int contactID, Size photoSize, String imageExtension)
        {
            if (photoSize.IsEmpty || contactID == 0)
                throw new ArgumentException();

            return String.Concat(BuildFileDirectory(contactID), BuildFileName(contactID, photoSize), imageExtension);
        }

        private static String BuildFileTmpPath(int contactID, Size photoSize, String imageExtension, String tmpDirName)
        {
            if (photoSize.IsEmpty || (contactID == 0 && String.IsNullOrEmpty(tmpDirName)))
                throw new ArgumentException();

            return String.Concat(
                String.IsNullOrEmpty(tmpDirName)
                    ? BuildFileTmpDirectory(contactID)
                    : BuildFileTmpDirectory(tmpDirName),
                BuildFileName(contactID, photoSize), imageExtension);
        }

        private static void ExecResizeImage(ResizeWorkerItem resizeWorkerItem)
        {
            foreach (var fotoSize in resizeWorkerItem.RequireFotoSize)
            {
                var data = resizeWorkerItem.ImageData;
                using (var stream = new MemoryStream(data))
                using (var img = new Bitmap(stream))
                {
                    var imgFormat = img.RawFormat;
                    if (fotoSize != img.Size)
                    {
                        using (var img2 = CommonPhotoManager.DoThumbnail(img, fotoSize, false, false, false))
                        {
                            data = CommonPhotoManager.SaveToBytes(img2, Global.GetImgFormatName(imgFormat));
                        }
                    }
                    else
                    {
                        data = Global.SaveToBytes(img);
                    }

                    var fileExtension = String.Concat("." + Global.GetImgFormatName(imgFormat));

                    var photoPath = !resizeWorkerItem.UploadOnly
                                        ? BuildFilePath(resizeWorkerItem.ContactID, fotoSize, fileExtension)
                                        : BuildFileTmpPath(resizeWorkerItem.ContactID, fotoSize, fileExtension, resizeWorkerItem.TmpDirName);

                    using (var fileStream = new MemoryStream(data))
                    {
                        var photoUri = resizeWorkerItem.DataStore.Save(photoPath, fileStream).ToString();
                        photoUri = String.Format("{0}?cd={1}", photoUri, DateTime.UtcNow.Ticks);

                        if (!resizeWorkerItem.UploadOnly)
                        {
                            ToCache(resizeWorkerItem.ContactID, photoUri, fotoSize);
                        }
                    }
                }
            }
        }

        private static String GetDefaultPhoto(bool isCompany, Size photoSize)
        {
            int contactID;

            if (isCompany)
                contactID = -1;
            else
                contactID = -2;

            var defaultPhotoUri = FromCache(contactID, photoSize);

            if (!String.IsNullOrEmpty(defaultPhotoUri)) return defaultPhotoUri;

            if (isCompany)
                defaultPhotoUri = WebImageSupplier.GetAbsoluteWebPath(String.Format("empty_company_logo_{0}_{1}.png", photoSize.Height, photoSize.Width), ProductEntryPoint.ID);
            else
                defaultPhotoUri = WebImageSupplier.GetAbsoluteWebPath(String.Format("empty_people_logo_{0}_{1}.png", photoSize.Height, photoSize.Width), ProductEntryPoint.ID);

            ToCache(contactID, defaultPhotoUri, photoSize);

            return defaultPhotoUri;
        }

        #endregion

        #region Delete Methods

        public static void DeletePhoto(int contactID)
        {
            DeletePhoto(contactID, false, null, true);
        }

        public static void DeletePhoto(int contactID, bool isTmpDir, string tmpDirName, bool recursive)
        {
            if (contactID == 0)
                throw new ArgumentException();

            lock (locker)
            {
                ResizeQueue.GetItems().Where(item => item.ContactID == contactID)
                           .All(item =>
                               {
                                   ResizeQueue.Remove(item);
                                   return true;
                               });

                var photoDirectory = !isTmpDir
                                         ? BuildFileDirectory(contactID)
                                         : (String.IsNullOrEmpty(tmpDirName) ? BuildFileTmpDirectory(contactID) : BuildFileTmpDirectory(tmpDirName));
                var store = Global.GetStore();

                if (store.IsDirectory(photoDirectory))
                {
                    store.DeleteFiles(photoDirectory, "*", recursive);
                    if (recursive)
                    {
                        store.DeleteDirectory(photoDirectory);
                    }
                }

                if (!isTmpDir)
                {
                    RemoveFromCache(contactID);
                }
            }
        }

        public static void DeletePhoto(string tmpDirName)
        {
            lock (locker)
            {

                var photoDirectory = BuildFileTmpDirectory(tmpDirName);
                var store = Global.GetStore();

                if (store.IsDirectory(photoDirectory))
                {
                    store.DeleteFiles(photoDirectory, "*", false);
                }
            }
        }

        #endregion

        public static void TryUploadPhotoFromTmp(int contactID, bool isNewContact, string tmpDirName)
        {
            var directoryPath = BuildFileDirectory(contactID);
            var dataStore = Global.GetStore();

            try
            {
                if (dataStore.IsDirectory(directoryPath))
                {
                    DeletePhoto(contactID, false, null, false);
                }
                foreach (var photoSize in new[] { _bigSize, _mediumSize, _smallSize })
                {
                    var photoTmpPath = FromDataStoreRelative(isNewContact ? 0 : contactID, photoSize, true, tmpDirName);
                    if (string.IsNullOrEmpty(photoTmpPath)) throw new Exception("Temp phono not found");

                    var imageExtension = Path.GetExtension(photoTmpPath);

                    var photoPath = String.Concat(directoryPath, BuildFileName(contactID, photoSize), imageExtension).TrimStart('/');

                    byte[] data;
                    using (var photoTmpStream = dataStore.GetReadStream(photoTmpPath))
                    {
                        data = Global.ToByteArray(photoTmpStream);
                    }
                    using (var fileStream = new MemoryStream(data))
                    {
                        var photoUri = dataStore.Save(photoPath, fileStream).ToString();
                        photoUri = String.Format("{0}?cd={1}", photoUri, DateTime.UtcNow.Ticks);
                        ToCache(contactID, photoUri, photoSize);
                    }
                }
                DeletePhoto(contactID, true, tmpDirName, true);
            }
            catch (Exception ex)
            {
                LogManager.GetLogger("ASC.CRM").ErrorFormat("TryUploadPhotoFromTmp for contactID={0} failed witth error: {1}", contactID, ex);
                return;
            }
        }

        #region Get Photo Methods

        public static String GetSmallSizePhoto(int contactID, bool isCompany)
        {
            if (contactID <= 0)
                return GetDefaultPhoto(isCompany, _smallSize);

            return GetPhotoUri(contactID, isCompany, _smallSize);
        }

        public static String GetMediumSizePhoto(int contactID, bool isCompany)
        {
            if (contactID <= 0)
                return GetDefaultPhoto(isCompany, _mediumSize);

            return GetPhotoUri(contactID, isCompany, _mediumSize);
        }

        public static String GetBigSizePhoto(int contactID, bool isCompany)
        {
            if (contactID <= 0)
                return GetDefaultPhoto(isCompany, _bigSize);

            return GetPhotoUri(contactID, isCompany, _bigSize);
        }

        #endregion

        private static PhotoData ResizeToBigSize(byte[] imageData, string tmpDirName)
        {
            return ResizeToBigSize(imageData, 0, true, tmpDirName);
        }

        private static PhotoData ResizeToBigSize(byte[] imageData, int contactID, bool uploadOnly, string tmpDirName)
        {
            var resizeWorkerItem = new ResizeWorkerItem
            {
                ContactID = contactID,
                UploadOnly = uploadOnly,
                RequireFotoSize = new[] { _bigSize },
                ImageData = imageData,
                DataStore = Global.GetStore(),
                TmpDirName = tmpDirName
            };

            ExecResizeImage(resizeWorkerItem);

            if (!uploadOnly)
            {
                return new PhotoData { Url = FromCache(contactID, _bigSize) };
            }
            else if (String.IsNullOrEmpty(tmpDirName))
            {
                return new PhotoData { Url = FromDataStore(contactID, _bigSize, true, null), Path = PhotosDefaultTmpDirName };
            }
            else
            {
                return FromDataStore(_bigSize, tmpDirName);
            }
        }

        private static void ExecGenerateThumbnail(byte[] imageData, int contactID, bool uploadOnly)
        {
            ExecGenerateThumbnail(imageData, contactID, uploadOnly, null);
        }

        private static void ExecGenerateThumbnail(byte[] imageData, string tmpDirName)
        {
            ExecGenerateThumbnail(imageData, 0, true, tmpDirName);
        }


        private static void ExecGenerateThumbnail(byte[] imageData, int contactID, bool uploadOnly, string tmpDirName)
        {
            var resizeWorkerItem = new ResizeWorkerItem
            {
                ContactID = contactID,
                UploadOnly = uploadOnly,
                RequireFotoSize = new[] { _mediumSize, _smallSize },
                ImageData = imageData,
                DataStore = Global.GetStore(),
                TmpDirName = tmpDirName
            };

            if (!ResizeQueue.GetItems().Contains(resizeWorkerItem))
                ResizeQueue.Add(resizeWorkerItem);

            if (!ResizeQueue.IsStarted) ResizeQueue.Start(ExecResizeImage);
        }

        private static byte[] ToByteArray(Stream inputStream, int streamLength)
        {
            using (var br = new BinaryReader(inputStream))
            {
                return br.ReadBytes(streamLength);
            }
        }

        #region UploadPhoto Methods

        public static PhotoData UploadPhoto(String imageUrl, int contactID, bool uploadOnly, bool checkFormat = true)
        {
            var request = (HttpWebRequest)WebRequest.Create(imageUrl);
            using (var response = request.GetResponse())
            {
                using (var inputStream = response.GetResponseStream())
                {
                    var imageData = ToByteArray(inputStream, (int)response.ContentLength);
                    return UploadPhoto(imageData, contactID, uploadOnly, checkFormat);
                }
            }
        }

        public static PhotoData UploadPhoto(Stream inputStream, int contactID, bool uploadOnly, bool checkFormat = true)
        {
            var imageData = Global.ToByteArray(inputStream);
            return UploadPhoto(imageData, contactID, uploadOnly, checkFormat);
        }

        public static PhotoData UploadPhoto(byte[] imageData, int contactID, bool uploadOnly, bool checkFormat = true)
        {
            if (contactID == 0)
                throw new ArgumentException();

            if (checkFormat)
                CheckImgFormat(imageData);

            DeletePhoto(contactID, uploadOnly, null, false);

            ExecGenerateThumbnail(imageData, contactID, uploadOnly);

            return ResizeToBigSize(imageData, contactID, uploadOnly, null);
        }


        public static PhotoData UploadPhotoToTemp(String imageUrl, String tmpDirName, bool checkFormat = true)
        {
            var request = (HttpWebRequest)WebRequest.Create(imageUrl);
            using (var response = request.GetResponse())
            {
                using (var inputStream = response.GetResponseStream())
                {
                    var imageData = ToByteArray(inputStream, (int)response.ContentLength);
                    if (string.IsNullOrEmpty(tmpDirName))
                    {
                        tmpDirName = Guid.NewGuid().ToString();
                    }
                    return UploadPhotoToTemp(imageData, tmpDirName, checkFormat);
                }
            }
        }

        public static PhotoData UploadPhotoToTemp(Stream inputStream, String tmpDirName, bool checkFormat = true)
        {
            var imageData = Global.ToByteArray(inputStream);
            return UploadPhotoToTemp(imageData, tmpDirName, checkFormat);
        }

        public static PhotoData UploadPhotoToTemp(byte[] imageData, String tmpDirName, bool checkFormat = true)
        {
            if (checkFormat)
                CheckImgFormat(imageData);

            DeletePhoto(tmpDirName);

            ExecGenerateThumbnail(imageData, tmpDirName);

            return ResizeToBigSize(imageData, tmpDirName);
        }

        public static ImageFormat CheckImgFormat(byte[] imageData)
        {
            using (var stream = new MemoryStream(imageData))
            using (var img = new Bitmap(stream))
            {
                var format = img.RawFormat;

                if (!format.Equals(ImageFormat.Png) && !format.Equals(ImageFormat.Jpeg))
                    throw new Exception(CRMJSResource.ErrorMessage_NotImageSupportFormat);

                return format;
            }
        }

        public class PhotoData
        {
            public string Url;
            public string Path;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/ChainEngine.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Linq.Expressions;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;
using ASC.Core;
using ASC.ElasticSearch;
using ASC.Mail.Core.Dao.Expressions.Conversation;
using ASC.Mail.Core.Dao.Expressions.Message;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Data.Search;
using ASC.Mail.Enums;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Engine
{
    public class ChainEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ILog Log { get; private set; }

        public EngineFactory Factory { get; private set; }

        private const int CHUNK_SIZE = 3;

        public ChainEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.ChainEngine");

            Factory = new EngineFactory(Tenant, User, Log);
        }

        public List<Chain> GetChainsById(string id)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoChain = daoFactory.CreateChainDao(Tenant, User);

                var exp = SimpleConversationsExp.CreateBuilder(Tenant, User)
                    .SetChainIds(new List<string> { id })
                    .Build();

                return daoChain.GetChains(exp);
            }
        }

        public long GetNextConversationId(int id, MailSearchFilterData filter)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoMail = daoFactory.CreateMailDao(Tenant, User);

                var mail = daoMail.GetMail(new ConcreteUserMessageExp(id, Tenant, User));

                if (mail == null)
                    return 0;

                filter.FromDate = mail.ChainDate;
                filter.FromMessage = id;
                filter.PageSize = 1;

                bool hasMore;
                var messages = GetFilteredConversations(daoFactory, filter, out hasMore);
                return messages.Any() ? messages.First().Id : 0;
            }
        }

        public List<MailMessageData> GetConversations(MailSearchFilterData filterData, out bool hasMore)
        {
            if (filterData == null)
                throw new ArgumentNullException("filterData");

            var filter = (MailSearchFilterData)filterData.Clone();

            if (filter.UserFolderId.HasValue && Factory.UserFolderEngine.Get((uint)filter.UserFolderId.Value) == null)
                throw new ArgumentException("Folder not found");

            using (var daoFactory = new DaoFactory())
            {
                var filteredConversations = GetFilteredConversations(daoFactory, filter, out hasMore);

                if (!filteredConversations.Any())
                    return filteredConversations;

                var chainIds = new List<string>();
                filteredConversations.ForEach(x => chainIds.Add(x.ChainId));

                var daoChain = daoFactory.CreateChainDao(Tenant, User);

                var exp = SimpleConversationsExp.CreateBuilder(Tenant, User)
                    .SetChainIds(chainIds)
                    .SetFoldersIds(
                        filter.PrimaryFolder == FolderType.Inbox ||
                        filter.PrimaryFolder == FolderType.Sent
                            ? new List<int> { (int)FolderType.Inbox, (int)FolderType.Sent }
                            : new List<int> { (int)filter.PrimaryFolder })
                    .Build();

                var extendedInfo = daoChain.GetChains(exp);

                foreach (var chain in filteredConversations)
                {
                    var chainMessages = extendedInfo.FindAll(x => x.MailboxId == chain.MailboxId && x.Id == chain.ChainId);
                    if (!chainMessages.Any()) continue;
                    chain.IsNew = chainMessages.Any(x => x.Unread);
                    chain.HasAttachments = chainMessages.Any(x => x.HasAttachments);
                    chain.Important = chainMessages.Any(x => x.Importance);
                    chain.ChainLength = chainMessages.Sum(x => x.Length);
                    var firstOrDefault = chainMessages.FirstOrDefault(x => !string.IsNullOrEmpty(x.Tags));
                    chain.LabelsString = firstOrDefault != null ? firstOrDefault.Tags : "";
                }

                return filteredConversations;
            }
        }

        public List<MailMessageData> GetConversationMessages(int tenant, string user, int messageId,
            bool loadAllContent, bool needProxyHttp, bool needMailSanitazer, bool markRead = false)
        {
            var engine = new EngineFactory(tenant, user);

            using (var daoFactory = new DaoFactory())
            {
                var db = daoFactory.DbManager;

                var daoMailInfo = daoFactory.CreateMailInfoDao(tenant, user);

                var messageInfo = daoMailInfo.GetMailInfoList(
                    SimpleMessagesExp.CreateBuilder(tenant, user)
                        .SetMessageId(messageId)
                        .Build())
                    .SingleOrDefault();

                if (messageInfo == null)
                    throw new ArgumentException("Message Id not found");

                var searchFolders = new List<int>();

                if (messageInfo.Folder == FolderType.Inbox || messageInfo.Folder == FolderType.Sent)
                    searchFolders.AddRange(new[] { (int)FolderType.Inbox, (int)FolderType.Sent });
                else
                    searchFolders.Add((int)messageInfo.Folder);

                var exp = SimpleMessagesExp.CreateBuilder(tenant, user)
                    .SetMailboxId(messageInfo.MailboxId)
                    .SetChainId(messageInfo.ChainId)
                    .SetFoldersIds(searchFolders)
                    .Build();

                var mailInfoList = daoMailInfo.GetMailInfoList(exp);

                var ids = mailInfoList.Select(m => m.Id).ToList();

                var messages =
                    ids.Select(
                        (id, i) =>
                            engine.MessageEngine.GetMessage(daoFactory, id,
                                new MailMessageData.Options
                                {
                                    LoadImages = false,
                                    LoadBody = loadAllContent || (id == messageId),
                                    NeedProxyHttp = needProxyHttp,
                                    NeedSanitizer = needMailSanitazer
                                }))
                        .Where(mailInfo => mailInfo != null)
                        .OrderBy(m => m.Date)
                        .ToList();

                if (!markRead)
                    return messages;

                var unreadMessages = messages.Where(message => message.WasNew).ToList();
                if (!unreadMessages.Any())
                    return messages;

                var unreadMessagesCountByFolder = new Dictionary<FolderType, int>();

                foreach (var message in unreadMessages)
                {
                    if (unreadMessagesCountByFolder.ContainsKey(message.Folder))
                        unreadMessagesCountByFolder[message.Folder] += 1;
                    else
                        unreadMessagesCountByFolder.Add(message.Folder, 1);
                }

                var userFolderXmailDao = daoFactory.CreateUserFolderXMailDao(tenant, user);

                uint? userFolder = null;

                if (unreadMessagesCountByFolder.Keys.Any(k => k == FolderType.UserFolder))
                {
                    var item = userFolderXmailDao.Get(ids.First());
                    userFolder = item == null ? (uint?)null : item.FolderId;
                }

                List<int> ids2Update;

                using (var tx = db.BeginTransaction())
                {
                    ids2Update = unreadMessages.Select(x => x.Id).ToList();

                    daoMailInfo.SetFieldValue(
                        SimpleMessagesExp.CreateBuilder(tenant, user)
                            .SetMessageIds(ids2Update)
                            .Build(),
                        MailTable.Columns.Unread,
                        false);

                    var daoChain = daoFactory.CreateChainDao(tenant, user);

                    foreach (var keyPair in unreadMessagesCountByFolder)
                    {
                        var folderType = keyPair.Key;

                        var unreadMessDiff = keyPair.Value != 0 ? keyPair.Value * (-1) : (int?)null;

                        engine.FolderEngine.ChangeFolderCounters(daoFactory, folderType, userFolder,
                            unreadMessDiff, unreadConvDiff: -1);

                        daoChain.SetFieldValue(
                            SimpleConversationsExp.CreateBuilder(tenant, user)
                                .SetChainId(messageInfo.ChainId)
                                .SetMailboxId(messageInfo.MailboxId)
                                .SetFolder((int)keyPair.Key)
                                .Build(),
                            ChainTable.Columns.Unread,
                            false);
                    }

                    if (userFolder.HasValue)
                    {
                        var userFoldersIds = userFolderXmailDao.GetList(mailIds: ids)
                            .Select(ufxm => (int)ufxm.FolderId)
                            .Distinct()
                            .ToList();

                        engine.UserFolderEngine.RecalculateCounters(daoFactory, userFoldersIds);
                    }

                    tx.Commit();
                }

                var data = new MailWrapper
                {
                    Unread = false
                };

                engine.IndexEngine.Update(data, s => s.In(m => m.Id, ids2Update.ToArray()), wrapper => wrapper.Unread);

                return messages;
            }
        }

        public List<MailInfo> GetChainedMessagesInfo(DaoFactory daoFactory, List<int> ids)
        {
            var daoMailInfo = daoFactory.CreateMailInfoDao(Tenant, User);

            var chainsInfo = daoMailInfo.GetMailInfoList(
                SimpleMessagesExp.CreateBuilder(Tenant, User)
                    .SetMessageIds(ids)
                    .Build());

            var chainArray = chainsInfo.Select(r => r.ChainId).Distinct().ToArray();

            const int max_query_count = 25;
            var i = 0;
            var unsortedMessages = new List<MailInfo>();

            do
            {
                var partChains = chainArray.Skip(i).Take(max_query_count).ToList();

                if (!partChains.Any())
                    break;

                var selectedMessages = daoMailInfo.GetMailInfoList(
                    SimpleMessagesExp.CreateBuilder(Tenant, User)
                        .SetChainIds(partChains)
                        .Build());

                unsortedMessages.AddRange(selectedMessages);

                i += max_query_count;

            } while (true);

            var result = unsortedMessages
                .Where(r => chainsInfo.FirstOrDefault(c =>
                    c.ChainId == r.ChainId &&
                    c.MailboxId == r.MailboxId &&
                    ((r.Folder == FolderType.Inbox || r.Folder == FolderType.Sent)
                        ? c.Folder == FolderType.Inbox || c.Folder == FolderType.Sent
                        : c.Folder == r.Folder)) != null)
                .ToList();

            return result;
        }

        public void SetConversationsFolder(List<int> ids, FolderType folder, uint? userFolderId = null)
        {
            if (!ids.Any())
                throw new ArgumentNullException("ids");

            var engine = new EngineFactory(Tenant, User, Log);

            List<MailInfo> listObjects;

            using (var daoFactory = new DaoFactory())
            {
                listObjects = GetChainedMessagesInfo(daoFactory, ids);

                if (!listObjects.Any())
                    return;

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    engine.MessageEngine.SetFolder(daoFactory, listObjects, folder, userFolderId);
                    tx.Commit();
                }
            }

            if (folder == FolderType.Inbox || folder == FolderType.Sent || folder == FolderType.Spam)
                engine.OperationEngine.ApplyFilters(listObjects.Select(o => o.Id).ToList());

            if (!FactoryIndexer<MailWrapper>.Support)
                return;

            var data = new MailWrapper
            {
                Folder = (byte)folder,
                UserFolders = userFolderId.HasValue
                    ? new List<UserFolderWrapper>
                    {
                        new UserFolderWrapper
                        {
                            Id = (int) userFolderId.Value
                        }
                    }
                    : new List<UserFolderWrapper>()
            };

            Expression<Func<Selector<MailWrapper>, Selector<MailWrapper>>> exp =
                s => s.In(m => m.Id, listObjects.Select(o => o.Id).ToArray());

            engine.IndexEngine.Update(data, exp, w => w.Folder);

            engine.IndexEngine.Update(data, exp, UpdateAction.Replace, w => w.UserFolders);
        }

        public void RestoreConversations(int tenant, string user, List<int> ids)
        {
            if (!ids.Any())
                throw new ArgumentNullException("ids");

            var engine = new EngineFactory(tenant, user, Log);

            List<MailInfo> listObjects;

            using (var daoFactory = new DaoFactory())
            {
                listObjects = GetChainedMessagesInfo(daoFactory, ids);

                if (!listObjects.Any())
                    return;

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    engine.MessageEngine.Restore(daoFactory, listObjects);
                    tx.Commit();
                }
            }

            var filterApplyIds =
                listObjects.Where(
                    m =>
                        m.FolderRestore == FolderType.Inbox || m.FolderRestore == FolderType.Sent ||
                        m.FolderRestore == FolderType.Spam).Select(m => m.Id).ToList();

            if (filterApplyIds.Any())
                engine.OperationEngine.ApplyFilters(filterApplyIds);

            if (!FactoryIndexer<MailWrapper>.Support)
                return;

            var mails = listObjects.ConvertAll(m => new MailWrapper
            {
                Id = m.Id,
                Folder = (byte)m.FolderRestore
            });

            engine.IndexEngine.Update(mails, wrapper => wrapper.Folder);
        }

        public void DeleteConversations(int tenant, string user, List<int> ids)
        {
            if (!ids.Any())
                throw new ArgumentNullException("ids");

            long usedQuota;

            var engine = new EngineFactory(tenant, user);

            List<MailInfo> listObjects;

            using (var daoFactory = new DaoFactory())
            {
                listObjects = GetChainedMessagesInfo(daoFactory, ids);

                if (!listObjects.Any())
                    return;

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    usedQuota = engine.MessageEngine.SetRemoved(daoFactory, listObjects);
                    tx.Commit();
                }
            }

            engine.QuotaEngine.QuotaUsedDelete(usedQuota);

            if (!FactoryIndexer<MailWrapper>.Support)
                return;

            engine.IndexEngine.Remove(listObjects.Select(info => info.Id).ToList(), Tenant, new Guid(User));
        }

        private const string MM_ALIAS = "mm";

        public void SetConversationsImportanceFlags(int tenant, string user, bool important, List<int> ids)
        {
            List<MailInfo> mailInfos;

            using (var daoFactory = new DaoFactory())
            {
                mailInfos = GetChainedMessagesInfo(daoFactory, ids);

                var chainsInfo = mailInfos
                    .Select(m => new
                    {
                        m.ChainId,
                        m.MailboxId,
                        m.Folder
                    })
                    .Distinct().ToList();

                if (!chainsInfo.Any())
                    throw new Exception("no chain messages belong to current user");

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    var daoMailInfo = daoFactory.CreateMailInfoDao(tenant, user);

                    var exp = Exp.Empty;
                    var сhains = new List<Tuple<int, string>>();

                    foreach (var chain in chainsInfo)
                    {
                        var key = new Tuple<int, string>(chain.MailboxId, chain.ChainId);

                        if (сhains.Any() &&
                            сhains.Contains(key) &&
                            (chain.Folder == FolderType.Inbox || chain.Folder == FolderType.Sent))
                        {
                            continue;
                        }

                        var innerWhere = Exp.And(
                            Exp.Eq(MailTable.Columns.ChainId.Prefix(MM_ALIAS), chain.ChainId),
                            Exp.Eq(MailTable.Columns.MailboxId.Prefix(MM_ALIAS), chain.MailboxId));

                        if (chain.Folder == FolderType.Inbox || chain.Folder == FolderType.Sent)
                        {
                            innerWhere &= Exp.Or(
                                Exp.Eq(MailTable.Columns.Folder.Prefix(MM_ALIAS), (int)FolderType.Inbox),
                                Exp.Eq(MailTable.Columns.Folder.Prefix(MM_ALIAS), (int)FolderType.Sent));

                            сhains.Add(key);
                        }
                        else
                        {
                            innerWhere &= Exp.Eq(MailTable.Columns.Folder.Prefix(MM_ALIAS), (int)chain.Folder);
                        }

                        exp |= innerWhere;
                    }

                    daoMailInfo.SetFieldValue(
                        SimpleMessagesExp.CreateBuilder(tenant, user)
                            .SetExp(exp)
                            .Build(),
                        MailTable.Columns.Importance,
                        important);

                    var daoChain = daoFactory.CreateChainDao(tenant, user);

                    foreach (var chain in chainsInfo)
                    {
                        daoChain.SetFieldValue(
                            SimpleConversationsExp.CreateBuilder(tenant, user)
                                .SetChainId(chain.ChainId)
                                .SetMailboxId(chain.MailboxId)
                                .SetFolder((int)chain.Folder)
                                .Build(),
                            ChainTable.Columns.Importance,
                            important);
                    }

                    tx.Commit();
                }
            }

            var factory = new EngineFactory(Tenant, User);

            var data = new MailWrapper
            {
                Importance = important
            };

            factory.IndexEngine.Update(data, s => s.In(m => m.Id, mailInfos.Select(o => o.Id).ToArray()),
                wrapper => wrapper.Importance);
        }

        public void UpdateMessageChainAttachmentsFlag(IDaoFactory daoFactory, int tenant, string user, int messageId)
        {
            UpdateMessageChainFlag(daoFactory, tenant, user, messageId, MailTable.Columns.AttachCount, ChainTable.Columns.HasAttachments);
        }

        public void UpdateMessageChainUnreadFlag(IDaoFactory daoFactory, int tenant, string user, int messageId)
        {
            UpdateMessageChainFlag(daoFactory, tenant, user, messageId, MailTable.Columns.Unread, ChainTable.Columns.Unread);
        }

        public void UpdateMessageChainImportanceFlag(IDaoFactory daoFactory, int tenant, string user, int messageId)
        {
            UpdateMessageChainFlag(daoFactory, tenant, user, messageId, MailTable.Columns.Importance, ChainTable.Columns.Importance);
        }

        private static void UpdateMessageChainFlag(IDaoFactory daoFactory, int tenant, string user, int messageId, string fieldFrom, string fieldTo)
        {
            var daoMail = daoFactory.CreateMailDao(tenant, user);

            var mail = daoMail.GetMail(new ConcreteUserMessageExp(messageId, tenant, user));

            if (mail == null)
                return;

            var daoMailInfo = daoFactory.CreateMailInfoDao(tenant, user);

            var maxValue = daoMailInfo.GetFieldMaxValue<bool>(
                SimpleMessagesExp.CreateBuilder(tenant, user)
                    .SetChainId(mail.ChainId)
                    .SetMailboxId(mail.MailboxId)
                    .SetFolder((int)mail.Folder)
                    .Build(),
                fieldFrom);

            var daoChain = daoFactory.CreateChainDao(tenant, user);

            daoChain.SetFieldValue(
                SimpleConversationsExp.CreateBuilder(tenant, user)
                    .SetChainId(mail.ChainId)
                    .SetMailboxId(mail.MailboxId)
                    .SetFolder((int)mail.Folder)
                    .Build(),
                fieldTo,
                maxValue);
        }

        public void UpdateChain(string chainId, FolderType folder, uint? userFolderId, int mailboxId, int tenant, string user)
        {
            using (var daoFactory = new DaoFactory())
            {
                UpdateChain(daoFactory, chainId, folder, userFolderId, mailboxId, tenant, user);
            }
        }

        public void UpdateChainFields(IDaoFactory daoFactory, int tenant, string user, List<int> ids)
        {
            var daoMailInfo = daoFactory.CreateMailInfoDao(tenant, user);

            var mailInfoList = daoMailInfo.GetMailInfoList(
                SimpleMessagesExp.CreateBuilder(tenant, user, null)
                    .SetMessageIds(ids)
                    .Build())
                .ConvertAll(x => new
                {
                    id_mailbox = x.MailboxId,
                    chain_id = x.ChainId,
                    folder = x.Folder
                });

            if (!mailInfoList.Any()) return;

            foreach (var info in mailInfoList.GroupBy(t => new { t.id_mailbox, t.chain_id, t.folder }))
            {
                uint? userFolder = null;

                if (info.Key.folder == FolderType.UserFolder)
                {
                    var userFolderXmailDao = daoFactory.CreateUserFolderXMailDao(Tenant, User);
                    var item = userFolderXmailDao.Get(ids.First());
                    userFolder = item == null ? (uint?)null : item.FolderId;
                }

                UpdateChain(daoFactory, info.Key.chain_id, info.Key.folder, userFolder, info.Key.id_mailbox, tenant, user);
            }
        }

        // Method for updating chain flags, date and length.
        public void UpdateChain(IDaoFactory daoFactory, string chainId, FolderType folder, uint? userFolderId, int mailboxId,
            int tenant, string user)
        {
            if (string.IsNullOrEmpty(chainId)) return;

            var db = daoFactory.DbManager;
            var engine = new EngineFactory(tenant, user, Log);

            var daoMailInfo = daoFactory.CreateMailInfoDao(tenant, user);

            const string m_alias = "m";

            var getChainQuery = new SqlQuery(MailTable.TABLE_NAME.Alias(m_alias))
                .SelectCount()
                .SelectMax(MailTable.Columns.DateSent.Prefix(m_alias))
                .SelectMax(MailTable.Columns.Unread.Prefix(m_alias))
                .SelectMax(MailTable.Columns.AttachCount.Prefix(m_alias))
                .SelectMax(MailTable.Columns.Importance.Prefix(m_alias))
                .Where(MailTable.Columns.Tenant.Prefix(m_alias), tenant)
                .Where(MailTable.Columns.User.Prefix(m_alias), user)
                .Where(MailTable.Columns.IsRemoved.Prefix(m_alias), 0)
                .Where(MailTable.Columns.ChainId.Prefix(m_alias), chainId)
                .Where(MailTable.Columns.MailboxId.Prefix(m_alias), mailboxId)
                .Where(MailTable.Columns.Folder.Prefix(m_alias), (int)folder);

            var chainInfo = db.ExecuteList(getChainQuery)
                .ConvertAll(x => new
                {
                    length = Convert.ToInt32(x[0]),
                    date = Convert.ToDateTime(x[1]),
                    unread = Convert.ToBoolean(x[2]),
                    attach_count = Convert.ToInt32(x[3]),
                    importance = Convert.ToBoolean(x[4])
                })
                .FirstOrDefault();

            if (chainInfo == null)
                throw new InvalidDataException("Conversation is absent in MAIL_MAIL");

            var daoChain = daoFactory.CreateChainDao(tenant, user);

            var query = SimpleConversationsExp.CreateBuilder(tenant, user)
                .SetMailboxId(mailboxId)
                .SetChainId(chainId)
                .SetFolder((int)folder)
                .Build();

            var storedChainInfo = daoChain.GetChains(query);

            var chainUnreadFlag = storedChainInfo.Any(c => c.Unread);

            if (0 == chainInfo.length)
            {
                var deletQuery = SimpleConversationsExp.CreateBuilder(tenant, user)
                    .SetFolder((int)folder)
                    .SetMailboxId(mailboxId)
                    .SetChainId(chainId)
                    .Build();

                var result = daoChain.Delete(deletQuery);

                Log.DebugFormat(
                    "UpdateChain() row deleted from chain table tenant='{0}', user_id='{1}', id_mailbox='{2}', folder='{3}', chain_id='{4}' result={5}",
                    tenant, user, mailboxId, folder, chainId, result);

                var unreadConvDiff = chainUnreadFlag ? -1 : (int?)null;

                engine.FolderEngine.ChangeFolderCounters(daoFactory, folder, userFolderId,
                    unreadConvDiff: unreadConvDiff, totalConvDiff: -1);
            }
            else
            {
                //var updateMailQuery = new SqlUpdate(MailTable.TABLE_NAME)
                //    .Where(MailTable.Columns.Tenant, tenant)
                //    .Where(MailTable.Columns.User, user)
                //    .Where(MailTable.Columns.IsRemoved, 0)
                //    .Where(MailTable.Columns.ChainId, chainId)
                //    .Where(MailTable.Columns.MailboxId, mailboxId)
                //    .Where(MailTable.Columns.Folder, (int) folder)
                //    // Folder condition important because chain has different dates in different folders(Ex: Sent and Inbox).
                //    .Set(MailTable.Columns.ChainDate, chainInfo.date);

                //db.ExecuteNonQuery(updateMailQuery);

                var updateQuery = SimpleMessagesExp.CreateBuilder(tenant, user)
                        .SetChainId(chainId)
                        .SetMailboxId(mailboxId)
                        .SetFolder((int)folder)
                        .Build();

                daoMailInfo.SetFieldValue(updateQuery,
                    MailTable.Columns.ChainDate,
                    chainInfo.date);

                var tags = GetChainTags(daoFactory, chainId, folder, mailboxId, tenant, user);

                var chain = new Chain
                {
                    Id = chainId,
                    Tenant = tenant,
                    User = user,
                    MailboxId = mailboxId,
                    Folder = folder,
                    Length = chainInfo.length,
                    Unread = chainInfo.unread,
                    HasAttachments = chainInfo.attach_count > 0,
                    Importance = chainInfo.importance,
                    Tags = tags
                };

                var result = daoChain.SaveChain(chain);

                if (result <= 0)
                    throw new InvalidOperationException(string.Format("Invalid insert into {0}", ChainTable.TABLE_NAME));

                Log.DebugFormat(
                    "UpdateChain() row inserted to chain table tenant='{0}', user_id='{1}', id_mailbox='{2}', folder='{3}', chain_id='{4}'",
                    tenant, user, mailboxId, folder, chainId);

                var unreadConvDiff = (int?)null;
                var totalConvDiff = (int?)null;

                if (!storedChainInfo.Any())
                {
                    totalConvDiff = 1;
                    unreadConvDiff = chainInfo.unread ? 1 : (int?)null;
                }
                else
                {
                    if (chainUnreadFlag != chainInfo.unread)
                    {
                        unreadConvDiff = chainInfo.unread ? 1 : -1;
                    }
                }

                engine.FolderEngine.ChangeFolderCounters(daoFactory, folder, userFolderId,
                    unreadConvDiff: unreadConvDiff, totalConvDiff: totalConvDiff);
            }
        }

        public void UpdateChainTags(IDaoFactory daoFactory, string chainId, FolderType folder, int mailboxId, int tenant, string user)
        {
            var tags = GetChainTags(daoFactory, chainId, folder, mailboxId, tenant, user);

            var daoChain = daoFactory.CreateChainDao(tenant, user);

            var updateQuery = SimpleConversationsExp.CreateBuilder(tenant, user)
                    .SetChainId(chainId)
                    .SetMailboxId(mailboxId)
                    .SetFolder((int)folder)
                    .Build();

            daoChain.SetFieldValue(
                updateQuery,
                ChainTable.Columns.Tags,
                tags);
        }

        private static string GetChainTags(IDaoFactory daoFactory, string chainId, FolderType folder, int mailboxId, int tenant, string user)
        {
            const string mm_alias = "ch";
            const string mtm_alias = "tm";

            var db = daoFactory.DbManager;

            var newQuery = new SqlQuery(TagMailTable.TABLE_NAME.Alias(mtm_alias))
                .Select(TagMailTable.Columns.TagId.Prefix(mtm_alias))
                .InnerJoin(MailTable.TABLE_NAME.Alias(mm_alias),
                           Exp.EqColumns(MailTable.Columns.Id.Prefix(mm_alias), TagMailTable.Columns.MailId.Prefix(mtm_alias)))
                .Where(MailTable.Columns.ChainId.Prefix(mm_alias), chainId)
                .Where(MailTable.Columns.IsRemoved.Prefix(mm_alias), 0)
                .Where(TagMailTable.Columns.Tenant.Prefix(mtm_alias), tenant)
                .Where(TagMailTable.Columns.User.Prefix(mtm_alias), user)
                .Where(MailTable.Columns.Folder.Prefix(mm_alias), (int)folder)
                .Where(MailTable.Columns.MailboxId.Prefix(mm_alias), mailboxId)
                .GroupBy(1)
                .OrderBy(TagMailTable.Columns.TimeCreated.Prefix(mtm_alias), true);

            var tags = db.ExecuteList(newQuery)
                         .ConvertAll(x => x[0].ToString());

            return string.Join(",", tags.ToArray());
        }

        private List<MailMessageData> GetFilteredConversations(IDaoFactory daoFactory, MailSearchFilterData filter, out bool hasMore)
        {
            var conversations = new List<MailMessageData>();
            var skipFlag = false;
            var chunkIndex = 0;

            if (filter.FromDate.HasValue && filter.FromMessage.HasValue && filter.FromMessage.Value > 0)
            {
                skipFlag = true;
            }

            var prevFlag = filter.PrevFlag.GetValueOrDefault(false);
            var tenantInfo = CoreContext.TenantManager.GetTenant(Tenant);
            var utcNow = DateTime.UtcNow;
            var pageSize = filter.PageSize.GetValueOrDefault(25);

            var daoMailInfo = daoFactory.CreateMailInfoDao(Tenant, User);

            while (conversations.Count < pageSize + 1)
            {
                filter.PageSize = CHUNK_SIZE * pageSize;

                IMessagesExp exp = null;

                if (!filter.IsDefault() && FactoryIndexer<MailWrapper>.Support && FactoryIndexer.CheckState(false))
                {
                    filter.Page = chunkIndex * CHUNK_SIZE * pageSize; // Elastic Limit from {index of last message} to {count of messages}

                    List<MailWrapper> mailWrappers;
                    if (FilterChainMessagesExp.TryGetFullTextSearchChains(filter, User, out mailWrappers))
                    {
                        if (!mailWrappers.Any())
                            break;

                        var ids = mailWrappers.Select(c => c.Id).ToList();

                        var query = SimpleMessagesExp.CreateBuilder(Tenant, User)
                            .SetMessageIds(ids)
                            .SetOrderBy(filter.Sort);

                        if (prevFlag)
                        {
                            query.SetOrderAsc(!(filter.SortOrder == Defines.ASCENDING));
                        }
                        else
                        {
                            query.SetOrderAsc(filter.SortOrder == Defines.ASCENDING);
                        }

                        exp = query
                            .Build();
                    }
                }
                else
                {
                    filter.Page = chunkIndex; // MySQL Limit from {page by size} to {size}

                    exp = new FilterChainMessagesExp(filter, Tenant, User);
                }

                chunkIndex++;

                var listMessages = daoMailInfo.GetMailInfoList(exp, true)
                    .ConvertAll(m => MessageEngine.ToMailMessage(m, tenantInfo, utcNow));

                if (0 == listMessages.Count)
                    break;

                if (skipFlag && filter.FromMessage.HasValue)
                {
                    var messageData = listMessages.FirstOrDefault(m => m.Id == filter.FromMessage.Value);

                    if (messageData != null)
                    {
                        // Skip chain messages by FromMessage.
                        listMessages =
                            listMessages.Where(
                                m => !(m.ChainId.Equals(messageData.ChainId) && m.MailboxId == messageData.MailboxId))
                                .ToList();
                    }

                    skipFlag = false;
                }

                foreach (var messageData in listMessages)
                {
                    var existingChainIndex =
                        conversations.FindIndex(
                            c => c.ChainId == messageData.ChainId && c.MailboxId == messageData.MailboxId);

                    if (existingChainIndex > -1)
                    {
                        if (conversations[existingChainIndex].Date < messageData.Date)
                            conversations[existingChainIndex] = messageData;
                    }
                    else
                    {
                        conversations.Add(messageData);
                    }
                }

                if (conversations.Count > pageSize)
                    break;
            }

            hasMore = conversations.Count > pageSize;

            if (hasMore)
            {
                conversations = conversations.Take(pageSize).ToList();
            }

            if (prevFlag)
            {
                conversations.Reverse();
            }

            return conversations;
        }
    }
}


<|start_filename|>module/ASC.Feed.Aggregator/Modules/IFeedModule.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Feed.Data;

namespace ASC.Feed.Aggregator.Modules
{
    public interface IFeedModule
    {
        string Name { get; }

        string Product { get; }

        IEnumerable<int> GetTenantsWithFeeds(DateTime fromTime);

        IEnumerable<Tuple<Feed, object>> GetFeeds(FeedFilter filter);

        bool VisibleFor(Feed feed, object data, Guid userId);

        void VisibleFor(List<Tuple<FeedRow, object>> feed, Guid userId);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/userfolders/page.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.userFoldersPage = (function($) {
    var isInit = false,
        page,
        header,
        container,
        idPrefix = "uf_page_",
        idRoot = "v_root",
        isLoading = false,
        stateId = "jstreeUserFoldersPage";

    function init() {
        if (isInit === true) return;
        isInit = true;

        page = $('#user_folders_page');
        
        header = $('#pageActionContainer');

        header.on('click','#createUserFolder', function() {
            if (!$(this).hasClass('disable')) {
                createFolder();
            }
            return false;
        });

        header.on('click', '#editUserFolder', function () {
            if (!$(this).hasClass('disable')) {
                editFolder();
            }
            return false;
        });

        header.on('click', '#deleteUserFolder', function () {
            if (!$(this).hasClass('disable')) {
                deleteFolder();
            }
            return false;
        });
        
        header.on('click', '#userFoldersHelpCenterSwitcher', function (e) {
            jq('#userFoldersHelpCenterSwitcher').helper({ BlockHelperID: 'UserFoldersHelperBlock' });
            e.preventDefault();
            e.stopPropagation();
        });

        container = $('#userFolderTree .userFolders')
            .on("loading.jstree",
                function(e) {
                    $(e.currentTarget).find(".jstree-anchor").text(ASC.Mail.Resources.MailResource.LoadingLabel);
                })
            .on("changed.jstree",
                function(e, data) {
                    setupButtons(data.changed);
                })
            .jstree({
                "plugins": ["wholerow", "state", "changed", "dnd"],
                'core': {
                    "animation": 0,
                    "multiple": false,
                    "force_text": true,
                    'data': loadTree,
                    'check_callback': function (op, node, nodeParent, nodePosition, more) {
                        if (more && more.dnd && op === 'move_node' && nodeParent.id === "#") {
                            return false;
                        }
                        return true;
                    },
                    "keyboard": {
                        "f2": false
                    },
                    "themes": {
                        "ellipsis": true
                    }
                },
                "state": { "key": stateId }
            });

        $(document)
            .on("dnd_scroll.vakata",
                function(e, data) {
                    console.log("dnd_scroll.vakata", data);
                })
            .on("dnd_start.vakata",
                function(e, data) {
                    console.log("dnd_start.vakata", data);
                })
            .on("dnd_stop.vakata",
                function(e, data) {
                    console.log("dnd_stop.vakata", data);

                    var ref = container.jstree(true);

                    var node = ref.get_node(data.data.nodes);

                    var id = node.id.replace(idPrefix, "");

                    var toId = node.parent === idRoot ? 0 : node.parent.replace(idPrefix, "");

                    console.log("userFoldersManager.moveTo", id, toId);

                    userFoldersManager.moveTo(id, toId);
                });

        userFoldersManager.bind(userFoldersManager.events.OnCreate, onCreated);
        userFoldersManager.bind(userFoldersManager.events.OnUpdate, onEdited);
        userFoldersManager.bind(userFoldersManager.events.OnDelete, onDeleted);
        userFoldersManager.bind(userFoldersManager.events.OnError, refresh);
    }

    var rootNode = {
        id: idRoot,
        text: "..",
        icon: "",
        state: {
            opened: true,
            disabled: false,
            selected: true
        },
        children: false
    };

    function loadTree(node, cb) {
        isLoading = true;

        userFoldersManager.loadTree(node.id === "#" ? 0 : node.id.replace(idPrefix, ""))
            .then(function(params, data) {
                    var result = data.map(function(v) {
                        return {
                            id: idPrefix + v.id,
                            parent: v.parent === 0 ? "#" : idPrefix + v.parent,
                            text: v.name,
                            icon: "",
                            state: {
                                opened: false,
                                disabled: false,
                                selected: false
                            },
                            li_attr: { unread: v.unread_count },
                            a_attr: { folderid: v.id, href: "#userfolder={0}".format(v.id) },
                            children: v.folder_count > 0 ? true : false
                        };
                    });

                    if (node.id === "#") {
                        rootNode.children = result;
                        cb(rootNode);
                        isLoading = false;
                        return;
                    }

                    cb(result);
                    isLoading = false;
                },
                function(params, errors) {
                    console.error("Error", errors, arguments);
                    window.toastr.error(errors[0]);
                    refresh();
                    isLoading = false;
                });
    }

    function createFolder() {
        var ref = container.jstree(true),
            sel = ref.get_selected();

        var parentFolder = {
            id: 0,
            name: ""
        };

        if (sel.length && sel[0] !== idRoot) {
            sel = sel[0];
            var node = ref.get_node(sel);

            parentFolder.id = parseInt(node.id.replace(idPrefix, ""));
            parentFolder.name = node.text;
        }

        var newFolder = {
            name: "",
            parent: parentFolder.id
        };

        var options = {
            disableSelector: userFoldersManager.getList().length === 0
                ? true
                : false
        };

        userFoldersManager.create(newFolder, parentFolder, options);

        return true;
    }

    function editFolder() {
        var ref = container.jstree(true),
            sel = ref.get_selected();
        if (!sel.length || sel[0] === "#") {
            return false;
        }
        var nodeId = sel[0];
        if (nodeId === idRoot)
            return false;

        var node = ref.get_node(nodeId);

        var folder = {
            id: parseInt(node.id.replace(idPrefix, "")),
            name: node.text,
            parent: node.parent !== idRoot 
                ? parseInt(node.parent.replace(idPrefix, ""))
                : 0
        };

        var parentFolder = {
            id: folder.parent,
            name: ""
        };

        if (node.parent !== idRoot) {
            node = ref.get_node(node.parent);
            parentFolder.name = node.text;
        }

        var options = {
            disableSelector: userFoldersManager.getList().length === 0
                ? true
                : false
        };

        userFoldersManager.update(folder, parentFolder, options);

        return true;
    }

    function deleteFolder() {
        var ref = container.jstree(true),
            sel = ref.get_selected();
        if (!sel.length || sel[0] === "#") {
            return false;
        }

        var nodeId = sel[0];
        if (nodeId === idRoot)
            return false;

        var node = ref.get_node(nodeId);

        var folder = {
            id: parseInt(node.id.replace(idPrefix, "")),
            name: node.text,
            parent: node.parent !== idRoot
                ? parseInt(node.parent.replace(idPrefix, ""))
                : 0
        }

        userFoldersManager.remove(folder);

        return true;
    }

    function onCreated(e, folder) {
        console.log("userFoldersPage -> onCreated", folder);

        var ref = container.jstree(true);

        var parentId = folder.parent === 0 ? idRoot : idPrefix + folder.parent;

        var res = ref.create_node(parentId, {
            id: idPrefix + folder.id,
            parent: parentId,
            text: folder.name,
            icon: "",
            state: {
                opened: false,
                disabled: false,
                selected: false
            },
            children: false
        });

        if (!res) {
            refresh();
        } else {
            ref.open_node(parentId);
        }

        show();
    }

    function onEdited(e, newFolder, oldFolder) {
        console.log("userFoldersPage -> onEdited", newFolder, oldFolder);

        var ref = container.jstree(true);

        var id = idPrefix + newFolder.id;

        ref.set_text(id, newFolder.name);

        var oldParentId = oldFolder.parent === 0 ? idRoot : idPrefix + oldFolder.parent;
        var newParentId = newFolder.parent === 0 ? idRoot : idPrefix + newFolder.parent;

        if (oldParentId !== newParentId) {
            if (newParentId !== idRoot && ref.is_loaded(newParentId)) {
                var res = ref.move_node(id,
                    newParentId,
                    "last");

                if (!res) {
                    refresh();
                }
                else {
                    ref.open_node(newParentId);
                }

            } else {
                refresh();
            }
        }
    }

    function onDeleted(e, folder) {
        console.log("userFoldersPage -> onDeleted", folder);

        var ref = container.jstree(true);

        var id = idPrefix + folder.id;

        if (!id)
            return;

        var node = ref.get_node(id);

        var parent = ref.get_node(node.parent);

        var children = parent.children;

        if (!children)
            return;

        var index = children.indexOf(id);
        var nextItem = -1;
        if (index >= 0 && index < children.length - 1)
            nextItem = children[index + 1];

        var res = ref.delete_node(id);

        if (!res) {
            refresh();
        }

        if (nextItem >= 0) {
            ref.select_node(nextItem);
        } else {
            if (node.parent !== "#") {
                ref.select_node(node.parent);
            }
        }

        show();
    }

    function setupButtons(changes) {
        var selectedId = changes.selected;
        var deselectedId = changes.deselected;

        if (!selectedId || !deselectedId)
            return false;

        var ref = container.jstree(true);
        var selectedNode = ref.get_node(selectedId);
        var deselectedNode = ref.get_node(deselectedId);

        if (selectedNode.parent === "#" || deselectedNode.parent === "#")
            disableButtons(selectedNode.parent === "#");

        return true;
    }

    function disableButtons(disable, all) {
        if (all) {
            header.find('#createUserFolder').toggleClass("disable", disable);
        }

        header.find('#editUserFolder, #deleteUserFolder').toggleClass("disable", disable);
    }

    function refresh() {
        console.log("userFoldersPage -> refresh");

        container.jstree("refresh");
    }

    function show() {
        if (!TMMail.pageIs('foldersettings')) return;

        if (isLoading || userFoldersManager.isLoading()) {
            window.LoadingBanner.displayMailLoading();
            setTimeout(show, 100);
            return;
        }

        window.LoadingBanner.hideLoading();

        if (!userFoldersManager.getList().length) {
            hide();
            blankPages.showEmptyUserFolders();
        } else {
            blankPages.hide();
            header.html($.tmpl('userFoldersPageHeaderTmpl'));
            page.show();
        }
    }

    function hide() {
        if (!page) return;

        page.hide();
        header.empty();
    }

    return {
        init: init,

        show: show,
        hide: hide,

        refresh: refresh,

        createFolder: createFolder
    };
})
(jQuery);

<|start_filename|>module/ASC.Api/ASC.Api.Client/ApiRequest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Specialized;
using System.IO;
using System.Web;

namespace ASC.Api.Client
{
    public class ApiRequest
    {
        public string Url { get; private set; }

        public string AuthToken { get; private set; }

        public HttpMethod Method { get; set; }

        public RequestType RequestType { get; set; }

        public ResponseType ResponseType { get; set; }

        public RequestParameterCollection Parameters { get; private set; }

        public RequestFileCollection Files { get; private set; }

        public NameValueCollection Headers { get; private set; }

        public ApiRequest(string url)
            : this(url, null)
        {

        }

        public ApiRequest(string url, string authToken)
        {
            if (url == null)
                throw new ArgumentNullException("url");

            if (string.IsNullOrEmpty(authToken) && HttpContext.Current != null)
            {
                HttpCookie authCookie = HttpContext.Current.Request.Cookies.Get("asc_auth_key");
                if (authCookie != null)
                    authToken = authCookie.Value;
            }

            url = url.Trim('/');

            int queryIndex = url.IndexOf('?');
            if (queryIndex > 0)
                url = url.Remove(queryIndex);

            if (url.EndsWith(".xml"))
            {
                url = url.Remove(url.Length - 4);
                ResponseType = ResponseType.Xml;
            }
            else if (url.EndsWith(".json"))
            {
                url = url.Remove(url.Length - 5);
                ResponseType = ResponseType.Json;
            }

            Url = url;
            AuthToken = <PASSWORD>;
            Parameters = new RequestParameterCollection();
            Files = new RequestFileCollection();
            Headers = new NameValueCollection();
        }

        public ApiRequest WithMethod(HttpMethod method)
        {
            Method = method;
            return this;
        }

        public ApiRequest WithRequestType(RequestType requestType)
        {
            RequestType = requestType;
            return this;
        }

        public ApiRequest WithResponseType(ResponseType responseType)
        {
            ResponseType = responseType;
            return this;
        }

        public ApiRequest WithParameter(string name, object value)
        {
            Parameters.Add(new RequestParameter { Name = name, Value = value });
            return this;
        }

        public ApiRequest WithFile(string name, Stream data, bool closeStream = false)
        {
            return WithFile(name, null, data);
        }

        public ApiRequest WithFile(string name, string contentType, Stream data, bool closeStream = false)
        {
            Files.Add(new RequestFile { Name = name, ContentType = contentType, Data = data, CloseStream = closeStream });
            return this;
        }

        public ApiRequest WithHeader(string name, string value)
        {
            Headers.Add(name, value);
            return this;
        }

        public override string ToString()
        {
            return Method.ToString().ToUpper() + " " + Url + "." + ResponseType.ToString().ToLower();
        }
    }
}


<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Controllers/CheckServiceApiController.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Core.Billing;
using ASC.HealthCheck.Classes;
using ASC.HealthCheck.Models;
using ASC.HealthCheck.Resources;
using log4net;
using System;
using System.Linq;
using System.Net.Http;
using System.Web.Http;

namespace ASC.HealthCheck.Controllers
{
    public class CheckServiceApiController : ApiController
    {
        private readonly ILog log = LogManager.GetLogger(typeof(CheckServiceApiController));
        public IServiceRepository ServiceRepository { get; set; }

        public ResultHelper ResultHelper { get { return new ResultHelper(Configuration.Formatters.JsonFormatter); } }

        public CheckServiceApiController()
        {
            ServiceRepository = HealthCheckRunner.ServiceRepository;
        }

        [HttpGet]
        public HttpResponseMessage GetState()
        {
            try
            {
                log.Debug("GetState: Get state of host");

                return HealthCheckRunner.ServerStatusIsOk()
                    ? ResultHelper.Success(HealthCheckResource.HostWorks)
                    : ResultHelper.Error(HealthCheckResource.HostError);
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Unexpected error on GetState: {0} {1}", ex.ToString(), ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return ResultHelper.ServerError();
            }
        }

        [HttpGet]
        public HttpResponseMessage GetStates()
        {
            try
            {
                log.Debug("GetStates: Get states of services");
                return ResultHelper.GetContent(
                    new
                    {
                        code = 1,
                        services = ServiceRepository.GetServices()
                    });
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Unexpected error on GetStates: {0} {1}", ex.ToString(), ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return ResultHelper.Error(HealthCheckResource.ServiceError);
            }
        }

        [HttpGet]
        public HttpResponseMessage RefreshLicense()
        {
            try
            {
                log.Debug("ChangeLicenseStatus");
                LicenseReader.RefreshLicense();
                if (!ServiceRepository.GetServicesSnapshot().Any())
                {
                    HealthCheckRunner.Run();
                }

                return ResultHelper.Success();
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Unexpected error on RefreshLicense: {0} {1}", ex.ToString(), ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return ResultHelper.ServerError();
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/Search/SearchResults.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using ASC.Web.Studio.Core.Search;

namespace ASC.Web.Studio.UserControls.Common.Search
{
    public partial class SearchResults : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Common/Search/SearchResults.ascx"; }
        }

        internal int MaxResultCount = 5;

        public IEnumerable<SearchResult> SearchResultsData { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterStyle("~/UserControls/Common/Search/css/searchresults.less")
                .RegisterBodyScripts("~/UserControls/Common/Search/js/searchresults.js");

            results.ItemDataBound += ResultsItemDataBound;
            results.DataSource = SearchResultsData;
            results.DataBind();
        }

        private static void ResultsItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                var control = ((SearchResult)e.Item.DataItem).PresentationControl;
                if (control == null)
                    return;
                control.Items = ((SearchResult)e.Item.DataItem).Items;
                e.Item.FindControl("resultItems").Controls.Add(control);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/WhiteLabel/js/whitelabel.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var WhiteLabelManager = new function () {
    var _successMsgTest = "";
    var _uploadWhiteLabelLogoComplete = function (file, response, logotype) {
        //jq.unblockUI();

        var result = eval("(" + response + ")");
        if (result.Success) {
            jq('#studio_whiteLabelSettings .logo_' + logotype).attr('src', result.Message);
            jq("canvas[id^=canvas_logo_" + logotype + "]").hide();
            jq('#logoPath_' + logotype).val(result.Message);
        } else {
            toastr.error(result.Message);
        }
        LoadingBanner.hideLoaderBtn("#studio_whiteLabelSettings");
    };

    var _updateWhiteLabelLogosSrc = function (whiteLabelLogos) {
        for (var logo in whiteLabelLogos) {
            if (whiteLabelLogos.hasOwnProperty(logo)) {
                var now = new Date();
                jq('#studio_whiteLabelSettings .logo_' + logo).attr('src', whiteLabelLogos[logo] + '?' + now.getTime());
            }
        }
    }

    this.SaveWhiteLabelOptions = function () {
        var logoList = [],

            $logoPaths = jq('[id^=logoPath_]'),
            needToSave = false;

        for (var i = 0, n = $logoPaths.length; i < n; i++) {
            var logotype = jq($logoPaths[i]).attr('id').split('_')[1],
                logoPath = jq.trim(jq($logoPaths[i]).val());

            logoList.push({ key: logotype, value: logoPath });

            if (logoPath != "") { needToSave = true; }
        }

        if (jq("#studio_whiteLabelLogoText").val() !== jq("#studio_whiteLabelLogoText").attr("data-value")) { needToSave = true; }

        if (needToSave) {
            Teamlab.saveWhiteLabelSettings({},
             {
                 logoText: jq("#studio_whiteLabelLogoText").val(),
                 logo: logoList
             },
             {
                 before: function (params) { LoadingBanner.showLoaderBtn("#studio_whiteLabelSettings"); },
                 after: function (params) { LoadingBanner.hideLoaderBtn("#studio_whiteLabelSettings"); },
                 success: function (params, response) {
                     //clean logo path input
                     jq('[id^=logoPath_]').val('');

                     window.location.reload(true);
                     LoadingBanner.showMesInfoBtn("#studio_whiteLabelSettings", _successMsgTest, "success");
                 },
                 error: function (params, errors) {
                     var err = errors[0];
                     LoadingBanner.showMesInfoBtn("#studio_whiteLabelSettings", err, "error");

                 }
             });
        }
    };

    this.RestoreWhiteLabelOptions = function () {

        Teamlab.restoreWhiteLabelSettings({},
             {
                 before: function (params) { LoadingBanner.showLoaderBtn("#studio_whiteLabelSettings"); },
                 after: function (params) { LoadingBanner.hideLoaderBtn("#studio_whiteLabelSettings"); },
                 success: function (params, response) {
                     //clean logo path input
                     jq('[id^=logoPath_]').val('');

                     window.location.reload(true);
                     LoadingBanner.showMesInfoBtn("#studio_whiteLabelSettings", _successMsgTest, "success");
                 },
                 error: function (params, errors) {
                     var err = errors[0];
                     LoadingBanner.showMesInfoBtn("#studio_whiteLabelSettings", err, "error");
                 }
             });
    };

    this.UseTextAsLogo = function () {

        var $canvas = jq("[id^=canvas_logo_]"),
            text = jq("#studio_whiteLabelLogoText").val();
        
        for (var i = 0, n = $canvas.length; i < n; i++) {
            var cnv = $canvas[i],
                $c = jq(cnv),
                fontsize = $c.attr("data-fontsize"),
                fontcolor = $c.attr("data-fontcolor"),
                logotype = $c.attr("id").replace("canvas_logo_", ""),
                x = logotype == 3 ? cnv.width / 2 : 0,
                firstChar = jq.trim(text).charAt(0),
                firstCharCode = firstChar.charCodeAt(0),
                ctx = cnv.getContext("2d");

            if (logotype.indexOf('_') !== -1) logotype = logotype.split('_')[0]; // for docs editor

            if (firstCharCode >= 0xD800 && firstCharCode <= 0xDBFF) firstChar = jq.trim(text).substr(0, 2); // Note: for surrogates pairs only
            
            ctx.fillStyle = "transparent";
            ctx.clearRect(0, 0, cnv.width, cnv.height);
            ctx.fillStyle = fontcolor;
            ctx.textAlign = logotype == 3 ? "center" : "start";
            ctx.textBaseline = "top";

            ctx.font = fontsize + "px Arial";

            ctx.fillText(logotype == 3 ? firstChar : text, x, (cnv.height - parseInt(fontsize)) / 2);

            var img = cnv.toDataURL("image/png", 1.0);
            jq('#logoPath_' + logotype).val(img);

            $c.show();
        }
    };

    this.Init = function (successMsgTest) {
        _successMsgTest = successMsgTest;
        var isRetina = jq.cookies.get("is_retina");

        WhiteLabelManager.IsRetina = isRetina != null && isRetina == true;

        jq('#saveWhiteLabelSettingsBtn:not(.disable)').on("click", function () { WhiteLabelManager.SaveWhiteLabelOptions(); });
        jq('#restoreWhiteLabelSettingsBtn:not(.disable)').on("click", function () { WhiteLabelManager.RestoreWhiteLabelOptions(); });
        jq("#useAsLogoBtn").on("click", function () { WhiteLabelManager.UseTextAsLogo(); });

        var $uploaderBtns = jq('[id^=logoUploader_]');

        for (var i = 0, n = $uploaderBtns.length; i < n; i++) {
            var logotype = jq($uploaderBtns[i]).attr('id').split('_')[1];

            new AjaxUpload($uploaderBtns[i], {
                action: 'ajaxupload.ashx?type=ASC.Web.Studio.UserControls.WhiteLabel.LogoUploader,ASC.Web.Studio',
                data: { logotype: logotype },
                onChange: function (file, ext) {
                    LoadingBanner.showLoaderBtn("#studio_whiteLabelSettings");
                },
                onComplete: function (file, response) {
                    _uploadWhiteLabelLogoComplete(file, response, this._settings.data.logotype);
                }
            });
        }
     
    };

};

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/PortalAccessSettings/js/portalaccess.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


jq(function () {
    jq("input[name='PortalAccess']").click(PortalAccess.SwitchAccessType);
    jq("input[type=radio][name=PortalAccess][checked=checked]").prop("checked", true);
    jq("#cbxRegisterUsers[checked=checked]").prop("checked", true);
    PortalAccess.SwitchAccessType();
});

var PortalAccess = new function () {
    this.SwitchAccessType = function () {
        if (jq("#radioPublicPortal").is(":checked")) {
            jq("#cbxRegisterUsersContainer").show();
        } else {
            jq("#cbxRegisterUsersContainer").hide();
        }
    };

    this.SaveSettings = function (btnObj) {

        if (jq(btnObj).hasClass("disable")) return;

        AjaxPro.onLoading = function (b) {
            if (b) {
                jq("#studio_portalAccessSettings input").prop("disabled", true);
                LoadingBanner.showLoaderBtn("#studio_portalAccessSettings");
            } else {
                jq("#studio_portalAccessSettings input").prop("disabled", false);
                LoadingBanner.hideLoaderBtn("#studio_portalAccessSettings");
            }
        };

        window.PortalAccessController.SaveSettings(jq("#radioPublicPortal").is(":checked"), jq("#cbxRegisterUsers").is(":checked"), function (result) {
            var res = result.value;
            LoadingBanner.showMesInfoBtn("#studio_portalAccessSettings", res.Message, res.Status == 1 ? "success" : "error");
            if (res.Status == 1) {
                window.location.reload();
            }
        });
    };
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/ImapFlagsDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Data;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao
{
    public class ImapFlagsDao : BaseDao, IImapFlagsDao
    {
        protected static ITable table = new MailTableFactory().Create<ImapFlagsTable>();

        public ImapFlagsDao(IDbManager dbManager)
            : base(table, dbManager)
        {
        }

        public List<ImapFlag> GetImapFlags()
        {
            var query = Query();

            return Db.ExecuteList(query)
                .ConvertAll(ToImapFlag);
        }

        protected ImapFlag ToImapFlag(object[] r)
        {
            var imapFlag = new ImapFlag
            {
                FolderId = Convert.ToInt32(r[0]),
                Name = Convert.ToString(r[1]),
                Skip = Convert.ToBoolean(r[2]),
            };

            return imapFlag;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Expressions/Message/FilterChainMessagesExp.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data.Sql.Expressions;
using ASC.ElasticSearch;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Data.Search;
using ASC.Mail.Enums;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao.Expressions.Message
{
    public class FilterChainMessagesExp : FilterMessagesExp
    {
        public FilterChainMessagesExp(MailSearchFilterData filter, int tenant, string user, List<int> ids = null)
            : base(ids ?? new List<int>(), tenant, user, filter)
        {
        }

        private const string MM_ALIAS = "mm";

        public override Exp GetExpression()
        {
            var exp = base.GetExpression();

            if (Filter.FromDate.HasValue)
            {
                var prevFlag = Filter.PrevFlag.GetValueOrDefault(false);

                if (Filter.SortOrder == Defines.DESCENDING)
                {
                    exp &= prevFlag
                    ? Exp.Ge(MailTable.Columns.ChainDate.Prefix(MM_ALIAS), Filter.FromDate.Value)
                    : Exp.Le(MailTable.Columns.ChainDate.Prefix(MM_ALIAS), Filter.FromDate.Value);
                }
                else
                {
                    exp &= prevFlag
                    ? Exp.Le(MailTable.Columns.ChainDate.Prefix(MM_ALIAS), Filter.FromDate.Value)
                    : Exp.Ge(MailTable.Columns.ChainDate.Prefix(MM_ALIAS), Filter.FromDate.Value);
                }

                if (prevFlag)
                {
                    OrderAsc = string.IsNullOrEmpty(Filter.SortOrder)
                    ? (bool?)null
                    : !OrderAsc.Value;
                }
            }

            return exp;
        }

        public static bool TryGetFullTextSearchChains(MailSearchFilterData filter, string user,
            out List<MailWrapper> mailWrappers)
        {
            mailWrappers = new List<MailWrapper>();

            if (!FactoryIndexer<MailWrapper>.Support)
            {
                return false;
            }

            var userId = new Guid(user);

            Selector<MailWrapper> selector = null;

            if (!string.IsNullOrEmpty(filter.SearchText))
            {
                selector = new Selector<MailWrapper>().MatchAll(filter.SearchText);
            }

            if (!string.IsNullOrEmpty(filter.FromAddress))
            {
                Selector<MailWrapper> tempSelector;

                if (filter.PrimaryFolder == FolderType.Sent || filter.PrimaryFolder == FolderType.Draft)
                {
                    tempSelector = new Selector<MailWrapper>().Match(s => s.ToText, filter.FromAddress);
                }
                else
                {
                    tempSelector = new Selector<MailWrapper>().Match(s => s.FromText, filter.FromAddress);
                }

                if (selector != null)
                    selector &= tempSelector;
                else
                    selector = tempSelector;
            }

            if (!string.IsNullOrEmpty(filter.ToAddress))
            {
                Selector<MailWrapper> tempSelector;

                if (filter.PrimaryFolder == FolderType.Sent || filter.PrimaryFolder == FolderType.Draft)
                {
                    tempSelector = new Selector<MailWrapper>().Match(s => s.FromText, filter.ToAddress);
                }
                else
                {
                    tempSelector = new Selector<MailWrapper>().Match(s => s.ToText, filter.ToAddress);
                }

                if (selector != null)
                    selector &= tempSelector;
                else
                    selector = tempSelector;
            }

            if (selector == null)
                selector = new Selector<MailWrapper>();

            selector.Where(r => r.Folder, (int)filter.PrimaryFolder);

            if (filter.MailboxId.HasValue)
            {
                selector.Where(r => r.MailboxId, filter.MailboxId.Value);
            }

            if (filter.Unread.HasValue)
            {
                selector.Where(s => s.Unread, filter.Unread.Value);
            }

            if (filter.Important.HasValue)
            {
                selector.Where(s => s.Importance, filter.Important.Value);
            }

            if (filter.Attachments.HasValue)
            {
                selector.Where(s => s.HasAttachments, filter.Attachments.Value);
            }

            if (filter.PrimaryFolder == FolderType.UserFolder && filter.UserFolderId.HasValue)
            {
                selector.InAll(s => s.UserFolders.Select(f => f.Id), new[] { filter.UserFolderId.Value });
            }

            if (filter.WithCalendar.HasValue)
            {
                selector.Where(m => m.WithCalendar, filter.WithCalendar.Value);
            }

            if (filter.CustomLabels != null && filter.CustomLabels.Any())
            {
                selector.InAll(r => r.Tags.Select(t => t.Id), filter.CustomLabels.ToArray());
            }

            if (filter.FromDate.HasValue)
            {
                var prevFlag = filter.PrevFlag.GetValueOrDefault(false);

                if (filter.SortOrder == Defines.DESCENDING)
                {
                    if (prevFlag)
                    {
                        selector.Ge(r => r.ChainDate, filter.FromDate.Value);
                    }
                    else
                    {
                        selector.Le(r => r.ChainDate, filter.FromDate.Value);
                    }
                }
                else
                {
                    if (prevFlag)
                    {
                        selector.Le(r => r.ChainDate, filter.FromDate.Value);
                    }
                    else
                    {
                        selector.Ge(r => r.ChainDate, filter.FromDate.Value);
                    }
                }
            }

            if (filter.PeriodFrom.HasValue && filter.PeriodTo.HasValue)
            {
                var fromTs = TimeSpan.FromMilliseconds(filter.PeriodFrom.Value);
                var from = Defines.BaseJsDateTime.Add(fromTs);

                var toTs = TimeSpan.FromMilliseconds(filter.PeriodTo.Value);
                var to = Defines.BaseJsDateTime.Add(toTs);

                selector.Ge(s => s.DateSent, from);
                selector.Le(s => s.DateSent, to);
            }

            if (filter.Page.HasValue)
            {
                selector.Limit(filter.Page.Value, filter.PageSize.GetValueOrDefault(25));
            }
            else if (filter.PageSize.HasValue)
            {
                selector.Limit(0, filter.PageSize.Value);
            }

            selector.Where(r => r.UserId, userId)
                .Sort(r => r.ChainDate, filter.SortOrder == Defines.ASCENDING);

            IReadOnlyCollection<MailWrapper> result;

            if (!FactoryIndexer<MailWrapper>.TrySelect(s => selector, out result))
                return false;

            mailWrappers = result.ToList();

            return true;
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailTemplateData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Data.Contracts.Base;
using ASC.Mail.Enums;

namespace ASC.Mail.Data.Contracts
{
    public class MailTemplateData : MailComposeBase
    {
        public MailTemplateData(int id, MailBoxData mailBoxData, string from, List<string> to, List<string> cc,
            List<string> bcc,
            string subject, string mimeMessageId, string mimeReplyToId, bool important,
            List<int> tags, string body, string streamId, List<MailAttachmentData> attachments, string calendarIcs = "")
            : base(
                id, mailBoxData, FolderType.Templates, from, to, cc, bcc, subject, mimeMessageId, mimeReplyToId, important,
                tags, body, streamId, attachments, calendarIcs)
        {
        }
    }
}

<|start_filename|>module/ASC.Files.Thirdparty/ProviderDao/ProviderSecutiryDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Files.Core;
using ASC.Files.Core.Security;

namespace ASC.Files.Thirdparty.ProviderDao
{
    internal class ProviderSecurityDao : ProviderDaoBase, ISecurityDao
    {
        public void Dispose()
        {

        }

        public void SetShare(FileShareRecord r)
        {
            using (var securityDao = TryGetSecurityDao())
            {
                securityDao.SetShare(r);
            }
        }

        public IEnumerable<FileShareRecord> GetShares(IEnumerable<FileEntry> entries)
        {
            var result = new List<FileShareRecord>();

            if (entries == null || !entries.Any()) return result;

            var defaultSelectorEntries = entries.Where(x => x != null && Default.IsMatch(x.ID)).ToArray();
            var otherSelectorEntries = entries.Where(x => x != null && !Default.IsMatch(x.ID)).ToArray();

            if (defaultSelectorEntries.Any())
            {
                using (var securityDao = TryGetSecurityDao())
                {
                    if (securityDao != null)
                    {
                        var shares = securityDao.GetShares(defaultSelectorEntries);
                        if (shares != null) result.AddRange(shares);
                    }
                }
            }

            if (!otherSelectorEntries.Any()) return result;

            var files = otherSelectorEntries.Where(x => x.FileEntryType == FileEntryType.File).ToArray();
            var folders = otherSelectorEntries.Where(x => x.FileEntryType == FileEntryType.Folder).ToList();

            if (files.Any())
            {
                var folderIds = files.Select(x => ((File)x).FolderID).Distinct();
                foreach (var folderId in folderIds)
                {
                    GetFoldersForShare(folderId, folders);
                }

                using (var securityDao = TryGetSecurityDao())
                {
                    if (securityDao != null)
                    {
                        var pureShareRecords = securityDao.GetPureShareRecords(files);
                        if (pureShareRecords != null)
                        {
                            foreach (var pureShareRecord in pureShareRecords)
                            {
                                if (pureShareRecord == null) continue;
                                pureShareRecord.Level = -1;
                                result.Add(pureShareRecord);
                            }
                        }
                    }
                }
            }

            result.AddRange(GetShareForFolders(folders));

            return result;
        }

        public IEnumerable<FileShareRecord> GetShares(FileEntry entry)
        {
            var result = new List<FileShareRecord>();

            if (entry == null) return result;

            if (Default.IsMatch(entry.ID))
            {
                using (var securityDao = TryGetSecurityDao())
                {
                    if (securityDao != null)
                    {
                        var shares = securityDao.GetShares(entry);
                        if (shares != null) result.AddRange(shares);
                    }
                }

                return result;
            }


            var file = entry as File;
            var folders = new List<FileEntry>();
            var entryFolder = entry as Folder;
            if (entryFolder != null)
            {
                folders.Add(entryFolder);
            }

            if (file != null)
            {
                GetFoldersForShare(file.FolderID, folders);

                using (var securityDao = TryGetSecurityDao())
                {
                    if (securityDao != null)
                    {
                        var pureShareRecords = securityDao.GetPureShareRecords(entry);
                        if (pureShareRecords != null)
                        {
                            foreach (var pureShareRecord in pureShareRecords)
                            {
                                if (pureShareRecord == null) continue;
                                pureShareRecord.Level = -1;
                                result.Add(pureShareRecord);
                            }
                        }
                    }
                }
            }

            result.AddRange(GetShareForFolders(folders));

            return result;
        }

        private void GetFoldersForShare(object folderId, ICollection<FileEntry> folders)
        {
            var selector = GetSelector(folderId);
            var folderDao = selector.GetFolderDao(folderId);
            if (folderDao == null) return;

            var folder = folderDao.GetFolder(selector.ConvertId(folderId));
            if (folder != null) folders.Add(folder);
        }

        private List<FileShareRecord> GetShareForFolders(IReadOnlyCollection<FileEntry> folders)
        {
            if (!folders.Any()) return new List<FileShareRecord>();

            var result = new List<FileShareRecord>();

            foreach (var folder in folders)
            {
                var selector = GetSelector(folder.ID);
                var folderDao = selector.GetFolderDao(folder.ID);
                if (folderDao == null) continue;

                var parentFolders = folderDao.GetParentFolders(selector.ConvertId(folder.ID));
                if (parentFolders == null || !parentFolders.Any()) continue;

                parentFolders.Reverse();
                var pureShareRecords = GetPureShareRecords(parentFolders.Cast<FileEntry>().ToArray());
                if (pureShareRecords == null) continue;

                foreach (var pureShareRecord in pureShareRecords)
                {
                    if (pureShareRecord == null) continue;
                    pureShareRecord.Level = parentFolders.IndexOf(new Folder { ID = pureShareRecord.EntryId });
                    pureShareRecord.EntryId = folder.ID;
                    result.Add(pureShareRecord);
                }
            }

            return result;
        }

        public void RemoveSubject(Guid subject)
        {
            using (var securityDao = TryGetSecurityDao())
            {
                securityDao.RemoveSubject(subject);
            }
        }

        public IEnumerable<FileShareRecord> GetShares(IEnumerable<Guid> subjects)
        {
            using (var securityDao = TryGetSecurityDao())
            {
                return securityDao.GetShares(subjects);
            }
        }

        public IEnumerable<FileShareRecord> GetPureShareRecords(IEnumerable<FileEntry> entries)
        {
            using (var securityDao = TryGetSecurityDao())
            {
                return securityDao.GetPureShareRecords(entries);
            }
        }

        public IEnumerable<FileShareRecord> GetPureShareRecords(FileEntry entry)
        {
            using (var securityDao = TryGetSecurityDao())
            {
                return securityDao.GetPureShareRecords(entry);
            }
        }

        public void DeleteShareRecords(IEnumerable<FileShareRecord> records)
        {
            using (var securityDao = TryGetSecurityDao())
            {
                securityDao.DeleteShareRecords(records);
            }
        }

        public bool IsShared(object entryId, FileEntryType type)
        {
            using (var securityDao = TryGetSecurityDao())
            {
                return securityDao.IsShared(entryId, type);
            }
        }
    }
}

<|start_filename|>web/core/ASC.Web.Core/Calendars/CalendarColors.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

namespace ASC.Web.Core.Calendars
{
    public class CalendarColors
    {
        public string BackgroudColor { get; set; }
        public string TextColor { get; set; }
        public static List<CalendarColors> BaseColors
        {
            get
            {
                return new List<CalendarColors>(){
                    new CalendarColors(){ BackgroudColor = "#e34603", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#f88e14", TextColor="#000000"},
                    new CalendarColors(){ BackgroudColor = "#ffb403", TextColor="#000000"},
                    new CalendarColors(){ BackgroudColor = "#9fbb4c", TextColor="#000000"},
                    new CalendarColors(){ BackgroudColor = "#288e31", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#4cbb78", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#0797ba", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#1d5f99", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#4c76bb", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#3552d2", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#473388", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#884cbb", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#cb59ba", TextColor="#000000"},
                    new CalendarColors(){ BackgroudColor = "#ca3083", TextColor="#ffffff"},
                    new CalendarColors(){ BackgroudColor = "#e24e78", TextColor="#000000"},
                    new CalendarColors(){ BackgroudColor = "#bf0036", TextColor="#ffffff"}
                };
            }
        }

    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/CookieSettings/js/cookiesettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


CookieSettingsManager = new function () {
    this.Init = function () {
        jq("#saveCookieSettingsBtn").click(CookieSettingsManager.Save);
        
        jq("#lifeTimeTxt").keydown(function (e) {
            // Allow: backspace, delete, tab, escape, enter and .
            if (jq.inArray(e.keyCode, [46, 8, 9, 27, 13, 110, 190]) !== -1 ||
                // Allow: Ctrl+A, Command+A
                (e.keyCode === 65 && (e.ctrlKey === true || e.metaKey === true)) || 
                // Allow: home, end, left, right, down, up
                (e.keyCode >= 35 && e.keyCode <= 40)) {
                // let it happen, don't do anything
                return;
            }
            // Ensure that it is a number and stop the keypress
            if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
                e.preventDefault();
            }
        });
        
        jq("#cookieSettingsOff").on("click", CookieSettingsManager.HideLifeTimeSettings);
        
        jq("#cookieSettingsOn").on("click", CookieSettingsManager.ShowLifeTimeSettings);
    };

    this.Save = function () {
        AjaxPro.onLoading = function (b) {
            if (b)
                LoadingBanner.showLoaderBtn("#studio_cookieSettings");
            else
                LoadingBanner.hideLoaderBtn("#studio_cookieSettings");
        };

        var callback = function (result) {
            var res = result.value;
            if (res.Status == 1) {
                LoadingBanner.showMesInfoBtn("#studio_cookieSettings", res.Message, "success");
            } else {
                LoadingBanner.showMesInfoBtn("#studio_cookieSettings", res.Message, "error");
            }
        };

        if (jq("#cookieSettingsOn").is(":checked")) {
            var lifeTime = parseInt(jq("#lifeTimeTxt").val().trim());
            if (lifeTime > 0) {
                window.CookieSettingsController.Save(lifeTime, callback);
            }
        } else {
            window.CookieSettingsController.Restore(callback);
        } 
    };

    this.HideLifeTimeSettings = function () {
        jq("#lifeTimeSettings").addClass("display-none");
    };
    
    this.ShowLifeTimeSettings = function () {
        jq("#lifeTimeSettings").removeClass("display-none");
    };
};

jq(document).ready(function () {
    CookieSettingsManager.Init();
});

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/TagDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.CRM.Core;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema;
using ASC.Mail.Core.DbSchema.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class TagDao : BaseDao, ITagDao
    {
        protected static ITable table = new MailTableFactory().Create<TagTable>();

        protected string CurrentUserId { get; private set; }

        public TagDao(IDbManager dbManager, int tenant, string user)
            : base(table, dbManager, tenant)
        {
            CurrentUserId = user;
        }

        public Tag GetTag(int id)
        {
            if (id < 0)
                return GetCrmTag(id);

            var query = Query()
                .Where(TagTable.Columns.Tenant, Tenant)
                .Where(TagTable.Columns.User, CurrentUserId)
                .Where(TagTable.Columns.Id, id);

            return Db.ExecuteList(query)
                .ConvertAll(ToTag)
                .SingleOrDefault();
        }

        public Tag GetCrmTag(int id)
        {
            var crmTagId = id < 0 ? -id : id;

            var query = new SqlQuery(CrmTagTable.TABLE_NAME)
                   .Select(CrmTagTable.Columns.Id, CrmTagTable.Columns.Title)
                   .Where(CrmTagTable.Columns.Tenant, Tenant)
                   .Where(CrmTagTable.Columns.EntityType, (int)EntityType.Contact)
                   .Where(CrmTagTable.Columns.Id, crmTagId);

            return Db.ExecuteList(query)
                .ConvertAll(ToCrmTag)
                .SingleOrDefault();
        }

        public Tag GetTag(string name)
        {
            var query = Query()
                .Where(TagTable.Columns.Tenant, Tenant)
                .Where(TagTable.Columns.User, CurrentUserId)
                .Where(TagTable.Columns.TagName, name);

            return Db.ExecuteList(query)
                .ConvertAll(ToTag)
                .SingleOrDefault();
        }

        public List<Tag> GetTags()
        {
            var query = Query()
                .Where(TagTable.Columns.Tenant, Tenant)
                .Where(TagTable.Columns.User, CurrentUserId);

            return Db.ExecuteList(query)
                .ConvertAll(ToTag);
        }

        public List<Tag> GetCrmTags()
        {
            var query = new SqlQuery(CrmTagTable.TABLE_NAME)
                   .Select(CrmTagTable.Columns.Id, CrmTagTable.Columns.Title)
                   .Where(CrmTagTable.Columns.Tenant, Tenant)
                   .Where(CrmTagTable.Columns.EntityType, (int)EntityType.Contact);

            return Db.ExecuteList(query)
                .ConvertAll(ToCrmTag);
        }

        public List<Tag> GetCrmTags(List<int> contactIds)
        {
            const string cet = "cet";
            const string ct = "ct";

            var query = new SqlQuery(CrmEntityTagTable.TABLE_NAME.Alias(cet))
                .InnerJoin(CrmTagTable.TABLE_NAME.Alias(ct),
                    Exp.EqColumns(CrmEntityTagTable.Columns.TagId.Prefix(cet), CrmTagTable.Columns.Id.Prefix(ct)))
                .Distinct()
                .Select(CrmTagTable.Columns.Id.Prefix(ct), CrmTagTable.Columns.Title.Prefix(ct))
                .Where(CrmTagTable.Columns.Tenant.Prefix(ct), Tenant)
                .Where(CrmEntityTagTable.Columns.EntityType.Prefix(cet), (int)EntityType.Contact)
                .Where(Exp.In(CrmEntityTagTable.Columns.EntityId.Prefix(cet), contactIds));

            return Db.ExecuteList(query)
                .ConvertAll(ToCrmTag);
        }

        public int SaveTag(Tag tag)
        {
            var query = new SqlInsert(TagTable.TABLE_NAME, true)
                .InColumnValue(TagTable.Columns.Id, tag.Id)
                .InColumnValue(TagTable.Columns.Tenant, tag.Tenant)
                .InColumnValue(TagTable.Columns.User, tag.User)
                .InColumnValue(TagTable.Columns.TagName, tag.TagName)
                .InColumnValue(TagTable.Columns.Style, tag.Style)
                .InColumnValue(TagTable.Columns.Addresses, tag.Addresses)
                .InColumnValue(TagTable.Columns.Count, tag.Count)
                .InColumnValue(TagTable.Columns.CrmId, tag.CrmId)
                .Identity(0, 0, true);

            return Db.ExecuteScalar<int>(query);
        }

        public int DeleteTag(int id)
        {
            var query = new SqlDelete(TagTable.TABLE_NAME)
                .Where(TagTable.Columns.Tenant, Tenant)
                .Where(TagTable.Columns.User, CurrentUserId)
                .Where(TagTable.Columns.Id, id);

            return Db.ExecuteNonQuery(query);
        }

        public int DeleteTags(List<int> tagIds)
        {
            var query = new SqlDelete(TagTable.TABLE_NAME)
                .Where(TagTable.Columns.Tenant, Tenant)
                .Where(TagTable.Columns.User, CurrentUserId)
                .Where(Exp.In(TagTable.Columns.Id, tagIds));

            return Db.ExecuteNonQuery(query);
        }

        protected Tag ToTag(object[] r)
        {
            var f = new Tag
            {
                Id = Convert.ToInt32(r[0]),
                Tenant = Convert.ToInt32(r[1]),
                User = Convert.ToString(r[2]),
                TagName = Convert.ToString(r[3]),
                Style = Convert.ToString(r[4]),
                Addresses = Convert.ToString(r[5]),
                Count = Convert.ToInt32(r[6]),
                CrmId = Convert.ToInt32(r[7])
            };

            return f;
        }

        protected Tag ToCrmTag(object[] r)
        {
            var f = new Tag
            {
                Id = -Convert.ToInt32(r[0]),
                TagName = Convert.ToString(r[1]),
                Tenant = Tenant,
                User = CurrentUserId,
                Style = "",
                Addresses = "",
                Count = 0,
                CrmId = 0
            };

            return f;
        }
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/WebStudioModuleSpecifics.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Text.RegularExpressions;

using ASC.Data.Backup.Tasks.Data;

namespace ASC.Data.Backup.Tasks.Modules
{
    internal class WebStudioModuleSpecifics : ModuleSpecificsBase
    {
        private static readonly Guid CrmSettingsId = new Guid("fdf39b9a-ec96-4eb7-aeab-63f2c608eada");

        private readonly TableInfo[] _tables = new[]
            {
                new TableInfo("webstudio_fckuploads", "TenantID") {InsertMethod = InsertMethod.None},
                new TableInfo("webstudio_settings", "TenantID") {UserIDColumns = new[] {"UserID"}},
                new TableInfo("webstudio_uservisit", "tenantid") {InsertMethod = InsertMethod.None}
            };

        private readonly RelationInfo[] _relations = new[]
            {
                new RelationInfo("crm_organisation_logo", "id", "webstudio_settings", "Data", typeof(CrmInvoiceModuleSpecifics),
                                 x => CrmSettingsId == new Guid(Convert.ToString(x["ID"])))
            };

        public override ModuleName ModuleName
        {
            get { return ModuleName.WebStudio; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return _tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return _relations; }
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
        {
            if (relation.ParentTable == "crm_organisation_logo")
            {
                bool success = true;
                value = Regex.Replace(
                    Convert.ToString(value),
                    @"(?<=""CompanyLogoID"":)\d+",
                    match =>
                        {
                            if (Convert.ToInt32(match.Value) == 0)
                            {
                                success = true;
                                return match.Value;
                            }
                            var mappedMessageId = Convert.ToString(columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, match.Value));
                            success = !string.IsNullOrEmpty(mappedMessageId);
                            return mappedMessageId;
                        });
                return success;
            }
            return base.TryPrepareValue(connection, columnMapper, relation, ref value);
        }
    }
}


<|start_filename|>web/core/ASC.Web.Core/Files/FilesLinkUtility.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;

using ASC.Core;
using ASC.Security.Cryptography;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Core.Files
{
    public static class FilesLinkUtility
    {
        public const string FilesBaseVirtualPath = "~/Products/Files/";
        public const string EditorPage = "DocEditor.aspx";
        private static readonly string FilesUploaderURL = ConfigurationManagerExtension.AppSettings["files.uploader.url"] ?? "~";

        public static string FilesBaseAbsolutePath
        {
            get { return CommonLinkUtility.ToAbsolute(FilesBaseVirtualPath); }
        }

        public const string FileId = "fileid";
        public const string FolderId = "folderid";
        public const string Version = "version";
        public const string FileUri = "fileuri";
        public const string FileTitle = "title";
        public const string Action = "action";
        public const string DocShareKey = "doc";
        public const string TryParam = "try";
        public const string FolderUrl = "folderurl";
        public const string OutType = "outputtype";
        public const string AuthKey = "stream_auth";
        public const string Anchor = "anchor";

        public static string FileHandlerPath
        {
            get { return FilesBaseAbsolutePath + "HttpHandlers/filehandler.ashx"; }
        }

        public static string DocServiceUrl
        {
            get
            {
                var url = GetUrlSetting("public");
                if (!string.IsNullOrEmpty(url) && url != "/")
                {
                    url = url.TrimEnd('/') + "/";
                }
                return url;
            }
            set
            {
                SetUrlSetting("api", null);

                value = (value ?? "").Trim().ToLowerInvariant();
                if (!string.IsNullOrEmpty(value))
                {
                    value = value.TrimEnd('/') + "/";
                    if (!new Regex(@"(^https?:\/\/)|^\/", RegexOptions.CultureInvariant).IsMatch(value))
                    {
                        value = "http://" + value;
                    }
                }

                SetUrlSetting("public", value);
            }
        }

        public static string DocServiceUrlInternal
        {
            get
            {
                var url = GetUrlSetting("internal");
                if (string.IsNullOrEmpty(url))
                {
                    url = DocServiceUrl;
                }
                else
                {
                    url = url.TrimEnd('/') + "/";
                }
                return url;
            }
            set
            {
                SetUrlSetting("converter", null);
                SetUrlSetting("storage", null);
                SetUrlSetting("command", null);
                SetUrlSetting("docbuilder", null);

                value = (value ?? "").Trim().ToLowerInvariant();
                if (!string.IsNullOrEmpty(value))
                {
                    value = value.TrimEnd('/') + "/";
                    if (!new Regex(@"(^https?:\/\/)", RegexOptions.CultureInvariant).IsMatch(value))
                    {
                        value = "http://" + value;
                    }
                }

                SetUrlSetting("internal", value);
            }
        }

        public static string DocServiceApiUrl
        {
            get
            {
                var url = GetUrlSetting("api");
                if (string.IsNullOrEmpty(url))
                {
                    url = DocServiceUrl;
                    if (!string.IsNullOrEmpty(url))
                    {
                        url += "web-apps/apps/api/documents/api.js";
                    }
                }
                return url;
            }
        }

        public static string DocServiceConverterUrl
        {
            get
            {
                var url = GetUrlSetting("converter");
                if (string.IsNullOrEmpty(url))
                {
                    url = DocServiceUrlInternal;
                    if (!string.IsNullOrEmpty(url))
                    {
                        url += "ConvertService.ashx";
                    }
                }
                return url;
            }
        }

        public static string DocServiceCommandUrl
        {
            get
            {
                var url = GetUrlSetting("command");
                if (string.IsNullOrEmpty(url))
                {
                    url = DocServiceUrlInternal;
                    if (!string.IsNullOrEmpty(url))
                    {
                        url += "coauthoring/CommandService.ashx";
                    }
                }
                return url;
            }
        }

        public static string DocServiceDocbuilderUrl
        {
            get
            {
                var url = GetUrlSetting("docbuilder");
                if (string.IsNullOrEmpty(url))
                {
                    url = DocServiceUrlInternal;
                    if (!string.IsNullOrEmpty(url))
                    {
                        url += "docbuilder";
                    }
                }
                return url;
            }
        }

        public static string DocServiceHealthcheckUrl
        {
            get
            {
                var url = GetUrlSetting("healthcheck");
                if (string.IsNullOrEmpty(url))
                {
                    url = DocServiceUrlInternal;
                    if (!string.IsNullOrEmpty(url))
                    {
                        url += "healthcheck";
                    }
                }
                return url;
            }
        }

        public static string DocServicePortalUrl
        {
            get { return GetUrlSetting("portal"); }
            set
            {
                value = (value ?? "").Trim().ToLowerInvariant();
                if (!string.IsNullOrEmpty(value))
                {
                    value = value.TrimEnd('/') + "/";
                    if (!new Regex(@"(^https?:\/\/)", RegexOptions.CultureInvariant).IsMatch(value))
                    {
                        value = "http://" + value;
                    }
                }

                SetUrlSetting("portal", value);
            }
        }

        public static string FileDownloadUrlString
        {
            get { return FileHandlerPath + "?" + Action + "=download&" + FileId + "={0}"; }
        }

        public static string GetFileDownloadUrl(object fileId)
        {
            return GetFileDownloadUrl(fileId, 0, string.Empty);
        }

        public static string GetFileDownloadUrl(object fileId, int fileVersion, string convertToExtension)
        {
            return string.Format(FileDownloadUrlString, HttpUtility.UrlEncode(fileId.ToString()))
                   + (fileVersion > 0 ? "&" + Version + "=" + fileVersion : string.Empty)
                   + (string.IsNullOrEmpty(convertToExtension) ? string.Empty : "&" + OutType + "=" + convertToExtension);
        }

        public static string GetFileWebMediaViewUrl(object fileId)
        {
            return FilesBaseAbsolutePath + "#preview/" + HttpUtility.UrlEncode(fileId.ToString());
        }

        public static string FileWebViewerUrlString
        {
            get { return FileWebEditorUrlString + "&" + Action + "=view"; }
        }

        public static string GetFileWebViewerUrlForMobile(object fileId, int fileVersion)
        {
            var viewerUrl = CommonLinkUtility.ToAbsolute("~/../Products/Files/") + EditorPage + "?" + FileId + "={0}";

            return string.Format(viewerUrl, HttpUtility.UrlEncode(fileId.ToString()))
                   + (fileVersion > 0 ? "&" + Version + "=" + fileVersion : string.Empty);
        }

        public static string FileWebViewerExternalUrlString
        {
            get { return FilesBaseAbsolutePath + EditorPage + "?" + FileUri + "={0}&" + FileTitle + "={1}&" + FolderUrl + "={2}"; }
        }

        public static string GetFileWebViewerExternalUrl(string fileUri, string fileTitle, string refererUrl = "")
        {
            return string.Format(FileWebViewerExternalUrlString, HttpUtility.UrlEncode(fileUri), HttpUtility.UrlEncode(fileTitle), HttpUtility.UrlEncode(refererUrl));
        }

        public static string FileWebEditorUrlString
        {
            get { return FilesBaseAbsolutePath + EditorPage + "?" + FileId + "={0}"; }
        }

        public static string GetFileWebEditorUrl(object fileId)
        {
            return string.Format(FileWebEditorUrlString, HttpUtility.UrlEncode(fileId.ToString()));
        }

        public static string GetFileWebEditorTryUrl(FileType fileType)
        {
            return FilesBaseAbsolutePath + EditorPage + "?" + TryParam + "=" + fileType;
        }

        public static string FileWebEditorExternalUrlString
        {
            get { return FileHandlerPath + "?" + Action + "=create&" + FileUri + "={0}&" + FileTitle + "={1}"; }
        }

        public static string GetFileWebEditorExternalUrl(string fileUri, string fileTitle)
        {
            return GetFileWebEditorExternalUrl(fileUri, fileTitle, false);
        }

        public static string GetFileWebEditorExternalUrl(string fileUri, string fileTitle, bool openFolder)
        {
            var url = string.Format(FileWebEditorExternalUrlString, HttpUtility.UrlEncode(fileUri), HttpUtility.UrlEncode(fileTitle));
            if (openFolder)
                url += "&openfolder=true";
            return url;
        }

        public static string GetFileWebPreviewUrl(string fileTitle, object fileId)
        {
            if (FileUtility.CanImageView(fileTitle) || FileUtility.CanMediaView(fileTitle))
                return GetFileWebMediaViewUrl(fileId);

            if (FileUtility.CanWebView(fileTitle))
            {
                if (FileUtility.ExtsMustConvert.Contains(FileUtility.GetFileExtension(fileTitle)))
                    return string.Format(FileWebViewerUrlString, HttpUtility.UrlEncode(fileId.ToString()));
                return GetFileWebEditorUrl(fileId);
            }

            return GetFileDownloadUrl(fileId);
        }

        public static string FileRedirectPreviewUrlString
        {
            get { return FileHandlerPath + "?" + Action + "=redirect"; }
        }

        public static string GetFileRedirectPreviewUrl(object enrtyId, bool isFile)
        {
            return FileRedirectPreviewUrlString + "&" + (isFile ? FileId : FolderId) + "=" + HttpUtility.UrlEncode(enrtyId.ToString());
        }

        public static string FileThumbnailUrlString
        {
            get { return FileHandlerPath + "?" + Action + "=thumb&" + FileId + "={0}"; }
        }

        public static string GetFileThumbnailUrl(object fileId, int fileVersion)
        {
            return string.Format(FileThumbnailUrlString, HttpUtility.UrlEncode(fileId.ToString()))
                   + (fileVersion > 0 ? "&" + Version + "=" + fileVersion : string.Empty);
        }


        public static string GetInitiateUploadSessionUrl(object folderId, object fileId, string fileName, long contentLength, bool encrypted)
        {
            var queryString = string.Format("?initiate=true&{0}={1}&fileSize={2}&tid={3}&userid={4}&culture={5}&encrypted={6}",
                                            FileTitle,
                                            HttpUtility.UrlEncode(fileName),
                                            contentLength,
                                            TenantProvider.CurrentTenantID,
                                            HttpUtility.UrlEncode(InstanceCrypto.Encrypt(SecurityContext.CurrentAccount.ID.ToString())),
                                            Thread.CurrentThread.CurrentUICulture.Name,
                                            encrypted.ToString().ToLower());

            if (fileId != null)
                queryString = queryString + "&" + FileId + "=" + HttpUtility.UrlEncode(fileId.ToString());

            if (folderId != null)
                queryString = queryString + "&" + FolderId + "=" + HttpUtility.UrlEncode(folderId.ToString());

            return CommonLinkUtility.GetFullAbsolutePath(GetFileUploaderHandlerVirtualPath() + queryString);
        }

        public static string GetUploadChunkLocationUrl(string uploadId)
        {
            var queryString = "?uid=" + uploadId;
            return CommonLinkUtility.GetFullAbsolutePath(GetFileUploaderHandlerVirtualPath() + queryString);
        }

        public static bool IsLocalFileUploader
        {
            get { return !Regex.IsMatch(FilesUploaderURL, "^http(s)?://\\.*"); }
        }

        private static string GetFileUploaderHandlerVirtualPath()
        {
            var virtualPath = FilesUploaderURL;
            return virtualPath.EndsWith(".ashx") ? virtualPath : virtualPath.TrimEnd('/') + "/ChunkedUploader.ashx";
        }

        private static string GetUrlSetting(string key, string appSettingsKey = null)
        {
            var value = string.Empty;
            if (CoreContext.Configuration.Standalone)
            {
                value = CoreContext.Configuration.GetSetting(GetSettingsKey(key));
            }
            if (string.IsNullOrEmpty(value))
            {
                value = ConfigurationManagerExtension.AppSettings["files.docservice.url." + (appSettingsKey ?? key)];
            }
            return value;
        }

        private static void SetUrlSetting(string key, string value)
        {
            if (!CoreContext.Configuration.Standalone)
            {
                throw new NotSupportedException("Method for server edition only.");
            }
            value = (value ?? "").Trim();
            if (string.IsNullOrEmpty(value)) value = null;
            if (GetUrlSetting(key) != value)
                CoreContext.Configuration.SaveSetting(GetSettingsKey(key), value);
        }

        private static string GetSettingsKey(string key)
        {
            return "DocKey_" + key;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Search/CasesWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Core;
using ASC.ElasticSearch;

namespace ASC.Web.CRM.Core.Search
{
    public sealed class CasesWrapper : Wrapper
    {
        [ColumnLastModified("last_modifed_on")]
        public override DateTime LastModifiedOn { get; set; }

        [Column("title", 1)]
        public string Title { get; set; }

        protected override string Table { get { return "crm_case"; } }

        public static implicit operator CasesWrapper(ASC.CRM.Core.Entities.Cases d)
        {
            return new CasesWrapper
            {
                Id = d.ID,
                Title = d.Title,
                TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId
            };
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Specific/CapabilitiesApi/CapabilitiesEntryPoint.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Linq;
using System.Web;

using ASC.ActiveDirectory.Base.Settings;
using ASC.Api.Attributes;
using ASC.Api.Impl;
using ASC.Api.Interfaces;
using ASC.Common.Logging;
using ASC.Core;
using ASC.FederatedLogin.LoginProviders;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.UserControls.Management.SingleSignOnSettings;
using ASC.Web.Studio.UserControls.Users.UserProfile;
using ASC.Web.Studio.Utility;

namespace ASC.Specific.CapabilitiesApi
{
    /// <summary>
    /// Capabilities for api
    /// </summary>
    public class CapabilitiesEntryPoint : IApiEntryPoint
    {
        /// <summary>
        /// Entry point name
        /// </summary>
        public string Name
        {
            get { return "capabilities"; }
        }

        ///<summary>
        /// Constructor
        ///</summary>
        ///<param name="context"></param>
        public CapabilitiesEntryPoint(ApiContext context)
        {
        }

        ///<summary>
        ///Returns the information about portal capabilities
        ///</summary>
        ///<short>
        ///Get portal capabilities
        ///</short>
        ///<returns>CapabilitiesData</returns>
        [Read("", false, false)] //NOTE: this method doesn't requires auth!!!  //NOTE: this method doesn't check payment!!!
        public CapabilitiesData GetPortalCapabilities()
        {
            var result = new CapabilitiesData
            {
                LdapEnabled = false,
                Providers = null,
                SsoLabel = string.Empty,
                SsoUrl = string.Empty
            };

            try
            {
                if (SetupInfo.IsVisibleSettings(ManagementType.LdapSettings.ToString())
                    && (!CoreContext.Configuration.Standalone
                        || CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Ldap))
                {
                    var settings = LdapSettings.Load();

                    result.LdapEnabled = settings.EnableLdapAuthentication;
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger("ASC").Error(ex.Message);
            }

            try
            {
                result.Providers = AccountLinkControl.AuthProviders
                                                     .Where(loginProvider =>
                                                         {
                                                             var provider = ProviderManager.GetLoginProvider(loginProvider);
                                                             return provider != null && provider.IsEnabled;
                                                         })
                                                     .ToList();
            }
            catch (Exception ex)
            {
                LogManager.GetLogger("ASC").Error(ex.Message);
            }

            try
            {
                if (SetupInfo.IsVisibleSettings(ManagementType.SingleSignOnSettings.ToString())
                    && CoreContext.TenantManager.GetTenantQuota(TenantProvider.CurrentTenantID).Sso)
                {
                    var settings = SsoSettingsV2.Load();

                    if (settings.EnableSso)
                    {
                        var uri = HttpContext.Current.Request.GetUrlRewriter();

                        var configUrl = GetAppSettings("web.sso.saml.login.url", "");

                        result.SsoUrl = string.Format("{0}://{1}{2}{3}", uri.Scheme, uri.Host,
                                                      (uri.Port == 80 || uri.Port == 443) ? "" : ":" + uri.Port, configUrl);

                        result.SsoLabel = settings.SpLoginLabel;
                    }
                }
            }
            catch (Exception ex)
            {
                LogManager.GetLogger("ASC").Error(ex.Message);
            }

            return result;
        }

        private static string GetAppSettings(string key, string defaultValue)
        {
            var result = ConfigurationManagerExtension.AppSettings[key] ?? defaultValue;

            if (!string.IsNullOrEmpty(result))
                result = result.Trim();

            return result;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/NotifyService/NotifyClient.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;

using ASC.Core;
using ASC.Files.Core;
using ASC.Files.Core.Security;
using ASC.Notify;
using ASC.Notify.Patterns;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Resources;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Files.Services.NotifyService
{
    public static class NotifyClient
    {
        public static INotifyClient Instance { get; private set; }

        static NotifyClient()
        {
            Instance = WorkContext.NotifyContext.NotifyService.RegisterClient(NotifySource.Instance);
        }

        public static void SendDocuSignComplete(File file, string sourceTitle)
        {
            var recipient = NotifySource.Instance.GetRecipientsProvider().GetRecipient(SecurityContext.CurrentAccount.ID.ToString());

            Instance.SendNoticeAsync(
                NotifyConstants.Event_DocuSignComplete,
                file.UniqID,
                recipient,
                true,
                new TagValue(NotifyConstants.Tag_DocumentUrl, CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.GetFileWebPreviewUrl(file.Title, file.ID))),
                new TagValue(NotifyConstants.Tag_DocumentTitle, file.Title),
                new TagValue(NotifyConstants.Tag_Message, sourceTitle)
                );
        }

        public static void SendDocuSignStatus(string subject, string status)
        {
            var recipient = NotifySource.Instance.GetRecipientsProvider().GetRecipient(SecurityContext.CurrentAccount.ID.ToString());

            Instance.SendNoticeAsync(
                NotifyConstants.Event_DocuSignStatus,
                null,
                recipient,
                true,
                new TagValue(NotifyConstants.Tag_DocumentTitle, subject),
                new TagValue(NotifyConstants.Tag_Message, status)
                );
        }

        public static void SendMailMergeEnd(Guid userId, int countMails, int countError)
        {
            var recipient = NotifySource.Instance.GetRecipientsProvider().GetRecipient(userId.ToString());

            Instance.SendNoticeAsync(
                NotifyConstants.Event_MailMergeEnd,
                null,
                recipient,
                true,
                new TagValue(NotifyConstants.Tag_MailsCount, countMails),
                new TagValue(NotifyConstants.Tag_Message, countError > 0 ? string.Format(FilesCommonResource.ErrorMassage_MailMergeCount, countError) : string.Empty)
                );
        }

        public static void SendShareNotice(FileEntry fileEntry, Dictionary<Guid, FileShare> recipients, string message)
        {
            if (fileEntry == null || recipients.Count == 0) return;

            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                if (fileEntry.FileEntryType == FileEntryType.File
                    && folderDao.GetFolder(((File)fileEntry).FolderID) == null) return;

                var url = fileEntry.FileEntryType == FileEntryType.File
                              ? FilesLinkUtility.GetFileWebPreviewUrl(fileEntry.Title, fileEntry.ID)
                              : PathProvider.GetFolderUrl((Folder)fileEntry);

                var recipientsProvider = NotifySource.Instance.GetRecipientsProvider();

                var action = fileEntry.FileEntryType == FileEntryType.File
                            ? ((File)fileEntry).Encrypted
                                ? NotifyConstants.Event_ShareEncryptedDocument
                                : NotifyConstants.Event_ShareDocument
                            : NotifyConstants.Event_ShareFolder;

                foreach (var recipientPair in recipients)
                {
                    var u = CoreContext.UserManager.GetUsers(recipientPair.Key);
                    var culture = string.IsNullOrEmpty(u.CultureName)
                                      ? CoreContext.TenantManager.GetCurrentTenant().GetCulture()
                                      : CultureInfo.GetCultureInfo(u.CultureName);

                    var aceString = GetAccessString(recipientPair.Value, culture);
                    var recipient = recipientsProvider.GetRecipient(u.ID.ToString());

                    Instance.SendNoticeAsync(
                        action,
                        fileEntry.UniqID,
                        recipient,
                        true,
                        new TagValue(NotifyConstants.Tag_DocumentTitle, fileEntry.Title),
                        new TagValue(NotifyConstants.Tag_DocumentUrl, CommonLinkUtility.GetFullAbsolutePath(url)),
                        new TagValue(NotifyConstants.Tag_AccessRights, aceString),
                        new TagValue(NotifyConstants.Tag_Message, message.HtmlEncode()),
                        Studio.Core.Notify.TagValues.Image(0, "privacy.png")
                        );
                }
            }
        }

        public static void SendEditorMentions(FileEntry file, string documentUrl, List<Guid> recipientIds, string message)
        {
            if (file == null || recipientIds.Count == 0) return;

            var recipientsProvider = NotifySource.Instance.GetRecipientsProvider();

            foreach (var recipientId in recipientIds)
            {
                var u = CoreContext.UserManager.GetUsers(recipientId);

                var recipient = recipientsProvider.GetRecipient(u.ID.ToString());

                Instance.SendNoticeAsync(
                    NotifyConstants.Event_EditorMentions,
                    file.UniqID,
                    recipient,
                    true,
                    new TagValue(NotifyConstants.Tag_DocumentTitle, file.Title),
                    new TagValue(NotifyConstants.Tag_DocumentUrl, CommonLinkUtility.GetFullAbsolutePath(documentUrl)),
                    new TagValue(NotifyConstants.Tag_Message, message.HtmlEncode())
                    );
            }
        }

        private static String GetAccessString(FileShare fileShare, CultureInfo cultureInfo)
        {
            switch (fileShare)
            {
                case FileShare.Read:
                    return FilesCommonResource.ResourceManager.GetString("AceStatusEnum_Read", cultureInfo);
                case FileShare.ReadWrite:
                    return FilesCommonResource.ResourceManager.GetString("AceStatusEnum_ReadWrite", cultureInfo);
                case FileShare.CustomFilter:
                    return FilesCommonResource.ResourceManager.GetString("AceStatusEnum_CustomFilter", cultureInfo);
                case FileShare.Review:
                    return FilesCommonResource.ResourceManager.GetString("AceStatusEnum_Review", cultureInfo);
                case FileShare.FillForms:
                    return FilesCommonResource.ResourceManager.GetString("AceStatusEnum_FillForms", cultureInfo);
                case FileShare.Comment:
                    return FilesCommonResource.ResourceManager.GetString("AceStatusEnum_Comment", cultureInfo);
                default:
                    return String.Empty;
            }
        }
    }
}

<|start_filename|>module/ASC.Files.Thirdparty/SharePoint/SharePointErrorEntry.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using Microsoft.SharePoint.Client;

namespace ASC.Files.Thirdparty.SharePoint
{
    public class SharePointFileErrorEntry : File
    {
        public SharePointFileErrorEntry(ClientRuntimeContext cc, ObjectPath op)
            : base(cc, op)
        {
        }

        public string Error { get; set; }

        public object ID { get; set; }
    }

    public class SharePointFolderErrorEntry : Folder
    {
        public SharePointFolderErrorEntry(ClientRuntimeContext cc, ObjectPath op)
            : base(cc, op)
        {
        }

        public string Error { get; set; }

        public object ID { get; set; }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Services/WCFService/FileEntrySerializer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;

using ASC.Core;
using ASC.Files.Core;

namespace ASC.Web.Files.Services.WCFService
{
    public class FileEntrySerializer
    {
        private static readonly IDictionary<Type, XmlObjectSerializer> serializers = new Dictionary<Type, XmlObjectSerializer>();
        private static readonly bool oldMonoSerializer = false;


        static FileEntrySerializer()
        {
            serializers[typeof(File)] = new DataContractSerializer(typeof(File));
            serializers[typeof(ItemList<FileEntry>)] = new DataContractSerializer(typeof(ItemList<FileEntry>));
            serializers[typeof(DataWrapper)] = new DataContractSerializer(typeof(DataWrapper));

            if (WorkContext.IsMono && !string.IsNullOrEmpty(WorkContext.MonoVersion))
            {
                // in version higher 4.0 use standard DataContractResolver
                var version = WorkContext.MonoVersion.Split('.', ' ');
                if (2 <= version.Length && (Convert.ToInt32(version[0]) * 1000 + Convert.ToInt32(version[1])) < 4002)
                {
                    oldMonoSerializer = true;
                    serializers[typeof(ItemList<FileEntry>)] = new DataContractSerializer(typeof(ItemList<FileEntry>), Type.EmptyTypes, UInt16.MaxValue, false, false, null, new FileEntryResolver());
                    serializers[typeof(DataWrapper)] = new DataContractSerializer(typeof(DataWrapper), Type.EmptyTypes, UInt16.MaxValue, false, false, null, new FileEntryResolver());
                }
            }
        }

        public System.IO.MemoryStream ToXml(object o)
        {
            var result = new System.IO.MemoryStream();
            if (o == null)
            {
                return result;
            }

            using (var writer = XmlDictionaryWriter.CreateTextWriter(result, Encoding.UTF8, false))
            {
                var serializer = serializers[o.GetType()];
                serializer.WriteObject(writer, o);
            }
            result.Seek(0, System.IO.SeekOrigin.Begin);

            if (oldMonoSerializer)
            {
                var xml = new XmlDocument();
                xml.PreserveWhitespace = true;
                xml.Load(result);
                result.Close();

                //remove incorrect ns
                foreach (XmlNode entry in xml.SelectNodes("//entry"))
                {
                    var nsattr = entry.Attributes.Cast<XmlAttribute>().FirstOrDefault(a => a.Value == typeof(FileEntry).Name);
                    if (nsattr != null)
                    {
                        foreach (XmlAttribute a in entry.Attributes)
                        {
                            if (a.Value.StartsWith(nsattr.LocalName + ":"))
                            {
                                a.Value = a.Value.Substring(nsattr.LocalName.Length + 1);
                            }
                        }
                        entry.Attributes.Remove(nsattr);
                    }
                }

                //http://stackoverflow.com/questions/13483138/mono-does-not-honor-system-runtime-serialization-datamemberattribute-emitdefault
                var nsmanager = new XmlNamespaceManager(xml.NameTable);
                nsmanager.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
                foreach (XmlNode nil in xml.SelectNodes("//*[@i:nil='true']", nsmanager))
                {
                    nil.ParentNode.RemoveChild(nil);
                }

                result = new System.IO.MemoryStream();
                xml.Save(result);
                result.Seek(0, System.IO.SeekOrigin.Begin);
            }

            return result;
        }


        private class FileEntryResolver : DataContractResolver
        {
            public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
            {
                return null;
            }

            public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
            {
                typeName = XmlDictionaryString.Empty;
                typeNamespace = XmlDictionaryString.Empty;

                if (declaredType == typeof(FileEntry))
                {
                    typeName = new XmlDictionaryString(XmlDictionary.Empty, type.Name.ToLower(), 0);
                    typeNamespace = new XmlDictionaryString(XmlDictionary.Empty, declaredType.Name, 0);
                    return true;
                }
                return false;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Core/Notify/Actions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Notify.Model;

namespace ASC.Web.Studio.Core.Notify
{
    static class Actions
    {
        public static readonly INotifyAction AdminNotify = new NotifyAction("admin_notify", "admin notifications");
        public static readonly INotifyAction PeriodicNotify = new NotifyAction("periodic_notify", "periodic notifications");

        public static readonly INotifyAction SelfProfileUpdated = new NotifyAction("self_profile_updated", "self profile updated");
        public static readonly INotifyAction UserHasJoin = new NotifyAction("user_has_join", "user has join");
        public static readonly INotifyAction UserMessageToAdmin = new NotifyAction("for_admin_notify", "for_admin_notify");
        public static readonly INotifyAction VoipWarning = new NotifyAction("admin_voip_warning", "admin_voip_warning");
        public static readonly INotifyAction VoipBlocked = new NotifyAction("admin_voip_blocked", "admin_voip_blocked");
        public static readonly INotifyAction RequestTariff = new NotifyAction("request_tariff", "request_tariff");
        public static readonly INotifyAction RequestLicense = new NotifyAction("request_license", "request_license");

        public static readonly INotifyAction YourProfileUpdated = new NotifyAction("profile_updated", "profile updated");
        public static readonly INotifyAction JoinUsers = new NotifyAction("join", "join users");
        public static readonly INotifyAction SendWhatsNew = new NotifyAction("send_whats_new", "send whats new");
        public static readonly INotifyAction BackupCreated = new NotifyAction("backup_created", "backup created");
        public static readonly INotifyAction RestoreStarted = new NotifyAction("restore_started", "restore_started");
        public static readonly INotifyAction RestoreCompletedV115 = new NotifyAction("restore_completed_v115");
        public static readonly INotifyAction PortalDeactivate = new NotifyAction("portal_deactivate", "portal deactivate");
        public static readonly INotifyAction PortalDelete = new NotifyAction("portal_delete", "portal delete");
        public static readonly INotifyAction PortalDeleteSuccessV115 = new NotifyAction("portal_delete_success_v115");

        public static readonly INotifyAction ProfileDelete = new NotifyAction("profile_delete", "profile_delete");
        public static readonly INotifyAction ProfileHasDeletedItself = new NotifyAction("profile_has_deleted_itself", "profile_has_deleted_itself");
        public static readonly INotifyAction ReassignsCompleted = new NotifyAction("reassigns_completed", "reassigns_completed");
        public static readonly INotifyAction ReassignsFailed = new NotifyAction("reassigns_failed", "reassigns_failed");
        public static readonly INotifyAction RemoveUserDataCompleted = new NotifyAction("remove_user_data_completed", "remove_user_data_completed");
        public static readonly INotifyAction RemoveUserDataCompletedCustomMode = new NotifyAction("remove_user_data_completed_custom_mode");
        public static readonly INotifyAction RemoveUserDataFailed = new NotifyAction("remove_user_data_failed", "remove_user_data_failed");
        public static readonly INotifyAction DnsChange = new NotifyAction("dns_change", "dns_change");

        public static readonly INotifyAction ConfirmOwnerChange = new NotifyAction("owner_confirm_change", "owner_confirm_change");
        public static readonly INotifyAction ActivateEmail = new NotifyAction("activate_email", "activate_email");
        public static readonly INotifyAction EmailChangeV115 = new NotifyAction("change_email_v115", "change_email_v115");
        public static readonly INotifyAction PasswordChange = new NotifyAction("change_password", "change_password");
        public static readonly INotifyAction PhoneChange = new NotifyAction("change_phone", "change_phone");
        public static readonly INotifyAction TfaChange = new NotifyAction("change_tfa", "change_tfa");
        public static readonly INotifyAction MigrationPortalStart = new NotifyAction("migration_start", "migration start");
        public static readonly INotifyAction MigrationPortalSuccessV115 = new NotifyAction("migration_success_v115");
        public static readonly INotifyAction MigrationPortalError = new NotifyAction("migration_error", "migration error");
        public static readonly INotifyAction MigrationPortalServerFailure = new NotifyAction("migration_server_failure", "migration_server_failure");
        public static readonly INotifyAction PortalRename = new NotifyAction("portal_rename", "portal_rename");

        public static readonly INotifyAction MailboxCreated = new NotifyAction("mailbox_created");
        public static readonly INotifyAction MailboxWithoutSettingsCreated = new NotifyAction("mailbox_without_settings_created");
        public static readonly INotifyAction MailboxPasswordChanged = new NotifyAction("mailbox_password_changed");

        public static readonly INotifyAction SaasAdminActivationV115 = new NotifyAction("saas_admin_activation_v115");
        public static readonly INotifyAction EnterpriseAdminActivationV10 = new NotifyAction("enterprise_admin_activation_v10");
        public static readonly INotifyAction EnterpriseWhitelabelAdminActivationV10 = new NotifyAction("enterprise_whitelabel_admin_activation_v10");
        public static readonly INotifyAction OpensourceAdminActivationV11 = new NotifyAction("opensource_admin_activation_v11");

        public static readonly INotifyAction SaasAdminWelcomeV115 = new NotifyAction("saas_admin_welcome_v115");
        public static readonly INotifyAction EnterpriseAdminWelcomeV10 = new NotifyAction("enterprise_admin_welcome_v10");
        public static readonly INotifyAction EnterpriseWhitelabelAdminWelcomeV10 = new NotifyAction("enterprise_whitelabel_admin_welcome_v10");
        public static readonly INotifyAction OpensourceAdminWelcomeV11 = new NotifyAction("opensource_admin_welcome_v11");

        public static readonly INotifyAction SaasUserActivationV115 = new NotifyAction("saas_user_activation_v115");
        public static readonly INotifyAction EnterpriseUserActivationV10 = new NotifyAction("enterprise_user_activation_v10");
        public static readonly INotifyAction EnterpriseWhitelabelUserActivationV10 = new NotifyAction("enterprise_whitelabel_user_activation_v10");
        public static readonly INotifyAction OpensourceUserActivationV11 = new NotifyAction("opensource_user_activation_v11");

        public static readonly INotifyAction SaasUserWelcomeV115 = new NotifyAction("saas_user_welcome_v115");
        public static readonly INotifyAction EnterpriseUserWelcomeV10 = new NotifyAction("enterprise_user_welcome_v10");
        public static readonly INotifyAction EnterpriseWhitelabelUserWelcomeV10 = new NotifyAction("enterprise_whitelabel_user_welcome_v10");
        public static readonly INotifyAction EnterpriseWhitelabelUserWelcomeCustomMode = new NotifyAction("enterprise_whitelabel_user_welcome_custom_mode");
        public static readonly INotifyAction OpensourceUserWelcomeV11 = new NotifyAction("opensource_user_welcome_v11");

        public static readonly INotifyAction SaasGuestActivationV115 = new NotifyAction("saas_guest_activation_v115");
        public static readonly INotifyAction EnterpriseGuestActivationV10 = new NotifyAction("enterprise_guest_activation_v10");
        public static readonly INotifyAction EnterpriseWhitelabelGuestActivationV10 = new NotifyAction("enterprise_whitelabel_guest_activation_v10");
        public static readonly INotifyAction OpensourceGuestActivationV11 = new NotifyAction("opensource_guest_activation_v11");

        public static readonly INotifyAction SaasGuestWelcomeV115 = new NotifyAction("saas_guest_welcome_v115");
        public static readonly INotifyAction EnterpriseGuestWelcomeV10 = new NotifyAction("enterprise_guest_welcome_v10");
        public static readonly INotifyAction EnterpriseWhitelabelGuestWelcomeV10 = new NotifyAction("enterprise_whitelabel_guest_welcome_v10");
        public static readonly INotifyAction OpensourceGuestWelcomeV11 = new NotifyAction("opensource_guest_welcome_v11");

        public static readonly INotifyAction EnterpriseAdminCustomizePortalV10 = new NotifyAction("enterprise_admin_customize_portal_v10");
        public static readonly INotifyAction EnterpriseWhitelabelAdminCustomizePortalV10 = new NotifyAction("enterprise_whitelabel_admin_customize_portal_v10");
        public static readonly INotifyAction EnterpriseAdminInviteTeammatesV10 = new NotifyAction("enterprise_admin_invite_teammates_v10");
        public static readonly INotifyAction EnterpriseAdminWithoutActivityV10 = new NotifyAction("enterprise_admin_without_activity_v10");
        public static readonly INotifyAction EnterpriseAdminUserDocsTipsV10 = new NotifyAction("enterprise_admin_user_docs_tips_v10");
        public static readonly INotifyAction EnterpriseAdminUserAppsTipsV10 = new NotifyAction("enterprise_admin_user_apps_tips_v10");

        public static readonly INotifyAction EnterpriseAdminTrialWarningBefore7V10 = new NotifyAction("enterprise_admin_trial_warning_before7_v10");
        public static readonly INotifyAction EnterpriseAdminTrialWarningV10 = new NotifyAction("enterprise_admin_trial_warning_v10");

        public static readonly INotifyAction EnterpriseAdminPaymentWarningBefore7V10 = new NotifyAction("enterprise_admin_payment_warning_before7_v10");
        public static readonly INotifyAction EnterpriseWhitelabelAdminPaymentWarningBefore7V10 = new NotifyAction("enterprise_whitelabel_admin_payment_warning_before7_v10");
        public static readonly INotifyAction EnterpriseAdminPaymentWarningV10 = new NotifyAction("enterprise_admin_payment_warning_v10");
        public static readonly INotifyAction EnterpriseWhitelabelAdminPaymentWarningV10 = new NotifyAction("enterprise_whitelabel_admin_payment_warning_v10");

        public static readonly INotifyAction SaasAdminUserDocsTipsV115 = new NotifyAction("saas_admin_user_docs_tips_v115");
        public static readonly INotifyAction SaasAdminComfortTipsV115 = new NotifyAction("saas_admin_comfort_tips_v115");
        public static readonly INotifyAction SaasAdminUserAppsTipsV115 = new NotifyAction("saas_admin_user_apps_tips_v115");

        public static readonly INotifyAction SaasAdminTrialWarningBefore5V115 = new NotifyAction("saas_admin_trial_warning_before5_v115");
        public static readonly INotifyAction SaasAdminTrialWarningV115 = new NotifyAction("saas_admin_trial_warning_v115");
        public static readonly INotifyAction SaasAdminTrialWarningAfter1V115 = new NotifyAction("saas_admin_trial_warning_after1_v115");
        public static readonly INotifyAction SaasAdminTrialWarningAfterHalfYearV115 = new NotifyAction("saas_admin_trial_warning_after_half_year_v115");

        public static readonly INotifyAction SaasAdminPaymentWarningEvery2MonthsV115 = new NotifyAction("saas_admin_payment_warning_every_2months_v115");

        public static readonly INotifyAction SaasAdminModulesV115 = new NotifyAction("saas_admin_modules_v115");

        public static readonly INotifyAction OpensourceAdminDocsTipsV11 = new NotifyAction("opensource_admin_docs_tips_v11");
        public static readonly INotifyAction OpensourceUserDocsTipsV11 = new NotifyAction("opensource_user_docs_tips_v11");

        public static readonly INotifyAction PersonalActivate = new NotifyAction("personal_activate");
        public static readonly INotifyAction PersonalAfterRegistration1 = new NotifyAction("personal_after_registration1");
        public static readonly INotifyAction PersonalAfterRegistration7 = new NotifyAction("personal_after_registration7");
        public static readonly INotifyAction PersonalAfterRegistration14 = new NotifyAction("personal_after_registration14");
        public static readonly INotifyAction PersonalAfterRegistration21 = new NotifyAction("personal_after_registration21");
        public static readonly INotifyAction PersonalAfterRegistration28 = new NotifyAction("personal_after_registration28");
        public static readonly INotifyAction PersonalConfirmation = new NotifyAction("personal_confirmation");
        public static readonly INotifyAction PersonalPasswordChange = new NotifyAction("personal_change_password");
        public static readonly INotifyAction PersonalEmailChangeV115 = new NotifyAction("personal_change_email_v115");
        public static readonly INotifyAction PersonalProfileDelete = new NotifyAction("personal_profile_delete");

        public static readonly INotifyAction PersonalCustomModeAfterRegistration1 = new NotifyAction("personal_custom_mode_after_registration1");
        public static readonly INotifyAction PersonalCustomModeAfterRegistration7 = new NotifyAction("personal_custom_mode_after_registration7");
        public static readonly INotifyAction PersonalCustomModeConfirmation = new NotifyAction("personal_custom_mode_confirmation");
        public static readonly INotifyAction PersonalCustomModePasswordChange = new NotifyAction("personal_custom_mode_change_password");
        public static readonly INotifyAction PersonalCustomModeEmailChangeV115 = new NotifyAction("personal_custom_mode_change_email_v115");
        public static readonly INotifyAction PersonalCustomModeProfileDelete = new NotifyAction("personal_custom_mode_profile_delete");

        public static readonly INotifyAction SaasCustomModeRegData = new NotifyAction("saas_custom_mode_reg_data");

        public static readonly INotifyAction StorageEncryptionStart = new NotifyAction("storage_encryption_start");
        public static readonly INotifyAction StorageEncryptionSuccess = new NotifyAction("storage_encryption_success");
        public static readonly INotifyAction StorageEncryptionError = new NotifyAction("storage_encryption_error");
        public static readonly INotifyAction StorageDecryptionStart = new NotifyAction("storage_decryption_start");
        public static readonly INotifyAction StorageDecryptionSuccess = new NotifyAction("storage_decryption_success");
        public static readonly INotifyAction StorageDecryptionError = new NotifyAction("storage_decryption_error");
    }
}

<|start_filename|>module/ASC.ElasticSearch/Engine/FactoryIndexer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;

using ASC.Common.Caching;
using ASC.Common.DependencyInjection;
using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.ElasticSearch.Core;
using ASC.ElasticSearch.Service;

using Autofac;

using Elasticsearch.Net;

using Nest;

namespace ASC.ElasticSearch
{
    public class FactoryIndexer<T> where T : Wrapper, new()
    {
        private static readonly ICache Cache = AscCache.Memory;
        private static readonly TaskScheduler Scheduler = new LimitedConcurrencyLevelTaskScheduler(10);
        private static readonly ILog Logger = LogManager.GetLogger("ASC.Indexer");

        public static bool Support
        {
            get
            {
                if (!FactoryIndexer.CheckState()) return false;
                var t = new T();

                var cacheTime = DateTime.UtcNow.AddMinutes(15);
                var key = "elasticsearch " + t.IndexName;
                try
                {
                    var cacheValue = Cache.Get<string>(key);
                    if (!string.IsNullOrEmpty(cacheValue))
                    {
                        return Convert.ToBoolean(cacheValue);
                    }

                    var service = new Service.Service();

                    var result = service.Support(t.IndexName);

                    Cache.Insert(key, result.ToString(CultureInfo.InvariantCulture).ToLower(), cacheTime);

                    return result;
                }
                catch (Exception e)
                {
                    Cache.Insert(key, "false", cacheTime);
                    Logger.Error("FactoryIndexer CheckState", e);
                    return false;
                }
            }
        }

        public static bool TrySelect(Expression<Func<Selector<T>, Selector<T>>> expression, out IReadOnlyCollection<T> result)
        {
            if (!Support || !Indexer.CheckExist(new T()))
            {
                result = new List<T>();
                return false;
            }

            try
            {
                result = Indexer.Select(expression);
            }
            catch (Exception e)
            {
                Logger.Error("Select", e);
                result = new List<T>();
                return false;
            }
            return true;
        }

        public static bool TrySelectIds(Expression<Func<Selector<T>, Selector<T>>> expression, out List<int> result)
        {
            if (!Support || !Indexer.CheckExist(new T()))
            {
                result = new List<int>();
                return false;
            }

            try
            {
                result = Indexer.Select(expression, true).Select(r => r.Id).ToList();
            }
            catch (Exception e)
            {
                Logger.Error("Select", e);
                result = new List<int>();
                return false;
            }

            return true;
        }

        public static bool TrySelectIds(Expression<Func<Selector<T>, Selector<T>>> expression, out List<int> result, out long total)
        {
            if (!Support || !Indexer.CheckExist(new T()))
            {
                result = new List<int>();
                total = 0;
                return false;
            }

            try
            {
                result = Indexer.Select(expression, true, out total).Select(r => r.Id).ToList();
            }
            catch (Exception e)
            {
                Logger.Error("Select", e);
                total = 0;
                result = new List<int>();
                return false;
            }

            return true;
        }

        public static bool Index(T data, bool immediately = true)
        {
            if (!Support) return false;

            try
            {
                Indexer.Index(data, immediately);
                return true;
            }
            catch (Exception e)
            {
                Logger.Error("Index", e);
            }
            return false;
        }

        public static void Index(List<T> data, bool immediately = true, int retry = 0)
        {
            if (!Support || !data.Any()) return;

            try
            {
                Indexer.Index(data, immediately);
            }
            catch(ElasticsearchClientException e)
            {
                Logger.Error(e);

                if (e.Response != null)
                {
                    Logger.Error(e.Response.HttpStatusCode);

                    if (e.Response.HttpStatusCode == 413 || e.Response.HttpStatusCode == 403 || e.Response.HttpStatusCode == 408)
                    {
                        data.ForEach(r => Index(r, immediately));
                    }
                    else if (e.Response.HttpStatusCode == 429)
                    {
                        Thread.Sleep(60000);
                        if (retry < 5)
                        {
                            Index(data, immediately, retry++);
                            return;
                        }

                        throw;
                    }
                }
            }
            catch (AggregateException e) //ElasticsearchClientException
            {
                if (e.InnerExceptions.Count == 0) throw;

                var inner = e.InnerExceptions.OfType<ElasticsearchClientException>().FirstOrDefault();


                if (inner != null)
                {
                    Logger.Error(inner);

                    if (inner.Response.HttpStatusCode == 413 || inner.Response.HttpStatusCode == 403)
                    {
                        Logger.Error(inner.Response.HttpStatusCode);
                        data.ForEach(r => Index(r, immediately));
                    }
                    else if(inner.Response.HttpStatusCode == 429)
                    {
                        Thread.Sleep(60000);
                        if (retry < 5)
                        {
                            Index(data, immediately, retry++);
                            return;
                        }

                        throw;
                    }
                }
                else
                {
                    throw;
                }
            }
        }

        public static async Task IndexAsync(List<T> data, bool immediately = true, int retry = 0)
        {
            if (!Support || !data.Any()) return;

            try
            {
                await Indexer.IndexAsync(data, immediately).ConfigureAwait(false);
            }
            catch(ElasticsearchClientException e)
            {
                Logger.Error(e);

                if (e.Response != null)
                {
                    Logger.Error(e.Response.HttpStatusCode);

                    if (e.Response.HttpStatusCode == 413 || e.Response.HttpStatusCode == 403 || e.Response.HttpStatusCode == 408)
                    {
                        data.ForEach(r => Index(r, immediately));
                    }
                    else if (e.Response.HttpStatusCode == 429)
                    {
                        await Task.Delay(60000);
                        if (retry < 5)
                        {
                            await IndexAsync(data, immediately, retry++);
                            return;
                        }

                        throw;
                    }
                }
            }
            catch (AggregateException e) //ElasticsearchClientException
            {
                if (e.InnerExceptions.Count == 0) throw;

                var inner = e.InnerExceptions.OfType<ElasticsearchClientException>().FirstOrDefault();


                if (inner != null)
                {
                    Logger.Error(inner);

                    if (inner.Response.HttpStatusCode == 413 || inner.Response.HttpStatusCode == 403)
                    {
                        Logger.Error(inner.Response.HttpStatusCode);
                        data.ForEach(r => Index(r, immediately));
                    }
                    else if(inner.Response.HttpStatusCode == 429)
                    {
                        await Task.Delay(60000);
                        if (retry < 5)
                        {
                            await IndexAsync(data, immediately, retry++);
                            return;
                        }

                        throw;
                    }
                }
                else
                {
                    throw;
                }
            }
        }

        public static void Update(T data, bool immediately = true, params Expression<Func<T, object>>[] fields)
        {
            if (!Support) return;

            try
            {
                Indexer.Update(data, immediately, fields);
            }
            catch (Exception e)
            {
                Logger.Error("Update", e);
            }
        }

        public static void Update(T data, UpdateAction action, Expression<Func<T, IList>> field, bool immediately = true)
        {
            if (!Support) return;
            try
            {
                Indexer.Update(data, action, field, immediately);
            }
            catch (Exception e)
            {
                Logger.Error("Update", e);
            }
        }

        public static void Update(T data, Expression<Func<Selector<T>, Selector<T>>> expression, bool immediately = true, params Expression<Func<T, object>>[] fields)
        {
            if (!Support) return;
            try
            {
                var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;
                Indexer.Update(data, expression, tenant, immediately, fields);
            }
            catch (Exception e)
            {
                Logger.Error("Update", e);
            }
        }

        public static void Update(T data, Expression<Func<Selector<T>, Selector<T>>> expression, UpdateAction action, Expression<Func<T, IList>> fields, bool immediately = true)
        {
            if (!Support) return;
            try
            {
                var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;
                Indexer.Update(data, expression, tenant, action, fields, immediately);
            }
            catch (Exception e)
            {
                Logger.Error("Update", e);
            }
        }

        public static void Delete(T data, bool immediately = true)
        {
            if (!Support) return;
            try
            {
                Indexer.Delete(data, immediately);
            }
            catch (Exception e)
            {
                Logger.Error("Delete", e);
            }
        }

        public static void Delete(Expression<Func<Selector<T>, Selector<T>>> expression, bool immediately = true)
        {
            if (!Support) return;
            var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;

            try
            {
                Indexer.Delete(expression, tenant, immediately);
            }
            catch (Exception e)
            {
                Logger.Error("Index", e);
            }
        }

        public static Task<bool> IndexAsync(T data, bool immediately = true)
        {
            if (!Support) return Task.FromResult(false);
            return Queue(() => Indexer.Index(data, immediately));
        }

        //public static Task<bool> IndexAsync(List<T> data, bool immediately = true)
        //{
        //    if (!Support) return Task.FromResult(false);
        //    return Queue(() => Indexer.Index(data, immediately));
        //}

        public static Task<bool> UpdateAsync(T data, bool immediately = true, params Expression<Func<T, object>>[] fields)
        {
            if (!Support) return Task.FromResult(false);
            return Queue(() => Indexer.Update(data, immediately, fields));
        }

        public static Task<bool> DeleteAsync(T data, bool immediately = true)
        {
            if (!Support) return Task.FromResult(false);
            return Queue(() => Indexer.Delete(data, immediately));
        }

        public static Task<bool> DeleteAsync(Expression<Func<Selector<T>, Selector<T>>> expression, bool immediately = true)
        {
            if (!Support) return Task.FromResult(false);
            var tenant = CoreContext.TenantManager.GetCurrentTenant().TenantId;
            return Queue(() => Indexer.Delete(expression, tenant, immediately));
        }


        public static void Flush()
        {
            if (!Support) return;
            Indexer.Flush();
        }

        public static void Refresh()
        {
            if (!Support) return;
            Indexer.Refresh();
        }

        private static BaseIndexer<T> Indexer
        {
            get { return new BaseIndexer<T>(FactoryIndexer.Builder.Resolve<T>()); }
        }

        private static Task<bool> Queue(Action actionData)
        {
            var task = new Task<bool>(() =>
            {
                try
                {
                    actionData();
                    return true;
                }
                catch (AggregateException agg)
                {
                    foreach (var e in agg.InnerExceptions)
                    {
                        Logger.Error(e);
                    }
                    throw;
                }

            }, TaskCreationOptions.LongRunning);

            task.ConfigureAwait(false);
            task.Start(Scheduler);
            return task;
        }
    }

    public class FactoryIndexer
    {
        private static readonly ICache cache = AscCache.Memory;
        internal static IContainer Builder { get; set; }
        internal static bool Init { get; set; }

        static FactoryIndexer()
        {
            try
            {
                var container = AutofacConfigLoader.Load("search");
                if (container != null)
                {
                    Builder = container.Build();
                    Init = true;
                }
                else
                {
                    LogManager.GetLogger("ASC.Indexer").Fatal("FactoryIndexer container == null");
                    return;
                }

                if (CheckState())
                {
                    Client.Instance.Ingest.PutPipeline("attachments", p => p
                        .Processors(pp => pp
                            .Attachment<Attachment>(a => a.Field("document.data").TargetField("document.attachment"))
                        ));
                }
            }
            catch (Exception e)
            {
                LogManager.GetLogger("ASC.Indexer").Fatal("FactoryIndexer", e);
            }
        }

        public static bool CheckState(bool cacheState = true)
        {
            if (!Init) return false;

            const string key = "elasticsearch";

            if (cacheState)
            {
                var cacheValue = cache.Get<string>(key);
                if (!string.IsNullOrEmpty(cacheValue))
                {
                    return Convert.ToBoolean(cacheValue);
                }
            }

            var cacheTime = DateTime.UtcNow.AddMinutes(15);
            var logger = LogManager.GetLogger("ASC.Indexer");

            try
            {
                var result = Client.Instance.Ping(new PingRequest());

                var isValid = result.IsValid;

                logger.DebugFormat("CheckState ping {0}", result.DebugInformation);

                if (cacheState)
                {
                    cache.Insert(key, isValid.ToString(CultureInfo.InvariantCulture).ToLower(), cacheTime);
                }

                return isValid;
            }
            catch (Exception e)
            {
                if (cacheState)
                {
                    cache.Insert(key, "false", cacheTime);
                }

                logger.Error("Ping false", e);
                return false;
            }
        }

        public static object GetState()
        {
            State state = null;
            IEnumerable<object> indices = null;
            Dictionary<string, long> count = null;

            if (!CoreContext.Configuration.Standalone)
            {
                return new
                {
                    state,
                    indices,
                    status = CheckState()
                };
            }

            using (var service = new ServiceClient())
            {
                state = service.GetState();
                count = service.GetCount();
            }

            if (state.LastIndexed.HasValue)
            {
                state.LastIndexed = TenantUtil.DateTimeFromUtc(state.LastIndexed.Value);
            }

            indices = Client.Instance.Cat.Indices(new CatIndicesRequest { SortByColumns = new[] { "index" } }).Records
                .Select(r => new
                {
                    r.Index,
                    Count = count.ContainsKey(r.Index) ? count[r.Index] : 0,
                    DocsCount = Client.Instance.Count(new CountRequest(r.Index)).Count,
                    r.StoreSize
                })
                .Where(r =>
                {
                    return r.Count > 0;
                });

            return new
            {
                state,
                indices,
                status = CheckState()
            };
        }

        public static void Reindex(string name)
        {
            if (!CoreContext.Configuration.Standalone) return;

            var generic = typeof(BaseIndexer<>);
            var indexers = Builder.Resolve<IEnumerable<Wrapper>>()
                .Where(r => string.IsNullOrEmpty(name) || r.IndexName == name)
                .Select(r => (IIndexer)Activator.CreateInstance(generic.MakeGenericType(r.GetType()), r));

            foreach (var indexer in indexers)
            {
                indexer.ReIndex();
            }
        }

    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_MultiValueHF.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Text;

    #endregion

    /// <summary>
    /// Implements generic multi value SIP header field.
    /// This is used by header fields like Via,Contact, ... .
    /// </summary>
    public class SIP_MultiValueHF<T> : SIP_HeaderField where T : SIP_t_Value, new()
    {
        #region Members

        private readonly List<T> m_pValues;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets header field value.
        /// </summary>
        public override string Value
        {
            get { return ToStringValue(); }

            set
            {
                if (value != null)
                {
                    throw new ArgumentNullException("Property Value value may not be null !");
                }

                Parse(value);

                base.Value = value;
            }
        }

        /// <summary>
        /// Gets header field values.
        /// </summary>
        public List<T> Values
        {
            get { return m_pValues; }
        }

        /// <summary>
        /// Gets values count.
        /// </summary>
        public int Count
        {
            get { return m_pValues.Count; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="name">Header field name.</param>
        /// <param name="value">Header field value.</param>
        public SIP_MultiValueHF(string name, string value) : base(name, value)
        {
            m_pValues = new List<T>();

            SetMultiValue(true);

            Parse(value);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets header field values.
        /// </summary>
        /// <returns></returns>
        public object[] GetValues()
        {
            return m_pValues.ToArray();
        }

        /// <summary>
        /// Removes value from specified index.
        /// </summary>
        /// <param name="index">Index of value to remove.</param>
        public void Remove(int index)
        {
            if (index > -1 && index < m_pValues.Count)
            {
                m_pValues.RemoveAt(index);
            }
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Parses multi value header field values.
        /// </summary>
        /// <param name="value">Header field value.</param>
        private void Parse(string value)
        {
            m_pValues.Clear();

            StringReader r = new StringReader(value);
            while (r.Available > 0)
            {
                r.ReadToFirstChar();
                // If we have COMMA, just consume it, it last value end.
                if (r.StartsWith(","))
                {
                    r.ReadSpecifiedLength(1);
                }

                // Allow xxx-param to pasre 1 value from reader.
                T param = new T();
                param.Parse(r);
                m_pValues.Add(param);
            }
        }

        /// <summary>
        /// Converts to valid mutli value header field value.
        /// </summary>
        /// <returns></returns>
        private string ToStringValue()
        {
            StringBuilder retVal = new StringBuilder();
            // Syntax: xxx-parm *(COMMA xxx-parm)
            for (int i = 0; i < m_pValues.Count; i++)
            {
                retVal.Append(m_pValues[i].ToStringValue());

                // Don't add comma for last item.
                if (i < m_pValues.Count - 1)
                {
                    retVal.Append(',');
                }
            }

            return retVal.ToString();
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Mail/MailApi.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;

using ASC.Api.Attributes;
using ASC.Api.Impl;
using ASC.Api.Interfaces;
using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Core;
using ASC.Mail.Core;
using ASC.Mail.Core.Engine.Operations.Base;
using ASC.Web.Mail.Resources;

namespace ASC.Api.Mail
{
    public partial class MailApi : IApiEntryPoint
    {
        private readonly ApiContext _context;

        private EngineFactory _engineFactory;

        private ILog _log;

        public const int DEFAULT_PAGE_SIZE = 25;

        ///<summary>
        /// Api name entry
        ///</summary>
        public string Name
        {
            get { return "mail"; }
        }

        private EngineFactory MailEngineFactory
        {
            get { return _engineFactory ?? (_engineFactory = new EngineFactory(TenantId, Username)); }
        }

        private ILog Logger
        {
            get { return _log ?? (_log = LogManager.GetLogger("ASC.Api")); }
        }

        private static int TenantId
        {
            get { return CoreContext.TenantManager.GetCurrentTenant().TenantId; }
        }

        private static string Username
        {
            get { return SecurityContext.CurrentAccount.ID.ToString(); }
        }

        private static CultureInfo CurrentCulture
        {
            get
            {
                var u = CoreContext.UserManager.GetUsers(new Guid(Username));

                var culture = !string.IsNullOrEmpty(u.CultureName)
                    ? u.GetCulture()
                    : CoreContext.TenantManager.GetCurrentTenant().GetCulture();

                return culture;
            }
        }

        /// <summary>
        /// Limit result per Contact System
        /// </summary>
        private static int MailAutocompleteMaxCountPerSystem
        {
            get
            {
                var count = 20;
                if (ConfigurationManagerExtension.AppSettings["mail.autocomplete-max-count"] == null)
                    return count;

                int.TryParse(ConfigurationManagerExtension.AppSettings["mail.autocomplete-max-count"], out count);
                return count;
            }
        }

        /// <summary>
        /// Timeout in milliseconds
        /// </summary>
        private static int MailAutocompleteTimeout
        {
            get
            {
                var count = 3000;
                if (ConfigurationManagerExtension.AppSettings["mail.autocomplete-timeout"] == null)
                    return count;

                int.TryParse(ConfigurationManagerExtension.AppSettings["mail.autocomplete-timeout"], out count);
                return count;
            }
        }

        ///<summary>
        /// Constructor
        ///</summary>
        ///<param name="context"></param>
        public MailApi(ApiContext context)
        {
            _context = context;
        }

        /// <summary>
        /// Returns all Mail runnung operations (only complex)
        /// </summary>
        /// <short>
        /// Get all Mail running complex operations
        /// </short>
        /// <returns>list of MailOperationResult</returns>
        [Read("operations")]
        public List<MailOperationStatus> GetMailOperations()
        {
            var list = MailEngineFactory.OperationEngine.GetMailOperations(TranslateMailOperationStatus);
            return list;
        }

        /// <summary>
        /// Returns Mail complex operation status
        /// </summary>
        /// <short>
        /// Get Mail complex operation status
        /// </short>
        /// <param name="operationId">Id of operation</param>
        /// <returns>MailOperationResult</returns>
        [Read("operations/{operationId}")]
        public MailOperationStatus GetMailOperation(string operationId)
        {
            return MailEngineFactory.OperationEngine.GetMailOperationStatus(operationId, TranslateMailOperationStatus);
        }

        /// <summary>
        /// Method for translation mail operation statuses
        /// </summary>
        /// <param name="op">instance of DistributedTask</param>
        /// <returns>translated status text</returns>
        private static string TranslateMailOperationStatus(DistributedTask op)
        {
            var type = op.GetProperty<MailOperationType>(MailOperation.OPERATION_TYPE);
            var status = op.GetProperty<string>(MailOperation.STATUS);
            //TODO: Move strings to Resource file
            switch (type)
            {
                case MailOperationType.DownloadAllAttachments:
                {
                    var progress = op.GetProperty<MailOperationDownloadAllAttachmentsProgress>(MailOperation.PROGRESS);
                    switch (progress)
                    {
                        case MailOperationDownloadAllAttachmentsProgress.Init:
                            return MailApiResource.SetupTenantAndUserHeader;
                        case MailOperationDownloadAllAttachmentsProgress.GetAttachments:
                            return MailApiResource.GetAttachmentsHeader;
                        case MailOperationDownloadAllAttachmentsProgress.Zipping:
                            return MailApiResource.ZippingAttachmentsHeader;
                        case MailOperationDownloadAllAttachmentsProgress.ArchivePreparation:
                            return MailApiResource.PreparationArchiveHeader;
                        case MailOperationDownloadAllAttachmentsProgress.CreateLink:
                            return MailApiResource.CreatingLinkHeader;
                        case MailOperationDownloadAllAttachmentsProgress.Finished:
                            return MailApiResource.FinishedHeader;
                        default:
                            return status;
                    }
                }
                case MailOperationType.RemoveMailbox:
                {
                    var progress = op.GetProperty<MailOperationRemoveMailboxProgress>(MailOperation.PROGRESS);
                    switch (progress)
                    {
                        case MailOperationRemoveMailboxProgress.Init:
                            return "Setup tenant and user";
                        case MailOperationRemoveMailboxProgress.RemoveFromDb:
                            return "Remove mailbox from Db";
                        case MailOperationRemoveMailboxProgress.FreeQuota:
                            return "Decrease newly freed quota space";
                        case MailOperationRemoveMailboxProgress.RecalculateFolder:
                            return "Recalculate folders counters";
                        case MailOperationRemoveMailboxProgress.ClearCache:
                            return "Clear accounts cache";
                        case MailOperationRemoveMailboxProgress.Finished:
                            return "Finished";
                        default:
                            return status;
                    }
                }
                case MailOperationType.RecalculateFolders:
                {
                    var progress = op.GetProperty<MailOperationRecalculateMailboxProgress>(MailOperation.PROGRESS);
                    switch (progress)
                    {
                        case MailOperationRecalculateMailboxProgress.Init:
                            return "Setup tenant and user";
                        case MailOperationRecalculateMailboxProgress.CountUnreadMessages:
                            return "Calculate unread messages";
                        case MailOperationRecalculateMailboxProgress.CountTotalMessages:
                            return "Calculate total messages";
                        case MailOperationRecalculateMailboxProgress.CountUreadConversation:
                            return "Calculate unread conversations";
                        case MailOperationRecalculateMailboxProgress.CountTotalConversation:
                            return "Calculate total conversations";
                        case MailOperationRecalculateMailboxProgress.UpdateFoldersCounters:
                            return "Update folders counters";
                        case MailOperationRecalculateMailboxProgress.CountUnreadUserFolderMessages:
                            return "Calculate unread messages in user folders";
                        case MailOperationRecalculateMailboxProgress.CountTotalUserFolderMessages:
                            return "Calculate total messages in user folders";
                        case MailOperationRecalculateMailboxProgress.CountUreadUserFolderConversation:
                            return "Calculate unread conversations in user folders";
                        case MailOperationRecalculateMailboxProgress.CountTotalUserFolderConversation:
                            return "Calculate total conversations in user folders";
                        case MailOperationRecalculateMailboxProgress.UpdateUserFoldersCounters:
                            return "Update user folders counters";
                        case MailOperationRecalculateMailboxProgress.Finished:
                            return "Finished";
                        default:
                            return status;
                    }
                }
                case MailOperationType.RemoveUserFolder:
                {
                    var progress = op.GetProperty<MailOperationRemoveUserFolderProgress>(MailOperation.PROGRESS);
                    switch (progress)
                    {
                        case MailOperationRemoveUserFolderProgress.Init:
                            return "Setup tenant and user";
                        case MailOperationRemoveUserFolderProgress.MoveMailsToTrash:
                            return "Move mails into Trash folder";
                        case MailOperationRemoveUserFolderProgress.DeleteFolders:
                            return "Delete folder";
                        case MailOperationRemoveUserFolderProgress.Finished:
                            return "Finished";
                        default:
                            return status;
                    }
                }
                default:
                    return status;
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/js/subtasks.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.Projects.SubtasksManager = (function () {
    var common = ASC.Projects.Common;

    var currentUserId,
        currentProjectId,
        teamsHash = {},
        $subtaskContainer = null,
        editFlag = false,
        subtaskResponsible = null,
        isInit,
        tasks,
        clickEventName = "click",
        $subtaskNameInput,
        teamlab,
        resources = ASC.Projects.Resources;

    // key codes
    var escKey = 27,
        enterKey = 13;

    var allUsers;

    var init = function () {
        if (isInit) {
            return;
        }

        isInit = true;
        teamlab = Teamlab;
        allUsers = UserManager.getAllUsers(true);

        currentUserId = teamlab.profile.id;
        currentProjectId = jq.getURLParam("prjID");

        if (currentProjectId) {
            teamsHash = {};
            teamsHash[currentProjectId] = ASC.Projects.Master.Team;
        }

        //add subtask panels

        ASC.Projects.DescriptionPanel.init(jq("#CommonListContainer"), null,
        {
            getItem: function (target) {
                var $targetObject = jq(target),
                    $targetParent = $targetObject.parents(".subtask"),
                    subtask = getFilteredSubTaskById($targetParent.attr("id"));

                return subtask;
            },
            selector: '.subtask .taskName span'
        });

        jq(document).on('dblclick', '.subtask .taskName', function () {
            var $self = jq(this);
            if (!$self.is('.canedit') || $self.parent('.subtask').is('.closed')) return false;

            var editedSubtaskId = $self.parent(".subtask").attr('id');
            editSubtask(editedSubtaskId);
            return true;
        });

        jq(document).on(clickEventName, ".subtask-add-button .button", function () {
            beforeSubtaskAction();
            return false;
        });

        jq(document).on("keydown", ".subtask-name-input", function (e) {
            switch(e.which){
                case escKey:
                    hideSubtaskFields();
                    break;
                case enterKey:
                    jq(this).prop("disabled", true);
                    beforeSubtaskAction();
                    break;
                default:
            }
        });

        jq(document).on('change', '.subtask .check input', function () {
            var self = jq(this).parents(".subtask"),
                subtaskId = self.attr('id'),
                subtask = getFilteredSubTaskById(subtaskId),
                taskId = subtask.taskid;

            if (jq(this).is(':checked')) {
                closeSubTask(self, taskId);
            } else {
                showSubtaskLoader(self.closest(".check"));
                updateSubtaskStatus({}, taskId, subtaskId, { status: 'open' });
            }
        });

        // click events
        jq(document).on(clickEventName, '.quickAddSubTaskLink span', function () {
            showNewSubtaskField(jq(this).parent());
            return false;
        });

        jq(document).on(clickEventName, "#quickAddSubTaskField", function (event) {
            $subtaskNameInput = jq('.subtask-name-input');
            $subtaskNameInput.focus();
        });

        teamlab.bind(teamlab.events.updatePrjTeam, function(params, team) {
            teamsHash[params.projectId] = team;
        });
    };

    function staEditHandler(subtaskid) {
        editSubtask(subtaskid);
        return false;
    };

    function staAcceptHandler(subtask, taskId) {
        var data = {
            title: subtask.title,
            responsible: currentUserId,
            description: ''
        };

        teamlab.updatePrjSubtask({}, taskId, subtask.id, data, { success: onUpdateSubtask });
        return false;
    };

    function staCopyHandler(subtaskid, taskid) {
        $subtaskContainer = jq('.subtasks[taskid=' + taskid + ']');
        teamlab.copyPrjSubtask({ taskid: taskid }, taskid, subtaskid, { success: onAddSubtask });
        return false;
    };

    function staRemoveHandler(subtaskid, taskId) {
        teamlab.removePrjSubtask({ taskId: taskId }, taskId, subtaskid, { success: onRemoveSubtask });
        return false;
    };

    function showEntityMenu(selectedActionCombobox) {
        var subtaskid = selectedActionCombobox.attr("id"),
            subtask = getFilteredSubTaskById(subtaskid),
            taskid = subtask.taskid,
            task = getFilteredTaskById(taskid),
            ActionMenuItem = ASC.Projects.ActionMenuItem;

        var menuItems = [];

        if (subtask.status != 2) {
            if (!subtask.responsible) {
                menuItems.push(new ActionMenuItem("sta_accept", resources.TaskResource.AcceptSubtask, staAcceptHandler.bind(null, subtask, taskid), "accept"));
            }

            if (subtask.canEdit) {
                menuItems.push(new ActionMenuItem("sta_edit", resources.TaskResource.Edit, staEditHandler.bind(null, subtaskid, taskid), "edit"));
            }

            if (task.canCreateSubtask) {
                menuItems.push(new ActionMenuItem("sta_copy", resources.ProjectsCommonResource.Copy, staCopyHandler.bind(null, subtaskid, taskid), "move-or-copy"));
            }
        }

        if (subtask.canEdit) {
            if (menuItems.length == 3) {
                menuItems.push(new ActionMenuItem(null, null, null, null, true));
            }

            menuItems.push(new ActionMenuItem("sta_remove", resources.ProjectsCommonResource.Delete, staRemoveHandler.bind(null, subtaskid, taskid), "delete"));
        }
        return { menuItems: menuItems };
    }

    function onAddSubtask(params, subtask) {
        if ($subtaskContainer.find('.subtask').length) {
            var elem = $subtaskContainer.find('.quickAddSubTaskLink');
            jq.tmpl("projects_subtaskTemplate", subtask).insertBefore(elem);

        } else {
            jq.tmpl("projects_subtaskTemplate", subtask).prependTo($subtaskContainer);
            $subtaskContainer.show();
        }
        jq(".subtask-loader").remove();

        $subtaskNameInput = jq('.subtask-name-input');
        $subtaskNameInput.removeAttr('disabled');
        $subtaskNameInput.val('');
        $subtaskNameInput.focus();
    };

    function onUpdateSubtask(params, subtask) {
        jq('.subtask[id="' + subtask.id + '"]').replaceWith(jq.tmpl("projects_subtaskTemplate", subtask));
        hideSubtaskFields();
        setFilteredSubTask(subtask);
    };

    function closeSubTask($subtask, taskId) {
        showSubtaskLoader($subtask.find(".check"));
        setTimeout(function () { $subtask.yellowFade(); }, 0);

        var data = {
            title:jq.trim( $subtask.find(".taskName span").text()),
            responsible: currentUserId,
            status: 'closed'
        };

        updateSubtaskStatus({}, taskId, $subtask.attr("id"), data);
    };

    function updateSubtaskStatus(params, taskId, subtaskId, data) {
        teamlab.updatePrjSubtask(params, taskId, subtaskId, data, { success: onUpdateSubtaskStatus });
    };

    function onUpdateSubtaskStatus(params, subtask) {
        var $oldSubtask = getSubtaskElem(subtask.id);
        var $subtaskCont = jq($oldSubtask).closest('.subtasks');

        $oldSubtask.remove();

        if (subtask.status == 1) {
            jq.tmpl("projects_subtaskTemplate", subtask).prependTo($subtaskCont);
        } else {
            jq.tmpl("projects_subtaskTemplate", subtask).appendTo($subtaskCont);
        }

        jq('.subtask-loader').remove();
    };

    function onRemoveSubtask(params, subtask) {
        getSubtaskElem(subtask.id).remove();
    };

    function showSubtaskLoader(inputBox) {
        if (inputBox.hasClass("check")) {
            inputBox.find("input").hide();
        }
        inputBox.prepend('<div class="subtask-loader"></div>');
    };

    function setTeamForResponsibleSelect(projectId) {
        if (teamsHash && teamsHash.hasOwnProperty(projectId)) {
            initResponsibleSelector(teamsHash[projectId]);
        } else {
            teamlab.getPrjTeam({projectId: projectId}, projectId, {
                success: function (params, team) {
                    teamsHash[params.projectId] = team;
                    initResponsibleSelector(team);
                }
            });
        }
    };

    function initResponsibleSelector(team) {
        var validTeamMembers = common.excludeVisitors(team),
            nobody = {
                id: "00000000-0000-0000-0000-000000000000",
                displayName: ASC.Projects.Resources.TaskResource.NoResponsible
            },
            $responsibleSelector = jq(".subtask-responsible-selector");

        validTeamMembers = common.removeBlockedUsersFromTeam(validTeamMembers);
        validTeamMembers = [nobody].concat(validTeamMembers);

        function mapTeamMember(item) {
            return { id: item.id, title: item.displayName };
        }

        var choose = allUsers[subtaskResponsible];
        if (!choose) {
            choose = nobody;
        }

        $responsibleSelector.advancedSelector({
            showSearch: false,
            onechosen: true,
            itemsChoose: validTeamMembers.map(mapTeamMember),
            sortMethod: function () { return 0; },
            inPopup: true,
            $parent: jq(".mainPageContent"),
        }).on("showList", function (event, item) {
            $responsibleSelector.attr("data-id", item.id).html(item.title).attr("title", item.title);
            $subtaskNameInput = jq('.subtask-name-input');
            $subtaskNameInput.focus();
        });

        $responsibleSelector.advancedSelector("selectBeforeShow", mapTeamMember(choose));
    };

    function beforeSubtaskAction() {
        $subtaskNameInput = jq('.subtask-name-input');
        $subtaskContainer = $subtaskNameInput.closest(".subtasks");

        var subtask = {
            title: $subtaskNameInput.val().trim()
        };

        if (subtask.title.length == 0) {
            if (!editFlag) {
                hideSubtaskFields();
            } else {
                $subtaskNameInput.focus();
            }
            return false;
        }

        subtask.responsible = jq(".subtask-responsible-selector").attr("data-id");
        subtask.taskId = $subtaskContainer.attr("taskid");

        var params = {
            taskid: subtask.taskId
        };

        showSubtaskLoader($subtaskNameInput.closest(".subtask-name"));

        if (editFlag) {
            subtask.id = $subtaskNameInput.data("subtaskid");
            teamlab.updatePrjSubtask(params, subtask.taskId, subtask.id, subtask, { success: onUpdateSubtask });
        } else {
            teamlab.addPrjSubtask(params, subtask.taskId, subtask, { success: onAddSubtask });
        }
    };

    var showNewSubtaskField = function ($addLink) {
        hideSubtaskFields();

        var subtask = {
            subtaskid: "-1",
            title: "",
            projectid: "",
            responsible: null
        };

        var task = getFilteredTaskById($addLink.parents(".subtasks").attr('taskid'));
        if (!task) return;
        jq.tmpl("projects_fieldForAddSubtask", subtask).insertAfter($addLink);
        subtaskResponsible = null;
        setTeamForResponsibleSelect(task.projectId);
        $addLink.hide();
        jq("#quickAddSubTaskField").removeClass("display-none");

        $subtaskNameInput = jq('.subtask-name-input');
        $subtaskNameInput.focus();
    };

    function editSubtask(subtaskid) {
        hideSubtaskFields();
        editFlag = true;

        var $subtask = getSubtaskElem(subtaskid);
        var subtask = getFilteredSubTaskById(subtaskid);
        var taskid = subtask.taskid;

        var task = getFilteredTaskById(taskid);

        var data = {
            subtaskid: subtaskid,
            title: subtask.title,
            taskid: subtask.taskid,
            projectid: task.projectId,
            responsible: subtask.responsible == null ? null : subtask.responsible.id

        };

        subtaskResponsible = subtask.responsible == null ? common.emptyGuid : subtask.responsible.id;
        
        jq.tmpl("projects_fieldForAddSubtask", data).insertAfter($subtask);
        setTeamForResponsibleSelect(data.projectid);
        $subtask.find(".taskName").hide();

        var editField = jq("#quickAddSubTaskField");
        editField.addClass("absolute");
        editField.css("top", $subtask.position().top + "px");
        editField.removeClass("display-none");

        $subtaskNameInput = jq('.subtask-name-input');
        $subtaskNameInput.removeAttr('disabled');
        $subtaskNameInput.focus();
    };

    function hideSubtaskFields() {
        jq("#quickAddSubTaskField").remove();
        if (!editFlag) {
            jq(".task:not(.closed)").next().find(".quickAddSubTaskLink").show();
            jq("#subtaskContainer .quickAddSubTaskLink").show();
        }
        jq(".subtask .taskName").show();
        editFlag = false;
    };

    function setTasks(currentTasks) {
        tasks = currentTasks;
    }

    function getFilteredTaskById(taskId) {
        for (var i = 0, max = tasks.length; i < max; i++) {
            if (tasks[i].id == taskId) {
                return tasks[i];
            }
        }
    };

    function getFilteredSubTaskById(subtaskId) {
        for (var i = 0, max = tasks.length; i < max; i++) {
            var subtasks = tasks[i].subtasks;
            for (var j = 0, maxSubtasks = subtasks.length; j < maxSubtasks; j++) {
                if (subtasks[j].id == subtaskId) {
                    return subtasks[j];
                }
            }
        }
    };

    function setFilteredSubTask(subtask) {
        for (var i = 0, max = tasks.length; i < max; i++) {
            var subtasks = tasks[i].subtasks;
            for (var j = 0, maxSubtasks = subtasks.length; j < maxSubtasks; j++) {
                if (subtasks[j].id == subtask.id) {
                    subtasks[j] = subtask;
                    return;
                }
            }
        }
    };

    function getSubtaskElem(subtaskId) {
        return jq(".subtasks div[id=" + subtaskId + "]:visible");
    }

    return {
        init: init,
        hideSubtaskFields: hideSubtaskFields,
        addFirstSubtask: showNewSubtaskField,
        setTasks: setTasks,
        showEntityMenu: showEntityMenu
    };
})(jQuery);

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/DbSchema/Tables/MailboxAutoreplyTable.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


// ReSharper disable InconsistentNaming

using System.Collections.Generic;

using ASC.Mail.Core.DbSchema.Interfaces;

namespace ASC.Mail.Core.DbSchema.Tables
{
    public class MailboxAutoreplyTable : ITable
    {
        public const string TABLE_NAME = "mail_mailbox_autoreply";

        public static class Columns
        {
            public const string MailboxId = "id_mailbox";
            public const string Tenant = "tenant";
            public const string TurnOn = "turn_on";
            public const string OnlyContacts = "only_contacts";
            public const string TurnOnToDate = "turn_on_to_date";
            public const string FromDate = "from_date";
            public const string ToDate = "to_date";
            public const string Subject = "subject";
            public const string Html = "html";
        }

        public string Name
        {
            get { return TABLE_NAME; }
        }

        public IEnumerable<string> OrderedColumnCollection { get; private set; }

        public MailboxAutoreplyTable()
        {
            OrderedColumnCollection = new List<string>
            {
                Columns.MailboxId,
                Columns.Tenant,
                Columns.TurnOn,
                Columns.OnlyContacts,
                Columns.TurnOnToDate,
                Columns.FromDate,
                Columns.ToDate,
                Columns.Subject,
                Columns.Html
            };
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/MIME/O/MIME_MultipartBody.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

using LumiSoft.Net.IO;

namespace LumiSoft.Net.MIME
{
    /// <summary>
    /// Represents MIME entity multipart/... body. Defined in RFC 2045.
    /// </summary>
    public class MIME_MultipartBody : MIME_Body
    {
        #region class _MIME_MultipartReader

        /// <summary>
        /// This class implements mulitpart/xxx body parts reader.
        /// </summary>
        internal class _MIME_MultipartReader : LineReader
        {
            #region enum State

            /// <summary>
            /// Specifies reader state.
            /// </summary>
            private enum State
            {            
                /// <summary>
                /// Body reading pending, the whole body isn't readed yet.
                /// </summary>
                InBody,

                /// <summary>
                /// First "body part" start must be searched.
                /// </summary>
                SeekFirst,

                /// <summary>
                /// Multipart "body part" reading has completed, next "body part" reading is pending.
                /// </summary>
                NextWaited,

                /// <summary>
                /// All "body parts" readed.
                /// </summary>
                Finished,
            }

            #endregion

            private LineReader m_pReader  = null;
            private string     m_Boundary = "";
            private State      m_State    = State.SeekFirst;

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="reader">Line reader.</param>
            /// <param name="boundary">Boundary ID.</param>
            public _MIME_MultipartReader(LineReader reader,string boundary) : base(reader.Stream,false,32000)
            {
                m_pReader  = reader;
                m_Boundary = boundary;

                if(reader.CanSyncStream){
                    reader.SyncStream();
                }
            }


            #region method Next

            /// <summary>
            /// Moves to next "body part". Returns true if moved to next "body part" or false if there are no more parts.
            /// </summary>
            /// <returns>Returns true if moved to next "body part" or false if there are no more parts.</returns>
            public bool Next()
            {
                // Seek first.
                if(m_State == State.SeekFirst){
                    while(true){
                        string line = m_pReader.ReadLine();
                        // We reached end of stream, no more data.
                        if(line == null){
                            m_State = State.Finished;

                            return false;
                        }
                        else if(line == "--" + m_Boundary){
                            m_State = State.InBody;

                            return true;
                        }
                    }
                }
                else if(m_State != State.NextWaited){
                    return false;
                }
                else{
                    m_State = State.InBody;

                    return true;
                }
            }

            #endregion


            #region method override ReadLine

            /// <summary>
            /// Reads binary line and stores it to the specified buffer.
            /// </summary>
            /// <param name="buffer">Buffer where to store line data.</param>
            /// <param name="offset">Start offset in the buffer.</param>
            /// <param name="count">Maximum number of bytes store to the buffer.</param>
            /// <param name="exceededAction">Specifies how reader acts when line buffer too small.</param>
            /// <param name="rawBytesReaded">Gets raw number of bytes readed from source.</param>
            /// <returns>Returns number of bytes stored to <b>buffer</b> or -1 if end of stream reached.</returns>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
            /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
            /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
            /// <exception cref="LineSizeExceededException">Is raised when line is bigger than <b>buffer</b> can store.</exception>
            public override int ReadLine(byte[] buffer,int offset,int count,SizeExceededAction exceededAction,out int rawBytesReaded)
            {
                rawBytesReaded = 0;

                // We are at the end of body or "body part".
                if(m_State == State.Finished || m_State == State.NextWaited){
                    return -1;
                }
                // Read next line.
                else{
                    int readedCount = m_pReader.ReadLine(buffer,offset,count,exceededAction,out rawBytesReaded);
                    // End of stream reached, no more data.
                    if(readedCount == -1){
                        m_State = State.Finished;

                        return -1;
                    }
                    // For multipart we must check boundary tags.
                    else if(!string.IsNullOrEmpty(m_Boundary) && readedCount > 2 && buffer[0] == '-'){
                        string line = Encoding.Default.GetString(buffer,0,readedCount);

                        // Boundray end-tag reached, no more "body parts".
                        if(line == "--" + m_Boundary + "--"){
                            m_State = State.Finished;

                            return -1;
                        }
                        // Boundary start-tag reached, wait for this.Next() call.
                        else if(line == "--" + m_Boundary){
                            m_State = State.NextWaited;

                            return -1;
                        }
                    }

                    return readedCount;
                }
            }

            #endregion

            #region method SyncStream

            /// <summary>
            /// Sets stream position to the place we have consumed from stream and clears buffer data.
            /// For example if we have 10 byets in buffer, stream position is actually +10 bigger than 
            /// we readed, the result is that stream.Position -= 10 and buffer is cleared.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
            /// <exception cref="InvalidOperationException">Is raised when source stream won't support seeking.</exception>
            public override void SyncStream()
            {
                m_pReader.SyncStream();
            }

            #endregion


            #region Properties Implementation

            #endregion
        }

        #endregion

        private string                m_Boundary = "";
        private MIME_EntityCollection m_pParts   = null;

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner MIME entity.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> is null.</exception>
        internal MIME_MultipartBody(MIME_Entity owner) : base(owner)
        {
            m_Boundary = owner.ContentType.Param_Boundary;

            m_pParts = new MIME_EntityCollection();
        }
                        
        
        #region override method ToStream

        /// <summary>
        /// Stores MIME entity body data to the specified stream
        /// </summary>
        /// <param name="stream">Stream where to store body. Storing starts from stream current position.</param> 
        /// <param name="encoded">If true, encoded data is stored, if false, decoded data will be stored.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null.</exception>
        public override void ToStream(Stream stream,bool encoded)
        {
        }

        #endregion


        #region override method ParseFromReader

        /// <summary>
        /// Parses MIME entity body from the specified reader.
        /// </summary>
        /// <param name="reader">Body reader from where to parse body.</param>
        /// <param name="owner">Specifies if body will be stream owner.</param>
        /// <returns>Returns true if this is last boundary in the message or in multipart "body parts".</returns>
        internal override void ParseFromReader(LineReader reader,bool owner)
        {
            // For multipart we need todo new limiting(limits to specified boundary) reader.
            _MIME_MultipartReader r = new _MIME_MultipartReader(reader,m_Boundary);
            while(r.Next()){
                MIME_Entity bodyPart = new MIME_Entity();                
                bodyPart.Parse(r,owner);
                m_pParts.Add(bodyPart);                
            }
        }

        #endregion


        #region Properties Implementation

        /// <summary>
        /// Gets boundary ID.
        /// </summary>
        public string Boundary
        {
            get{ return m_Boundary; }
        }

        /// <summary>
        /// Gets body parts collection.
        /// </summary>
        public MIME_EntityCollection BodyParts
        {
            get{ return m_pParts; }
        }

        #endregion

    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/_Obsolete/SocketServerSession.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net
{
    #region usings

    using System;
    using System.Net;

    #endregion

    /// <summary>
    /// This is base class for SocketServer sessions.
    /// </summary>
    public abstract class SocketServerSession
    {
        #region Members

        private readonly IPBindInfo m_pBindInfo;
        private readonly SocketServer m_pServer;
        private readonly SocketEx m_pSocket;
        private readonly string m_SessionID = "";
        private readonly DateTime m_SessionStartTime;
        private string m_UserName = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets session ID.
        /// </summary>
        public string SessionID
        {
            get { return m_SessionID; }
        }

        /// <summary>
        /// Gets session start time.
        /// </summary>
        public DateTime SessionStartTime
        {
            get { return m_SessionStartTime; }
        }

        /// <summary>
        /// Gets if session is authenticated.
        /// </summary>
        public bool Authenticated
        {
            get
            {
                if (m_UserName.Length > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Gets authenticated user name.
        /// </summary>
        public string UserName
        {
            get { return m_UserName; }
        }

        /// <summary>
        /// Gets how many seconds has left before timout is triggered.
        /// </summary>
        public int ExpectedTimeout
        {
            get
            {
                return
                    (int)
                    ((m_pServer.SessionIdleTimeOut - ((DateTime.Now.Ticks - SessionLastDataTime.Ticks)/10000))/
                     1000);
            }
        }

        /// <summary>
        /// Gets last data activity time.
        /// </summary>
        public DateTime SessionLastDataTime
        {
            get
            {
                if (m_pSocket == null)
                {
                    return DateTime.MinValue;
                }
                else
                {
                    return m_pSocket.LastActivity;
                }
            }
        }

        /// <summary>
        /// Gets EndPoint which accepted conection.
        /// </summary>
        public IPEndPoint LocalEndPoint
        {
            get { return (IPEndPoint) m_pSocket.LocalEndPoint; }
        }

        /// <summary>
        /// Gets connected Host(client) EndPoint.
        /// </summary>
        public IPEndPoint RemoteEndPoint
        {
            get
            {
                try
                {
                    return (IPEndPoint) m_pSocket.RemoteEndPoint;
                }
                catch
                {
                    // Socket closed/disposed already
                    return null;
                }
            }
        }

        /// <summary>
        /// Gets or sets custom user data.
        /// </summary>
        public object Tag { get; set; }

        /// <summary>
        /// Gets log entries that are currently in log buffer.
        /// </summary>
        public SocketLogger SessionActiveLog
        {
            get { return m_pSocket.Logger; }
        }

        /// <summary>
        /// Gets how many bytes are readed through this session.
        /// </summary>
        public long ReadedCount
        {
            get { return m_pSocket.ReadedCount; }
        }

        /// <summary>
        /// Gets how many bytes are written through this session.
        /// </summary>
        public long WrittenCount
        {
            get { return m_pSocket.WrittenCount; }
        }

        /// <summary>
        /// Gets if the connection is an SSL connection.
        /// </summary>
        public bool IsSecureConnection
        {
            get { return m_pSocket.SSL; }
        }

        /// <summary>
        /// Gets access to SocketEx.
        /// </summary>
        protected SocketEx Socket
        {
            get { return m_pSocket; }
        }

        /// <summary>
        /// Gets access to BindInfo what accepted socket.
        /// </summary>
        protected IPBindInfo BindInfo
        {
            get { return m_pBindInfo; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="sessionID">Session ID.</param>
        /// <param name="socket">Server connected socket.</param>
        /// <param name="bindInfo">BindInfo what accepted socket.</param>
        /// <param name="server">Reference to server.</param>
        public SocketServerSession(string sessionID, SocketEx socket, IPBindInfo bindInfo, SocketServer server)
        {
            m_SessionID = sessionID;
            m_pSocket = socket;
            m_pBindInfo = bindInfo;
            m_pServer = server;

            m_SessionStartTime = DateTime.Now;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Kills session.
        /// </summary>
        public virtual void Kill() {}

        #endregion

        #region Virtual methods

        /// <summary>
        /// Times session out.
        /// </summary>
        protected internal virtual void OnSessionTimeout() {}

        #endregion

        /// <summary>
        /// Sets property UserName value.
        /// </summary>
        /// <param name="userName">User name.</param>
        protected void SetUserName(string userName)
        {
            m_UserName = userName;

            if (m_pSocket.Logger != null)
            {
                m_pSocket.Logger.UserName = m_UserName;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/CreateBookmarkUserControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using AjaxPro;

using ASC.Bookmarking;
using ASC.Bookmarking.Common;
using ASC.Web.Community.Modules.Bookmarking.UserControls.Resources;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;

namespace ASC.Web.UserControls.Bookmarking
{
    public partial class CreateBookmarkUserControl : System.Web.UI.UserControl
    {
        public bool IsNewBookmark { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            Utility.RegisterTypeForAjax(typeof(BookmarkingUserControl));
            Utility.RegisterTypeForAjax(typeof(SingleBookmarkUserControl));

            InitActionButtons();
        }

        #region Init Action Buttons

        private void InitActionButtons()
        {
            SaveBookmarkButton.ButtonText = BookmarkingUCResource.Save;
            SaveBookmarkButton.AjaxRequestText = BookmarkingUCResource.BookmarkCreationIsInProgressLabel;

            SaveBookmarkButtonCopy.ButtonText = BookmarkingUCResource.AddToFavourite;
            SaveBookmarkButtonCopy.AjaxRequestText = BookmarkingUCResource.BookmarkCreationIsInProgressLabel;

            AddToFavouritesBookmarkButton.ButtonText = BookmarkingUCResource.AddToFavourite;
            AddToFavouritesBookmarkButton.AjaxRequestText = BookmarkingUCResource.BookmarkCreationIsInProgressLabel;

            CheckBookmarkUrlLinkButton.ButtonText = BookmarkingUCResource.CheckBookmarkUrlButton;
            CheckBookmarkUrlLinkButton.AjaxRequestText = BookmarkingUCResource.CheckingUrlIsInProgressLabel;
        }

        #endregion

        public string NavigateToMainPage
        {
            get
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                return BookmarkDisplayMode.CreateBookmark.Equals(displayMode).ToString().ToLower();
            }
        }

        public bool CreateBookmarkMode
        {
            get
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                return BookmarkDisplayMode.CreateBookmark.Equals(displayMode);
            }
        }

        public bool IsEditMode
        {
            get
            {
                var displayMode = BookmarkingBusinessFactory.GetDisplayMode();

                var serviceHelper = BookmarkingServiceHelper.GetCurrentInstanse();

                return BookmarkDisplayMode.SelectedBookmark.Equals(displayMode) && serviceHelper.IsCurrentUserBookmark();
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiSmartListResponceFilter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region usings

using System;
using System.Collections;

using ASC.Api.Collections;
using ASC.Api.Interfaces;

#endregion

namespace ASC.Api.Impl
{
    public class ApiSmartListResponceFilter : IApiResponceFilter
    {

        #region IApiResponceFilter Members

        public object FilterResponce(object responce, ApiContext context)
        {
            if (responce != null && !context.FromCache)
            {
                ISmartList smartList = null;
                var type = responce.GetType();
                if (responce is ISmartList)
                {
                    smartList = responce as ISmartList;
                }
                else if (Utils.Binder.IsCollection(type) && !typeof(IDictionary).IsAssignableFrom(type))
                {
                    try
                    {
                        var elementType = Utils.Binder.GetCollectionType(type);
                        var smartListType = SmartListFactory.GetSmartListType().MakeGenericType(elementType);
                        smartList = Activator.CreateInstance(smartListType, (IEnumerable)responce) as ISmartList;
                    }
                    catch (Exception)
                    {

                    }
                }
                if (smartList != null)
                {
                    return TransformList(context, smartList);
                }
            }
            return responce;
        }

        private static object TransformList(ApiContext context, ISmartList smartList)
        {
            bool getTotalCount = context.SpecifiedCount < smartList.Count && !context.TotalCount.HasValue;/*We have already more items than needed and no one set totalcount*/

            smartList.TakeCount = context.SpecifiedCount;
            smartList.StartIndex = context.StartIndex;
            smartList.IsDescending = context.SortDescending;
            smartList.SortBy = context.SortBy;
            smartList.FilterBy = context.FilterBy;
            smartList.FilterOp = context.FilterOp;
            smartList.FilterValue = context.FilterValues;
            smartList.UpdatedSince = context.UpdatedSince;
            smartList.FilterType = context.FilterToType;
            var list = smartList.Transform(getTotalCount);
            if (getTotalCount)
            {
                context.TotalCount = smartList.TotalCount;
            }
            return list;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Posts.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;

using AjaxPro;

using ASC.Forum;
using ASC.Web.Community.Modules.Forum.Resources;
using ASC.Web.Community.Resources;
using ASC.Web.Studio;
using ASC.Web.Studio.Utility;
using ASC.Web.UserControls.Forum;
using ASC.Web.UserControls.Forum.Common;

namespace ASC.Web.Community.Forum
{
    public partial class Posts : MainPage
    {
        protected string ForumPageTitle { get; set; }
        protected string ForumPageParentTitle { get; set; }
        protected string ForumPageParentURL { get; set; }
        protected string ForumPageParentIn { get; set; }

        private UserControls.Forum.Common.ForumManager _forumManager;
        public Topic Topic { get; set; }
        public Guid SettingsID { get; set; }
        protected string SubscribeStatus { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            _forumManager = ForumManager.Settings.ForumManager;

            ForumManager.Instance.SetCurrentPage(ForumPage.PostList);

            var idTopic = 0;
            if (!String.IsNullOrEmpty(Request["t"]))
            {
                try
                {
                    idTopic = Convert.ToInt32(Request["t"]);
                }
                catch
                {
                    idTopic = 0;
                }
            }
            if (idTopic == 0)
                Response.Redirect("Default.aspx");


            var topic = ForumDataProvider.GetTopicByID(TenantProvider.CurrentTenantID, idTopic);
            if (topic == null)
                Response.Redirect("Default.aspx");

            Topic = topic;

            var postListControl = LoadControl(ForumManager.Settings.UserControlsVirtualPath + "/PostListControl.ascx") as PostListControl;
            postListControl.SettingsID = ForumManager.Settings.ID;
            postListControl.Topic = topic;
            postListControl.PaggingHolder = PagingHolder;
            postListHolder.Controls.Add(postListControl);
            Utility.RegisterTypeForAjax(typeof(TopicControl), Page);
            Utility.RegisterTypeForAjax(typeof(Subscriber));
            var subscriber = new Subscriber();

            var isTopicSubscribe = subscriber.IsTopicSubscribe(topic.ID);
            var SubscribeTopicLink = subscriber.RenderTopicSubscription(!isTopicSubscribe, topic.ID);

            //master.ActionsPlaceHolder.Controls.Add(new HtmlMenuItem(subscriber.RenderThreadSubscription(!isThreadSubscribe, topic.ThreadID)));
            //master.ActionsPlaceHolder.Controls.Add(new HtmlMenuItem(subscriber.RenderTopicSubscription(!isTopicSubscribe, topic.ID)));

            ForumPageParentTitle = topic.ThreadTitle;
            ForumPageParentIn = CommunityResource.InForParentPage;
            ForumPageParentURL = "topics.aspx?f=" + topic.ThreadID.ToString();
            ForumPageTitle = topic.Title;
            Title = HeaderStringHelper.GetPageTitle((Master as ForumMasterPage).CurrentPageCaption ?? ForumResource.AddonName);
            SubscribeStatus = isTopicSubscribe ? "subscribed" : "unsubscribed";

            RenderModeratorFunctionsHeader();

            SubscribeLinkBlock.Text = SubscribeTopicLink;
        }

        protected void RenderModeratorFunctionsHeader()
        {
            var sb = new StringBuilder();
            var bitMask = 0;

            if (!Topic.IsApproved && _forumManager.ValidateAccessSecurityAction(ForumAction.ApprovePost, Topic))
                bitMask += 1;

            if (_forumManager.ValidateAccessSecurityAction(ForumAction.TopicDelete, Topic))
                bitMask += 2;

            if (_forumManager.ValidateAccessSecurityAction(ForumAction.TopicSticky, Topic))
                bitMask += 4;

            if (_forumManager.ValidateAccessSecurityAction(ForumAction.TopicClose, Topic))
                bitMask += 8;

            if (_forumManager.ValidateAccessSecurityAction(ForumAction.TopicEdit, Topic))
                bitMask += 32;

            var _settings = ForumManager.Settings.LinkProvider;

            if (bitMask > 0)
            {
                sb.Append("<span class=\"menu-small\" onclick=\"javascript:ForumManager.ShowModeratorFunctions('" + Topic.ID + "'," + bitMask + "," + (int)Topic.Status + ",'" + _settings.EditTopic(Topic.ID) + "');\"></span>");
            }

            menuToggle.Text = sb.ToString();
        }
    }
}

<|start_filename|>common/ASC.Common/DependencyInjection/AutofacConfigLoader.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Linq;

using Autofac;

namespace ASC.Common.DependencyInjection
{
    public class AutofacConfigLoader
    {
        public static ContainerBuilder Load(string containerName, string section = "autofac")
        {
            var container = new ContainerBuilder();

            var autofacConfigurationSection = (AutofacConfigurationSection)ConfigurationManagerExtension.GetSection(section);

            if (autofacConfigurationSection == null) return null;

            foreach (var component in autofacConfigurationSection.GetComponents(containerName))
            {
                var componentType = Type.GetType(component.Type);
                if (componentType == null) continue;

                var builder = container.RegisterType(componentType).AsSelf();

                if (!string.IsNullOrEmpty(component.Service))
                {
                    var serviceType = Type.GetType(component.Service);
                    builder.As(serviceType);

                    if (!string.IsNullOrEmpty(component.Name))
                    {
                        builder.Named(component.Name, serviceType)
                            .Named(component.Name.ToLower(), serviceType);
                    }
                }

                if (!string.IsNullOrEmpty(component.Name))
                {
                    builder.Named(component.Name, componentType)
                        .Named(component.Name.ToLower(), componentType);
                }

                if (component.Parameters != null && component.Parameters.Count > 0)
                {
                    foreach (var parameter in component.Parameters)
                    {
                        if (!string.IsNullOrEmpty(parameter.Type))
                        {
                            var parameterType = Type.GetType(parameter.Type);
                            var parameterName = parameter.Name;
                            if (parameterType == null) continue;

                            builder.WithParameter(
                                (pi, ctx) => parameterType.IsSubclassOf(pi.ParameterType) && pi.Name == parameterName,
                                (pi, ctx) => Activator.CreateInstance(parameterType));
                        }
                        else if (parameter.List != null && parameter.List.Any())
                        {
                            builder.WithParameter(new NamedParameter(parameter.Name, parameter.List.Select(r => r.Value).ToArray()));
                        }
                        else if (parameter.Dictionary != null && parameter.Dictionary.Any())
                        {
                            builder.WithParameter(new NamedParameter(parameter.Name, parameter.Dictionary.ToDictionary(r => r.Key, r => r.Value)));
                        }
                        else
                        {
                            builder.WithParameter(new NamedParameter(parameter.Name, parameter.Value));
                        }
                    }
                }

                switch (component.InstanceScope)
                {
                    case "single-instance":
                        builder.SingleInstance();
                        break;
                    case "per-lifetime-scope":
                        builder.InstancePerLifetimeScope();
                        break;
                    case "per-request":
                        builder.InstancePerRequest();
                        break;
                }

                if (component.InjectProperties == "yes")
                {
                    builder.PropertiesAutowired();
                }
            }

            return container;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Client/IMAP_Acl.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP.Client
{
    #region usings

    using Server;

    #endregion

    /// <summary>
    /// IMAP ACL entry. Defined in RFC 2086.
    /// </summary>
    public class IMAP_Acl
    {
        #region Members

        private readonly string m_Name = "";
        private readonly IMAP_ACL_Flags m_Rights = IMAP_ACL_Flags.None;

        #endregion

        #region Properties

        /// <summary>
        /// Gets authentication identifier name. Normally this is user or group name.
        /// </summary>
        public string Name
        {
            get { return m_Name; }
        }

        /// <summary>
        /// Gets the rights associated with this ACL entry.
        /// </summary>
        public IMAP_ACL_Flags Rights
        {
            get { return m_Rights; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="name">Authentication identifier name. Normally this is user or group name.</param>
        /// <param name="rights">Rights associated with this ACL entry.</param>
        public IMAP_Acl(string name, IMAP_ACL_Flags rights)
        {
            m_Name = name;
            m_Rights = rights;
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Parses ACL entry from IMAP ACL response string.
        /// </summary>
        /// <param name="aclResponseString">IMAP ACL response string.</param>
        /// <returns></returns>
        internal static IMAP_Acl Parse(string aclResponseString)
        {
            string[] args = TextUtils.SplitQuotedString(aclResponseString, ' ', true);
            return new IMAP_Acl(args[1], IMAP_Utils.ACL_From_String(args[2]));
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/ABNF/ABNF_Option.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.ABNF
{
    #region usings

    using System;
    using System.IO;

    #endregion

    /// <summary>
    /// This class represent ABNF "option". Defined in RFC 5234 4.
    /// </summary>
    public class ABNF_Option : ABNF_Element
    {
        #region Members

        private ABNF_Alternation m_pAlternation;

        #endregion

        #region Properties

        /// <summary>
        /// Gets option alternation elements.
        /// </summary>
        public ABNF_Alternation Alternation
        {
            get { return m_pAlternation; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static ABNF_Option Parse(StringReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // option = "[" *c-wsp alternation *c-wsp "]"

            if (reader.Peek() != '[')
            {
                throw new ParseException("Invalid ABNF 'option' value '" + reader.ReadToEnd() + "'.");
            }

            // Eat "[".
            reader.Read();

            // TODO: *c-wsp

            ABNF_Option retVal = new ABNF_Option();

            // We reached end of stream, no closing "]".
            if (reader.Peek() == -1)
            {
                throw new ParseException("Invalid ABNF 'option' value '" + reader.ReadToEnd() + "'.");
            }

            retVal.m_pAlternation = ABNF_Alternation.Parse(reader);

            // We don't have closing ")".
            if (reader.Peek() != ']')
            {
                throw new ParseException("Invalid ABNF 'option' value '" + reader.ReadToEnd() + "'.");
            }
            else
            {
                reader.Read();
            }

            return retVal;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Core/Presenters/SubscriberPresenter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Forum.Module;
using ASC.Notify.Model;
using ASC.Notify.Recipients;

namespace ASC.Forum
{
    internal class SubscriberPresenter : PresenterTemplate<ISubscriberView>
    {
        public static void UnsubscribeAllOnTopic(int topicID)
        {
            ForumNotifySource.Instance.GetSubscriptionProvider().UnSubscribe(Constants.NewPostInTopic, topicID.ToString());
        }

        public static void UnsubscribeAllOnThread(int threadID)
        {
            ForumNotifySource.Instance.GetSubscriptionProvider().UnSubscribe(Constants.NewPostInThread, threadID.ToString());
        }


        protected override void RegisterView()
        {
            _view.Subscribe += new EventHandler<SubscribeEventArgs>(SubscribeHandler);
            _view.UnSubscribe += new EventHandler<SubscribeEventArgs>(UnSubscribeHandler);
            _view.GetSubscriptionState += new EventHandler<SubscribeEventArgs>(GetSubscriptionStateHandler);

        }

        void UnSubscribeHandler(object sender, SubscribeEventArgs e)
        {
            var recipient = (IDirectRecipient)ForumNotifySource.Instance.GetRecipientsProvider().GetRecipient(e.UserID.ToString());
            if (recipient != null)
                ForumNotifySource.Instance.GetSubscriptionProvider().UnSubscribe(e.NotifyAction, e.ObjectID, recipient);
        }

        void GetSubscriptionStateHandler(object sender, SubscribeEventArgs e)
        {
            var recipient = (IDirectRecipient)ForumNotifySource.Instance.GetRecipientsProvider().GetRecipient(e.UserID.ToString());
            if (recipient == null)
                return;

            ISubscriptionProvider subscriptionProvider = ForumNotifySource.Instance.GetSubscriptionProvider();
            List<string> objectIDs = new List<string>(subscriptionProvider.GetSubscriptions(e.NotifyAction, recipient, false));

            if (e.ObjectID == null && objectIDs.Count == 1 && objectIDs[0] == null)
            {
                _view.IsSubscribe = true;
                return;
            }

            _view.IsSubscribe = (objectIDs.Find(id => String.Compare(id, e.ObjectID, true) == 0) != null);

        }

        private void SubscribeHandler(object sender, SubscribeEventArgs e)
        {
            var recipient = (IDirectRecipient)ForumNotifySource.Instance.GetRecipientsProvider().GetRecipient(e.UserID.ToString());
            if (recipient != null)
                ForumNotifySource.Instance.GetSubscriptionProvider().Subscribe(e.NotifyAction, e.ObjectID, recipient);

        }
    }
}


<|start_filename|>module/ASC.Notify/ASC.Notify/Config/NotifyServiceCfgSectionHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Configuration;

namespace ASC.Notify.Config
{
    public class NotifyServiceCfgSectionHandler : ConfigurationSection
    {
        [ConfigurationProperty("connectionStringName", IsRequired = true)]
        public string ConnectionStringName
        {
            get { return (string)base["connectionStringName"]; }
        }

        [ConfigurationProperty("storeDays", DefaultValue = 7)]
        [IntegerValidator(MinValue = 1, MaxValue = short.MaxValue)]
        public int StoreMessagesDays
        {
            get { return (int)base["storeDays"]; }
        }

        [ConfigurationProperty("process")]
        public NotifyServiceCfgProcessElement Process
        {
            get { return (NotifyServiceCfgProcessElement)base["process"]; }
        }

        [ConfigurationProperty("senders")]
        [ConfigurationCollection(typeof(NotifyServiceCfgSendersCollection), AddItemName = "sender")]
        public NotifyServiceCfgSendersCollection Senders
        {
            get { return (NotifyServiceCfgSendersCollection)base["senders"]; }
        }

        [ConfigurationProperty("schedulers")]
        [ConfigurationCollection(typeof(NotifyServiceCfgSchedulersCollection), AddItemName = "scheduler")]
        public NotifyServiceCfgSchedulersCollection Schedulers
        {
            get { return (NotifyServiceCfgSchedulersCollection)base["schedulers"]; }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/FirstTime/js/view.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof (ASC) == 'undefined')
    ASC = {};
if (typeof (ASC.Controls) == 'undefined')
    ASC.Controls = {};

ASC.Controls.FirstTimeView = new function() {

    this.Finish = function() {
        window.onbeforeunload = null;

        var url = "Default.aspx";
        if (jq("body").is(".desktop")) {
            url += "?desktop=true&first=true";
        }

        location.href = url;
    };

    this.SaveRequiredStep = function() {

        AjaxPro.onLoading = function(b) {
            if (b)
                LoadingBanner.showLoaderBtn(".wizardContent");
            else
                LoadingBanner.hideLoaderBtn(".wizardContent");
        };

        var FTManager = new ASC.Controls.FirstTimeManager();
        FTManager.SaveRequiredData(this.SaveRequiredStepCallback);
    };

    this.SaveRequiredStepCallback = function(result) {

        if (result.Status == 1) {
            var time = new TimeAndLanguageContentManager();
            time.SaveTimeLangSettings(ASC.Controls.FirstTimeView.SaveTimeLangSettingsCallback);
        } else {
            ASC.Controls.FirstTimeView.ShowOperationInfo(result);
        }
    };

    this.SaveTimeLangSettingsCallback = function(result) {
        if (result.Status == 1) {
            ASC.Controls.FirstTimeView.Finish(); // enter redirect on the dash of modules
        } else {
            ASC.Controls.FirstTimeView.ShowOperationInfo(result);
            window.onbeforeunload = function(e) {
                return ASC.Resources.Master.ResourceJS.WizardCancelConfirmMessage;
            };
        }
    };

    this.ShowOperationInfo = function(result) {
        if (result.Status == 1)
            toastr.success(result.Message);
        else
            toastr.error(result.Message);
    };
};


jq(document).ready(function() {
    jq(document).keyup(function (e) {
    if (e.which == 13) {
        ASC.Controls.FirstTimeView.SaveRequiredStep();
        }
    });
    window.onbeforeunload = function(e) {
    return ASC.Resources.Master.ResourceJS.WizardCancelConfirmMessage;
    };
});


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Controls/MainMenu/MainMenu.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web.UI;

using ASC.Web.Files.Classes;
using ASC.Web.Studio.UserControls.Common.HelpCenter;
using ASC.Web.Studio.UserControls.Common.InviteLink;
using ASC.Web.Studio.UserControls.Common.Support;
using ASC.Web.Studio.UserControls.Common.UserForum;

namespace ASC.Web.Files.Controls
{
    public partial class MainMenu : UserControl
    {
        public static string Location
        {
            get { return PathProvider.GetFileControlPath("MainMenu/MainMenu.ascx"); }
        }

        public bool EnableThirdParty;
        public bool Desktop;

        protected void Page_Load(object sender, EventArgs e)
        {
            ControlHolder.Controls.Add(LoadControl(TreeBuilder.Location));
            InviteUserHolder.Controls.Add(LoadControl(InviteLink.Location));

            if (!Desktop)
            {
                var helpCenter = (HelpCenter)LoadControl(HelpCenter.Location);
                helpCenter.IsSideBar = true;
                sideHelpCenter.Controls.Add(helpCenter);

                sideSupport.Controls.Add(LoadControl(Support.Location));
                UserForumHolder.Controls.Add(LoadControl(UserForum.Location));
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Core/Dao/DomainDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Server.Core.Dao.Interfaces;
using ASC.Mail.Server.Core.DbSchema;
using ASC.Mail.Server.Core.DbSchema.Interfaces;
using ASC.Mail.Server.Core.DbSchema.Tables;
using ASC.Mail.Server.Core.Entities;

namespace ASC.Mail.Server.Core.Dao
{
    public class DomainDao : BaseDao, IDomainDao
    {
        protected static ITable table = new MailServerTableFactory().Create<DomainTable>();

        public DomainDao(IDbManager dbManager)
            : base(table, dbManager)
        {
        }

        public int Save(Domain domain)
        {
            var query = new SqlInsert(DomainTable.TABLE_NAME, true)
                .InColumnValue(DomainTable.Columns.DOMAIN, domain.Name)
                .InColumnValue(DomainTable.Columns.DESCRIPTION, domain.Description)
                .InColumnValue(DomainTable.Columns.CREATED, domain.Created)
                .InColumnValue(DomainTable.Columns.MODIFIED, domain.Modified)
                .InColumnValue(DomainTable.Columns.ACTIVE, domain.Active);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }

        public int Remove(string domain)
        {
            var query = new SqlDelete(DomainTable.TABLE_NAME)
                .Where(DomainTable.Columns.DOMAIN, domain);

            var result = Db.ExecuteNonQuery(query);
            return result;
        }
    }
}

<|start_filename|>module/ASC.Socket.IO/app/middleware/auth.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


module.exports = function (socket, next) {
    const apiRequestManager = require('../apiRequestManager.js');
    const req = socket.client.request;
    const authService = require('./authService.js')();
    const co = require('co');
    const session = socket.handshake.session;

    if (req.user) {
        next();
        return;
    }

    if (!req.cookies || (!req.cookies['asc_auth_key'] && !req.cookies['authorization'])) {
        socket.disconnect('unauthorized');
        next(new Error('Authentication error'));
        return;
    }

    if(session && session.user && session.portal && typeof(session.mailEnabled) !== "undefined") {
        req.user = session.user;
        req.portal = session.portal;
        req.mailEnabled = session.mailEnabled;
        next();
        return;
    }

    if(req.cookies['authorization']){
        if(!authService(req)){
            next(new Error('Authentication error'));
        } else{
            next();
        }
        return;
    }

    co(function*(){
        var batchRequest = apiRequestManager.batchFactory()
            .get("people/@self.json?fields=id,userName,displayName")
            .get("portal.json?fields=tenantId,tenantDomain")
            .get("settings/security/2A923037-8B2D-487b-9A22-5AC0918ACF3F");

        [session.user, session.portal, session.mailEnabled] = [req.user, req.portal, req.mailEnabled] = yield apiRequestManager.batch(batchRequest, req);
        session.save();
        next();
    }).catch((err) => {
        socket.disconnect('unauthorized');
        next(new Error('Authentication error'));
    });
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Users/UserSubscriptions/js/subscription_manager.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var CommonSubscriptionManager = new function() {
    this.currentModuleSubsTab;
    this.currentModuleSubsSubtabContents;

    this.LoadSubscriptions = function() {
        AjaxPro.onLoading = function(b) {
            if (b) {
                LoadingBanner.displayLoading();
            } else {
                LoadingBanner.hideLoading();
            }
        };

        var timeoutPeriod = AjaxPro.timeoutPeriod;
        AjaxPro.timeoutPeriod = 5 * 60 * 1000;
        AjaxPro.SubscriptionManager.GetAllSubscriptions(function(result) {
            jq('#modules_notifySenders').html(jq("#headerSubscriptionsTemplate").tmpl(result.value));
            jq('#contents_notifySenders').html(jq("#contentSubscriptionsTemplate").tmpl(result.value));
            CommonSubscriptionManager.InitNotifyByComboboxes();
            CommonSubscriptionManager.InitListTabsComboboxes();
            AjaxPro.timeoutPeriod = timeoutPeriod;
        });

        jq('.subs-tabs .subs-module').on('click', function() {
            CommonSubscriptionManager.ClickProductTag(jq(this).attr("data-id"));
        });

    };

    this.SubscribeToWhatsNew = function() {
        AjaxPro.SubscriptionManager.SubscribeToWhatsNew(function(result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#studio_newSubscriptionButton').html(res.rs2);
            } else {
                toastr.error(res.rs2);
            }
        });
    };

    this.SubscribeToTipsAndTricks = function () {
        AjaxPro.SubscriptionManager.SubscribeToTipsAndTricks(function (result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#studio_tipsSubscriptionButton').html(res.rs2);
            } else {
                toastr.error(res.rs2);
            }
        });
    };

    this.SubscribeToSpam = function () {
        AjaxPro.SubscriptionManager.SubscribeToSpam(function (result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#studio_spamSubscriptionButton').html(res.rs2);
            } else {
                toastr.error(res.rs2);
            }
        });
    };

    this.SubscribeToAdminNotify = function() {
        AjaxPro.SubscriptionManager.SubscribeToAdminNotify(function (result) {
            var res = result.value;
            if (res.rs1 == '1') {
                jq('#studio_adminSubscriptionButton').html(res.rs2);
            } else {
                toastr.error(res.rs2);
            }
        });
    };

    var UpdateTypeSubscriptionCallback = function(result) {
        var res = result.value;
        if (res.Status == 1) {
            var but = jq('#studio_subscribeType_' + res.Data.Id + '_' + res.SubItemId + '_' + res.SubscriptionTypeID).find("a.on_off_button");
            if (but.hasClass("on")) {
                but.removeClass("on").addClass("off");
            } else {
                but.removeClass("off").addClass("on");
            }
        } 
    };

    var UpdateProductSubscriptionCallback = function(result) {
        var res = result.value;
        if (res.Status == 1) {
            if (jq('#content_product_subscribeBox_' + res.Data.Id).find(".subs-subtab").length) {
                jq(".subs-tabs .subs-module.active").removeClass("active");
                jq(".subs-subtab .module.active").removeClass("active");
                jq("[id^='studio_subscriptions_" + res.Data.Id + "']").remove();
                CommonSubscriptionManager.ClickProductTag(res.Data.Id);
                return;
            }
            
            jq('#content_product_subscribeBox_' + res.Data.Id).replaceWith(jq('#contentSubscriptionsTemplate').tmpl({ Items: [res.Data] }));
            var subscribeBox = jq('#content_product_subscribeBox_' + res.Data.Id);
            subscribeBox.addClass("active");
            CommonSubscriptionManager.InitNotifyByComboboxes();
            CommonSubscriptionManager.InitListTabsComboboxes();
        } else {
            jq('#content_product_subscribeBox_' + res.ItemId).html('<div class="errorBox">' + res.Message + '</div>');
        }
    };

    this.RememberCurrentModuleSubtab = function(productID) {
        var subscribeBox = jq('#content_product_subscribeBox_' + productID);
        if (subscribeBox.find(".subs-subtab").length) {
            CommonSubscriptionManager.currentModuleSubsTab = subscribeBox.find(".subs-subtab .active").attr("id");
            CommonSubscriptionManager.currentModuleSubsSubtabContents = subscribeBox.find(".subs-subtab-contents .active").attr("id");
        }
    };

    this.UnsubscribeProduct = function (productID, productName) {
        var mes = (ASC.Resources.Master.ResourceJS.UnsubscribeProductMessage).format(productName);
        if (!confirm(mes))
            return;

        AjaxPro.SubscriptionManager.UnsubscribeProduct(productID, UpdateProductSubscriptionCallback);
    };

    this.SubscribeType = function (productID, moduleID, subscribeType) {
        var subscribe = jq('#studio_subscribeType_' + productID + '_' + moduleID + '_' + subscribeType).find("a.on_off_button").hasClass("on");
        
        if (subscribe && !confirm(ASC.Resources.Master.ResourceJS.ConfirmMessage))
            return;

        CommonSubscriptionManager.RememberCurrentModuleSubtab(productID);

        if (subscribe)
            AjaxPro.SubscriptionManager.UnsubscribeType(productID, moduleID, subscribeType, UpdateTypeSubscriptionCallback);
        else
            AjaxPro.SubscriptionManager.SubscribeType(productID, moduleID, subscribeType, UpdateTypeSubscriptionCallback);
        
    };

    this.SubscribeObject = function(productID, moduleID, subscribeType, obj) {
        var item = jq(obj).attr("data-value");
        var subscribe = jq(obj).hasClass("off");
        AjaxPro.SubscriptionManager.SubscribeObject(productID, moduleID, subscribeType, item, subscribe, function (result) {
            var res = result.value;
            if (res.rs1 == '1') {
                var but = jq('#studio_subscribeItem_' + productID + '_' + moduleID + '_' + subscribeType + '_' + item).find('a');
                if (subscribe) {
                    but.removeClass('off').addClass('on');
                } else {
                    but.removeClass('on').addClass('off');
                }
            } else {
                jq('#studio_subscribeType_' + productID + '_' + moduleID + '_' + subscribeType).html(res.rs6);
            }

        });
    };
    
    this.ClickProductTag = function(productID) {

        var id = "product_subscribeBox_" + productID;
        var module;

        if (id != jq(".subs-tabs .subs-module.active").attr("id")) {
            jq(".subs-tabs .subs-module").removeClass("active");
            jq("#" + id).addClass("active");
            jq(".subs-contents div").removeClass("active");
            jq("#content_" + id).addClass("active");

            var left = jq("#" + id).position().left + (jq("#" + id).width() - jq("#productSelector").width()) / 2;
            jq("#productSelector").css("left", left);

            if (jq("#content_" + id + " .subs-subtab select").length != 0) {
                var option = jq("#content_" + id + " .subs-subtab option");
                var num = jq("#content_" + id + " .selected-item").attr("data-value");
                module = jq(option[num]).attr("data-id");

                jq("#content_" + id + " .subs-subtab select").change(function() {
                    var elem = jq("#content_" + id + " .subs-subtab option")[jq(this).val()];
                    var selected = jq(elem).attr("data-id");
                    CommonSubscriptionManager.ClickModuleTag(productID, selected);
                });
            }
            else {
                module = jq("#content_" + id + " .subs-subtab span").first().attr("data-id");
            }
            CommonSubscriptionManager.ClickModuleTag(productID, module);
        }
    }
    this.ClickModuleTag = function(productID, moduleID) {
        var id = "module_subscribeBox_" + productID + "_" + moduleID;

        if (id != jq(".subs-subtab .module.active").attr("id")) {
            jq(".subs-subtab .module").removeClass("active");
            jq("#" + id).addClass("active");
            jq(".subs-subtab-contents div").removeClass("active");
            jq("#content_" + id).addClass("active");
        }
        var sections = jq("#content_" + id).children(".subs-sections");
        jq(sections).each(function() {
            var typeID = jq(this).attr("data-type");
            var subscriptionElementID = 'studio_subscriptions_' + productID + '_' + moduleID + '_' + typeID;
            var subscriptionElement = jq('#' + subscriptionElementID);

            if (subscriptionElement == null || subscriptionElement.attr('id') == null) {

                AjaxPro.SubscriptionManager.RenderGroupItemSubscriptions(productID, moduleID, typeID, function(res) {
                    var el = jq('#studio_types_' + productID + '_' + moduleID + '_' + typeID);
                    var resultHTML = '';
                    if (res.value.Status = 1) {

                        resultHTML = jq('<div></div>').html(jq("#subscribtionObjectsTemplate").tmpl(res.value)).html();
                    }

                    if (resultHTML == null || '' == resultHTML) {
                        resultHTML = "<div id='" + subscriptionElementID + "' style='height: 0px;'>&nbsp</div>";
                    }
                    el.html(resultHTML);
                });
            };
        });
    }

    this.InitNotifyByComboboxes = function() {
        jq(".subsSelector").each(function () {
            var el = jq(this);

            var notify = parseInt(el.attr("data-notify"));
            if (!notify) return;

            var subId = el.attr("data-id");
            var fun = el.attr("data-function");
            el.removeAttr("data-id").removeAttr("data-notify").removeAttr("data-function");

            var f = subId ? function () { AjaxPro.SubscriptionManager[fun](subId, parseCheckBoxes(el)); } : function () { AjaxPro.SubscriptionManager[fun](parseCheckBoxes(el)); };

            el.html(jq("#subsSelectorTemplate").tmpl({ type: notify }));

            el.find("input[type=\"checkbox\"]").change(f);

            var connector = el.find(".baseLinkAction");
            if (connector.hasClass("tgConnector")) {
                telegramConnect.init(connector);
            }
        });
    };

    this.InitListTabsComboboxes = function() {
        jq('select[id^="ListTabsCombobox_"]').each(
            function() {
                jq(this).tlcombobox({ align: "left" });
            }
		);
    };

    var telegramConnect = (function () {
        var isInit = false;
        var elements = [];

        var helper = jq("#telegramConnectTemplate").tmpl();
        var body = jq("body");

        var tgConnect = helper.children("#tgConnect");
        var tgConnected = helper.children("#tgConnected");
        var tgLink = helper.children("#tgLink");
        var tgCopy = helper.children("#tgCopy");
        var tgDisconnect = helper.children("#tgDisconnect");

        var clipboard;
        var timeout;

        function onApiFail(params, error) {
            LoadingBanner.hideLoading();
            toastr.error(error[0]);
        };

        function hideAll() {
            tgConnect.addClass("display-none");
            tgConnected.addClass("display-none");
            tgLink.addClass("display-none");
            tgCopy.addClass("display-none");
            tgDisconnect.addClass("display-none");
        };

        var lastRender;
        function render(isConnected) {
            lastRender = isConnected;
            for (var i = 0; i < elements.length; i++) {
                elements[i].children("span").toggleClass("display-none", isConnected);
                elements[i].parent().children("input").toggleClass("display-none", !isConnected);
            }

            tgConnect.toggleClass("display-none", isConnected);
            tgConnected.toggleClass("display-none", !isConnected);
            tgLink.toggleClass("display-none", isConnected);
            tgCopy.toggleClass("display-none", isConnected && ASC.Clipboard.enable);
            tgDisconnect.toggleClass("display-none", !isConnected);
        };

        function renderSingle(element) {
            if (lastRender == undefined) return;
            element.children("span").toggleClass("display-none", lastRender);
            element.parent().children("input").toggleClass("display-none", !lastRender);
        }

        function generateLink() {
            Teamlab.telegramLink({ success: linkCallback, error: onApiFail });
        };

        function isConnected(stealth) {
            Teamlab.telegramIsConnected({ success: stealth ? function (params, response) { render(response == 1); } : isConnectedCallback, error: onApiFail });
        };

        function disconnect() {
            LoadingBanner.displayLoading();
            Teamlab.telegramDisconnect({ success: function () { tgDisconnect.off("click"); isConnectedCallback(null, 0); }, error: onApiFail });
        };

        function linkCallback(params, response) {
            if (clipboard) ASC.Clipboard.destroy(clipboard);

            tgLink.on("click", linkUsed);
            if (ASC.Clipboard.enable) {
                tgCopy.on("click", linkUsed);

                clipboard = ASC.Clipboard.create(response, "tgCopy", {
                    onComplete: function () {
                        toastr.success(ASC.Resources.Master.ResourceJS.LinkCopySuccess);
                    }
                });
            }

            tgLink.children("a").attr("href", "https://" + response).text(response.slice(0, 30) + "...");
        };

        function isConnectedCallback(params, response) {
            render(response == 1);
            LoadingBanner.hideLoading();

            if (response != 1) {
                generateLink();

                if (response == 2) {
                    timeout = timeOutFunction()
                }
            } else {
                if (clipboard) ASC.Clipboard.destroy(clipboard);
                tgDisconnect.on("click", disconnect);
            }
        };

        function timeOutFunction() {
            return setTimeout(Teamlab.telegramIsConnected, 1500, { success: timeOutCallback });
        };

        function timeOutCallback(params, response) {
            if (response != 2) {
                isConnectedCallback(params, response);
            } else {
                timeout = timeOutFunction();
            }
        };

        function linkUsed() {
            tgLink.off("click");
            tgCopy.off("click");

            if (!timeout) {
                timeout = timeOutFunction();
            }
        };

        function onClose() {
            body.unbind("click.tgConnect");
            tgDisconnect.off("click");

            if (timeout) {
                clearTimeout(timeout);
            }
        };

        function init(element) {
            elements.push(element);
            element.removeAttr("data-value");
            element.click(function (e) {
                e.stopPropagation(true);

                var height = jq(window).height();
                var top = e.pageY + jq(e.target).height();
                var diff = height - (top - jq(window).scrollTop() + helper.height() + parseInt(helper.css("padding-top")) * 2);
                top = diff >= 0 ? top : top + diff;

                helper.css({
                    position: "absolute",
                    left: e.pageX,
                    top: top - 10,
                }).toggleClass("display-none");

                if (!helper.hasClass("display-none")) {
                    hideAll();
                    LoadingBanner.displayLoading();
                    isConnected();

                    body.bind("click.tgConnect", function (e) {
                        if (jq(e.target).parents("#telegramConnect").length) return;

                        helper.addClass("display-none");
                        onClose();
                    });
                } else {
                    onClose();
                }
            });
            renderSingle(element);

            if (isInit) return;
            isInit = true;

            hideAll();
            helper.appendTo(body);
            isConnected(true);
        };

        return {
            init: init
        };
    })();

    var parseCheckBoxes = function (el) {
        var notifyBy = 0;

        el.find("input[type=\"checkbox\"]").each(function () {
            var checkBox = jq(this);
            if (checkBox.prop("checked")) {
                var num = parseInt(jq(this).attr("data-value"));
                notifyBy |= num;
            }
        });

        return notifyBy;
    };
};

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/IMAP_MessageFlags.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP
{
    using System;

    /// <summary>
    /// IMAP message flags.
    /// </summary>
    [Flags]
    public enum IMAP_MessageFlags
    {
        /// <summary>
        /// No flags defined.
        /// </summary>
        None = 0,

        /// <summary>
        /// Message has been read.
        /// </summary>
        Seen = 2,

        /// <summary>
        /// Message has been answered.
        /// </summary>
        Answered = 4,

        /// <summary>
        /// Message is "flagged" for urgent/special attention.
        /// </summary>
        Flagged = 8,

        /// <summary>
        /// Message is "deleted" for removal by later EXPUNGE.
        /// </summary>
        Deleted = 16,

        /// <summary>
        /// Message has not completed composition.
        /// </summary>
        Draft = 32,

        /// <summary>
        /// Message is "recently" arrived in this mailbox.
        /// </summary>
        Recent = 64,
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/CalendarEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Linq;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Utils;

namespace ASC.Mail.Core.Engine
{
    public class CalendarEngine
    {
        public ILog Log { get; private set; }

        public CalendarEngine(ILog log = null)
        {
            Log = log ?? LogManager.GetLogger("ASC.Mail.CalendarEngine");
        }

        public void UploadIcsToCalendar(MailBoxData mailBoxData, int calendarId, string calendarEventUid, string calendarIcs,
            string calendarCharset, string calendarContentType, string calendarEventReceiveEmail, string httpContextScheme)
        {
            try
            {
                if (string.IsNullOrEmpty(calendarEventUid) ||
                    string.IsNullOrEmpty(calendarIcs) ||
                    calendarContentType != "text/calendar")
                    return;

                var calendar = MailUtil.ParseValidCalendar(calendarIcs, Log);

                if (calendar == null)
                    return;

                var alienEvent = true;

                var organizer = calendar.Events[0].Organizer;

                if (organizer != null)
                {
                    var orgEmail = calendar.Events[0].Organizer.Value.ToString()
                        .ToLowerInvariant()
                        .Replace("mailto:", "");

                    if (orgEmail.Equals(calendarEventReceiveEmail))
                        alienEvent = false;
                }
                else
                {
                    throw new ArgumentException("calendarIcs.organizer is null");
                }

                if (alienEvent)
                {
                    if (calendar.Events[0].Attendees.Any(
                        a =>
                            a.Value.ToString()
                                .ToLowerInvariant()
                                .Replace("mailto:", "")
                                .Equals(calendarEventReceiveEmail)))
                    {
                        alienEvent = false;
                    }
                }

                if (alienEvent)
                    return;

                CoreContext.TenantManager.SetCurrentTenant(mailBoxData.TenantId);
                SecurityContext.AuthenticateMe(new Guid(mailBoxData.UserId));

                using (var ms = new MemoryStream(EncodingTools.GetEncodingByCodepageName(calendarCharset).GetBytes(calendarIcs)))
                {
                    var apiHelper = new ApiHelper(httpContextScheme, Log);
                    apiHelper.UploadIcsToCalendar(calendarId, ms, "calendar.ics", calendarContentType);
                }

                Log.Info("CalendarEngine->UploadIcsToCalendar() has been succeeded");
            }
            catch (Exception ex)
            {
                Log.ErrorFormat("CalendarEngine->UploadIcsToCalendar with \r\n" +
                          "calendarId: {0}\r\n" +
                          "calendarEventUid: '{1}'\r\n" +
                          "calendarIcs: '{2}'\r\n" +
                          "calendarCharset: '{3}'\r\n" +
                          "calendarContentType: '{4}'\r\n" +
                          "calendarEventReceiveEmail: '{5}'\r\n" +
                          "Exception:\r\n{6}\r\n",
                    calendarId, calendarEventUid, calendarIcs, calendarCharset, calendarContentType,
                    calendarEventReceiveEmail, ex.ToString());
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/Core/Views/ISecurityActionView.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Forum
{
    public interface ISecurityActionView
    {
        bool IsAccessible { set; }

        event EventHandler<SecurityAccessEventArgs> ValidateAccess;
    }

    public class SecurityAccessEventArgs : EventArgs
    {
        public ForumAction Action { get; private set; }

        public Object TargetObject { get; private set; }

        public SecurityAccessEventArgs(ForumAction action, object targetObject)
        {
            this.Action = action;
            this.TargetObject = targetObject;

        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Imap/UidInterval.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Mail.Data.Imap
{
    public class UidInterval
    {
        public UidInterval(int from, int to)
        {
            if (from < 1)
                throw new ArgumentException("UidlInterval constructor from argument must be greater then 1");

            if (to < 1)
                throw new ArgumentException("UidlInterval constructor to argument must be greater then 1");

            if (from > to)
                throw new ArgumentException("UidlInterval constructor to argument must be greater then from argument");

            From = from;
            To = to;
        }

        public int From { get; private set; }
        public int To { get; private set; }

        public bool In(int val)
        {
            return val >= From && val <= To;
        }

        public static bool operator ==(UidInterval a, UidInterval b)
        {
            // If both are null, or both are same instance, return true.
            if (ReferenceEquals(a, b))
            {
                return true;
            }

            // If one is null, but not both, return false.
            if (((object)a == null) || ((object)b == null))
            {
                return false;
            }

            // Return true if the fields match:
            return a.From == b.From && a.To == b.To;
        }

        public static bool operator !=(UidInterval a, UidInterval b)
        {
            return !(a == b);
        }

        public override bool Equals(Object obj)
        {
            // If parameter is null return false.
            if (obj == null)
            {
                return false;
            }

            // If parameter cannot be cast to Point return false.
            var p = obj as UidInterval;
            if ((Object)p == null)
            {
                return false;
            }

            // Return true if the fields match:
            return (From == p.From) && (To == p.To);
        }

        public bool Equals(UidInterval p)
        {
            // If parameter is null return false:
            if ((object)p == null)
            {
                return false;
            }

            // Return true if the fields match:
            return (From == p.From) && (To == p.To);
        }

        public override int GetHashCode()
        {
            return From ^ To;
        }

        public bool IsToUidMax()
        {
            return To == int.MaxValue;
        }

        public bool IsFromUidMin()
        {
            return From == 1;
        }
    }
}


<|start_filename|>common/ASC.Data.Storage/PathUtils.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Web.Hosting;

namespace ASC.Data.Storage
{
    class PathUtils
    {
        public static string Normalize(string path, bool addTailingSeparator = false)
        {
            path = path
                .Replace('/', Path.DirectorySeparatorChar)
                .Replace('\\', Path.DirectorySeparatorChar)
                .Replace("\\\\", Path.DirectorySeparatorChar.ToString())
                .Replace("//", Path.DirectorySeparatorChar.ToString())
                .TrimEnd(Path.DirectorySeparatorChar);
            return addTailingSeparator && 0 < path.Length ? path + Path.DirectorySeparatorChar : path;
        }

        public static string ResolveVirtualPath(string module, string domain)
        {
            var url = string.Format("~/storage/{0}/{1}/",
                                 module,
                                 string.IsNullOrEmpty(domain) ? "root" : domain);
            return ResolveVirtualPath(url);
        }

        public static string ResolveVirtualPath(string virtPath, bool addTrailingSlash = true)
        {
            if (virtPath.StartsWith("~") && !Uri.IsWellFormedUriString(virtPath, UriKind.Absolute))
            {
                var rootPath = "/";
                if (!string.IsNullOrEmpty(HostingEnvironment.ApplicationVirtualPath) && 1 < HostingEnvironment.ApplicationVirtualPath.Length)
                {
                    rootPath = HostingEnvironment.ApplicationVirtualPath.Trim('/');
                }
                virtPath = virtPath.Replace("~", rootPath);
            }
            if (addTrailingSlash)
            {
                virtPath += "/";
            }
            else
            {
                virtPath = virtPath.TrimEnd('/');
            }
            return virtPath.Replace("//", "/");
        }

        public static string ResolvePhysicalPath(string physPath, IDictionary<string, string> storageConfig)
        {
            physPath = Normalize(physPath, false).TrimStart('~');

            if (physPath.Contains(Constants.STORAGE_ROOT_PARAM))
            {
                physPath = physPath.Replace(Constants.STORAGE_ROOT_PARAM, storageConfig[Constants.STORAGE_ROOT_PARAM]);
            }

            if (!Path.IsPathRooted(physPath))
            {
                physPath = Path.GetFullPath(Path.Combine(storageConfig[Constants.CONFIG_DIR], physPath.Trim(Path.DirectorySeparatorChar)));
            }
            return physPath;
        }
    }
}


<|start_filename|>common/ASC.Common/Security/Authorizing/AzManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

namespace ASC.Common.Security.Authorizing
{
    public class AzManager
    {
        private readonly IPermissionProvider permissionProvider;
        private readonly IRoleProvider roleProvider;


        internal AzManager()
        {
        }

        public AzManager(IRoleProvider roleProvider, IPermissionProvider permissionProvider)
            : this()
        {
            if (roleProvider == null) throw new ArgumentNullException("roleProvider");
            if (permissionProvider == null) throw new ArgumentNullException("permissionProvider");

            this.roleProvider = roleProvider;
            this.permissionProvider = permissionProvider;
        }


        public bool CheckPermission(ISubject subject, IAction action, ISecurityObjectId objectId,
                                    ISecurityObjectProvider securityObjProvider, out ISubject denySubject,
                                    out IAction denyAction)
        {
            if (subject == null) throw new ArgumentNullException("subject");
            if (action == null) throw new ArgumentNullException("action");

            var acl = GetAzManagerAcl(subject, action, objectId, securityObjProvider);
            denySubject = acl.DenySubject;
            denyAction = acl.DenyAction;
            return acl.IsAllow;
        }

        public AzManagerAcl GetAzManagerAcl(ISubject subject, IAction action, ISecurityObjectId objectId, ISecurityObjectProvider securityObjProvider)
        {
            if (action.AdministratorAlwaysAllow && (Constants.Admin.ID == subject.ID || roleProvider.IsSubjectInRole(subject, Constants.Admin)))
            {
                return AzManagerAcl.Allow;
            }

            var acl = AzManagerAcl.Default;
            var exit = false;

            foreach (var s in GetSubjects(subject, objectId, securityObjProvider))
            {
                var aceList = permissionProvider.GetAcl(s, action, objectId, securityObjProvider);
                foreach (var ace in aceList)
                {
                    if (ace.Reaction == AceType.Deny && !exit)
                    {
                        acl.IsAllow = false;
                        acl.DenySubject = s;
                        acl.DenyAction = action;
                        exit = true;
                    }
                    if (ace.Reaction == AceType.Allow && !exit)
                    {
                        acl.IsAllow = true;
                        if (!action.Conjunction)
                        {
                            // disjunction: first allow and exit
                            exit = true;
                        }
                    }
                    if (exit) break;
                }
                if (exit) break;
            }
            return acl;
        }

        public IEnumerable<ISubject> GetSubjects(ISubject subject, ISecurityObjectId objectId, ISecurityObjectProvider securityObjProvider)
        {
            var subjects = new List<ISubject>();
            subjects.Add(subject);
            subjects.AddRange(
                roleProvider.GetRoles(subject)
                    .ConvertAll(r => { return (ISubject)r; })
                );
            if (objectId != null)
            {
                var secObjProviderHelper = new AzObjectSecurityProviderHelper(objectId, securityObjProvider);
                do
                {
                    if (!secObjProviderHelper.ObjectRolesSupported) continue;
                    foreach (IRole role in secObjProviderHelper.GetObjectRoles(subject))
                    {
                        if (!subjects.Contains(role)) subjects.Add(role);
                    }
                } while (secObjProviderHelper.NextInherit());
            }
            return subjects;
        }

        #region Nested type: AzManagerAcl

        public class AzManagerAcl
        {
            public IAction DenyAction;
            public ISubject DenySubject;
            public bool IsAllow;

            public static AzManagerAcl Allow
            {
                get { return new AzManagerAcl { IsAllow = true }; }
            }

            public static AzManagerAcl Default
            {
                get { return new AzManagerAcl { IsAllow = false }; }
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/popup.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.popup = (function($) {
    var $el;
    var popupQueue = [];
    var onUnblock;

    function init() {
        $el = $('#commonPopup');
    }

    function show(size, blockuiOpts) {
        var options = $.extend(true, { bindEvents: false }, blockuiOpts || {});

        StudioBlockUIManager.blockUI($el, size, options);

        var cancelButton = $el.find('.popupCancel .cancelButton').attr('onclick', '');

        disableCancel(false);

        $el.find('.containerBodyBlock .buttons .cancel').add(cancelButton).unbind('click').bind('click', function() {
            if ($(this).hasClass('disable')) {
                return false;
            }
            hide();
            return false;
        });
    }

    function hide() {
        if ($el.is(':visible')) {
            $.unblockUI({ onUnblock: onUnblock });
            setTimeout(processQueue, 0);
        }
    }

    function processQueue() {
        if ($el.is(':visible')) {
            return;
        }
        var item = popupQueue.pop();
        if (item) {
            $el.find('div.containerHeaderBlock:first td:first').html(item.header);
            $el.find('div.containerBodyBlock:first').html(item.body);
            onUnblock = item.onUnblock;
            show(item.size, item.blockui_opts);
        }
    }

    function addBig(header, body, unblockCallback, toBegining, blockuiOpts) {
        addPopup(header, body, 530, unblockCallback, toBegining, blockuiOpts);
    }

    function addSmall(header, body, unblockCallback, toBegining, blockuiOpts) {
        addPopup(header, body, 350, unblockCallback, toBegining, blockuiOpts);
    }

    function addPopup(header, body, size, unblockCallback, toBegining, blockuiOpts) {
        if (!$el.is(':visible') || header !== $el.find('div.containerHeaderBlock:first td:first')[0].innerHTML ||
            body !== $el.find('div.containerBodyBlock:first')[0].innerHTML) {
            var item = { header: header, body: body, onUnblock: unblockCallback, size: size, blockui_opts: blockuiOpts };
            if (toBegining) {
                popupQueue.unshift(item);
            } else {
                popupQueue.push(item);
            }
            processQueue();
        }
    }

    function disableCancel(disable) {
        var cancelX = $el.find('.popupCancel .cancelButton');
        if (cancelX.length !== 0) {
            TMMail.disableButton(cancelX, disable);
            if (disable) {
                cancelX.css('cursor', 'default');
            } else {
                cancelX.css('cursor', 'pointer');
            }
        }
    }
    
    function success(text) {
        if (!$el.is(':visible')) return;
        showNotification("toast-success", text);
    }
    
    function info(text) {
        if (!$el.is(':visible')) return;
        showNotification("toast-info", text);
    }

    function warning(text) {
        if (!$el.is(':visible')) return;
        showNotification("toast-warning", text);
    }

    function error(text) {
        if (!$el.is(':visible')) return;
        showNotification("toast-error", text);
    }

    function showNotification(cssClass, text) {
        var $notification = $.tmpl("popupNotificationTmpl", { cssClass: cssClass, text: text });

        $el.find('.toast-popup-container').remove();

        var $progressBox = $el.find('.progressContainer');
        var $buttonsBox = $el.find('.buttons');

        if ($progressBox.length) {
            $progressBox.find('.loader').hide();
            $progressBox.append($notification);
        } else if ($buttonsBox.length) {
            $buttonsBox.before($notification);
        } else {
            $el.find('.containerBodyBlock').append($notification);
        }

        setTimeout(function() {
            $notification.remove();
        }, 5000);
    }

    return {
        init: init,
        hide: hide,
        addBig: addBig,
        addSmall: addSmall,
        addPopup: addPopup,
        disableCancel: disableCancel,
        
        success: success,
        info: info,
        warning: warning,
        error: error
    };
})(jQuery);

<|start_filename|>module/ASC.MessagingSystem/MessageFactory.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;

namespace ASC.MessagingSystem
{
    static class MessageFactory
    {
        private static readonly ILog log = LogManager.GetLogger("ASC.Messaging");
        private const string userAgentHeader = "User-Agent";
        private const string forwardedHeader = "X-Forwarded-For";
        private const string hostHeader = "Host";
        private const string refererHeader = "Referer";


        public static EventMessage Create(HttpRequest request, string initiator, MessageAction action, MessageTarget target, params string[] description)
        {
            try
            {
                return new EventMessage
                {
                    IP = request != null ? request.Headers[forwardedHeader] ?? request.UserHostAddress : null,
                    Initiator = initiator,
                    Date = DateTime.UtcNow,
                    TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId,
                    UserId = SecurityContext.CurrentAccount.ID,
                    Page = request != null && request.UrlReferrer != null ? request.UrlReferrer.ToString() : null,
                    Action = action,
                    Description = description,
                    Target = target,
                    UAHeader = request != null ? request.Headers[userAgentHeader] : null
                };
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Error while parse Http Request for {0} type of event: {1}", action, ex);
                return null;
            }
        }

        public static EventMessage Create(MessageUserData userData, Dictionary<string, string> headers, MessageAction action, MessageTarget target, params string[] description)
        {
            try
            {
                var message = new EventMessage
                {
                    Date = DateTime.UtcNow,
                    TenantId = userData == null ? CoreContext.TenantManager.GetCurrentTenant().TenantId : userData.TenantId,
                    UserId = userData == null ? SecurityContext.CurrentAccount.ID : userData.UserId,
                    Action = action,
                    Description = description,
                    Target = target
                };

                if (headers != null)
                {
                    var userAgent = headers.ContainsKey(userAgentHeader) ? headers[userAgentHeader] : null;
                    var forwarded = headers.ContainsKey(forwardedHeader) ? headers[forwardedHeader] : null;
                    var host = headers.ContainsKey(hostHeader) ? headers[hostHeader] : null;
                    var referer = headers.ContainsKey(refererHeader) ? headers[refererHeader] : null;

                    message.IP = forwarded ?? host;
                    message.UAHeader = userAgent;
                    message.Page = referer;
                }

                return message;
            }
            catch (Exception ex)
            {
                log.Error(string.Format("Error while parse Http Message for \"{0}\" type of event: {1}", action, ex));
                return null;
            }
        }

        public static EventMessage Create(string initiator, MessageAction action, MessageTarget target, params string[] description)
        {
            try
            {
                return new EventMessage
                {
                    Initiator = initiator,
                    Date = DateTime.UtcNow,
                    TenantId = CoreContext.TenantManager.GetCurrentTenant().TenantId,
                    Action = action,
                    Description = description,
                    Target = target
                };
            }
            catch (Exception ex)
            {
                log.Error(string.Format("Error while parse Initiator Message for \"{0}\" type of event: {1}", action, ex));
                return null;
            }
        }


    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/CrmLinkEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;

using ASC.Common.Logging;
using ASC.CRM.Core;
using ASC.Mail.Core.Dao.Expressions.Message;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Data.Storage;
using ASC.Mail.Exceptions;
using ASC.Mail.Utils;
using ASC.Web.CRM.Core;

using Autofac;

namespace ASC.Mail.Core.Engine
{
    public class CrmLinkEngine
    {
        public int Tenant { get; private set; }

        public string User { get; private set; }

        public ILog Log { get; private set; }

        public CrmLinkEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.CrmLinkEngine");
        }

        public List<CrmContactData> GetLinkedCrmEntitiesId(int messageId)
        {
            using (var daoFactory = new DaoFactory())
            {
                var daoCrmLink = daoFactory.CreateCrmLinkDao(Tenant, User);

                var daoMail = daoFactory.CreateMailDao(Tenant, User);

                var mail = daoMail.GetMail(new ConcreteUserMessageExp(messageId, Tenant, User));

                return daoCrmLink.GetLinkedCrmContactEntities(mail.ChainId, mail.MailboxId);
            }
        }

        public void LinkChainToCrm(int messageId, List<CrmContactData> contactIds, string httpContextScheme)
        {
            using (var scope = DIHelper.Resolve())
            {
                var factory = scope.Resolve<CRM.Core.Dao.DaoFactory>();
                foreach (var crmContactEntity in contactIds)
                {
                    switch (crmContactEntity.Type)
                    {
                        case CrmContactData.EntityTypes.Contact:
                            var crmContact = factory.ContactDao.GetByID(crmContactEntity.Id);
                            CRMSecurity.DemandAccessTo(crmContact);
                            break;
                        case CrmContactData.EntityTypes.Case:
                            var crmCase = factory.CasesDao.GetByID(crmContactEntity.Id);
                            CRMSecurity.DemandAccessTo(crmCase);
                            break;
                        case CrmContactData.EntityTypes.Opportunity:
                            var crmOpportunity = factory.DealDao.GetByID(crmContactEntity.Id);
                            CRMSecurity.DemandAccessTo(crmOpportunity);
                            break;
                    }
                }
            }

            using (var daoFactory = new DaoFactory())
            {
                var db = daoFactory.DbManager;

                var daoMail = daoFactory.CreateMailDao(Tenant, User);

                var mail = daoMail.GetMail(new ConcreteUserMessageExp(messageId, Tenant, User));

                var daoMailInfo = daoFactory.CreateMailInfoDao(Tenant, User);

                var chainedMessages = daoMailInfo.GetMailInfoList(
                    SimpleMessagesExp.CreateBuilder(Tenant, User)
                        .SetChainId(mail.ChainId)
                        .Build());

                if (!chainedMessages.Any())
                    return;

                var linkingMessages = new List<MailMessageData>();

                var engine = new EngineFactory(Tenant, User);

                foreach (var chainedMessage in chainedMessages)
                {
                    var message = engine.MessageEngine.GetMessage(chainedMessage.Id,
                        new MailMessageData.Options
                        {
                            LoadImages = true,
                            LoadBody = true,
                            NeedProxyHttp = false
                        });

                    message.LinkedCrmEntityIds = contactIds;

                    linkingMessages.Add(message);

                }

                var daoCrmLink = daoFactory.CreateCrmLinkDao(Tenant, User);

                using (var tx = db.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    daoCrmLink.SaveCrmLinks(mail.ChainId, mail.MailboxId, contactIds);

                    foreach (var message in linkingMessages)
                    {
                        try
                        {
                            AddRelationshipEvents(message, httpContextScheme);
                        }
                        catch (ApiHelperException ex)
                        {
                            if (!ex.Message.Equals("Already exists"))
                                throw;
                        }
                    }

                    tx.Commit();
                }
            }
        }

        public void MarkChainAsCrmLinked(int messageId, List<CrmContactData> contactIds)
        {
            using (var daoFactory = new DaoFactory())
            {
                var db = daoFactory.DbManager;

                var daoCrmLink = daoFactory.CreateCrmLinkDao(Tenant, User);

                using (var tx = db.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    var daoMail = daoFactory.CreateMailDao(Tenant, User);

                    var mail = daoMail.GetMail(new ConcreteUserMessageExp(messageId, Tenant, User));

                    daoCrmLink.SaveCrmLinks(mail.ChainId, mail.MailboxId, contactIds);

                    tx.Commit();
                }
            }
        }

        public void UnmarkChainAsCrmLinked(int messageId, IEnumerable<CrmContactData> contactIds)
        {
            using (var daoFactory = new DaoFactory())
            {
                var db = daoFactory.DbManager;

                var daoCrmLink = daoFactory.CreateCrmLinkDao(Tenant, User);

                using (var tx = db.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    var daoMail = daoFactory.CreateMailDao(Tenant, User);

                    var mail = daoMail.GetMail(new ConcreteUserMessageExp(messageId, Tenant, User));

                    daoCrmLink.RemoveCrmLinks(mail.ChainId, mail.MailboxId, contactIds);

                    tx.Commit();
                }
            }
        }

        public void ExportMessageToCrm(int messageId, IEnumerable<CrmContactData> crmContactIds)
        {
            if (messageId < 0)
                throw new ArgumentException(@"Invalid message id", "messageId");
            if (crmContactIds == null)
                throw new ArgumentException(@"Invalid contact ids list", "crmContactIds");

            var engine = new EngineFactory(Tenant, User);

            var messageItem = engine.MessageEngine.GetMessage(messageId, new MailMessageData.Options
            {
                LoadImages = true,
                LoadBody = true,
                NeedProxyHttp = false
            });

            messageItem.LinkedCrmEntityIds = crmContactIds.ToList();

            AddRelationshipEvents(messageItem);
        }

        public void AddRelationshipEventForLinkedAccounts(MailBoxData mailbox, MailMessageData messageItem, string httpContextScheme)
        {
            try
            {
                using (var daoFactory = new DaoFactory())
                {
                    var dao = daoFactory.CreateCrmLinkDao(mailbox.TenantId, mailbox.UserId);

                    messageItem.LinkedCrmEntityIds = dao.GetLinkedCrmContactEntities(messageItem.ChainId, mailbox.MailBoxId);
                }

                if (!messageItem.LinkedCrmEntityIds.Any()) return;

                AddRelationshipEvents(messageItem, httpContextScheme);
            }
            catch (Exception ex)
            {
                Log.Warn(string.Format("Problem with adding history event to CRM. mailId={0}", messageItem.Id), ex);
            }
        }

        public void AddRelationshipEvents(MailMessageData message, string httpContextScheme = null)
        {
            using (var scope = DIHelper.Resolve())
            {
                var factory = scope.Resolve<CRM.Core.Dao.DaoFactory>();
                foreach (var contactEntity in message.LinkedCrmEntityIds)
                {
                    switch (contactEntity.Type)
                    {
                        case CrmContactData.EntityTypes.Contact:
                            var crmContact = factory.ContactDao.GetByID(contactEntity.Id);
                            CRMSecurity.DemandAccessTo(crmContact);
                            break;
                        case CrmContactData.EntityTypes.Case:
                            var crmCase = factory.CasesDao.GetByID(contactEntity.Id);
                            CRMSecurity.DemandAccessTo(crmCase);
                            break;
                        case CrmContactData.EntityTypes.Opportunity:
                            var crmOpportunity = factory.DealDao.GetByID(contactEntity.Id);
                            CRMSecurity.DemandAccessTo(crmOpportunity);
                            break;
                    }

                    var fileIds = new List<object>();

                    var apiHelper = new ApiHelper(httpContextScheme ?? Defines.DefaultApiSchema, Log);

                    foreach (var attachment in message.Attachments.FindAll(attach => !attach.isEmbedded))
                    {
                        if (attachment.dataStream != null)
                        {
                            attachment.dataStream.Seek(0, SeekOrigin.Begin);

                            var uploadedFileId = apiHelper.UploadToCrm(attachment.dataStream, attachment.fileName,
                                attachment.contentType, contactEntity);

                            if (uploadedFileId != null)
                            {
                                fileIds.Add(uploadedFileId);
                            }
                        }
                        else
                        {
                            using (var file = attachment.ToAttachmentStream())
                            {
                                var uploadedFileId = apiHelper.UploadToCrm(file.FileStream, file.FileName,
                                    attachment.contentType, contactEntity);

                                if (uploadedFileId != null)
                                {
                                    fileIds.Add(uploadedFileId);
                                }
                            }
                        }
                    }

                    apiHelper.AddToCrmHistory(message, contactEntity, fileIds);

                    Log.InfoFormat(
                        "CrmLinkEngine->AddRelationshipEvents(): message with id = {0} has been linked successfully to contact with id = {1}",
                        message.Id, contactEntity.Id);
                }
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/LdapSettings/LdapSettings.ascx.designer.cs<|end_filename|>
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated. 
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Studio.UserControls.Management
{


    public partial class LdapSettings
    {

        /// <summary>
        /// ldapSettingsTurnOffContainer control.
        /// </summary>
        /// <remarks>
        /// Auto-generated field.
        /// To modify move field declaration from designer file to code-behind file.
        /// </remarks>
        protected global::ASC.Web.Studio.Controls.Common.Container ldapSettingsTurnOffContainer;

        /// <summary>
        /// ldapSettingsCronPanel control.
        /// </summary>
        /// <remarks>
        /// Auto-generated field.
        /// To modify move field declaration from designer file to code-behind file.
        /// </remarks>
        protected global::ASC.Web.Studio.Controls.Common.Container ldapSettingsCronPanel;

        /// <summary>
        /// ldapSettingsCronTurnOffContainer control.
        /// </summary>
        /// <remarks>
        /// Auto-generated field.
        /// To modify move field declaration from designer file to code-behind file.
        /// </remarks>
        protected global::ASC.Web.Studio.Controls.Common.Container ldapSettingsCronTurnOffContainer;

        /// <summary>
        /// ldapSettingsCertificateValidationContainer control.
        /// </summary>
        /// <remarks>
        /// Auto-generated field.
        /// To modify move field declaration from designer file to code-behind file.
        /// </remarks>
        protected global::ASC.Web.Studio.Controls.Common.Container ldapSettingsCertificateValidationContainer;

        /// <summary>
        /// ldapSettingsConfirmContainerId control.
        /// </summary>
        /// <remarks>
        /// Auto-generated field.
        /// To modify move field declaration from designer file to code-behind file.
        /// </remarks>
        protected global::ASC.Web.Studio.Controls.Common.Container ldapSettingsConfirmContainerId;

        /// <summary>
        /// ldapSettingsLimitPanelId control.
        /// </summary>
        /// <remarks>
        /// Auto-generated field.
        /// To modify move field declaration from designer file to code-behind file.
        /// </remarks>
        protected global::ASC.Web.Studio.Controls.Common.Container ldapSettingsLimitPanelId;
    }
}


<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiContext.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;

using ASC.Api.Interfaces;

using Autofac;

namespace ASC.Api.Impl
{
    public class ApiContext : ICloneable
    {
        public RequestContext RequestContext { get; set; }

        public ApiContext(RequestContext requestContext) : this(requestContext, null)
        {
        }

        public ApiContext(RequestContext requestContext, IApiConfiguration apiConfiguration)
        {
            if (apiConfiguration == null)
                apiConfiguration = ApiSetup.Builder.Resolve<IApiConfiguration>();

            if (requestContext == null) return;
            RequestContext = requestContext;

            //!!! Register in HttpContext. Needed for lifetime manager
            RequestContext.HttpContext.Items["_apiContext"] = this;

            Count = 0;
            //Try parse values
            string count = GetRequestValue("count");
            ulong countParsed;
            if (!string.IsNullOrEmpty(count) && ulong.TryParse(count, out countParsed))
            {
                //Count specified and valid
                SpecifiedCount = (long)Math.Max(0, Math.Min(apiConfiguration.ItemsPerPage, countParsed));
            }
            else
            {
                SpecifiedCount = Math.Max(0, apiConfiguration.ItemsPerPage);
            }
            Count = SpecifiedCount + 1;//NOTE: +1 added to see if it's last page


            string startIndex = GetRequestValue("startIndex");
            long startIndexParsed;
            if (startIndex != null && long.TryParse(startIndex, out startIndexParsed))
            {
                StartIndex = Math.Max(0, startIndexParsed);
                SpecifiedStartIndex = StartIndex;
            }

            string sortOrder = GetRequestValue("sortOrder");
            if ("descending".Equals(sortOrder))
            {
                SortDescending = true;
            }

            FilterToType = GetRequestValue("type");
            SortBy = GetRequestValue("sortBy");
            FilterBy = GetRequestValue("filterBy");
            FilterOp = GetRequestValue("filterOp");
            FilterValue = GetRequestValue("filterValue");
            FilterValues = GetRequestArray("filterValue");
            Fields = GetRequestArray("fields");

            string updatedSince = GetRequestValue("updatedSince");
            if (updatedSince != null)
            {
                UpdatedSince = Convert.ToDateTime(updatedSince);
            }
        }

        public string[] Fields { get; set; }

        private string[] GetRequestArray(string key)
        {
            if (RequestContext.HttpContext.Request.QueryString != null)
            {
                var values = RequestContext.HttpContext.Request.QueryString.GetValues(key + "[]");
                if (values != null)
                    return values;

                values = RequestContext.HttpContext.Request.QueryString.GetValues(key);
                if (values != null)
                {
                    if (values.Length == 1) //If it's only one element
                    {
                        //Try split
                        if (!string.IsNullOrEmpty(values[0]))
                            return values[0].Split(',');
                    }
                    return values;
                }
            }
            return null;
        }

        public string GetRequestValue(string key)
        {
            var reqArray = GetRequestArray(key);
            return reqArray != null ? reqArray.FirstOrDefault() : null;
        }

        public string[] FilterValues { get; set; }

        /// <summary>
        /// Filters responce to specific type from request parameter "type"
        /// </summary>
        /// <remarks>
        /// The type name is retrieved from [DataContractAttribute] name
        /// </remarks>
        public string FilterToType { get; set; }

        /// <summary>
        /// Gets count to get item from collection. Request parameter "count"
        /// </summary>
        /// <remarks>
        /// Don't forget to call _context.SetDataPaginated() to prevent SmartList from filtering response if you fetch data from DB with TOP & COUNT
        /// </remarks>
        public long Count { get; set; }

        /// <summary>
        /// Gets start index to get item from collection. Request parameter "startIndex"
        /// </summary>
        /// <remarks>
        /// Don't forget to call _context.SetDataPaginated() to prevent SmartList from filtering response if you fetch data from DB with TOP & COUNT
        /// </remarks>
        public long StartIndex { get; set; }

        internal long SpecifiedStartIndex { get; set; }

        /// <summary>
        /// Gets field to sort by from request parameter "sortBy"
        /// </summary>
        public string SortBy { get; set; }

        /// <summary>
        /// Gets field to filter from request parameter "filterBy"
        /// </summary>
        public string FilterBy { get; set; }

        /// <summary>
        /// Gets filter operation from request parameter "filterOp"
        /// can be one of the following:"contains","equals","startsWith","present"
        /// </summary>
        public string FilterOp { get; set; }

        /// <summary>
        /// Gets value to filter from request parameter "filterValue"
        /// </summary>
        public string FilterValue { get; set; }

        /// <summary>
        /// Sort direction. From request parameter "sortOrder" can be "descending" or "ascending"
        /// Like ...&sortOrder=descending&...
        /// </summary>
        public bool SortDescending { get; set; }

        /// <summary>
        /// Gets value to filter from request parameter "updatedSince"
        /// </summary>
        public DateTime UpdatedSince { get; set; }

        public bool FromCache { get; set; }

        private readonly List<Type> _knowntype = new List<Type>();

        internal long SpecifiedCount { get; private set; }

        /// <summary>
        /// Set mark that data is already paginated and additional filtering is not needed
        /// </summary>
        public ApiContext SetDataPaginated()
        {
            //Count = 0;//We always ask for +1 count so smart list should cut it
            StartIndex = 0;
            return this;
        }

        public ApiContext SetDataSorted()
        {
            SortBy = string.Empty;
            return this;
        }

        public ApiContext SetDataFiltered()
        {
            FilterBy = string.Empty;
            FilterOp = string.Empty;
            FilterValue = string.Empty;
            return this;
        }

        public ApiContext SetTotalCount(long totalCollectionCount)
        {
            TotalCount = totalCollectionCount;
            return this;
        }

        public long? TotalCount { get; set; }


        public void RegisterType(Type type)
        {
            if (!_knowntype.Contains(type))
            {
                _knowntype.Add(type);
            }
        }

        public void RegisterTypes(IEnumerable<Type> types)
        {
            _knowntype.AddRange(types);

        }

        internal IEnumerable<Type> GetKnownTypes()
        {
            return _knowntype.Distinct();
        }

        public object Clone()
        {
            return MemberwiseClone();
        }

        public override string ToString()
        {
            return string.Format("C:{0},S:{1},So:{2},Sd:{3},Fb;{4},Fo:{5},Fv:{6},Us:{7},Ftt:{8}", Count, StartIndex,
                                 SortBy, SortDescending, FilterBy, FilterOp, FilterValue, UpdatedSince.Ticks, FilterToType);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/contacts/tlgroups.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.tlGroups = (function($) {
    var initFlag = false;
    var groups = [];
    var events = $({});
    var init = function() {
        if (!initFlag) {
            initFlag = true;
            update();
        }
    };

    var onGroupsResponce = function(params, groupsParam) {
        groups = groupsParam;
        initFlag = true;
        events.trigger('update');
    };

    var update = function () {
        if (initFlag) {
            events.trigger('update');
        }

        try {
            onGroupsResponce(null, window.GroupManager.getAllGroups());
        } catch (err) {
            console.error(err);
            serviceManager.getTLGroups({}, { success: onGroupsResponce });
        }
    };

    var getGroups = function() {
        return groups;
    };

    return {
        init: init,
        update: update,
        getGroups: getGroups,
        events: events
    };
})(jQuery);

<|start_filename|>common/ASC.Common/Logging/Log.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

using ASC.Common.DependencyInjection;

using Autofac;

using log4net.Config;
using log4net.Core;

using NLog;

namespace ASC.Common.Logging
{
    public interface ILog
    {
        bool IsDebugEnabled { get; }
        bool IsInfoEnabled { get; }
        bool IsWarnEnabled { get; }
        bool IsErrorEnabled { get; }
        bool IsFatalEnabled { get; }
        bool IsTraceEnabled { get; }

        void Trace(object message);
        void TraceFormat(string message, object arg0);

        void DebugWithProps(string message, params KeyValuePair<string, object>[] props);
        void Debug(object message);
        void Debug(object message, Exception exception);
        void DebugFormat(string format, params object[] args);
        void DebugFormat(string format, object arg0);
        void DebugFormat(string format, object arg0, object arg1);
        void DebugFormat(string format, object arg0, object arg1, object arg2);
        void DebugFormat(IFormatProvider provider, string format, params object[] args);


        void Info(object message);
        void Info(string message, Exception exception);
        void InfoFormat(string format, params object[] args);
        void InfoFormat(string format, object arg0);
        void InfoFormat(string format, object arg0, object arg1);
        void InfoFormat(string format, object arg0, object arg1, object arg2);
        void InfoFormat(IFormatProvider provider, string format, params object[] args);

        void Warn(object message);
        void Warn(object message, Exception exception);
        void WarnFormat(string format, params object[] args);
        void WarnFormat(string format, object arg0);
        void WarnFormat(string format, object arg0, object arg1);
        void WarnFormat(string format, object arg0, object arg1, object arg2);
        void WarnFormat(IFormatProvider provider, string format, params object[] args);

        void Error(object message);
        void Error(object message, Exception exception);
        void ErrorFormat(string format, params object[] args);
        void ErrorFormat(string format, object arg0);
        void ErrorFormat(string format, object arg0, object arg1);
        void ErrorFormat(string format, object arg0, object arg1, object arg2);
        void ErrorFormat(IFormatProvider provider, string format, params object[] args);

        void Fatal(object message);
        void Fatal(string message, Exception exception);
        void FatalFormat(string format, params object[] args);
        void FatalFormat(string format, object arg0);
        void FatalFormat(string format, object arg0, object arg1);
        void FatalFormat(string format, object arg0, object arg1, object arg2);
        void FatalFormat(IFormatProvider provider, string format, params object[] args);

        string LogDirectory { get; }
    }

    public class Log : ILog
    {
        static Log()
        {
            XmlConfigurator.Configure();
        }

        private readonly log4net.ILog loger;

        public bool IsDebugEnabled { get; private set; }

        public bool IsInfoEnabled { get; private set; }

        public bool IsWarnEnabled { get; private set; }

        public bool IsErrorEnabled { get; private set; }

        public bool IsFatalEnabled { get; private set; }

        public bool IsTraceEnabled { get; private set; }

        public Log(string name)
        {
            loger = log4net.LogManager.GetLogger(name);

            IsDebugEnabled = loger.IsDebugEnabled;
            IsInfoEnabled = loger.IsInfoEnabled;
            IsWarnEnabled = loger.IsWarnEnabled;
            IsErrorEnabled = loger.IsErrorEnabled;
            IsFatalEnabled = loger.IsFatalEnabled;
            IsTraceEnabled = loger.Logger.IsEnabledFor(Level.Trace);
        }

        public void Trace(object message)
        {
            if (IsTraceEnabled) loger.Logger.Log(GetType(), Level.Trace, message, null);
        }

        public void TraceFormat(string message, object arg0)
        {
            if (IsTraceEnabled) loger.Logger.Log(GetType(), Level.Trace, string.Format(message, arg0), null);
        }

        public void Debug(object message)
        {
            if (IsDebugEnabled) loger.Debug(message);
        }

        public void Debug(object message, Exception exception)
        {
            if (IsDebugEnabled) loger.Debug(message, exception);
        }

        public void DebugFormat(string format, params object[] args)
        {
            if (IsDebugEnabled) loger.DebugFormat(format, args);
        }

        public void DebugFormat(string format, object arg0)
        {
            if (IsDebugEnabled) loger.DebugFormat(format, arg0);
        }

        public void DebugFormat(string format, object arg0, object arg1)
        {
            if (IsDebugEnabled) loger.DebugFormat(format, arg0, arg1);
        }

        public void DebugFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsDebugEnabled) loger.DebugFormat(format, arg0, arg1, arg2);
        }

        public void DebugFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsDebugEnabled) loger.DebugFormat(provider, format, args);
        }

        public void DebugWithProps(string message, params KeyValuePair<string, object>[] props)
        {
            if (!IsDebugEnabled) return;

            foreach (var p in props)
            {
                log4net.ThreadContext.Properties[p.Key] = p.Value;
            }

            loger.Debug(message);
        }


        public void Info(object message)
        {
            if (IsInfoEnabled) loger.Info(message);
        }

        public void Info(string message, Exception exception)
        {
            if (IsInfoEnabled) loger.Info(message, exception);
        }

        public void InfoFormat(string format, params object[] args)
        {
            if (IsInfoEnabled) loger.InfoFormat(format, args);
        }

        public void InfoFormat(string format, object arg0)
        {
            if (IsInfoEnabled) loger.InfoFormat(format, arg0);
        }

        public void InfoFormat(string format, object arg0, object arg1)
        {
            if (IsInfoEnabled) loger.InfoFormat(format, arg0, arg1);
        }

        public void InfoFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsInfoEnabled) loger.InfoFormat(format, arg0, arg1, arg2);
        }

        public void InfoFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsInfoEnabled) loger.InfoFormat(provider, format, args);
        }


        public void Warn(object message)
        {
            if (IsWarnEnabled) loger.Warn(message);
        }

        public void Warn(object message, Exception exception)
        {
            if (IsWarnEnabled) loger.Warn(message, exception);
        }

        public void WarnFormat(string format, params object[] args)
        {
            if (IsWarnEnabled) loger.WarnFormat(format, args);
        }

        public void WarnFormat(string format, object arg0)
        {
            if (IsWarnEnabled) loger.WarnFormat(format, arg0);
        }

        public void WarnFormat(string format, object arg0, object arg1)
        {
            if (IsWarnEnabled) loger.WarnFormat(format, arg0, arg1);
        }

        public void WarnFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsWarnEnabled) loger.WarnFormat(format, arg0, arg1, arg2);
        }

        public void WarnFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsWarnEnabled) loger.WarnFormat(provider, format, args);
        }


        public void Error(object message)
        {
            if (IsErrorEnabled) loger.Error(message);
        }

        public void Error(object message, Exception exception)
        {
            if (IsErrorEnabled) loger.Error(message, exception);
        }

        public void ErrorFormat(string format, params object[] args)
        {
            if (IsErrorEnabled) loger.ErrorFormat(format, args);
        }

        public void ErrorFormat(string format, object arg0)
        {
            if (IsErrorEnabled) loger.ErrorFormat(format, arg0);
        }

        public void ErrorFormat(string format, object arg0, object arg1)
        {
            if (IsErrorEnabled) loger.ErrorFormat(format, arg0, arg1);
        }

        public void ErrorFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsErrorEnabled) loger.ErrorFormat(format, arg0, arg1, arg2);
        }

        public void ErrorFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsErrorEnabled) loger.ErrorFormat(provider, format, args);
        }


        public void Fatal(object message)
        {
            if (IsFatalEnabled) loger.Fatal(message);
        }

        public void Fatal(string message, Exception exception)
        {
            if (IsFatalEnabled) loger.Fatal(message, exception);
        }

        public void FatalFormat(string format, params object[] args)
        {
            if (IsFatalEnabled) loger.FatalFormat(format, args);
        }

        public void FatalFormat(string format, object arg0)
        {
            if (IsFatalEnabled) loger.FatalFormat(format, arg0);
        }

        public void FatalFormat(string format, object arg0, object arg1)
        {
            if (IsFatalEnabled) loger.FatalFormat(format, arg0, arg1);
        }

        public void FatalFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsFatalEnabled) loger.FatalFormat(format, arg0, arg1, arg2);
        }

        public void FatalFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsFatalEnabled) loger.FatalFormat(provider, format, args);
        }

        public string LogDirectory
        {
            get
            {
                return log4net.GlobalContext.Properties["LogDirectory"].ToString();
            }
        }
    }

    public class LogNLog : ILog
    {
        private readonly NLog.ILogger loger;
        private readonly string name;

        public bool IsDebugEnabled { get; private set; }

        public bool IsInfoEnabled { get; private set; }

        public bool IsWarnEnabled { get; private set; }

        public bool IsErrorEnabled { get; private set; }

        public bool IsFatalEnabled { get; private set; }

        public bool IsTraceEnabled { get; private set; }

        static LogNLog()
        {
            var args = Environment.GetCommandLineArgs();

            for (var i = 0; i < args.Length; i++)
            {
                if (args[i] == "--log" && !string.IsNullOrEmpty(args[i + 1]))
                {
                    NLog.LogManager.Configuration.Variables["svcName"] = args[i + 1].Trim().Trim('"');
                }
            }

            NLog.Targets.Target.Register<SelfCleaningTarget>("SelfCleaning");
        }

        public LogNLog(string name)
        {
            this.name = name;

            loger = NLog.LogManager.GetLogger(name);

            IsDebugEnabled = loger.IsDebugEnabled;
            IsInfoEnabled = loger.IsInfoEnabled;
            IsWarnEnabled = loger.IsWarnEnabled;
            IsErrorEnabled = loger.IsErrorEnabled;
            IsFatalEnabled = loger.IsFatalEnabled;
            IsTraceEnabled = loger.IsEnabled(LogLevel.Trace);
        }

        public void Trace(object message)
        {
            if (IsTraceEnabled) loger.Log(LogLevel.Trace, message);
        }

        public void TraceFormat(string message, object arg0)
        {
            if (IsTraceEnabled) loger.Log(LogLevel.Trace, string.Format(message, arg0));
        }

        public void Debug(object message)
        {
            if (IsDebugEnabled) loger.Debug(message);
        }

        public void Debug(object message, Exception exception)
        {
            if (IsDebugEnabled) loger.Debug(exception, "{0}", message);
        }

        public void DebugFormat(string format, params object[] args)
        {
            if (IsDebugEnabled) loger.Debug(format, args);
        }

        public void DebugFormat(string format, object arg0)
        {
            if (IsDebugEnabled) loger.Debug(format, arg0);
        }

        public void DebugFormat(string format, object arg0, object arg1)
        {
            if (IsDebugEnabled) loger.Debug(format, arg0, arg1);
        }

        public void DebugFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsDebugEnabled) loger.Debug(format, arg0, arg1, arg2);
        }

        public void DebugFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsDebugEnabled) loger.Debug(provider, format, args);
        }

        public void DebugWithProps(string message, params KeyValuePair<string, object>[] props)
        {
            if (!IsDebugEnabled) return;

            var theEvent = new LogEventInfo { Message = message, LoggerName = name, Level = LogLevel.Debug };

            foreach (var p in props)
            {
                theEvent.Properties[p.Key] = p.Value;
            }

            loger.Log(theEvent);
        }

        public void Info(object message)
        {
            if (IsInfoEnabled) loger.Info(message);
        }

        public void Info(string message, Exception exception)
        {
            if (IsInfoEnabled) loger.Info(exception, message);
        }

        public void InfoFormat(string format, params object[] args)
        {
            if (IsInfoEnabled) loger.Info(format, args);
        }

        public void InfoFormat(string format, object arg0)
        {
            if (IsInfoEnabled) loger.Info(format, arg0);
        }

        public void InfoFormat(string format, object arg0, object arg1)
        {
            if (IsInfoEnabled) loger.Info(format, arg0, arg1);
        }

        public void InfoFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsInfoEnabled) loger.Info(format, arg0, arg1, arg2);
        }

        public void InfoFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsInfoEnabled) loger.Info(provider, format, args);
        }


        public void Warn(object message)
        {
            if (IsWarnEnabled) loger.Warn(message);
        }

        public void Warn(object message, Exception exception)
        {
            if (IsWarnEnabled) loger.Warn(exception, "{0}", message);
        }

        public void WarnFormat(string format, params object[] args)
        {
            if (IsWarnEnabled) loger.Warn(format, args);
        }

        public void WarnFormat(string format, object arg0)
        {
            if (IsWarnEnabled) loger.Warn(format, arg0);
        }

        public void WarnFormat(string format, object arg0, object arg1)
        {
            if (IsWarnEnabled) loger.Warn(format, arg0, arg1);
        }

        public void WarnFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsWarnEnabled) loger.Warn(format, arg0, arg1, arg2);
        }

        public void WarnFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsWarnEnabled) loger.Warn(provider, format, args);
        }


        public void Error(object message)
        {
            if (IsErrorEnabled) loger.Error(message);
        }

        public void Error(object message, Exception exception)
        {
            if (IsErrorEnabled) loger.Error(exception, "{0}", message);
        }

        public void ErrorFormat(string format, params object[] args)
        {
            if (IsErrorEnabled) loger.Error(format, args);
        }

        public void ErrorFormat(string format, object arg0)
        {
            if (IsErrorEnabled) loger.Error(format, arg0);
        }

        public void ErrorFormat(string format, object arg0, object arg1)
        {
            if (IsErrorEnabled) loger.Error(format, arg0, arg1);
        }

        public void ErrorFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsErrorEnabled) loger.Error(format, arg0, arg1, arg2);
        }

        public void ErrorFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsErrorEnabled) loger.Error(provider, format, args);
        }


        public void Fatal(object message)
        {
            if (IsFatalEnabled) loger.Fatal(message);
        }

        public void Fatal(string message, Exception exception)
        {
            if (IsFatalEnabled) loger.Fatal(exception, message);
        }

        public void FatalFormat(string format, params object[] args)
        {
            if (IsFatalEnabled) loger.Fatal(format, args);
        }

        public void FatalFormat(string format, object arg0)
        {
            if (IsFatalEnabled) loger.Fatal(format, arg0);
        }

        public void FatalFormat(string format, object arg0, object arg1)
        {
            if (IsFatalEnabled) loger.Fatal(format, arg0, arg1);
        }

        public void FatalFormat(string format, object arg0, object arg1, object arg2)
        {
            if (IsFatalEnabled) loger.Fatal(format, arg0, arg1, arg2);
        }

        public void FatalFormat(IFormatProvider provider, string format, params object[] args)
        {
            if (IsFatalEnabled) loger.Fatal(provider, format, args);
        }

        public string LogDirectory { get { return NLog.LogManager.Configuration.Variables["logDirectory"].Text; } }
    }

    public class NullLog : ILog
    {
        public bool IsDebugEnabled { get; set; }
        public bool IsInfoEnabled { get; set; }
        public bool IsWarnEnabled { get; set; }
        public bool IsErrorEnabled { get; set; }
        public bool IsFatalEnabled { get; set; }
        public bool IsTraceEnabled { get; set; }

        public void Trace(object message)
        {
        }

        public void TraceFormat(string message, object arg0)
        {
        }

        public void DebugWithProps(string message, params KeyValuePair<string, object>[] props)
        {
        }

        public void Debug(object message)
        {
        }

        public void Debug(object message, Exception exception)
        {
        }

        public void DebugFormat(string format, params object[] args)
        {
        }

        public void DebugFormat(string format, object arg0)
        {
        }

        public void DebugFormat(string format, object arg0, object arg1)
        {
        }

        public void DebugFormat(string format, object arg0, object arg1, object arg2)
        {
        }

        public void DebugFormat(IFormatProvider provider, string format, params object[] args)
        {
        }

        public void Info(object message)
        {
        }

        public void Info(string message, Exception exception)
        {
        }

        public void InfoFormat(string format, params object[] args)
        {
        }

        public void InfoFormat(string format, object arg0)
        {
        }

        public void InfoFormat(string format, object arg0, object arg1)
        {
        }

        public void InfoFormat(string format, object arg0, object arg1, object arg2)
        {
        }

        public void InfoFormat(IFormatProvider provider, string format, params object[] args)
        {
        }

        public void Warn(object message)
        {
        }

        public void Warn(object message, Exception exception)
        {
        }

        public void WarnFormat(string format, params object[] args)
        {
        }

        public void WarnFormat(string format, object arg0)
        {
        }

        public void WarnFormat(string format, object arg0, object arg1)
        {
        }

        public void WarnFormat(string format, object arg0, object arg1, object arg2)
        {
        }

        public void WarnFormat(IFormatProvider provider, string format, params object[] args)
        {
        }

        public void Error(object message)
        {
        }

        public void Error(object message, Exception exception)
        {
        }

        public void ErrorFormat(string format, params object[] args)
        {
        }

        public void ErrorFormat(string format, object arg0)
        {
        }

        public void ErrorFormat(string format, object arg0, object arg1)
        {
        }

        public void ErrorFormat(string format, object arg0, object arg1, object arg2)
        {
        }

        public void ErrorFormat(IFormatProvider provider, string format, params object[] args)
        {
        }

        public void Fatal(object message)
        {
        }

        public void Fatal(string message, Exception exception)
        {
        }

        public void FatalFormat(string format, params object[] args)
        {
        }

        public void FatalFormat(string format, object arg0)
        {
        }

        public void FatalFormat(string format, object arg0, object arg1)
        {
        }

        public void FatalFormat(string format, object arg0, object arg1, object arg2)
        {
        }

        public void FatalFormat(IFormatProvider provider, string format, params object[] args)
        {
        }

        public string LogDirectory { get { return ""; } }
    }

    public class LogManager
    {
        internal static IContainer Builder { get; set; }

        internal static ConcurrentDictionary<string, ILog> Logs;

        static LogManager()
        {
            var container = AutofacConfigLoader.Load("core");
            if (container != null)
            {
                Builder = container.Build();
            }

            Logs = new ConcurrentDictionary<string, ILog>();
        }

        public static ILog GetLogger(string name)
        {
            ILog result;
            if (!Logs.TryGetValue(name, out result))
            {
                result = Logs.AddOrUpdate(name, Builder != null ? Builder.Resolve<ILog>(new TypedParameter(typeof(string), name)) : new NullLog(), (k, v) => v);
            }

            return result;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Core/HelpCenter/VideoGuideStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

using HtmlAgilityPack;

namespace ASC.Web.Studio.Core.HelpCenter
{
    [Serializable]
    [DataContract(Name = "VideoGuideItem", Namespace = "")]
    public class VideoGuideItem
    {
        [DataMember(Name = "Title")]
        public string Title;

        [DataMember(Name = "Id")]
        public string Id;

        [DataMember(Name = "Link")]
        public string Link;

        [DataMember(Name = "Status")]
        public string Status;
    }


    [Serializable]
    [DataContract(Name = "VideoGuideStorageItem", Namespace = "")]
    public class VideoGuideData : BaseHelpCenterData
    {
        [DataMember(Name = "ListItems")]
        public List<VideoGuideItem> ListItems { get; set; }

        public VideoGuideData()
        {
            ListItems = new List<VideoGuideItem>();
        }

        public override void Init(string html, string helpLinkBlock, string baseUrl)
        {
            if (string.IsNullOrEmpty(html)) return;

            var doc = new HtmlDocument();
            doc.LoadHtml(html);

            var titles = doc.DocumentNode.SelectNodes("//div[@id='totalVideoList']//div");

            if (titles == null || titles.Count(a => a.Attributes["id"] != null) != titles.Count() || !titles.Elements("a").Any()) return;

            var needTitles = titles.Where(x =>
                                            x.Attributes["data-status"] != null
                                            && (x.Attributes["data-status"].Value == "new" || x.Attributes["data-status"].Value == "default")).ToList();

            foreach (var needTitle in needTitles)
            {
                var title = needTitle.SelectSingleNode(".//span[@class='link_to_video']").InnerText;
                var id = needTitle.Attributes["id"].Value;
                var link = string.Format("{0}/{1}", helpLinkBlock.TrimEnd('/'), needTitle.Element("a").Attributes["href"].Value.TrimStart('/'));
                var status = needTitle.Attributes["data-status"].Value;

                ListItems.Add(new VideoGuideItem { Title = title, Id = id, Link = link, Status = status });
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/js/talk.meseditorcontainer.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC = window.ASC || {};

window.ASC.TMTalk = window.ASC.TMTalk || {};

window.ASC.TMTalk.meseditorContainer = (function ($) {

  var
    isInit = false,
    taWindow = null,
    taStylePath = '',
    taFocused = false,
    maRange = null,
    maRangeMark = null,
    maSelection = null,
    composingMessages = {},
    pausedMesssagesTimeout = 5,
    simpleEditor = false,
    timeIntervalSendButton = null,
    browser = (function () {
      var
        ua = navigator.userAgent,
        browser = null,
        version = (ua.match(/.+(?:rv|it|ra|ie|ox|me|on|id|os)[\/:\s]([\d._]+)/i)||[0,'0'])[1].replace('_', '');

      browser = {
        version : isFinite(parseFloat(version)) ? parseFloat(version) : version,
        // browsers
        msie    : '\v' == 'v' || /msie/i.test(ua),
        opera   : window.opera ? true : false,
        chrome  : window.chrome ? true : false,
        safari  : /safari/i.test(ua) && !window.chrome,
        firefox : /firefox/i.test(ua),
        mozilla : /mozilla/i.test(ua) && !/(compatible|webkit)/.test(ua),
        // engine
        ios     : /iphone|ipad/i.test(ua),
        android : /android/i.test(ua),
        gecko   : /gecko/i.test(ua),
        webkit  : /webkit/i.test(ua),

        // support
        touch   : 'ontouchend' in document
      };

      if (browser.msie && window.addEventListener && browser.version < 9) {
        browser.version = 9;
      }

      return browser;
    })();

  //simpleEditor = simpleEditor || browser.ios || browser.android;

  function trimS (str) {
    if (typeof str !== 'string' || str.length === 0) {
      return '';
    }
    return str.replace(/^\s+|\s+$/g, '');
  }

  function trimN (str) {
    if (typeof str !== 'string' || str.length === 0) {
      return '';
    }
    return str.replace(/^\n+|\n+$/g, '');
  }

  function trim (str) {
    if (typeof str != 'string' || str.length === 0) {
      return '';
    }
    return str.replace(/^[\n\s]+|[\n\s]+$/g, '');
  }

  function translateSymbols (str, toText) { 
      var symbols = [
          ['&lt;', '<'],
          ['&gt;', '>'],
          ['&and;', '\\^'],
          ['&sim;', '~'],
          ['&amp;', '&']
      ];

    if (typeof str !== 'string') {
      return '';
    }
    // replace control symbols to spaces
    str = str.replace(/[\0-\x08\x0E-\x1F]/g, ' ');
    // replace html to symbols
    if (typeof toText === 'undefined' || toText === true) {
      var symInd = symbols.length;
      while (symInd--) {
        str = str.replace(new RegExp(symbols[symInd][0], 'g'), symbols[symInd][1]);
      }
    // replace symbols to html
    } else {
      var symInd = symbols.length;
      while (symInd--) {
        str = str.replace(new RegExp(symbols[symInd][1], 'g'), symbols[symInd][0]);
      }
    }
    return str;
  }

  function isBlockNode (node) {
    if (!node || typeof node == 'undefined' || typeof node.nodeName == 'undefined') {
      return false;
    }
    switch (node.nodeName.toLowerCase()) {
      case 'p' :
      case 'h1' :
      case 'h2' :
      case 'h3' :
      case 'h4' :
      case 'h5' :
      case 'h6' :
      case 'ul' :
      case 'ol' :
      case 'li' :
      case 'tr' :
      case 'div' :
      case 'table' :
        return true;
      default :
        return false;
    }
    return false;
  }

  function isNonblockNode (node) {
    if (!node || typeof node == 'undefined' || typeof node.nodeName == 'undefined') {
      return false;
    }
    return !isBlockNode(node);
  }

  function getNodeContent (node) {
    var
      content = '',
      child = null,
      childrens = node.childNodes;

    for (var i = 0, n = childrens.length; i < n; i++) {
      child = childrens.item(i);
      switch (child.nodeType) {
        case 1 :
        case 5 :
          switch (child.nodeName.toLowerCase()) {
            case 'br' :
              if (child.getAttribute('type') !== 'moz_') {
                content += '\n';
              }
              break;
            case 'a' :
              var attr = child.getAttribute('href');
              if (attr) {
                content += attr;
              } else {
                var textContent = child.textContent;
                if (textContent) {
                  content += textContent;
                }
              }
              break;
            case 'img' :
              var attr = child.getAttribute('alt');
              if (attr) {
                content += attr;
              }
              break;
            case 'p' :
            case 'h1' :
            case 'h2' :
            case 'h3' :
            case 'h4' :
            case 'h5' :
            case 'h6' :
            case 'ul' :
            case 'ol' :
            case 'li' :
            case 'tr' :
            case 'div' :
            case 'table' :
              var childContent = trimN(arguments.callee(child));
              content += (i !== 0 ? '\n' : '') + childContent;
              break;
            case 'style':
              break;
            default :
              content += arguments.callee(child);
              break;
          }
          break;
        case 2 :
        case 3 :
        case 4 :
          content += child.nodeValue;
          break;
        default :
          break;
      }
    }
    return content;
  }

  function setSelected () {
    if (browser.msie && maRange && maRangeMark) {
      maRange.moveToBookmark(maRangeMark);
      maRange.select();
    }
  }

  function setFocusToTextarea (wnd) {
    window.focus();
    wnd.focus();
  }

  var insertNewLineToTextarea = (function () {
    if (simpleEditor === true) {
      return function (wnd, fin) {
        if (document.selection) {
          var s = document.selection.createRange(); 
          if (s.text) {
            s.text = '\n';
	          s.select();
          }
        } else if (typeof wnd.selectionStart === 'number') {
          var
            start = wnd.selectionStart,
            end = wnd.selectionEnd;

          wnd.value = wnd.value.substring(0, start) + '\n' + wnd.value.substring(end);
          wnd.setSelectionRange(start + 1, start + 1);
        }
      };
    }
    return function (wnd, fin) {
      if (browser.msie && browser.version < 9) {
        var range = wnd.document.selection.createRange();
        range.pasteHTML('&nbsp;<p></p>');
        range.collapse(true);
      } else {
        var el = wnd.document.createElement('br');
        var selectionRange = wnd.getSelection().getRangeAt(0);
        selectionRange.deleteContents();
        selectionRange.insertNode(el);

       
        if (!el.parentNode) {
            el = jQuery(jQuery('div#talkTextareaContainer ul.textareas li.textarea.current iframe:first')[0].contentDocument).find('br')[0];
        }
        if (el.parentNode.tagName.toLowerCase() === 'a') {
            el.parentNode.parentNode.insertBefore(el, el.parentNode.nextElementSibling);
        }

        wnd.getSelection().collapseToEnd();
        wnd.getSelection().removeAllRanges();

        selectionRange = wnd.document.createRange();
        selectionRange.selectNode(el);
        wnd.getSelection().addRange(selectionRange);
        wnd.getSelection().collapseToEnd();
          // hack for webkit
        if (browser.webkit && fin !== true && el.previousSibling && el.previousSibling.nodeType === 3 && (!el.nextSibling || !el.nextSibling.data)) {
            try { insertNewLineToTextarea(wnd, true) } catch (err) { }
        }
      }
      wnd.document.body.scrollTop = ASC.TMTalk.dom.maxScrollTop(wnd.document.body);
    };
  })();

  var insertSmileToTextarea = (function () {
    if (simpleEditor === true) {
      return function (wnd, src, title) {
        if (document.selection && maSelection !== null) {
          var s = maSelection;
          s.text = title;
          s.select();
        } else if (typeof wnd.selectionStart === 'number' && maSelection !== null) {
          var
            start = maSelection.start,
            end = maSelection.end;

          wnd.value = wnd.value.substring(0, start) + title + wnd.value.substring(end);
          wnd.setSelectionRange(start + title.length, start + title.length);
        }
      };
    }
    return function (wnd, src, title) {
      setSelected();
      setFocusToTextarea(wnd);
      var selectionRange = null;
      var el = null;

      if (browser.msie) {
        el = '<img src="' + src + '" alt="' + title + '" contentEditable="false" onResizeStart="return false">';
        selectionRange = wnd.document.selection.createRange();
        selectionRange.pasteHTML(el);
        selectionRange.collapse(true);
      } else {
        el = wnd.document.createElement('img');
        el.src = src;
        el.alt = title;

        selectionRange = wnd.getSelection().getRangeAt(0);
        selectionRange.deleteContents();
        selectionRange.insertNode(el);
        wnd.getSelection().collapseToEnd();
        wnd.getSelection().removeAllRanges();

        selectionRange = wnd.document.createRange();
        selectionRange.selectNode(el);
        wnd.getSelection().addRange(selectionRange);
        wnd.getSelection().collapseToEnd();
      }
    };
  })();

  var emptyTexrarea = (function () {
    if (simpleEditor === true) {
      return function (wnd) {
        return trim(wnd.value).length === 0;
      };
    }
    return function (wnd) {
      return trim(getNodeContent(wnd.document.body)).length === 0;
    };
  })();

  var clearTextarea = (function () {
    if (simpleEditor === true) {
      return function (wnd) {
        wnd.value = '';
      };
    }
    return function (wnd) {
      var o = wnd.document.body;
	    while (o.firstChild) {
	      o.removeChild(o.firstChild);
	    }

      if (!browser.msie) {
        var bogus = wnd.document.createElement('br');
        bogus.setAttribute('type', 'moz_');
        wnd.document.body.appendChild(bogus);

        var selectionRange = wnd.document.createRange();
        selectionRange.selectNode(bogus);
        if (wnd.getSelection().rangeCount > 0) wnd.getSelection().removeAllRanges();
        wnd.getSelection().addRange(selectionRange);
        wnd.getSelection().collapseToStart();
      }
    };
  })();

  var getTextareaContent = (function () {
    if (simpleEditor === true) {
      return function (wnd) {
        return wnd.value;
      };
    }
    return function (wnd) {
      return wnd.document.body.innerHTML.replace(/\s+/g, ' ');
    };
  })();

  var init = function (id, cssfile) {
    if (isInit === true) {
      return undefined;
    }
    isInit = true;
    // TODO
    taStylePath = cssfile;

    ASC.TMTalk.roomsManager.bind(ASC.TMTalk.roomsManager.events.createRoom, onCreateRoom);
    ASC.TMTalk.roomsManager.bind(ASC.TMTalk.roomsManager.events.openRoom, onOpenRoom);
    ASC.TMTalk.roomsManager.bind(ASC.TMTalk.roomsManager.events.closeRoom, onCloseRoom);

    ASC.TMTalk.messagesManager.bind(ASC.TMTalk.messagesManager.events.openHistory, onOpenHistory);
    ASC.TMTalk.messagesManager.bind(ASC.TMTalk.messagesManager.events.closeHistory, onCloseHistory);

    ASC.TMTalk.msManager.bind(ASC.TMTalk.msManager.events.addContact, onAddContact);
    ASC.TMTalk.msManager.bind(ASC.TMTalk.msManager.events.removeContact, onRemoveContact);

    ASC.TMTalk.connectionManager.bind(ASC.TMTalk.connectionManager.events.connected, onClientConnected);
    ASC.TMTalk.connectionManager.bind(ASC.TMTalk.connectionManager.events.disconnected, onClientDisconnected);
    ASC.TMTalk.connectionManager.bind(ASC.TMTalk.connectionManager.events.connectingFailed, onClientConnectingFailed);
  };

  var createTextarea = (function () {
    if (simpleEditor === true) {
      return function (iframe) {
        if (typeof iframe === 'string') {
          var
            textareasContainer = document.getElementById('talkTextareaContainer'),
            roomId = iframe,
            node = null,
            nodes = null,
            nodesInd = 0;

          nodes = ASC.TMTalk.dom.getElementsByClassName(textareasContainer, 'textarea', 'li');
          nodesInd = nodes.length;
          while (nodesInd--) {
            node = nodes[nodesInd];
            if (node.getAttribute('data-roomid') === roomId) {
              nodes = node.getElementsByTagName('iframe');
              if (nodes.length > 0) {
                iframe = nodes[0];
              }
              break;
            }
          }
        }

        if (!iframe) {
          return undefined;
        }

        var textarea = document.createElement('textarea');
        iframe.parentNode.insertBefore(textarea, iframe);
        iframe.parentNode.removeChild(iframe);

        jQuery(textarea)
          .keydown(function (evt) {
            if (evt.target.tagName.toLowerCase() === 'textarea') {
              evt.originalEvent.stopPropagation ? evt.originalEvent.stopPropagation() : evt.originalEvent.cancelBubble = true;
            }
          })
          .keyup(ASC.TMTalk.meseditorContainer.keyUp)
          .focusout(ASC.TMTalk.meseditorContainer.setRange)
          .keypress(ASC.TMTalk.meseditorContainer.keyPress);

        ASC.TMTalk.meseditorContainer.startIntrevalSendButton();
      };
    }
    return function (iframe) {
      if (typeof iframe === 'string') {
        var
          textareasContainer = document.getElementById('talkTextareaContainer'),
          roomId = iframe,
          node = null,
          nodes = null,
          nodesInd = 0;

        nodes = ASC.TMTalk.dom.getElementsByClassName(textareasContainer, 'textarea', 'li');
        nodesInd = nodes.length;
        while (nodesInd--) {
          node = nodes[nodesInd];
          if (node.getAttribute('data-roomid') === roomId) {
            nodes = node.getElementsByTagName('iframe');
            if (nodes.length > 0) {
              iframe = nodes[0];
            }
            break;
          }
        }
      }

      if (!iframe) {
        return undefined;
      }
      iframe.setAttribute('src', 'javascript:false;');

      var html = [
        '<html xmlns="http://www.w3.org/1999/xhtml">',
          '<head>',
            '<link rel="stylesheet" type="text/css" href="' + taStylePath + '" />',
          '</head>',
          '<body',
            ' contentEditable="true" id="editable"',
            jQuery.browser.mozilla ? '' : ' onkeyup="return parent.ASC.TMTalk.meseditorContainer.keyUp(event)"',
            jQuery.browser.mozilla ? '' : ' onkeypress="return parent.ASC.TMTalk.meseditorContainer.keyPress(event)"',
            jQuery.browser.mozilla ? '' : ' onblur="parent.ASC.TMTalk.meseditorContainer.blur(event); return parent.TMTalk.blur(event)"',
            jQuery.browser.mozilla ? '' : ' onfocus="parent.ASC.TMTalk.meseditorContainer.focus(event); return parent.TMTalk.focus(event)"',
            jQuery.browser.mozilla ? '' : ' onclick="return parent.ASC.TMTalk.meseditorContainer.onClick(event)"',
            jQuery.browser.mozilla ? '' : ' onscroll="return parent.ASC.TMTalk.meseditorContainer.onscroll(event)"',
            jQuery.browser.mozilla ? '' : ' onkeydown="return parent.ASC.TMTalk.meseditorContainer.keyDown(event)"',
          '></body>',
        '</html>'
      ].join('');

      iframe.contentWindow.document.open();
      iframe.contentWindow.document.write(html);
      iframe.contentWindow.document.close();

      if (jQuery.browser.mozilla) {
        iframe.contentWindow.document.designMode = 'on';

        jQuery(iframe.contentWindow.document)
          .keydown(ASC.TMTalk.meseditorContainer.keyDown)
          .keyup(ASC.TMTalk.meseditorContainer.keyUp)
          .keypress(ASC.TMTalk.meseditorContainer.keyPress)
          .blur(TMTalk.blur).focus(TMTalk.focus).click(parent.TMTalk.clickcallback);
      }
        
      ASC.TMTalk.meseditorContainer.startIntrevalSendButton();

      var
        o = null,
        wnd = iframe.contentWindow;
      o = wnd.document.body;
      while (o.firstChild) {
        o.removeChild(o.firstChild);
      }
      if (!jQuery.browser.msie) {
        var bogus = wnd.document.createElement('br');
        bogus.setAttribute('type', 'moz_');
        wnd.document.body.appendChild(bogus);
      }

      nodes = wnd.document.getElementsByTagName('html');
      if (nodes.length > 0) {
        nodes[0].setAttribute('dir', 'ltr');
      }

      //try { wnd.document.execCommand('undo', false, null); } catch (err) {}
      try { wnd.document.execCommand('useCSS', false, true); } catch (err) {}
      try { wnd.document.execCommand('styleWithCSS',false, true); } catch (err) {}
      try { wnd.document.execCommand('enableObjectResizing', false, false); } catch (err) {}
    };
  })();

  var blur = function (evt) {
    taFocused = false;
  };

  var onClick = function (evt) {
      var currentRoom = jQuery('div#talkRoomsContainer ul.rooms li.room.current');
      if ((currentRoom.hasClass('conference') || currentRoom.hasClass('mailing')) && !currentRoom.hasClass('minimized')) {
          ASC.TMTalk.roomsContainer.minimizingUserList();
      }
  };
  var focus = function (evt) {
    taFocused = true;
  };

  var insertSmile = function (src, title) {
    if (taWindow) {
        insertSmileToTextarea(taWindow, src, title);
        $('div#talkTextareaContainer ul.textareas li.textarea.current div.meseditorContainerPlaceholder').hide();
    }
  };

  var setRange = (function () {
    if (simpleEditor === true) {
      return function () {
        if (taWindow !== null) {
          if (browser.msie) {
            if (taFocused === true) {
              maRange = document.selection.createRange();
              maRangeMark = maRange.getBookmark();
            }
          }

          if (document.selection) {
            maSelection = document.selection.createRange();
          } else if (typeof taWindow.selectionStart === 'number') {
            maSelection = {start : taWindow.selectionStart, end : taWindow.selectionEnd};
          }
        }
      };
    }
    return function () {
      if (taWindow !== null) {
        if (browser.msie) {
          if (taFocused === true) {
            maRange = taWindow.document.selection.createRange();
            maRangeMark = maRange.getBookmark();
          }
        }
      }
    };
  })();

  var setCursor = (function () {
    /*if (browser.touch) {
      return function (wnd) {
      };
    }*/
    if (simpleEditor === true) {
      return function (wnd) {
        window.focus();
        wnd.focus();
        if (wnd.createTextRange) {
          var r = wnd.createTextRange();
          r.collapse(false);
          r.select();
        }
      };
    }
    return function (wnd)  {
      if (!wnd || typeof wnd !== 'object') {
        var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
        if (currentRoomData === null) {
          return undefined;
        }

        var
          textareasContainer = document.getElementById('talkTextareaContainer'),
          roomId = currentRoomData.roomId,
          wnd = null,
          node = null,
          nodes = null,
          nodesInd = 0;

        nodes = ASC.TMTalk.dom.getElementsByClassName(textareasContainer, 'textarea', 'li');
        nodesInd = nodes.length;
        while (nodesInd--) {
          node = nodes[nodesInd];
          if (node.getAttribute('data-roomid') === roomId) {
            nodes = node.getElementsByTagName('iframe');
            if (nodes.length > 0) {
              wnd = nodes[0].contentWindow;
            }
            break;
          }
        }
      }

      if (!wnd) {
        return undefined;
      }

      window.focus();
      wnd.focus();

      if (jQuery.browser.msie) {
        var range = wnd.document.body.createTextRange(), textnode = wnd.document.createElement('span');

        textnode.appendChild(wnd.document.createTextNode('text'));
        var lastelement = ASC.TMTalk.dom.lastElementChild(wnd.document.body);
        (lastelement ? lastelement : wnd.document.body).appendChild(textnode);
        range.moveToElementText(textnode);
        range.select();

        range.pasteHTML('');
        range.collapse(true);
      } else {
        var range = wnd.document.createRange(), textnode = wnd.document.createElement('span');

        textnode.appendChild(wnd.document.createTextNode(''));
        wnd.document.body.insertBefore(textnode, ASC.TMTalk.dom.lastElementChild(wnd.document.body));
        range.selectNode(textnode);
        if (wnd.getSelection().rangeCount > 0) wnd.getSelection().removeAllRanges();
        wnd.getSelection().addRange(range);
        wnd.getSelection().collapseToStart();
        wnd.document.body.removeChild(textnode);
      }
    };
  })();

  var pausedMessage = function (jid) {
    if (ASC.TMTalk.connectionManager.connected() && composingMessages.hasOwnProperty(jid)) {
      clearTimeout(composingMessages[jid].handlerTimeout);
      delete composingMessages[jid];
      ASC.TMTalk.connectionManager.pausedMessage(jid);
    }
  };

  var pausedMessageCallback = function (jid) {
    return function () {
      pausedMessage(jid);
    }
  };

  var startIntrevalSendButton = function () {
    var interval = 1000;
    clearInterval(ASC.TMTalk.meseditorContainer.timeIntervalSendButton);
    ASC.TMTalk.meseditorContainer.timeIntervalSendButton = setInterval(ASC.TMTalk.meseditorContainer.intrevalSendButton, interval);
  };

  var intrevalSendButton = function () {
    if (taWindow) {
      if (emptyTexrarea(taWindow)) {
        ASC.TMTalk.dom.addClass("talkMeseditorContainer", "empty");
      } else {
        ASC.TMTalk.dom.removeClass("talkMeseditorContainer", "empty");
      }
    }
  };
  var resizeMeseditorcontainer = function () {

      var $talkMeseditorContainer = $('#talkMeseditorContainer'),
          talkMeseditorContainerHeight = parseInt($talkMeseditorContainer.css('height')),
          $talkVertSlider = $('#talkVertSlider'),
          contentContainer = document.getElementById('talkContentContainer'),
          $contentContainer = $(contentContainer),
          talkRoomsContainer = document.getElementById('talkRoomsContainer'),
          $talkRoomsContainer = $(talkRoomsContainer),
          talkTextareaContainer = document.getElementById('talkTextareaContainer'),
          $talkTextareaContainer = $(talkTextareaContainer),
          $frame = $talkTextareaContainer.find('ul.textareas li.current iframe'),
          bodyFrameHeight = $frame.contents().children().children()[1].offsetHeight,
          frameHeight = $frame[0].scrollHeight,
          $currentRoom = $talkRoomsContainer.find('li.room.current'),
          subPanel = ASC.TMTalk.dom.getElementsByClassName($currentRoom[0], 'sub-panel', 'div'),
          newHeight,newRoomsContainerHeight;
      
      newHeight = talkMeseditorContainerHeight + bodyFrameHeight - frameHeight;
      newRoomsContainerHeight = $contentContainer[0].offsetHeight - newHeight;
      
      
      if ((taWindow.scrollY > 0) || ((bodyFrameHeight - frameHeight) > 0)) {
          
          if (newHeight * 3 > $contentContainer[0].offsetHeight) { // if more 33%
              newHeight = $contentContainer.offsetHeight / 3; 
              newRoomsContainerHeight = $contentContainer[0].offsetHeight - newHeight;
          }
          correctionMeseditorcontainer($talkMeseditorContainer, $talkVertSlider, $talkRoomsContainer, subPanel, newRoomsContainerHeight, newHeight);
      } else {
          if ($talkTextareaContainer[0].offsetHeight > bodyFrameHeight) {
              
              if (!ASC.TMTalk.properties.meseditorHeight || ASC.TMTalk.properties.meseditorHeight < bodyFrameHeight) {
                  newHeight = bodyFrameHeight;
                  $talkMeseditorContainer.css('height', bodyFrameHeight + 'px');
                  newRoomsContainerHeight = $contentContainer[0].offsetHeight - bodyFrameHeight;
              } else if (ASC.TMTalk.properties.meseditorHeight >= bodyFrameHeight) {
                  newHeight = ASC.TMTalk.properties.meseditorHeight;
                  $talkMeseditorContainer.css('height', ASC.TMTalk.properties.meseditorHeight + 'px');
                  newRoomsContainerHeight = $contentContainer[0].offsetHeight - ASC.TMTalk.properties.meseditorHeight;
              }
              correctionMeseditorcontainer($talkMeseditorContainer, $talkVertSlider, $talkRoomsContainer, subPanel, newRoomsContainerHeight, newHeight);
          }
      }
  };
  function correctionMeseditorcontainer($talkMeseditorContainer, $talkVertSlider, $talkRoomsContainer, subPanel, newRoomsContainerHeight, newHeight) {
      var correctionForChat = 32,
          correctionForConference = 90;
      
      $talkMeseditorContainer.css('height', newHeight + 'px');
      $talkVertSlider.css('bottom', newHeight + 'px');
      if ($talkRoomsContainer.hasClass('chat')) {
          $talkRoomsContainer.css('height', (newRoomsContainerHeight - correctionForChat) + 'px');
      } else {
          $talkRoomsContainer.css('height', newRoomsContainerHeight + 'px');
          if (subPanel.length > 0) {
              subPanel[0].style.height = Math.ceil(newRoomsContainerHeight / 2) - correctionForConference + 'px';
          }
      }
  };
  var keyUp = function (evt) {
        var o = document.createElement('div');
        o.innerHTML = getTextareaContent(taWindow);
        if (translateSymbols(trim(getNodeContent(o))).length <= 0) {
            $('div#talkTextareaContainer ul.textareas li.textarea.current div.meseditorContainerPlaceholder').show();
        } else {
            $('div#talkTextareaContainer ul.textareas li.textarea.current div.meseditorContainerPlaceholder').hide();
        }
        resizeMeseditorcontainer();
        TMTalk.keyup(evt);
      
        if (taWindow) {
            if (emptyTexrarea(taWindow)) {
            ASC.TMTalk.dom.addClass('talkMeseditorContainer', 'empty');
            } else {
            ASC.TMTalk.dom.removeClass('talkMeseditorContainer', 'empty');
            }
        }
  };
    
  function isVisible(t, w) {
      var wt = w.scrollTop();
      var tt = t.offset().top;
      var tb = tt + t.height();
      return ((tb <= wt + w.height()) && (tt >= wt));
  }
    
  var keyDown = function (evt) {
      resizeMeseditorcontainer();
      
      //pageUp, pageDown hack for chrome
      if (jQuery.browser.chrome && (evt.keyCode == 33 || evt.keyCode == 34)) {
          var iframe = jq('#talkMeseditorContainer iframe');
          var iframeHeight = iframe[1].offsetHeight;
          var _doc = iframe.contents()[1];
          var editableDiv = _doc.getElementById("editable");
          var $editableDiv = jq(editableDiv);
         
          switch (evt.keyCode) {
              case 33:
                  $editableDiv.scrollTop($editableDiv.scrollTop() - iframeHeight);
                  if (editableDiv.childNodes.length > 2) {
                      for (var i = 1; i < editableDiv.childNodes.length; i++) {
                          if (isVisible(jq(editableDiv.childNodes[i]), $editableDiv)) {
                              _doc.getSelection().setPosition(editableDiv.childNodes[i], 0);
                              break;
                          }
                      }
                  }
                  return false;
              case 34:
                  $editableDiv.scrollTop($editableDiv.scrollTop() + iframeHeight);
                  
                  if (editableDiv.childNodes.length > 2) {
                      for (var i = 1; i < editableDiv.childNodes.length; i++) {
                          
                          if (isVisible(jq(editableDiv.childNodes[i]), $editableDiv)) {
                              if (jq(editableDiv.childNodes[i]).offset().top > iframeHeight + jq(editableDiv).scrollTop()) {
                                  _doc.getSelection().setPosition(editableDiv.childNodes[i - 1], 0);
                                  break;
                              }
                          }
                      }
                  }
                  return false;
              default:
        }
      }
  };
  var onscroll = function (evt) {
      resizeMeseditorcontainer();
  };
  var keyPress = function (evt) {
    switch (evt.keyCode) {
      case 9 :
        if (evt.shiftKey) {
          ASC.TMTalk.tabsContainer.nextTab();
          return false;
        }
        break;
      case 10 :
      case 13 :
        // if send by ctrl + enter
        if (ASC.TMTalk.properties.item('sndbyctrlentr') === '1') {
          // if pressed ctrl + enter
          if (evt.ctrlKey) {
            sendMessage();
          // or \n
          } else {
            return undefined;
          }
        // if send by enter
        } else {
          // set \n
          if (evt.ctrlKey) {
            insertNewLineToTextarea(taWindow);
          // if press ctrl
          } else if (!evt.shiftKey) {
              sendMessage();
          } else {
              return undefined;
          }
        }
        // short variant
        // if (evt.ctrlKey === (+ASC.TMTalk.properties.item('sndbyctrlentr') === 1)) {
        //  sendMessage();
        //} else {
        //  echoNewLineToTextArea(maWindow);
        //}
        return false;
      default :
        var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
        if (currentRoomData !== null && currentRoomData.type === 'chat') {
          var jid = currentRoomData.id;
          if (ASC.TMTalk.connectionManager.connected()) {
            if (composingMessages.hasOwnProperty(jid)) {
              clearTimeout(composingMessages[jid].handlerTimeout);
              composingMessages[jid].handlerTimeout = setTimeout(pausedMessageCallback(jid), pausedMesssagesTimeout * 1000);
            } else {
              composingMessages[jid] = {
                jid             : jid,
                handlerTimeout  : null
              };
              ASC.TMTalk.connectionManager.composingMessage(jid);
              composingMessages[jid].handlerTimeout = setTimeout(pausedMessageCallback(jid), pausedMesssagesTimeout * 1000);
            }
          }
        }
        break;
    }
  };

  var showErrorMessage = function (cid, message) {
    var o = document.createElement('div');
    o.innerHTML = message.replace(/\n/g, '');
    ASC.TMTalk.messagesManager.sendMessageToChat(cid, translateSymbols(getNodeContent(o)), true);
  };

  var sendMessage = function (cid, type, message) {
    if (typeof cid === 'string') {
      switch (type.toLowerCase()) {
        case 'chat' :
          var o = document.createElement('div');
          o.innerHTML = message.replace(/\n/g, '');
          pausedMessage(cid);
          ASC.TMTalk.messagesManager.sendMessageToChat(cid, translateSymbols(trim(getNodeContent(o))));
          break;
        case 'mailing' :
          var o = document.createElement('div');
          o.innerHTML = message.replace(/\n/g, '');
          ASC.TMTalk.msManager.sendMessage(cid, translateSymbols(trim(getNodeContent(o))));
          break;
        case 'conference' :
          var o = document.createElement('div');
          o.innerHTML = message.replace(/\n/g, '');
          ASC.TMTalk.messagesManager.sendMessageToConference(cid, translateSymbols(trim(getNodeContent(o))));
          break;
      }
      return undefined;
    }

    if (taWindow) {
      var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
      if (currentRoomData !== null) {
        var contentContainer = document.getElementById('talkContentContainer');
        var $contentContainer = $(contentContainer);
        var newRoomsContainerHeight = 0;
        switch (currentRoomData.type) {
          case 'chat' :
            if (ASC.TMTalk.connectionManager.connected()) {
              var o = document.createElement('div');
              o.innerHTML = getTextareaContent(taWindow);
              pausedMessage(currentRoomData.id);
              ASC.TMTalk.messagesManager.sendMessageToChat(currentRoomData.id, translateSymbols(trim(getNodeContent(o))));

              clearTextarea(taWindow);
            }
            if (ASC.TMTalk.properties.meseditorHeight) {
                newRoomsContainerHeight = $contentContainer[0].offsetHeight - ASC.TMTalk.properties.meseditorHeight;
                $('#talkMeseditorContainer').css('height', ASC.TMTalk.properties.meseditorHeight + 'px');
                $('#talkVertSlider').css('bottom', ASC.TMTalk.properties.meseditorHeight + 'px');
                $('#talkRoomsContainer').css('height', newRoomsContainerHeight + 'px');
            } else {
                newRoomsContainerHeight = $contentContainer[0].offsetHeight - 82;
                $('#talkMeseditorContainer').css('height', 50 + 'px');
                $('#talkVertSlider').css('bottom', 50 + 'px');
                $('#talkRoomsContainer').css('height', newRoomsContainerHeight + 'px');
            }
            break;
          case 'mailing' :
            if (ASC.TMTalk.connectionManager.connected() && ASC.TMTalk.msManager.getContacts(currentRoomData.id).length > 0) {
              var o = document.createElement('div');
              o.innerHTML = getTextareaContent(taWindow);
              ASC.TMTalk.msManager.sendMessage(currentRoomData.id, translateSymbols(trim(getNodeContent(o))));

              clearTextarea(taWindow);
            }
            if (ASC.TMTalk.properties.meseditorHeight) {
                newRoomsContainerHeight = $contentContainer[0].offsetHeight - ASC.TMTalk.properties.meseditorHeight;
                $('#talkMeseditorContainer').css('height', ASC.TMTalk.properties.meseditorHeight + 'px');
                $('#talkVertSlider').css('bottom', ASC.TMTalk.properties.meseditorHeight + 'px');
                $('#talkRoomsContainer').css('height', newRoomsContainerHeight + 'px');
            } else {
                newRoomsContainerHeight = $contentContainer[0].offsetHeight - 50;
                $('#talkMeseditorContainer').css('height', 50 + 'px');
                $('#talkVertSlider').css('bottom', 50 + 'px');
                $('#talkRoomsContainer').css('height', newRoomsContainerHeight + 'px');
            }
            break;
          case 'conference' :
            if (ASC.TMTalk.connectionManager.connected()) {
              var o = document.createElement('div');
              o.innerHTML = getTextareaContent(taWindow);
              ASC.TMTalk.messagesManager.sendMessageToConference(currentRoomData.id, translateSymbols(trim(getNodeContent(o))));

              clearTextarea(taWindow);
            }
            if (ASC.TMTalk.properties.meseditorHeight) {
                newRoomsContainerHeight = $contentContainer[0].offsetHeight - ASC.TMTalk.properties.meseditorHeight;
                $('#talkMeseditorContainer').css('height', ASC.TMTalk.properties.meseditorHeight + 'px');
                $('#talkVertSlider').css('bottom', ASC.TMTalk.properties.meseditorHeight + 'px');
                $('#talkRoomsContainer').css('height', newRoomsContainerHeight + 'px');
            } else {
                newRoomsContainerHeight = $contentContainer[0].offsetHeight - 50;
                $('#talkMeseditorContainer').css('height', 50 + 'px');
                $('#talkVertSlider').css('bottom', 50 + 'px');
                $('#talkRoomsContainer').css('height', newRoomsContainerHeight + 'px');
            }
            break;
        }
      }
    }
   
      
  };

  var onClientConnected = function () {
    ASC.TMTalk.dom.addClass('talkMeseditorContainer', 'connected');
    if (ASC.TMTalk.roomsManager.getRoomData()) {
      TMTalk.disableFileUploader(false);
    }
  };

  var onClientDisconnected = function () {
    for (var fld in composingMessages) {
      if (composingMessages.hasOwnProperty(fld)) {
        delete composingMessages[fld];
      }
    }
    ASC.TMTalk.dom.removeClass('talkMeseditorContainer', 'connected');
    TMTalk.disableFileUploader(true);
  };

  var onClientConnectingFailed = function () {
    for (var fld in composingMessages) {
      if (composingMessages.hasOwnProperty(fld)) {
        delete composingMessages[fld];
      }
    }
    ASC.TMTalk.dom.removeClass('talkMeseditorContainer', 'connected');
    TMTalk.disableFileUploader(true);
  };

  var onAddContact = function (listId, contactjid) {
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (listId === currentRoomData.id) {
      ASC.TMTalk.dom.removeClass('talkMeseditorContainer', 'unavailable');
      TMTalk.disableFileUploader(false);
    }
  };

  var onRemoveContact = function (listId, contactjid) {
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (listId === currentRoomData.id) {
      if (ASC.TMTalk.msManager.getContacts(listId).length === 0) {
        ASC.TMTalk.dom.addClass('talkMeseditorContainer', 'unavailable');
        TMTalk.disableFileUploader(true);
      } else {
        ASC.TMTalk.dom.removeClass('talkMeseditorContainer', 'unavailable');
        TMTalk.disableFileUploader(false);
      }
    }
  };

  var onCreateRoom = function (roomId, data) {
    var
      textareasContainer = document.getElementById('talkTextareaContainer'),
      nodes = null,
      newTextarea = null,
      defaultTextarea = null;

    nodes = ASC.TMTalk.dom.getElementsByClassName(textareasContainer, 'textarea default', 'li');
    if (nodes.length > 0) {
      defaultTextarea = nodes[0];
    }

    if (!defaultTextarea) {
      throw 'no templates';
    }

    newTextarea = defaultTextarea.cloneNode(true);
    newTextarea.className = newTextarea.className.replace(/\s*default\s*/, ' ').replace(/^\s+|\s+$/g, '');

    newTextarea.setAttribute('data-roomid', roomId);

    switch (data.type) {
      case 'chat' :
        break;
      case 'conference' :
        newTextarea.className += ' conference';
        break;
      case 'mailing' :
        break;
    }

    nodes = ASC.TMTalk.dom.getElementsByClassName(textareasContainer, 'textareas', 'ul');
    if (nodes.length > 0) {
      nodes[0].appendChild(newTextarea);
    }

    nodes = newTextarea.getElementsByTagName('iframe');
    if (nodes.length > 0) {
      if ($.browser.mozilla && simpleEditor === false) {
        setTimeout((function (id) {
          return function () {
            ASC.TMTalk.meseditorContainer.createTextarea(id);
          };
        })(roomId), 100);
      } else {
        ASC.TMTalk.meseditorContainer.createTextarea(nodes[0]);
      }
    }
  };

  var onOpenRoom = function (roomId, data, inBackground) {
    var
      textareasContainer = document.getElementById('talkTextareaContainer'),
      currentTextarea = null,
      node = null,
      nodes = null,
      nodesInd = 0;
    nodes = ASC.TMTalk.dom.getElementsByClassName(textareasContainer, 'textarea', 'li');
    nodesInd = nodes.length;
    while (nodesInd--) {
      node = nodes[nodesInd];
      if (node.getAttribute('data-roomid') === roomId) {
        currentTextarea = node;
        if (inBackground !== true) {
          ASC.TMTalk.dom.addClass(node, 'current');
        }
      } else {
        if (inBackground !== true) {
          ASC.TMTalk.dom.removeClass(node, 'current');
        }
      }
    }

    var meseditorContainer = document.getElementById('talkMeseditorContainer');
    ASC.TMTalk.dom.removeClass(meseditorContainer, 'disabled');
    TMTalk.disableFileUploader(false);

    if (inBackground !== true) {
      taWindow = null;
      if (currentTextarea !== null) {
        nodes = currentTextarea.getElementsByTagName('textarea');
        if (nodes.length > 0) {
          taWindow = nodes[0];
        }
        if (taWindow === null) {
          nodes = currentTextarea.getElementsByTagName('iframe');
          if (nodes.length > 0) {
            taWindow = nodes[0].contentWindow;
          }
        }
        if (!taWindow) {
          throw 'can\'t get textarea';
        }
        // my street magic. HOLY FUCKING SHIT FUCKS IE9.
        if (nodes.length > 0) {
          nodes[0].style.position = 'relative';
          nodes[0].style.position = 'absolute';
        }
      }

      switch (data.type) {
        case 'chat' :
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'conference');
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'mailing');
          ASC.TMTalk.dom.addClass(meseditorContainer, 'chat');

          ASC.TMTalk.dom.removeClass(meseditorContainer, 'unavailable');
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'owner');
          TMTalk.disableFileUploader(false);       
          break;
        case 'mailing' :
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'chat');
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'conference');
          ASC.TMTalk.dom.addClass(meseditorContainer, 'mailing');

          ASC.TMTalk.dom.removeClass(meseditorContainer, 'owner');
          if (ASC.TMTalk.msManager.getContacts(data.id).length === 0) {
            ASC.TMTalk.dom.addClass(meseditorContainer, 'unavailable');
            TMTalk.disableFileUploader(true);
          } else {
            ASC.TMTalk.dom.removeClass(meseditorContainer, 'unavailable');
            TMTalk.disableFileUploader(false);
          }
          break;
        case 'conference' :
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'chat');
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'mailing');
          ASC.TMTalk.dom.addClass(meseditorContainer, 'conference');

          if (data.affiliation === 'owner') {
            ASC.TMTalk.dom.addClass(meseditorContainer, 'owner');
          } else {
            ASC.TMTalk.dom.removeClass(meseditorContainer, 'owner');
          }
          ASC.TMTalk.dom.removeClass(meseditorContainer, 'unavailable');

          TMTalk.disableFileUploader(false);
          break;
      }
      if (emptyTexrarea(taWindow)) {
        ASC.TMTalk.dom.addClass(meseditorContainer, 'empty');
      } else {
        ASC.TMTalk.dom.removeClass(meseditorContainer, 'empty');
      }
      ASC.TMTalk.dom.removeClass(meseditorContainer, 'history');
      if (TMTalk.properties.focused) {
        if ($.browser.mozilla && simpleEditor === false) {
          setTimeout(ASC.TMTalk.meseditorContainer.setCursor, 100);
        } else {
          ASC.TMTalk.meseditorContainer.setCursor(taWindow);
        }
      }
    }
    $('div#talkRoomsContainer ul.rooms li.room.current div.filtering-panel:first').on('transitionend', function () {
        var $filteringPanel = $(this),
            $input = $(this).find('div.filtering-container div.textfield input');
        
        if ($filteringPanel.hasClass('show')) {
            $input.focus();
        } else {
            $filteringPanel.addClass('close');
        }
    });
  };

  var onCloseRoom = function (roomId, data) {
    var
      textareasContainer = document.getElementById('talkTextareaContainer'),
      isCurrent = false,
      nodes = null,
      nodesInd = 0;
    nodes = ASC.TMTalk.dom.getElementsByClassName(textareasContainer, 'textarea', 'li');
    nodesInd = nodes.length;
    while (nodesInd--) {
      if (nodes[nodesInd].getAttribute('data-roomid') === roomId) {
        isCurrent = ASC.TMTalk.dom.hasClass(nodes[nodesInd], 'current');
        nodes[nodesInd].parentNode.removeChild(nodes[nodesInd]);
        break;
      }
    }

    if (isCurrent === true) {
      var meseditorContainer = document.getElementById('talkMeseditorContainer');
      ASC.TMTalk.dom.addClass(meseditorContainer, 'disabled');
      TMTalk.disableFileUploader(true);

      ASC.TMTalk.dom.removeClass(meseditorContainer, 'chat');
      ASC.TMTalk.dom.removeClass(meseditorContainer, 'mailing');
      ASC.TMTalk.dom.removeClass(meseditorContainer, 'conference');

      ASC.TMTalk.dom.removeClass(meseditorContainer, 'owner');
      ASC.TMTalk.dom.removeClass(meseditorContainer, 'history');
      ASC.TMTalk.dom.removeClass(meseditorContainer, 'unavailable');

      //TMTalk.disableFileUploader(false);

      taWindow = null;
    }
  };

  var onOpenHistory = function (jid) {
      //jq("div.cha").removeClass('hidden').addClass('visible');
      jq.each(jq("select.historyPeriod"), function (index, item) {
          jq(item).tlCombobox();
      });
      
      
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (currentRoomData.type === 'chat' && currentRoomData.id === jid) {
        ASC.TMTalk.dom.addClass('talkMeseditorContainer', 'history');
        window.focus();
        
    }
  };

  var onCloseHistory = function (jid) {
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (currentRoomData.type === 'chat' && currentRoomData.id === jid) {
      ASC.TMTalk.dom.removeClass('talkMeseditorContainer', 'history');
      if ($.browser.mozilla && simpleEditor === false) {
        setTimeout(ASC.TMTalk.meseditorContainer.setCursor, 100);
      } else {
        ASC.TMTalk.meseditorContainer.setCursor(taWindow);
      }
      //jq("div.cha").removeClass('visible').addClass('hidden');
    }
  };

  var onSendFileStart = function () {
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (currentRoomData !== null) {
      jQuery('#talkMeseditorToolbarContainer div.button-container.send-file').addClass('sending');
      ASC.TMTalk.properties.item('dstcontact', {cid : currentRoomData.id, type : currentRoomData.type});
    }
  }

  var onSendFileComplete = function (response) {
    jQuery('#talkMeseditorToolbarContainer div.button-container.send-file').removeClass('sending');
    if (response.Success === true) {
      var link = response.FileURL.substring(0, response.FileURL.lastIndexOf('/')) + '/' + encodeURIComponent(response.FileName);
      var dstcontact = ASC.TMTalk.properties.item('dstcontact');
      if (dstcontact && typeof dstcontact === 'object') {
          ASC.TMTalk.meseditorContainer.sendMessage(dstcontact.cid, dstcontact.type, ASC.TMTalk.stringFormat(jq.format(ASC.TMTalk.TalkResource.SendFileMessage, "{0}<br/>", "{1}"), link, response.Data));
        ASC.TMTalk.properties.item('dstcontact', null);
      }
    } else {
        ASC.TMTalk.meseditorContainer.onSendFileError(response.Message);
    }
  }

  var onSendFileError = function (message) {
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (currentRoomData !== null) {
      ASC.TMTalk.properties.item('dstcontact', {cid : currentRoomData.id, type : currentRoomData.type});
    }
    var dstcontact = ASC.TMTalk.properties.item('dstcontact');
    if (dstcontact && typeof dstcontact === 'object') {
      ASC.TMTalk.meseditorContainer.showErrorMessage(dstcontact.cid, message);
    }
  };
  var openCreatingConferenceDialog = function() {
      jq("#chatOrSpam").tlCombobox();
      TMTalk.showDialog('create-room', null, { roomname: '', temproomchecked: true });
  };
    
  var openClearFilesDialog = function () {
      JabberClient.GetSpaceUsage(function (response) {
          if (response && response.value) {
              jq(".delete-files b").text(response.value);
              jq("#pop").hide();
              TMTalk.showDialog("delete-files", null, { roomname: '', temproomchecked: true });
          }
      });
  };

  var searchMessages = function() {
      jq.each(jq("select.historyPeriod"), function(index, item) {
          jq(item).tlCombobox();
      });
      var currentRoomData = ASC.TMTalk.roomsManager.getRoomData(),
          roomlistContainer = document.getElementById('talkRoomsContainer'),
          jid = currentRoomData.id,
          nodes = null,
          room = null,
          messagescontainer = null,
          searchinput = null,
          nodesInd = 0;
    
      if (currentRoomData.type === 'chat') {
        nodes = ASC.TMTalk.dom.getElementsByClassName(roomlistContainer, 'room', 'li');
          nodesInd = nodes.length;
          while (nodesInd--) {
              if (nodes[nodesInd].getAttribute('data-roomcid') === jid) {
                  room = nodes[nodesInd];
                  break;
              }
          }
          if (room !== null) {
              nodes = ASC.TMTalk.dom.getElementsByClassName(room, 'messages', 'ul');
              if (nodes.length > 0) {
                  messagescontainer = nodes[0];
              }
          }
          if (messagescontainer !== null) {
              ASC.TMTalk.roomsContainer.resetHistorySearch(room, ASC.TMTalk.dom.getElementsByClassName(messagescontainer, 'message', 'li'));
          }
          ASC.TMTalk.dom.toggleClass('talkRoomsContainer', 'searchmessage');
          if (room !== null) {
              nodes = ASC.TMTalk.dom.getElementsByClassName(room, 'search-value', 'input');
              if (nodes.length > 0) {
                  searchinput = nodes[0];
              }
              $(searchinput).focus();
          }
      }
  };

  return {
    init  : init,

    createTextarea  : createTextarea,
    insertSmile     : insertSmile,
    setCursor       : setCursor,
    setRange        : setRange,

    startIntrevalSendButton: startIntrevalSendButton,
    intrevalSendButton: intrevalSendButton,
    keyPress  : keyPress,
    keyUp: keyUp,
    keyDown: keyDown,
    focus     : focus,
    blur    : blur,
    onscroll: onscroll,
    onClick: onClick,

    sendMessage : sendMessage,
    showErrorMessage: showErrorMessage,

    onSendFileStart     : onSendFileStart,
    onSendFileComplete  : onSendFileComplete,
    onSendFileError: onSendFileError,
    
    openCreatingConferenceDialog: openCreatingConferenceDialog,
    openClearFilesDialog: openClearFilesDialog,
    searchMessages: searchMessages
  };
})(jQuery);

(function ($) {
  $(function () {
    if ($.browser.safari) {
      $('#talkMeseditorToolbarContainer div.toolbar:first div.button-container').not('.send-file').not('.emotions').mousedown(function () {
        if (window.getSelection) {
          window.getSelection().removeAllRanges();
        }
        return false;
      });

      $('#talkSendMenu').mousedown(function () {
        if (window.getSelection) {
          window.getSelection().removeAllRanges();
        }
        return false;
      });
    }

    $(document).mousedown(!$.browser.msie ? null : function () {
      ASC.TMTalk.meseditorContainer.setRange();
    });

    if (ASC.TMTalk.properties.item('sndbyctrlentr') === undefined) {
      ASC.TMTalk.properties.item('sndbyctrlentr', '1', true);
    }

    if (ASC.TMTalk.properties.item('sndbyctrlentr') === '0') {
        $('#talkMeseditorToolbarContainer div.button-container.toggle-sendbutton:first').removeClass('send-by-ctrlenter');
        $('#button-send-ctrl-enter').removeClass('on').addClass('off');
    } else {
        $('#talkMeseditorToolbarContainer div.button-container.toggle-sendbutton:first').addClass('send-by-ctrlenter');
        $('#button-send-ctrl-enter').removeClass('off').addClass('on');
    }

    if ($.support.touch) {
      $('#talkMeseditorToolbarContainer div.button-container.send-file:first').addClass('not-available');
    }

    TMTalk.createFileUploader();

    $('#talkMeseditorToolbarContainer div.button-talk.create-massend:first').click(function() {
      TMTalk.showDialog('create-mailing', null, {mailingname : ''});
    });

   // $('#talkMeseditorToolbarContainer div.button-talk.create-conference:first').click(function() {
   //   TMTalk.showDialog('create-room', null, {roomname : '', temproomchecked : true});
   // });
    
    
    
    $('#talkMeseditorToolbarContainer div.button-talk.emotions:first').click(function () {
      var $container = null;
      if(($container = $('#talkMeseditorToolbarContainer div.button-container.emotions:first div.container:first')).is(':hidden')) {
        $container.show('fast', function () {
          if ($.browser.msie) {
            window.focus();
          }
          $(document).one('click', function () {
            $('#talkMeseditorToolbarContainer div.button-container.emotions:first div.container:first').hide();
          });
        });
      }
    });

    $('#talkMeseditorToolbarContainer ul.smiles:first').click(function (evt) {
      var $target = $(evt.target);
      if ($target.hasClass('smile')) {
        var
          title = $target.attr('title'),
          smilesrc = $target.css('backgroundImage');
        title = typeof title === 'string' ? title : '';
        smilesrc = typeof smilesrc === 'string' ? smilesrc.replace(/^url|[\("'\)]+/g, '') : null;
        if (smilesrc) {
          ASC.TMTalk.meseditorContainer.insertSmile(smilesrc, title);
        }
      }
    });

    $('#talkMeseditorToolbarContainer div.button-talk.history:first').click(function() {
        var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
        
      if (currentRoomData !== null && currentRoomData.type === 'chat') {
        var jid = currentRoomData.id;
        if (jid) {
           // jq("#cha").tlCombobox();
            ASC.TMTalk.messagesManager.openHistory(jid);
   
            //jq("#cha").tlCombobox();
            
        }
      }
    });

    $('#talkMeseditorToolbarContainer div.button-talk.toggle-sendbutton:first').click(function() {
      ASC.TMTalk.properties.item('sndbyctrlentr', $('#talkMeseditorToolbarContainer div.button-container.toggle-sendbutton:first').toggleClass('send-by-ctrlenter').hasClass('send-by-ctrlenter') ? '1' : '0', true);
    });

    $('#talkSendMenu div.button-talk.send-message:first').click(function() {
        ASC.TMTalk.meseditorContainer.sendMessage();
        var currentRoom = jQuery('div#talkRoomsContainer ul.rooms li.room.current');
        if ((currentRoom.hasClass('conference') || currentRoom.hasClass('mailing')) && !currentRoom.hasClass('minimized')) {
            ASC.TMTalk.roomsContainer.minimizingUserList();
        }
        ASC.TMTalk.meseditorContainer.setCursor();
    });

    $('#talkDialogsContainer').click(function (evt) {
        var $target = $(evt.target);
        if ($target.hasClass('button-talk') && $target.hasClass('create-room')) {
            
            var roomname = ASC.TMTalk.trim($('#txtRoomName').val());
            var type = $('#chatOrSpam:first')[0].options.selectedIndex;
            if (type == 0)
            {
                if (roomname && ASC.TMTalk.mucManager.isValidName(roomname)) {
                    ASC.TMTalk.mucManager.createRoom(roomname, $('#cbxTemporaryRoom').is(':checked'));
                    TMTalk.hideDialog();
                } else {
                    //$('#txtRoomName').parents('div.textfield:first').addClass('invalid-input');
                    $('#txtRoomName').addClass('invalid-input');
                }

            }
            else if (type == 1) {
                var mailingname = roomname;
                if (mailingname && ASC.TMTalk.msManager.isValidName(mailingname)) {
                    ASC.TMTalk.msManager.createList(mailingname);
                    TMTalk.hideDialog();
                } else {
                    // $('#txtRoomName').parents('div.textfield:first').addClass('invalid-field');
                    $('#txtRoomName').addClass('invalid-input');
                }

           }                         
        } else if ($target.hasClass('option-item')) {
            if ($target[0].getAttribute('data-value') && $target[0].getAttribute('data-value') === 'Spam message') {

                $('div.popupContainerClass.dialog.create-room input#cbxTemporaryRoom').parents('table:first').hide();
            } else {
                $('div.popupContainerClass.dialog.create-room input#cbxTemporaryRoom').parents('table:first').show();
            }
            
        } else if ($target.hasClass('delete-files-btn')) {
            JabberClient.ClearSpaceUsage($('input[name=clearType]:checked').val(), function(response) {
                PopupKeyUpActionProvider.CloseDialog();
                if (response && response.value) {
                    $('#pop').addClass('has-files');
                } else {
                    $('#pop').removeClass('has-files');
                }
            });
        }
    });
  });
})(jQuery);


<|start_filename|>web/studio/ASC.Web.Studio/js/asc/plugins/jquery-advansedfilter.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function ($, win, doc, body) {
    var
      defaultAnykeyTimeout = 500,
      currentHash = '',
      cmplClassName = 'advansed-filter-complete',
      templates = {
          filterContainer: 'template-filter-container',
          filterItem: 'template-filter-item'
      },
      isFirstUpdateLocaleStorage = true,
      lazyTrigger = false,
      filterContainer = null,
      filterInputKeyupHandler = 0,
      filterInputKeyupObject = null,
      filterInputKeyupTimeout = 0,
      Resources = {},
      filterValues = [
        { type: 'sorter', id: 'sorter', hashmask: 'sorter/{0}' },
        { type: 'text', id: 'text', hashmask: 'text/{0}' }
      ],
      sorterValues = [];

    var
      path = '/',
      parts = location.pathname.split('/');
    parts.splice(parts.length - 1, 1);
    path = parts.join('/');

    function isArray(o) {
        return o ? o.constructor.toString().indexOf("Array") != -1 : false;
    }

    function converText(str, toText) {
        str = typeof str === 'string' ? str : '';
        if (!str) {
            return '';
        }

        if (toText === true) {
            var
              symbols = [
                ['&lt;', '<'],
                ['&gt;', '>'],
                ['&and;', '\\^'],
                ['&sim;', '~'],
                ['&amp;', '&']
              ];

            var symInd = symbols.length;
            while (symInd--) {
                str = str.replace(new RegExp(symbols[symInd][1], 'g'), symbols[symInd][0]);
            }
            return str;
        }

        var o = document.createElement('textarea');
        o.innerHTML = str;
        return o.value;
    }

    function format() {
        if (arguments.length === 0) {
            return '';
        }

        var pos = -1, str = arguments[0] || '', cnd = '', ind = -1, cnds = str.match(/{(\d+)}/g), cndsInd = cnds ? cnds.length : 0;
        while (cndsInd--) {
            pos = -1;
            cnd = cnds[cndsInd];
            ind = cnd.replace(/[{}]+/g, '');
            while ((pos = str.indexOf(cnd, pos + 1)) !== -1) {
                str = str.substring(0, pos) + (arguments[+ind + 1] || '') + str.substring(pos + cnd.length);
            }
        }
        return str;
    };

    function getFiltersHash(filtervalues) {
        var
          hash = [],
          filtervalue = null,
          filtervaluehash = '';

        for (var i = 0, n = filtervalues ? filtervalues.length : 0; i < n; i++) {
            filtervalue = filtervalues[i];
            
            if (!filtervalue.params) continue;

            switch (filtervalue.type) {
                case 'sorter':
                    filtervaluehash = {
                        id: filtervalue.id,
                        type: filtervalue.type,
                        params: {
                            id: filtervalue.params.id,
                            def: filtervalue.params.def,
                            dsc: filtervalue.params.dsc,
                            sortOrder: filtervalue.params.sortOrder
                        }
                    };
                    break;
                case 'daterange':
                    filtervaluehash = {
                        id: filtervalue.id,
                        type: filtervalue.type,
                        params: {
                            from: Teamlab.serializeTimestamp(new Date(filtervalue.params.from)),
                            to: Teamlab.serializeTimestamp(new Date(filtervalue.params.to))
                        }
                    };
                    break;
                default:
                    filtervaluehash = {
                        id: filtervalue.id,
                        type: filtervalue.type,
                        params: filtervalue.params
                    };
                    break;
            }

            filtervaluehash.params = $.base64.encode($.toJSON(filtervaluehash.params));
            hash.push($.toJSON(filtervaluehash));
        }

        return $.base64.encode(hash.join(';'));
    }

    function getkey() {
        var key = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '') + location.pathname + location.search;
        return encodeURIComponent(key.charAt(key.length - 1) === '/' ? key + 'Default.aspx' : key);
    }

    function toggleHasFilters(selectedfilters, $container) {
        if (selectedfilters.some(function (item) { return item.type != "sorter";})) {
            $container.addClass('has-filters');
        } else {
            $container.removeClass('has-filters');
        }
    }

    function updateLocalStorageFilters(opts, filtervalues) {
        if (isFirstUpdateLocaleStorage === true && (filtervalues.length === 0 || (filtervalues.length === 1 && filtervalues[0].id === 'sorter'))) {
            isFirstUpdateLocaleStorage = false;
            return undefined;
        }

        opts = opts && typeof opts === 'object' ? opts : {};
        isFirstUpdateLocaleStorage = false;

        var newhash = getFiltersHash(filtervalues);
        //currentHash = newhash;

        if (opts.inhash === true) {
            try { ASC.Controls.AnchorController.safemove(newhash) } catch (err) { }
        }

        // quota exceeded error workaround
        var key = getkey();
        localStorageManager.setItem(key, newhash);
    }

    function getLocalStorageFilters(opts) {
        var values = null;
        
        var key = getkey();
        if (localStorageManager.getItem(key)) {
            values = $.base64.decode(localStorageManager.getItem(key));
        }
        if (opts && typeof opts === 'object' && opts.inhash === true) {
            currentHash = location.hash;
            currentHash = currentHash && typeof currentHash === 'string' && currentHash.charAt(0) === '#' ? currentHash.substring(1) : currentHash;
            if (currentHash.length === 0) {
                currentHash = $.cookies.get(key);
                currentHash = decodeURIComponent(currentHash);
                currentHash = currentHash && typeof currentHash === 'string' && currentHash.charAt(0) === '#' ? currentHash.substring(1) : currentHash;
            }
            values = $.base64.decode(currentHash);
            if (currentHash && currentHash !== 'null') {
                try { ASC.Controls.AnchorController.safemove(currentHash) } catch (err) { }
                $.cookies.set(key, currentHash, { path: path });
            }
        }

        var
          params = null,
          filtervalue = null,
          filtervalues = [];

        values = typeof values === 'string' && values.length > 0 ? values.split(';') : [];
        for (var i = 0, n = values.length; i < n; i++) {
            try {
                filtervalue = $.parseJSON(values[i]);
                filtervalue.params = $.parseJSON($.base64.decode(filtervalue.params));
            } catch (err) {
                filtervalue = null;
            }
            if (filtervalue) {
                switch (filtervalue.type) {
                    case 'sorter':
                        filtervalues.push({ id: filtervalue.id, selected: true, params: filtervalue.params });
                        break;
                    case 'daterange':
                        filtervalues.push({ id: filtervalue.id, params: { from: Teamlab.serializeDate(filtervalue.params.from), to: Teamlab.serializeDate(filtervalue.params.to) } });
                        break;
                    default:
                        filtervalues.push({ id: filtervalue.id, params: filtervalue.params });
                        break;
                }
            }
        }

        return filtervalues || [];
    }

    function getContainerHash($container) {
        return getFiltersHash($container.data('filtervalues') || []);
    }

    function getStorageHash($container) {
        var key = getkey();
        return localStorageManager.getItem(key) || getContainerHash($container);
    }

    function getContainerFilters($container) {
        return $container.data('filtervalues') || [];
    }

    function getFilterValue(filtervalues, type) {
        var filtervaluesInd = filtervalues.length;
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].type === type) {
                return filtervalues[filtervaluesInd];
            }
        }
        return null;
    }

    function extendItemValue(dst, src) {
        for (var srcInd in src) {
            if (src.hasOwnProperty(srcInd) && !dst.hasOwnProperty(srcInd)) {
                dst[srcInd] = src[srcInd];
            }
        }
    }

    function extendItemValues(dst, src) {
        var
          rslt = [],
          dstInd = 0, srcInd = 0;

        dstInd = dst.length;
        while (dstInd--) {
            srcInd = src.length;
            while (srcInd--) {
                if (dst[dstInd] && src[srcInd] && dst[dstInd].id === src[srcInd].id) {
                    extendItemValue(dst[dstInd], src[srcInd]);
                    break;
                }
            }
            rslt.unshift(dst[dstInd]);
        }

        srcInd = src.length;
        while (srcInd--) {
            dstInd = dst.length;
            while (dstInd--) {
                if (src[srcInd].id === dst[dstInd].id) {
                    break;
                }
            }
            rslt.unshift(src[srcInd]);
        }

        return rslt;
    }

    function getGroupSelectorName($container, id) {
        var
          groups = $container.find(".filter-item.filter-item-group > .selector-wrapper:first").data('items'),
          groupsInd = 0;
        groups = groups ? groups : [];
        groupsInd = groups.length;

        while (groupsInd--) {
            if (groups[groupsInd].id == id) {
                return groups[groupsInd].title;
            }
        }
        return id;
    }

    function getUserSelectorName($container, id, name) {
        var
          users = $container.find(".filter-item.filter-item-person > .selector-wrapper:first").data('items'),
          usersInd = 0;

        users = users ? users : [];
        usersInd = users.length;

        while (usersInd--) {
            if (users[usersInd].id == id) {
                return users[usersInd].title;
            }
        }

        return typeof name === 'string' && name ? name : id;
    }

    function addFilterToGroup(groups, filtervalue) {
        if (!filtervalue.title) {
            return undefined;
        }

        var groupsInd = 0;
        groupsInd = groups ? groups.length : 0;
        while (groupsInd--) {
            if (filtervalue.groupid) {
                if (groups[groupsInd].id === filtervalue.groupid) {
                    groups[groupsInd].items.push(filtervalue);
                    break;
                } else {
                    continue;
                }
            }

            if (groups[groupsInd].title === filtervalue.group) {
                groups[groupsInd].items.push(filtervalue);
                break;
            }
        }
        if (groupsInd === -1) {
            groups.push({ title: filtervalue.group || '', items: [filtervalue], id: filtervalue.groupid || '' });
        }
    }

    function createDatepicker($o, $container, $filteritem, filtervalue, defaultDate) {
        var $datepicker =
          $o
          .datepicker({
              onSelect: (function ($container, $filteritem, filtervalue, callback) {
                  return function (datetext, inst) {
                      callback(this, $container, $filteritem, filtervalue, datetext, inst);
                  }
              })($container, $filteritem, filtervalue, onUserFilterDateSelectValue)
          })
          .click(function (evt) {
              evt.stopPropagation();
          });

        $datepicker.datepicker('setDate', defaultDate);
        return $datepicker;
    }

    function createComboboxOptions(options) {
        var option = null, html = [];

        for (var i = 0, n = options.length; i < n; i++) {
            option = options[i];
            html = html.concat(['<option', ' class="' + option.classname + '"' + ' value="' + option.value + '"', option.def === true ? ' selected="selected"' : '', '>', converText(option.title, true), '</option>']);
        }

        return html.join('');
    }

    function createFilterItem(filtervalue) {
        var
          html = [],
          o = null, $o = null;

        $o = jQuery.tmpl(templates.filterItem, filtervalue);
        return $o;
    }

    function createAdvansedFilterGroup(opts, itemgroups, type) {
        var
          colcount = 1,
          html = [],
          items = null,
          itemvalues = null,
          title = '',
          itemgroupsInd = 0, itemgroupsLen = 0,
          itemvaluesInd = 0, itemvaluesLen = 0;

        colcount = opts && typeof opts === 'object' && opts.hasOwnProperty('colcount') && isFinite(+opts.colcount) ? +opts.colcount : colcount;
        for (itemgroupsInd = 0, itemgroupsLen = itemgroups.length; itemgroupsInd < itemgroupsLen; itemgroupsInd++) {
            if (type === 'filter' && colcount >= 1) {
                if (itemgroupsInd < colcount) {
                    html.push('<li class="item-group-col"><ul class="group-items">');
                    for (var i = itemgroupsInd; i < itemgroupsLen; i += colcount) {
                        itemvalues = itemgroups[i].items;
                        items = [];
                        for (itemvaluesInd = 0, itemvaluesLen = itemvalues.length; itemvaluesInd < itemvaluesLen; itemvaluesInd++) {
                            items.push(createAdvansedFilterItem(itemvalues[itemvaluesInd], type));
                        }
                        title = converText(itemgroups[i].title, true);

                        html = html.concat([
                          '<li',
                            ' class="item-group ' + type + '-group',
                              //itemgroups[i].title ? '' : ' none-title',
                            '"',
                          '>',
                            '<span class="title" title="' + title + '">',
                              title,
                            '</span>',
                            '<ul class="filter-items">',
                              items.join(''),
                            '</ul>',
                          '</li>'
                        ]);
                    }
                    html.push('</ul><div class="clear"></div></li>');
                }
                //html = html.concat([
                //  '<li',
                //    ' class="item-group ' + type + '-group',
                //      //itemgroupsInd === 0 ? ' first-group' : '',
                //      itemgroups[itemgroupsInd].title ? '' : ' none-title',
                //    '"',
                //  '>',
                //    '<span class="title" title="' + title + '">',
                //      title,
                //    '</span>',
                //    '<ul class="filter-items">',
                //      items.join(''),
                //    '</ul>',
                //  '</li>'
                //]);
            } else {
                itemvalues = itemgroups[itemgroupsInd].items;
                items = [];
                for (itemvaluesInd = 0, itemvaluesLen = itemvalues.length; itemvaluesInd < itemvaluesLen; itemvaluesInd++) {
                    items.push(createAdvansedFilterItem(itemvalues[itemvaluesInd], type));
                }

                title = converText(itemgroups[itemgroupsInd].title, true);
                html = html.concat([
                  '<li',
                    ' class="item-group ' + type + '-group',
                      //itemgroupsInd === 0 ? ' first-group' : '',
                      type === 'sorter' && !itemgroups[itemgroupsInd].title ? ' none-title' : '',
                    '"',
                  '>',
                    '<span class="title" title="' + title + '">',
                      title,
                    '</span>',
                  '</li>',
                  items.join('')
                ]
                );
            }
            //if (itemgroupsInd > 0 && itemgroupsLen > colcount && itemgroupsInd !== (itemgroupsLen - 1) && (itemgroupsInd + 1) % colcount === 0) {
            //  html.push('<li class="item-list-separator ' + type + '-list-separator"></li>')
            //}
        }
        html.push('<li class="item-list-separator ' + type + '-list-separator"></li>');
        return html.join('');
    }

    function createAdvansedFilterItem(itemvalue, type) {
        return [
          '<li',
            ' class="item-item ' + type + '-item',
              itemvalue.def === true ? ' selected' : '',
              itemvalue.def === true ? (itemvalue.dsc = !!itemvalue.dsc) === true ? ' dsc-sort' : ' asc-sort' : '',
              itemvalue.dsc === true || itemvalue.sortOrder === 'descending' ? ' dsc-sort-default' : '',
            '"',
            ' title="' + converText(itemvalue.title, true) + '"',
            ' data-id="' + itemvalue.id + '"',
            itemvalue.type ? ' data-type="' + itemvalue.type + '"' : '',
            itemvalue.hashmask ? ' data-anchor="' + itemvalue.hashmask + '"' : '',
          '>',
            '<span class="inner-text">',
              converText(itemvalue.title, true),
              //itemvalue.title,
            '</span>',
          '</li>'
        ].join('');
    };

    function createAdvansedFilter(filtervalues, sortervalues, opts) {
        var
          html = null,
          filters = [],
          sorters = [],
          o = null, $o = null;

        $o = jQuery.tmpl(templates.filterContainer, { filtervalues: filtervalues, sortervalues: sortervalues });
        if (!$o || $o.length != 1) return null;
        $o = $o[0];
        o = doc.createElement('div');
        o.className = 'clearFix';
        o.innerHTML = $o.outerHTML;
        return $o;
    }

    function updateAdvansedFilter(opts, $container, filtervalues, sortervalues) {
        var
          o = null,
          wasAdded = false,
          groups = [],
          groupsInd = 0,
          filtervalues = [].concat(filtervalues),
          sortervalues = [].concat(sortervalues),
          filtervaluesInd = 0, filtervaluesLen = 0,
          filterid = '',
          $filter = null,
          $filters = $container.find('li.filter-item'),
          filtersInd = 0, filtersLen = 0;

        for (filtersInd = 0, filtersLen = $filters.length; filtersInd < filtersLen; filtersInd++) {
            $filter = $($filters[filtersInd]);
            filterid = $filter.attr('data-id');
            wasAdded = false;
            for (filtervaluesInd = 0, filtervaluesLen = filtervalues ? filtervalues.length : 0; filtervaluesInd < filtervaluesLen; filtervaluesInd++) {
                if (filtervalues[filtervaluesInd].id === filterid) {
                    addFilterToGroup(groups, filtervalues[filtervaluesInd]);
                    filtervalues.splice(filtervaluesInd, 1);
                    wasAdded = true;
                    break;
                }
            }
            if (wasAdded === false) {
                addFilterToGroup(groups, { type: $filter.attr('data-type'), title: $filter.text(), group: '', hashmask: $filter.attr('data-anchor') });
            }
        }

        for (filtervaluesInd = 0, filtervaluesLen = filtervalues ? filtervalues.length : 0; filtervaluesInd < filtervaluesLen; filtervaluesInd++) {
            addFilterToGroup(groups, filtervalues[filtervaluesInd]);
        }

        groupsInd = groups.length;
        while (groupsInd--) {
            if (groups[groupsInd].title === '') {
                groups.push(groups[groupsInd]);
                groups.splice(groupsInd, 1);
                break;
            }
        }

        o = $container.find('ul.filter-list:first').removeClass('multi-column').empty()[0] || null;
        if (o) {
            if (opts.colcount >= 1) {
                o.className += ' multi-column multi-column-' + opts.colcount;
            }
            o.innerHTML = createAdvansedFilterGroup(opts, groups, 'filter');
        }

        o = $container.find('ul.sorter-list:first').removeClass('multi-column').empty()[0] || null;
        if (o) {
            o.innerHTML = createAdvansedFilterGroup(opts, [{ title: '', items: sortervalues }], 'sorter');
        }

        return o;
    }

    function callSetFilterTrigger($container, filtervalue, needResetAllEvent) {
        var
          filtervalue = filtervalue || null,
          opts = $container.data('filteroptions'),
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd = filtervalues ? filtervalues.length : 0,
          selectedfilters = [];
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].isset === true) {
                selectedfilters.unshift(filtervalues[filtervaluesInd]);
            }
            if (filtervalue === null && filtervalues[filtervaluesInd].id === 'sorter') {
                filtervalue = filtervalues[filtervaluesInd];
            }
        }

        toggleHasFilters(selectedfilters, $container);

        updateLocalStorageFilters(opts, selectedfilters);
        if (needResetAllEvent === true) {
            $container.trigger('resetallfilters', [$container, filtervalue.id, selectedfilters]);
        }

        $container.trigger('setfilter', [$container, filtervalue, filtervalue != null ? filtervalue.params : null, selectedfilters]);
        $container.trigger('updatefilter', [$container, filtervalue != null ?  filtervalue.id : null, selectedfilters]);
    }

    function callResetFilterTrigger($container, filtervalue, needResetAllEvent) {
        var
          filtervalue = filtervalue || null,
          opts = $container.data('filteroptions'),
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd = filtervalues ? filtervalues.length : 0,
          selectedfilters = [];
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].isset === true) {
                selectedfilters.unshift(filtervalues[filtervaluesInd]);
            }
            if (filtervalue === null && filtervalues[filtervaluesInd].id === 'sorter') {
                filtervalue = filtervalues[filtervaluesInd];
            }
        }
        
        toggleHasFilters(selectedfilters, $container);
        
        updateLocalStorageFilters(opts, selectedfilters);
        if (needResetAllEvent === true) {
            $container.trigger('resetallfilters', [$container, filtervalue.id, selectedfilters]);
        }
        $container.trigger('resetfilter', [$container, filtervalue, selectedfilters]);
        $container.trigger('updatefilter', [$container, filtervalue.id, selectedfilters]);
    }


    function setFilterItem($container, $filteritem, filtervalue, params, nonetrigger) {
        $container.trigger('adv-setFilterItem', [$container, $filteritem, filtervalue, params, nonetrigger]);
        onBodyClick(true);

        updateTextFilter($container, true);

        if ($container.length > 0 && filtervalue && filtervalue.id === 'sorter') {
            var $sorter = $container.find('li.sorter-item[data-id="' + params.id + '"]:first');

            resizeUserSorterContainer($container, params.title);

            var
              $sortercontainer = $container.find('div.advansed-filter-sort-container:first');

            var classname = params.dsc === true ? 'dsc-sort' : 'asc-sort';
            $sortercontainer
              .removeClass('asc-sort')
              .removeClass('dsc-sort')
              .addClass(classname);
            $sorter
              .addClass('selected')
              .removeClass('asc-sort')
              .removeClass('dsc-sort')
              .addClass(classname)
              .siblings().removeClass('selected').removeClass('asc-sort').removeClass('dsc-sort');
        }

        if ($container.length > 0 && filtervalue) {
            var paramsitem = null;
            var paramsid = $filteritem && $filteritem.length > 0 ? $filteritem.attr('data-paramsid') || null : null;
            if (!filtervalue.params) {
                filtervalue.params = filtervalue.multiselect === true ? [] : {};
            }

            if (filtervalue.multiselect === true && isArray(filtervalue.params) && paramsid) {
                var
                  items = filtervalue.params,
                  itemsInd = items ? items.length : 0;
                while (itemsInd--) {
                    if (paramsid == items[itemsInd].__id) {
                        paramsitem = items[itemsInd];
                        break;
                    }
                }
                if (!paramsitem) {
                    paramsitem = { __id: paramsid };
                    filtervalue.params.push(paramsitem);
                }
            } else {
                paramsitem = filtervalue.params;
            }

            for (var fld in params) {
                if (params.hasOwnProperty(fld)) {
                    paramsitem[fld] = params[fld];
                }
            }

            filtervalue.isset = true;
            resizeUserFilterContainer($container);
            if (nonetrigger !== true && lazyTrigger === false) {
                callSetFilterTrigger($container, filtervalue);
            }
        }
    }

    function unsetFilterItem($container, $filteritem, filtervalue, nonetrigger) {
        $container.trigger('adv-unsetFilterItem', [$container, $filteritem, filtervalue, nonetrigger]);
        onBodyClick(true);

        updateTextFilter($container, true);

        if ($container.length > 0 && filtervalue) {
            var noParams = false;
            var paramsid = $filteritem && $filteritem.length > 0 ? $filteritem.attr('data-paramsid') || null : null;
            if (filtervalue.multiselect === true && isArray(filtervalue.params) && paramsid) {
                var
                  items = filtervalue.params,
                  itemsInd = items ? items.length : 0;
                while (itemsInd--) {
                    if (paramsid == items[itemsInd].__id) {
                        items.splice(itemsInd, 1);
                        break;
                    }
                }
                if (items.length === 0) {
                    noParams = true;
                }
            } else {
                noParams = true;
            }
            if (noParams === true) {
                filtervalue.params = null;
                filtervalue.isset = false;
            }
            if (nonetrigger !== true && lazyTrigger === false) {
                callResetFilterTrigger($container, filtervalue);
            }
        }
    }

    function updateFiltersList($container) {
        var $groups = $container.find("li.item-group.filter-group");

        for (var i = 0, j = $groups.length; i < j; i++) {
            var $group = $($groups[i]);
            $group.removeClass('hidden-item');

            if ($group.find('.item-item:not(.hidden-item)').length === 0) {
                $group.addClass('hidden-item');
            }
        }

        //$items.filter('.item-group').removeClass('first-group').not('.disabled-item').filter(':first').addClass('first-group');
    }

    function updateTextFilter($container, nonetrigger) {
        var
          $this = $container.find('input.advansed-filter-input:first'),
          value = $this.val(),
          filtervalue = null,
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd = 0;

        if (!filtervalues || filtervalues.length === 0) {
            return undefined;
        }

        filtervaluesInd = filtervalues.length;
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].id === 'text') {
                break;
            }
        }

        if (filtervaluesInd !== -1) {
            filtervalue = filtervalues[filtervaluesInd];
            if (typeof value === 'string' && value.length > 0) {
                var params = { value: value };
                if (!filtervalue.params) {
                    filtervalue.params = {};
                }
                for (var fld in params) {
                    if (params.hasOwnProperty(fld)) {
                        filtervalue.params[fld] = params[fld];
                    }
                }
                filtervalue.isset = true;
            } else {
                filtervalue.params = null;
                filtervalue.isset = false;
            }
        }
    }

    function resetTextFilter($container) {
        var
            $this = $container.find('input.advansed-filter-input:first'),
            filtervalue = null,
            filtervalues = $container.data('filtervalues'),
            filtervaluesInd = 0;

        if (!filtervalues || filtervalues.length === 0) {
            return undefined;
        }

        filtervaluesInd = filtervalues.length;
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].id === 'text') {
                break;
            }
        }

        $this.val('');

        if (filtervaluesInd !== -1) {
            filtervalue = filtervalues[filtervaluesInd];
            filtervalue.params = null;
            filtervalue.isset = false; 
        }
        $container.data('filtervalues', filtervalues);
    }
    /* <flag> */

    function onUserFilterFlagSelectValue($container, $filteritem, filtervalue, nonetrigger) {
        if ($container.length > 0 && filtervalue) {
            setFilterItem($container, $filteritem, filtervalue, {}, nonetrigger);
        }
    }

    function compareUserFilterParamsFlag($container, containerfiltervalue, filtervalue) {
        return true;
    }

    function customizeUserFilterFlag($container, $filteritem, filtervalue) {
        return filtervalue.hasOwnProperty('defaultparams') ? filtervalue.defaultparams : {};
    }

    function destroyUserFilterFlag($container, $filteritem, filtervalue) {

    }

    /* </flag> */
    /* <group> */

    function setUserFilterGroupValue($container, $filteritem, params) {
        if (params && params.hasOwnProperty('name')) {
            $filteritem.removeClass('default-value').find('span.group-selector:first span.custom-value:first').attr('title', params.name).find('span.value:first').text(params.name);
        }
    }

    function onUserFilterGroupSelectValue($container, $filteritem, filtervalue, group, nonetrigger) {
        if ($container.length > 0 && $filteritem.length > 0) {
            setUserFilterGroupValue($container, $filteritem, { id: group.id, name: converText(group.title) });
        }

        if ($container.length > 0 && filtervalue) {
            setFilterItem($container, $filteritem, filtervalue, { id: group.id, value: group.id, name: converText(group.title) }, nonetrigger);
        }
    }

    function showUserFilterGroup($container, $filteritem) {
        if ($container.hasClass('showed-groupselector')) {
            return undefined;
        }

        if (jQuery($container).find(".filter-item.filter-item-group > .advansed-filter-groupselector").length != 0){
            try {
                $container.addClass("showed-groupselector").find(".filter-item.filter-item-group > .selector-wrapper:first").groupadvancedSelector('reset', true);
            } catch (err) { }
        }

        //onBodyClick();
        jQuery(document.body).unbind('click', onBodyClick);

        resizeControlContainer($container, $filteritem, $container.find('div.advansed-filter-groupselector-container:first'));

        setTimeout(function () {
            jQuery(document.body).one('click', onBodyClick);
        }, 1);
    }

    function destroyUserFilterGroup($container, $filteritem, filtervalue) {

    }

    function compareUserFilterParamsGroup($container, containerfiltervalue, filtervalue) {
        return containerfiltervalue.id === filtervalue.id;
    }

    function customizeUserFilterGroup($container, $filteritem, filtervalue) {
        if (jQuery($filteritem).children(".advanced-selector-container").length == 0) {
            try {
                $container.addClass("showed-groupselector");
                $filteritem.children(".selector-wrapper:first").groupadvancedSelector(
                {
                    inPopup: true,
                    onechosen: true
                });
            } catch (err) { }

            try {
                jQuery($filteritem).children(".selector-wrapper:first")
                    .on("showList", 
                        (function ($container, $filteritem, filtervalue, callback) {
                            return function (event, group) {
                                callback($container, $filteritem, filtervalue, group);
                            }
                        })($container, $filteritem, filtervalue, onUserFilterGroupSelectValue)
                    );

                if (!filtervalue.isset && !filtervalue.bydefault) {
                    setTimeout(function() {
                        if ($filteritem.hasClass("default-value")) {
                            $filteritem.find(".selector-wrapper").click();
                        }
                    }, 0);
                }

            } catch (err) { }
        }
    }

    /* </group> */
    /* <person> */

    function setUserFilterPersonValue($container, $filteritem, params) {
        if (params && params.hasOwnProperty('name')) {
            $filteritem.removeClass('default-value').find('span.person-selector:first span.custom-value:first').attr('title', params.name).find('span.value:first').text(params.name);
        }
    }

    function onUserFilterPersonSelectValue($container, $filteritem, filtervalue, userid, username, nonetrigger) {
        if ($container.length > 0 && $filteritem.length > 0) {
            setUserFilterPersonValue($container, $filteritem, { id: userid, name: converText(username) });
        }

        if ($container.length > 0 && filtervalue) {
            setFilterItem($container, $filteritem, filtervalue, { id: userid, value: userid, name: converText(username) }, nonetrigger);
        }
    }

    function compareUserFilterParamsPerson($container, containerfiltervalue, filtervalue) {
        return containerfiltervalue.id === filtervalue.id;
    }

    function customizeUserFilterPerson($container, $filteritem, filtervalue) {
        if (jQuery($filteritem).children(".advansed-filter-userselector").length == 0) {
            try {
                var showme = filtervalue.hasOwnProperty('showme') ? Boolean(filtervalue.showme) : true;
                $container.addClass("showed-userselector");
                $filteritem.children(".selector-wrapper:first").useradvancedSelector(
                {
                    showme: showme,
                    inPopup: true,
                    onechosen: true,
                    showGroups: true,
                    itemsDisabledIds: showme ? [] : [window.Teamlab.profile.id],
                    showDisabled: window.Teamlab.profile.isAdmin
                });
            } catch (err) { }
            
            try {
                jQuery($filteritem).children(".selector-wrapper:first")
                    .on("showList", 
                        (function ($container, $filteritem, filtervalue, callback) {
                            return function (event, item) {
                                callback($container, $filteritem, filtervalue, item.id, item.title);
                            }
                        })($container, $filteritem, filtervalue, onUserFilterPersonSelectValue)
                    );

                if (!filtervalue.isset && !filtervalue.bydefault) {
                    setTimeout(function() {
                        if ($filteritem.hasClass("default-value")) {
                            $filteritem.find(".selector-wrapper").click();
                        }
                    }, 0);
                }

            } catch (err) { }
        }
    }

    function showUserFilterPerson($container, $filteritem) {
        if ($container.hasClass('showed-userselector')) {
            return undefined;
        }

        if (jQuery($container).find(".filter-item.filter-item-person > .advansed-filter-userselector").length != 0){
            try {
                $container.addClass("showed-userselector").find(".filter-item.filter-item-person > .selector-wrapper:first").useradvancedSelector('reset', true);
            } catch (err) { }
        }

        //onBodyClick();
        jQuery(document.body).unbind('click', onBodyClick);

        resizeControlContainer($container, $filteritem, $container.find('div.advansed-filter-userselector-container:first'));
        setTimeout(function () {
            jQuery(document.body).one('click', onBodyClick);
        }, 1);
    }

    function destroyUserFilterPerson($container, $filteritem, filtervalue) {

    }

    /* </person> */
    /* <date> */

    function onUserFilterDateSelectValue(target, $container, $filteritem, filtervalue, datetext, inst, nonetrigger, instDate) {
        var
          $target = jQuery(target),
          date = inst ? inst.input.datepicker('getDate') : instDate,
          $dateselector = $target.parents('span.advansed-filter-dateselector-date:first'),
          $dependentDatepicker = null,
          isFromDateDatepicker = false;

        if ($dateselector.hasClass("dateselector-from-date")) {
            isFromDateDatepicker = true;
            $dependentDatepicker = $dateselector.parents(".filter-item-daterange:first").find('span.to-daterange-selector:first span.datepicker-container:first');
        } else {
            isFromDateDatepicker = false;
            $dependentDatepicker = $dateselector.parents(".filter-item-daterange:first").find('span.from-daterange-selector:first span.datepicker-container:first');
        }

        if ($container.length > 0 && filtervalue) {
            $dateselector.find('span.btn-show-datepicker-title:first').text(datetext);
            if (date) {
                setFilterItem($container, $filteritem, filtervalue, isFromDateDatepicker ? { from: date.getTime() } : { to: date.getTime() }, nonetrigger);
                $dependentDatepicker.datepicker("option", isFromDateDatepicker ? "minDate" : "maxDate", date);
            }
        }
    }

    function compareUserFilterParamsDate($container, containerfiltervalue, filtervalue) {
        return containerfiltervalue.from == filtervalue.from && containerfiltervalue.to == filtervalue.to;
    }

    function customizeUserFilterDate($container, $filteritem, filtervalue) {
        var
          $datepicker = null,
          $fromDateContainer = null,
          $toDateContainer = null,
          tmpDate = new Date(),
          defaultFromDate,
          defaultToDate;

        defaultFromDate = new Date(tmpDate.getFullYear(), tmpDate.getMonth() - 6, tmpDate.getDate(), 0, 0, 0, 0);
        defaultToDate = new Date(tmpDate.getFullYear(), tmpDate.getMonth(), tmpDate.getDate(), 0, 0, 0, 0);

        $fromDateContainer = $filteritem.find('span.from-daterange-selector:first span.datepicker-container:first');
        $toDateContainer = $filteritem.find('span.to-daterange-selector:first span.datepicker-container:first')

        $datepicker = createDatepicker($fromDateContainer, $container, $filteritem, filtervalue, defaultFromDate);
        $datepicker.datepicker("option", "maxDate", defaultToDate);
        $filteritem.find('span.from-daterange-selector:first span.btn-show-datepicker-title:first').text($.datepicker.formatDate($datepicker.datepicker("option", "dateFormat"), $datepicker.datepicker("getDate")));

        $datepicker = createDatepicker($toDateContainer, $container, $filteritem, filtervalue, defaultToDate);
        $datepicker.datepicker("option", "minDate", defaultFromDate);
        $filteritem.find('span.to-daterange-selector:first span.btn-show-datepicker-title:first').text($.datepicker.formatDate($datepicker.datepicker("option", "dateFormat"), $datepicker.datepicker("getDate")));

        return { from: defaultFromDate.getTime(), to: defaultToDate.getTime() };
    }

    function showUserFilterDate(evt, $container, $filteritem, $dateselector) {
        if ($dateselector.hasClass('showed-datepicker')) {
            return undefined;
        }

        //onBodyClick(evt);
        jQuery(document.body).unbind('click', onBodyClick);

        var $datepicker = $dateselector.addClass('showed-datepicker').find('span.advansed-filter-datepicker-container:first').css('display', 'block');

        $datepicker.removeClass('reverse-position');
        if ($filteritem.parents('div.hidden-filters-container:first').length === 0) {
            if ($container.width() - $filteritem[0].offsetLeft - $filteritem.parent()[0].offsetLeft - $filteritem.width() < $datepicker.width()) {
                $datepicker.addClass('reverse-position');
            }
        }

        setTimeout(function () {
            jQuery(document.body).one('click', onBodyClick);
        }, 1);
    }

    function destroyUserFilterDate($container, $filteritem, filtervalue) {

    }

    /* </date> */
    /* <combobox> */

    function onUserFilterComboboxSelectValue(target, $container, $filteritem, filtervalue, nonetrigger) {
        var
          $target = jQuery(target),
          value = $target.val();

        if ($container.length > 0 && filtervalue) {
            if (isArray(value)) {
                var
                  values = value,
                  valuesInd = value.length;
                while (valuesInd--) {
                    if (values[valuesInd] == -1) {
                        values.splice(valuesInd, 1);
                        break;
                    }
                }
                value = values;
            }

            $filteritem.removeClass('default-value');

            setFilterItem($container, $filteritem, filtervalue, { value: value, title: $target.find('option[value="' + ("" + value).replace(/\"/g, '\\"') + '"]:first').text() }, nonetrigger);
        }
    }

    function compareUserFilterParamsCombobox($container, containerfiltervalue, filtervalue) {
        if (containerfiltervalue.value == filtervalue.value) {
            return true;
        }
        if (isArray(containerfiltervalue.value) && isArray(filtervalue.value) && containerfiltervalue.value.length === filtervalue.value.length) {
            return [].concat(containerfiltervalue.value).sort().join('') == [].concat(filtervalue.value).sort().join('');
        }
        return false;
    }

    function customizeUserFilterCombobox($container, $filteritem, filtervalue) {
        var
          $select = $filteritem.find('select.advansed-filter-combobox:first'),
          value = $select.val(),
          defaultvalue = filtervalue.hasOwnProperty('defaultvalue') ? filtervalue.defaultvalue : '-1';

        if (isArray(value)) {
            var
              values = value,
              valuesInd = value.length;
            while (valuesInd--) {
                if (values[valuesInd] == -1) {
                    values.splice(valuesInd, 1);
                    break;
                }
            }
            value = values;
        }

        value = value == defaultvalue ? null : value;
        value = isArray(value) && (value.length === 0 || (value.length === 1 && value[0] == '-1')) ? null : value;

        $select
          .advansedFilterCustomCombobox()
          .change((function ($container, $filteritem, filtervalue, callback) {
              return function (evt) {
                  callback(this, $container, $filteritem, filtervalue);
              }
          })($container, $filteritem, filtervalue, onUserFilterComboboxSelectValue));

        if (!filtervalue.isset && value === null) {
            setTimeout(function () {
                if ($filteritem.hasClass("default-value")) {
                    $filteritem.find(".selector-wrapper .combobox-selector .combobox-title").click();
                }
            }, 0);
        }

        // d'ohhh
        return !value ? null : { value: value, title: $select.find('option[value="' + ("" + value).replace(/\"/g, '\\"') + '"]:first').text() };
    }

    function destroyUserFilterCombobox($container, $filteritem, filtervalue) {

    }

    /* </combobox> */

    function compareUserFilterParams($container, filtervalue, params, nonetrigger) {
        var fn = null;
        switch (filtervalue.type) {
            case 'flag': fn = compareUserFilterParamsFlag; break;
            case 'group': fn = compareUserFilterParamsGroup; break;
            case 'person': fn = compareUserFilterParamsPerson; break;
            case 'daterange': fn = compareUserFilterParamsDate; break;
            case 'combobox': fn = compareUserFilterParamsCombobox; break;
        }

        if (fn !== null) {
            if (filtervalue.hasOwnProperty('params')) {
                return fn($container, filtervalue.params, params, nonetrigger);
            }
        }
        return false;
    }

    function customizeUserFilter($container, $filteritem, filtervalue, nonetrigger) {
        var fn = null;
        switch (filtervalue.type) {
            case 'flag': fn = customizeUserFilterFlag; break;
            case 'group': fn = customizeUserFilterGroup; break;
            case 'person': fn = customizeUserFilterPerson; break;
            case 'daterange': fn = customizeUserFilterDate; break;
            case 'combobox': fn = customizeUserFilterCombobox; break;
        }

        if (fn !== null) {
            var o = fn($container, $filteritem, filtervalue, nonetrigger);
            return filtervalue.hasOwnProperty('bydefault') && filtervalue.bydefault && typeof filtervalue.bydefault === 'object' ? filtervalue.bydefault : o;
        }
    }

    function destroyUserFilter($container, $filteritem, filtervalue) {
        var fn = null;
        switch (filtervalue.type) {
            case 'flag': fn = destroyUserFilterFlag; break;
            case 'group': fn = destroyUserFilterGroup; break;
            case 'person': fn = destroyUserFilterPerson; break;
            case 'daterange': fn = destroyUserFilterDate; break;
            case 'combobox': fn = destroyUserFilterCombobox; break;
        }

        if (fn !== null) {
            fn($container, $filteritem, filtervalue);
        }
    }

    function processUserFilter($container, $filteritem, filtervalue, params, nonetrigger) {
        switch (filtervalue.type) {
            case 'flag':
                onUserFilterFlagSelectValue($container, $filteritem, filtervalue, nonetrigger);
                break;
            case 'group':
                onUserFilterGroupSelectValue($container, $filteritem, filtervalue, { id: params.id, title: getGroupSelectorName($container, params.id) }, nonetrigger);
                break;
            case 'person':
                onUserFilterPersonSelectValue($container, $filteritem, filtervalue, params.id, getUserSelectorName($container, params.id, params.name), nonetrigger);
                break;
            case 'daterange':
                var date = null, instDate = null, $datepicker = null;

                if (params.hasOwnProperty('from')) {
                    $datepicker = $filteritem.find('span.from-daterange-selector:first span.datepicker-container:first');
                    date = new Date(+params.from);
                    instDate = $datepicker.datepicker('getDate');

                    if ($datepicker.length > 0 && instDate && date instanceof Date) {
                        $datepicker.datepicker('setDate', date);
                        instDate = $datepicker.datepicker('getDate');
                        onUserFilterDateSelectValue($datepicker, $container, $filteritem, filtervalue, $.datepicker.formatDate($datepicker.datepicker("option", "dateFormat"), instDate), null, nonetrigger, instDate);
                    }
                }

                if (params.hasOwnProperty('to')) {
                    $datepicker = $filteritem.find('span.to-daterange-selector:first span.datepicker-container:first');
                    date = new Date(+params.to);
                    instDate = $datepicker.datepicker('getDate');

                    if ($datepicker.length > 0 && instDate && date instanceof Date) {
                        $datepicker.datepicker('setDate', date);
                        instDate = $datepicker.datepicker('getDate');
                        onUserFilterDateSelectValue($datepicker, $container, $filteritem, filtervalue, $.datepicker.formatDate($datepicker.datepicker("option", "dateFormat"), instDate), null, nonetrigger, instDate);
                    }
                }
                break;
            case 'combobox':
                $filteritem.find('select').val(params.value).change();
                break;
            default:
                filtervalue.hasOwnProperty('process') && typeof filtervalue.process === 'function' ? filtervalue.process($container, $filteritem, filtervalue, params, nonetrigger) : null;
                break;
        }
    }

    function showUserFilterByOption($filterItem) {
        if (!$filterItem.hasClass('hidden-item')) return;

        $filterItem.removeClass('hidden-item');
    }

    function hideUserFilterByOption($container, $selectedfilterItem, $filterItem, nonetrigger) {
        if ($filterItem.hasClass('hidden-item')) return false;

        $filterItem.addClass('hidden-item');

        if ($selectedfilterItem.length > 0) {
            removeUserFilterByObject($container, $selectedfilterItem, nonetrigger);
            return true;
        }
    }

    function enableUserFilterByOption($filterItem) {
        if (!$filterItem.hasClass('disabled-item')) return;

        $filterItem.removeClass('disabled-item');
    }

    function disableUserFilterByOption($container, $selectedfilterItem, $filterItem, nonetrigger) {
        if ($filterItem.hasClass('disabled-item')) return false;

        $filterItem.addClass('disabled-item');

        if ($selectedfilterItem.length > 0) {
            removeUserFilterByObject($container, $selectedfilterItem, nonetrigger);
            return true;
        }
    }

    function resetUserFilterByOption($container, $selectedfilterItem, nonetrigger) {
        if ($selectedfilterItem.length > 0) {
            removeUserFilterByObject($container, $selectedfilterItem, nonetrigger);
            return true;
        }
    }

    function addUserFilter($container, filtervalue, params, nonetrigger) {
        if (typeof(nonetrigger) == "undefined" && typeof(filtervalue.nonetrigger) != "undefined") {
            nonetrigger = filtervalue.nonetrigger;
        }
        var
          $filteritem = null,
          $filters = $container.find('div.advansed-filter-filters:first');
        if ($filters.length === 0) {
            return undefined;
        }

        if (filtervalue.id === 'text') {
            if (params && typeof params === 'object' && params.hasOwnProperty('value')) {
                var $input = $container.find('input.advansed-filter-input:first');
                if ($input.val() != params.value) {
                    $input.val(params.value);
                    updateTextFilter($container, nonetrigger);
                    return true;
                }
            };
            return false;
        }

        if (($filteritem = $filters.find('div.filter-item[data-id="' + filtervalue.id + '"]:first')).length > 0 && filtervalue.multiselect !== true) {
            if (!filtervalue.hasOwnProperty('groupby') && (!params || compareUserFilterParams($container, filtervalue, params, nonetrigger))) {
                return false;
            }
            removeUserFilterByObject($container, $filteritem, true);
        }

        var groupby = filtervalue.hasOwnProperty('groupby') && typeof filtervalue.groupby === 'string' && filtervalue.groupby.length > 0 ? filtervalue.groupby : null;
        if (groupby !== null) {
            var $groupfilter = $filters.find('div.filter-item[data-group="' + groupby + '"]:first');
            if ($container.length > 0 && $groupfilter.length > 0) {
                removeUserFilterByObject($container, $groupfilter, true);
            }
        }

        var customdata = $container.data('customdata');
        if (customdata) {
            var maxfilters = customdata.hasOwnProperty('maxfilters') ? customdata.maxfilters : -1;
            if (maxfilters !== -1 && $filters.find('div.filter-item').length >= maxfilters) {
                var $firstfilter = $filters.find('div.filter-item:first');
                if ($container.length > 0 && $firstfilter.length > 0) {
                    removeUserFilterByObject($container, $firstfilter, true);
                }
            }
        }

        var paramsitems = isArray(params) ? params : [params];
        for (var i = 0, n = paramsitems.length; i < n; i++) {
            params = paramsitems[i];

            $filteritem = $((filtervalue.hasOwnProperty('create') && typeof filtervalue.create === 'function' ? filtervalue.create : createFilterItem)(filtervalue));

            if ($filteritem.length > 0) {
                $filters.append($filteritem);
                if (filtervalue) {
                    var paramsid = params && typeof params === 'object' && params.hasOwnProperty('__id') ? params.__id : Math.floor(Math.random() * 1000000);
                    $filteritem.attr('data-id', filtervalue.id).attr('data-paramsid', paramsid).attr('data-type', filtervalue.type).addClass('filter-item').addClass('filter-item-' + filtervalue.type);
                    if (groupby !== null) {
                        $filteritem.attr('data-group', groupby);
                    }

                    var defaultparams = (filtervalue.hasOwnProperty('customize') && typeof filtervalue.customize === 'function' ? filtervalue.customize : customizeUserFilter)($container, $filteritem, filtervalue, nonetrigger);
                    defaultparams = defaultparams && typeof defaultparams === 'object' ? defaultparams : null;
                    defaultparams = filtervalue.hasOwnProperty('value') ? filtervalue.value : defaultparams;
                    defaultparams ? defaultparams.__id = paramsid : null;
                    params = params && typeof params === 'object' ? params : null;
                    params ? params.__id = paramsid : null;
                    if (defaultparams && !params) {
                        setFilterItem($container, $filteritem, filtervalue, defaultparams, nonetrigger);
                        processUserFilter($container, $filteritem, filtervalue, defaultparams, true);
                    }
                    if (params) {
                        setFilterItem($container, $filteritem, filtervalue, params, nonetrigger);
                        processUserFilter($container, $filteritem, filtervalue, params, nonetrigger);
                    }
                }
            }
        }

        resizeUserFilterContainer($container);
        return true;
    }

    function removeUserFilter($container, filtervalue, $filteritem, nonetrigger) {
        var $filters = $container.find('div.advansed-filter-filters:first');
        if ($filters.length === 0) {
            return undefined;
        }

        if ($filteritem.length > 0) {
            if (filtervalue) {
                (filtervalue.hasOwnProperty('destroy') && typeof filtervalue.destroy === 'function' ? filtervalue.destroy : destroyUserFilter)($container, $filteritem, filtervalue);
                unsetFilterItem($container, $filteritem, filtervalue, nonetrigger);
            }
            $filteritem.find('div.advansed-filter-control').appendTo($container);
            $filteritem.remove();
        }

        resizeUserFilterContainer($container);
    }

    function removeUserFilterByObject($container, $filteritem, nonetrigger) {
        var
          id = $filteritem.attr('data-id'),
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd = 0;
        filtervaluesInd = filtervalues ? filtervalues.length : 0;
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].id === id) {
                break;
            }
        }
        removeUserFilter($container, filtervaluesInd !== -1 ? filtervalues[filtervaluesInd] : null, $filteritem, nonetrigger);
    }

    function enableUserSorter($container, sorterid, nonetrigger) {
        var
          $sorteritems = $container.find('li.item-item.sorter-item');

        $sorteritems.filter('[data-id="' + sorterid + '"]').removeClass('hidden-item');
    }

    function disableUserSorter($container, sorterid, nonetrigger) {
        var
          $sorteritems = $container.find('li.item-item.sorter-item'),
          $sorter = null;

        $sorter = $sorteritems.filter('[data-id="' + sorterid + '"]').addClass('hidden-item');

        if ($sorter.hasClass('selected')) {
            $sorter = $sorteritems.not('.hidden-item').filter(':first');
            if ($sorter.length > 0) {
                sorterid = $sorter.attr('data-id');
                if (sorterid) {
                    setUserSorter($container, sorterid, { dsc: false }, nonetrigger);
                    return true;
                }
            }
        }
    }

    function setUserSorter($container, sorterid, params, nonetrigger) {
        var
          filtervalues = $container.data('filtervalues') || [],
          filtervaluesInd = -1,
          sortervalues = $container.data('sortervalues') || [],
          sortervaluesInd = -1;

        if (sortervalues.length > 0) {
            sortervaluesInd = sortervalues.length;
            while (sortervaluesInd--) {
                if (sortervalues[sortervaluesInd].id === sorterid) {
                    break;
                }
            }
        }

        if (filtervalues.length > 0) {
            filtervaluesInd = filtervalues.length;
            while (filtervaluesInd--) {
                if (filtervalues[filtervaluesInd].id === 'sorter') {
                    break;
                }
            }
        }

        if (filtervaluesInd !== -1 && sortervaluesInd !== -1) {
            if (
              filtervalues[filtervaluesInd].params &&
              filtervalues[filtervaluesInd].params.id === sortervalues[sortervaluesInd].id &&
              filtervalues[filtervaluesInd].params.dsc === params.dsc
            ) {
                return false;
            }
            sortervalues[sortervaluesInd].dsc = params.dsc;
            sortervalues[sortervaluesInd].sortOrder = params.dsc === true ? 'descending' : 'ascending';
            setFilterItem($container, null, filtervalues[filtervaluesInd], sortervalues[sortervaluesInd], nonetrigger);
            return true;
        }
        return false;
    }

    function needHideFilters($container, $filters, $firstfilter) {
        var
          minInputWidth = parseInt($container.find("div.advansed-filter-input input:first").css("min-width") || 100) || 100,
          resetBtnWidth = parseInt($container.find("div.advansed-filter-input").css("margin-right") || 0),
          $lastfilter = $filters.children("div.filter-item:visible:last"),
          $btn = $container.find(".advansed-filter-button.btn-show-filters:first"),
          btnWidth = $btn.length == 1 ? $btn.width() : 0,
          visibleBlocksWidth = 0;

        $filters.children("div:visible").each(function(){
            visibleBlocksWidth += jq(this).outerWidth();
        });

        //console.log("$container[0].offsetWidth, $filters[0].offsetWidth, visibleBlocksWidth, visibleBlocksWidth + $filters[0].offsetLeft + btnWidth + minInputWidth + resetBtnWidth + 10);
        //console.log($firstfilter[0].offsetTop, $lastfilter[0].offsetTop);


        return $firstfilter.length === 0 || $lastfilter.length === 0 ? false :
          ($firstfilter[0].offsetTop !== $lastfilter[0].offsetTop) ||
          ($firstfilter[0].offsetHeight !== $lastfilter[0].offsetHeight) ||
          ($container[0].offsetWidth < $filters[0].offsetWidth + $filters[0].offsetLeft + btnWidth + minInputWidth) ||
          ($firstfilter.find('span.selector-wrapper:first')[0].offsetHeight !== $lastfilter.find('span.selector-wrapper:first')[0].offsetHeight) ||
          $container[0].offsetWidth < visibleBlocksWidth + $filters[0].offsetLeft + btnWidth + minInputWidth + resetBtnWidth + 10;
    }

    function resizeFilterGroupByHeight(opts, $container) {
        if (opts && typeof opts === 'object' && opts.colcount > 1) {
            var rowcount = 0, maxitemmetric = 0, itemmetric = 0,
                $grouplist = $container.find('ul.item-list.filter-list.multi-column:first'),
                $group = null,
                $cols = $grouplist.find('li.item-group-col'),
                $colsInd = 0,
                $groups = null;

            rowcount = Math.ceil($grouplist.find('li.item-group.filter-group').length / opts.colcount);
            while (rowcount--) {
                maxitemmetric = 0;
                $groups = $();
                $colsInd = $cols.length;
                while ($colsInd--) {
                    $group = $($($cols[$colsInd]).find('li.item-group.filter-group')[rowcount]);
                    if ($group.length > 0) {
                        $groups = $groups.add($group);
                        itemmetric = $group.height();
                        maxitemmetric < itemmetric ? maxitemmetric = itemmetric : null;
                    }
                }
                $groups.height(maxitemmetric + 'px');
            }
        }
    }

    function resizeUserSorterContainer($container, title) {
        var
          sortercontainerWidth = 0,
          $filtercontainer = $container.find('div.advansed-filter-container:first'),
          $sortercontainer = $container.find('div.advansed-filter-sort-container:first');
        if ($sortercontainer.length > 0) {
            $sortercontainer.addClass('sorter-isset');
            if (title) {
                $sortercontainer.find('span.value:first').text(title).attr("title", title);
            }
            sortercontainerWidth = $container.hasClass('disable-sorter-block') ? 0 : $sortercontainer.width();
            $filtercontainer.css('margin-right', (sortercontainerWidth > 0 ? sortercontainerWidth + 38 : 0) + 22 + 'px');
            $container.find('div.advansed-filter-helper:first').css('margin-right', (sortercontainerWidth > 0 ? sortercontainerWidth + 38 : 0) + 22 + 'px');
            //$container.find('label.advansed-filter-state:first').css('left', $filtercontainer.width() + 8 + 'px');
            $container.find('label.advansed-filter-state:first').css('left', 'auto').css('right', (sortercontainerWidth > 0 ? sortercontainerWidth + 38 : 0) + 'px');

            // if filter width change
            resizeUserFilterContainer($container);
        }
    }

    function resizeUserFilterContainer($container) {
        var
          containerWidth = $container.width(),
          $input = $container.find('div.advansed-filter-input:first'),
          $button = $container.find('div.advansed-filter-button:first'),
          $filters = $container.find('div.advansed-filter-filters:first'),
          $hiddenfilterscontainer = $filters.find('div.hidden-filters-container:first'),
          $hiddenfilteritems = $hiddenfilterscontainer.find('div.filter-item');

        if ($input.length === 0 || $filters.length === 0 || containerWidth === 0) {
            return undefined;
        }

        if ($filters.find('div.filter-item').length === 0) {
            $filters.addClass('empty-list');
            $container.addClass('empty-filter-list');
        } else {
            $filters.removeClass('empty-list');
            $container.removeClass('empty-filter-list');
        }

        //$filters.removeClass('has-hidden-filters').find('div.filter-item').removeClass('hidden-filter').appendTo($filters);
        $filters.removeClass('has-hidden-filters');
        $hiddenfilteritems.removeClass('hidden-filter').insertAfter($hiddenfilterscontainer);

        var
          titlewidth = 0,
          maxwidth = 0,
          $selectorwrapper = null,
          $el = null,
          ind = 0,
          opts = $container.data('filteroptions'),
          $advansedcontainer = $container.find('div.advansed-filter-container:first'),
          $firstfilter = $filters.find('div.filter-item:first'),

          //$selectedfilters = $filters.children('div.filter-item').not('.is-rendered'),
          //selectedfiltersInd = $selectedfilters.length,
          $selectedfilters = $filters.find('div.filter-item'),
          needhidefilters = false;


        ind = $selectedfilters.length;
        while (ind--) {
            $el = jQuery($selectedfilters[ind]);
            $selectorwrapper = $el.find('span.selector-wrapper:first');
            titlewidth = $el.find('span.title:first').width() + 8; //8 - padding
            $el.width(titlewidth + $selectorwrapper.width());
            $selectorwrapper.css('left', titlewidth + 'px');
        }
        $input[0].style.marginLeft = 'auto';
        needhidefilters = needHideFilters($advansedcontainer, $filters, $firstfilter);

        if ($firstfilter.length && needhidefilters) {
            $filters.addClass('has-hidden-filters');

            $firstfilter = $filters.find('div.filter-item:first:visible');
            while ($firstfilter.length > 0 && needHideFilters($advansedcontainer, $filters, $firstfilter)) {
                $el = $firstfilter;

                $firstfilter = $firstfilter.next("div.filter-item");

                $el.addClass('hidden-filter').appendTo($hiddenfilterscontainer);
            }
        }

        if ($filters.find('div.hidden-filter').length > 0) {
            $filters.addClass('has-hidden-filters');
        } else {
            $filters.removeClass('has-hidden-filters');
        }

        var
          $hiddenfilters = $hiddenfilterscontainer.find('div.filter-item'),
          hiddenfiltersInd = $hiddenfilters.length,
          zindex = 0;
        while (hiddenfiltersInd--) {
            $hiddenfilters[hiddenfiltersInd].style.zIndex = ++zindex;
        }

        if (opts && typeof opts === 'object' && opts.colcount > 1) {
            var $advansedfilterlist = $container.find('ul.item-list.filter-list.multi-column:first');

            if ($advansedfilterlist.addClass('show-item-list').height() > 0 && !$advansedfilterlist.hasClass('is-render')) {
                //resizeFilterGroupByHeight(opts, $container);

                var colwidth = 0, colswidth = 0,
                    $advansedfilterlistcols = $advansedfilterlist.find('li.item-group-col');

                $advansedfilterlist.width('auto')
                var $advansedfilterlistcolsInd = $advansedfilterlistcols.length;
                while ($advansedfilterlistcolsInd--) {
                    colwidth = getClientWidth($advansedfilterlistcols[$advansedfilterlistcolsInd]);
                    $advansedfilterlistcols[$advansedfilterlistcolsInd].style.width = colwidth + 'px';
                    colswidth += colwidth;
                }
                $advansedfilterlist.addClass('is-render').width(colswidth + 20 + 'px'); // 20 - padding
            }
            $advansedfilterlist.removeClass('show-item-list');
        }

        var offsetLeft = $filters.width() + 2;
        //if (/* !$filters.hasClass('is-render') && */$button.length > 0) {
        //  //$filters.addClass('is-render');
        //  //$filters.css('left', $button.width() + 1 + 3 + 'px');
        //  $button.css('left', offsetLeft + 'px');
        //  $container.find('div.advansed-filter-list:first').css('left', offsetLeft + 'px');
        //}
        $button.css('left', offsetLeft + 'px');
        $container.find('div.advansed-filter-list:first').css('left', offsetLeft + 'px');
        $input[0].style.marginLeft = $button[0].offsetWidth + offsetLeft + 'px';
    }

    function getClientWidth(elem) {
        var rect = elem.getBoundingClientRect();
        return Math.ceil(rect.width);
    }

    function resizeControlContainer($container, $filteritem, $control) {
        $control
          .addClass('reset-position')
          .parents('div.advansed-filter-control:first')
          .appendTo($filteritem.parents('div.hidden-filters-container:first').length === 0 ? $filteritem : $filteritem.parents('div.advansed-filter-filters:first').find('div.btn-show-hidden-filters:first'));

        if ($filteritem.parents('div.hidden-filters-container:first').length > 0) {
            return undefined;
        }

        if ($container.width() - $filteritem[0].offsetLeft - $filteritem.parent()[0].offsetLeft - $filteritem.width() < $control.width()) {
            var
              offset = $control.width() - ($container.width() - $filteritem[0].offsetLeft - $filteritem.parent()[0].offsetLeft - $filteritem.width()) + 40,
              offsetcontroltop = $control.find('div.control-top:first')[0].offsetLeft || 0,
              margincontainer = parseFloat($control.css('margin-left'));

            $control.removeClass('reset-position').css('margin-left', -offset + 'px')
              .find('div.control-top:first').css('left', offsetcontroltop + offset - (isFinite(margincontainer) ? Math.abs(margincontainer) : 0) + 'px');
        }
    }

    function resizeContainer($container) {
        var
          $support = $container.find('div.advansed-filter-support:first'),
          $label = $container.find('label.advansed-filter-label:first'),
          $input = $container.find('input.advansed-filter-input:first'),
          $filtercontainer = $container.find('div.advansed-filter-container:first'),
          $filterlist = $container.find('div.advansed-filter-list:first'),
          id = $input.attr('id') || Math.floor(Math.random() * 1000000);

        $input.attr('id', id);
        $label.attr('for', id);

        var supportwidth = $support.innerWidth();
        $filtercontainer.css('margin-left', supportwidth + 'px');
        $filterlist.css('margin-left', supportwidth + 'px');
    }

    function toggleSorterBlock($container, value) {
        value === true ? $container.removeClass('disable-sorter-block') : $container.addClass('disable-sorter-block');
    }

    function addReadyEvent(fn, args) {
        if (typeof fn === 'function') {
            jQuery((function (fn, args) { return function () { setTimeout(function () { fn.apply(window, args) }, 1) } })(fn, args));
        }
    }

    function setEvents($container, opts) {
        $container = $container.hasClass('advansed-filter') ? $container : $container.find('div.advansed-filter:first');
        if ($container.length === 0) {
            return undefined;
        }

        if (opts.hasOwnProperty('anykey') && opts.anykey === true) {
            var timeout = opts.hasOwnProperty('anykeytimeout') ? opts.anykeytimeout : defaultAnykeyTimeout;
            timeout = isFinite(+timeout) ? +timeout : defaultAnykeyTimeout;
            if (timeout > 0) {
                filterInputKeyupTimeout = timeout;
                $container.find('input.advansed-filter-input:first').unbind('keyup paste', onFilterInputKeyupHelper).bind('keyup paste', onFilterInputKeyupHelper);
            } else {
                $container.find('input.advansed-filter-input:first').unbind('keyup paste', onFilterInputKeyup).bind('keyup paste', onFilterInputKeyup);
            }
        } else {
            $container.find('input.advansed-filter-input:first').unbind('keyup paste', onFilterInputEnter).bind('keyup paste', onFilterInputEnter);
        }
        $container.find('input.advansed-filter-input:first').unbind('keyup paste input', onKeyUp).bind('keyup paste input', onKeyUp);

        $container.find('.btn-start-filter:first').unbind('click', onStartFilter).bind('click', onStartFilter);
        $container.find('label.btn-reset-filter:first').unbind('click', onResetFilter).bind('click', onResetFilter);
        $container.find('ul.filter-list:first').unbind('click', onSelectFilter).bind('click', onSelectFilter);
        $container.find('ul.sorter-list:first').unbind('click', onSelectSorter).bind('click', onSelectSorter);
        $container.find('div.btn-show-filters:first').unbind('click', onShowFilters).bind('click', onShowFilters);

        $container.find('span.btn-toggle-sorter:first').unbind('click', onToggleSorter).bind('click', onToggleSorter);
        $container.find('div.advansed-filter-sort-container:first span.title:first').unbind('click', onShowSorters).bind('click', onShowSorters);

        $container.find('div.advansed-filter-filters:first').unbind('click', onUserFilterClick).bind('click', onUserFilterClick);
        $container.find('div.advansed-filter-userselector:first').unbind('click', onUserSelectorClick).bind('click', onUserSelectorClick);
        $container.find('div.advansed-filter-groupselector:first').unbind('click', onGroupSelectorClick).bind('click', onGroupSelectorClick);
    }

    /* <callbacks> */

    function onBodyClick(p1) {
        var $target = p1 && typeof p1 === 'object' ? jQuery(p1.target) : null;

        if (
          ($target && $target.is('span.btn-show-datepicker') && $target.parents('div.hidden-filters-container:first').length > 0) ||
          ($target && $target.is('span.combobox-title') && $target.parents('div.hidden-filters-container:first').length > 0) ||
          ($target && $target.is('span.combobox-title-inner-text') && $target.parents('div.hidden-filters-container:first').length > 0)
        ) {
            jQuery(document.body).unbind('click', arguments.callee);
            jQuery(document.body).one('click', arguments.callee);

            jQuery('div.advansed-filter').find('span.advansed-filter-dateselector-date').removeClass('showed-datepicker').find('span.advansed-filter-datepicker-container').hide();
            return undefined;
        }

        if (p1 === true) {
            jQuery(document.body).trigger('click');
        }

        jQuery('div.advansed-filter').removeClass('showed-filters').find('ul.filter-list:first').hide();
        jQuery('div.advansed-filter').removeClass('showed-sorters').find('ul.sorter-list:first').hide();
        jQuery('div.advansed-filter').removeClass('showed-hidden-filters').find('div.hidden-filters-container:first').hide();
        jQuery('div.advansed-filter').removeClass('showed-userselector').find('div.advansed-filter-userselector-container:first').hide();
        jQuery('div.advansed-filter').removeClass('showed-groupselector').find('div.advansed-filter-groupselector-container:first').hide();

        jQuery('div.advansed-filter').find('span.advansed-filter-dateselector-date').removeClass('showed-datepicker').find('span.advansed-filter-datepicker-container').hide();
    }

    function onKeyUp() {
        if (this.value) {
            this.parentNode.classList.add('has-value');
        } else {
            this.parentNode.classList.remove('has-value');
        }
    }

    function onShowFilters(evt) {
        var $filter = jQuery(this).parents('div.advansed-filter:first');
        if ($filter.hasClass('showed-filters')) {
            return undefined;
        }

        onBodyClick(evt);
        jQuery(document.body).unbind('click', onBodyClick);
        $filter.addClass('showed-filters').find('ul.filter-list:first').show();
        setTimeout(function () {
            jQuery(document.body).one('click', onBodyClick);
        }, 1);
    }

    function onShowSorters(evt) {
        var $container = jQuery(this).parents('div.advansed-filter:first');
        if ($container.hasClass('disable-sorter-block') || $container.find('div.advansed-filter-sort-container:first').hasClass('sorter-nochange') || $container.hasClass('showed-sorters')) {
            return undefined;
        }

        onBodyClick(evt);
        jQuery(document.body).unbind('click', onBodyClick);
        $container.addClass('showed-sorters').find('ul.sorter-list:first').show();
        setTimeout(function () {
            jQuery(document.body).one('click', onBodyClick);
        }, 1);
    }

    function onToggleSorter(evt) {
        var $container = jQuery(this).parents('div.advansed-filter:first');
        if ($container.hasClass('disable-sorter-block')) {
            return undefined;
        }

        var $selsorter = $container.find('li.sorter-item.selected:first');

        if ($container.length === 0 || $selsorter.length === 0) {
            return undefined;
        }

        var sorterid = $selsorter.attr('data-id') || null;
        if (sorterid) {
            setUserSorter($container, sorterid, { dsc: $selsorter.hasClass('asc-sort') });
        }
    }

    function onSelectFilter(evt) {
        var $selfilter = jQuery(evt.target);
        if (!$selfilter.hasClass('filter-item')) {
            $selfilter = $selfilter.parents('li.filter-item:first');
        }
        var $container = $selfilter.parents('div.advansed-filter:first');
        if ($container.length === 0 || $selfilter.length === 0 || $selfilter.hasClass('hidden-item') || $selfilter.hasClass('disabled-item')) {
            return undefined;
        }

        var
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd = 0,
          filterid = $selfilter.attr('data-id') || '',
          filtervalue = null;

        filtervaluesInd = filtervalues ? filtervalues.length : 0;
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].id === filterid) {
                filtervalue = filtervalues[filtervaluesInd];
                break;
            }
        }

        if (!filtervalue.params) {
            filtervalue.params = filtervalue.multiselect === true ? [] : {};
        }

        if (filtervalue != null) {
            addUserFilter($container, filtervalue);
        }
    }

    function onSelectSorter(evt) {
        var $selsorter = jQuery(evt.target);
        if (!$selsorter.hasClass('sorter-item')) {
            $selsorter = $selsorter.parents('li.sorter-item:first');
        }
        var $container = $selsorter.parents('div.advansed-filter:first');
        if ($container.length === 0 || $selsorter.length === 0) {
            return undefined;
        }

        var sorterid = $selsorter.attr('data-id') || null;
        if (sorterid) {
            var dsc = $selsorter.hasClass('asc-sort');
            if (!$selsorter.hasClass('asc-sort') && !$selsorter.hasClass('dsc-sort') && $selsorter.hasClass('dsc-sort-default')) {
                dsc = true;
            }
            setUserSorter($container, sorterid, { dsc: dsc });
        }
    }

    function onUserFilterClick(evt) {
        var
          $container = null,
          $filteritem = null,
          $target = jQuery(evt.target);

        $container = $target.parents('div.advansed-filter:first');
        $filteritem = $target.hasClass('filter-item') ? $target : $target.parents('div.filter-item:first');

        if ($target.hasClass('btn-show-hidden-filters')) {
            var $filter = jQuery(this).parents('div.advansed-filter:first');
            if ($filter.hasClass('showed-hidden-filters')) {
                return undefined;
            }

            onBodyClick(evt);
            jQuery(document.body).unbind('click', onBodyClick);
            $filter.addClass('showed-hidden-filters').find('div.hidden-filters-container:first').show();
            setTimeout(function () {
                jQuery(document.body).one('click', onBodyClick);
            }, 1);
            return undefined;
        }

        if ($target.hasClass('btn-show-datepicker')) {
            var $dateselector = $target.parents('span.advansed-filter-dateselector-date:first');
            showUserFilterDate(evt, $container, $filteritem, $dateselector);
            return undefined;
        }

        if ($container.length === 0 || $filteritem.length === 0) {
            return undefined;
        }

        if ($target.hasClass('btn-delete')) {
            var
              id = $filteritem.attr('data-id'),
              filtervalues = $container.data('filtervalues'),
              filtervaluesInd = 0;
            filtervaluesInd = filtervalues ? filtervalues.length : 0;
            while (filtervaluesInd--) {
                if (filtervalues[filtervaluesInd].id === id) {
                    break;
                }
            }
            removeUserFilter($container, filtervaluesInd !== -1 ? filtervalues[filtervaluesInd] : null, $filteritem);
            return undefined;
        }

        if ($target.hasClass('group-selector') || $target.parents('span.group-selector:first').length > 0) {
            showUserFilterGroup($container, $filteritem);
        }

        if ($target.hasClass('person-selector') || $target.parents('span.person-selector:first').length > 0) {
            showUserFilterPerson($container, $filteritem);
        }
    }

    function onUserSelectorClick(evt) {
        var
          $container = null,
          $filteritem = null,
          $target = jQuery(evt.target);

        $container = $target.parents('div.advansed-filter:first');

        if ($container.length === 0) {
            return undefined;
        }

        evt.stopPropagation();
        //if ($target.is('#userSelector') || $target.hasClass('adv-userselector-deps') || $target.parents('div.adv-userselector-deps:first').length > 0) {
        //  evt.stopPropagation();
        //}
    }

    function onGroupSelectorClick(evt) {
        var
          $container = null,
          $filteritem = null,
          $target = jQuery(evt.target);

        $container = $target.parents('div.advansed-filter:first');

        if ($container.length === 0) {
            return undefined;
        }

        evt.stopPropagation();
        //if ($target.is('.groupSelectorContainer', $container) || $target.is('.filterBox') || $target.parents('div.filterBox:first').length > 0) {
        //  evt.stopPropagation();
        //}
    }

    function onFilterInputKeyup(evt) {
        if (!checkKeyCode(evt.keyCode)) {
            return;
        }

        var
          $this = jQuery(this),
          value = $this.val(),
          $container = $this.parents('div.advansed-filter:first'),
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd;

        if (!filtervalues || filtervalues.length === 0) {
            return;
        }

        filtervaluesInd = filtervalues.length;

        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].id === 'text') {
                break;
            }
        }

        if (filtervaluesInd === -1 || (!filtervalues[filtervaluesInd].params && !value)) {
            return;
        }

        if (value) {
            setFilterItem($container, null, filtervalues[filtervaluesInd], { value: value });
        } else {
            unsetFilterItem($container, null, filtervalues[filtervaluesInd]);
        }
    }

    function onFilterInputKeyupHelper(evt) {
        clearTimeout(filterInputKeyupHandler);

        filterInputKeyupHandler = setTimeout(function() {
            onFilterInputKeyup.call(evt.target, evt);
        }, filterInputKeyupTimeout);
    }

    function onFilterInputEnter(evt) {
        switch (evt.keyCode) {
            case 13:
                onFilterInputKeyup.call(evt.target, evt);
        }
    }

    function checkKeyCode(keyCode) {
        var excluded = [
            9, //tab,
            16, //shift
            17, //ctrl	
            18, //alt
            19, //pause/break
            20, //caps lock
            27, //escape
            33, //page up
            34, //page down
            35, //end
            36, //home
            37, //left arrow
            38, //up arrow
            39, //right arrow
            40, //down arrow
            44, //print
            45, //insert
            91, //left window key
            92, //right window key
            93, //select key
            112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, //f1-f12
            144, //num lock
            145 //scroll lock
        ];

        return !excluded.includes(keyCode);
    }

    function onStartFilter(evt) {
        var
          $this = jQuery(this),
          $container = $this.parents('div.advansed-filter:first'),
          value = $container.find('input.advansed-filter-input:first').val(),
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd = 0;

        if (!filtervalues || filtervalues.length === 0) {
            return undefined;
        }

        filtervaluesInd = filtervalues.length;
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].id === 'text') {
                break;
            }
        }

        if (filtervaluesInd !== -1) {
            if (typeof value === 'string' && value.length > 0) {
                setFilterItem($container, null, filtervalues[filtervaluesInd], { value: value });
            } else {
                unsetFilterItem($container, null, filtervalues[filtervaluesInd]);
            }
        }
    }

    function onResetFilter(evt) {
        var
          $container = jQuery(this).parents('div.advansed-filter:first'),
          filtervalues = $container.data('filtervalues'),
          sortervalues = $container.data('sortervalues'),
          filtervaluesInd = 0,
          filtervalue = null,
          sorterfilter = null,
          $filters = $container.find('div.filter-item'),
          $filter = null,
          filtersInd = 0,
          wasRemover = false;

        lazyTrigger = true;
        $container.removeClass('has-filters')
          .find('div.advansed-filter-input:first').removeClass('has-value')
            .find('input.advansed-filter-input:first').val('');
        filtervaluesInd = filtervalues ? filtervalues.length : 0;
        while (filtervaluesInd--) {
            filtervalue = filtervalues[filtervaluesInd];
            if (filtervalue.id === 'text' && filtervalue.isset === true) {
                wasRemover = true;
                unsetFilterItem($container, null, filtervalue);
            }
            if (filtervalue.id === 'sorter') {
                sorterfilter = filtervalue;
            }
        }

        filtersInd = $filters.length;
        while (filtersInd--) {
            wasRemover = true;
            $filter = jQuery($filters[filtersInd]);
            removeUserFilterByObject($container, $filter, true);
        }

        // TODO: add reset sorter

        lazyTrigger = false;
        if (wasRemover === true) {
            callSetFilterTrigger($container, null, true);
        }
    }

    function onChangeHash(opts, $container, hash) {
        if (currentHash !== hash) {
            readLastState(opts, $container, undefined, true);
        }
    }
    /* </callbacks> */

    function readLastState(opts, $container, nonetrigger, clearAndRestore) {
        var
          containerfiltervalues = $container.length > 0 ? $container.data('filtervalues') || [] : [],
          filtervalues = getLocalStorageFilters(opts, $container);

        if (clearAndRestore === true) {
            var
              containerfiltervalueId = null,
              containerfiltervalue = null,
              containerfiltervaluesInd = 0,
              filtervaluesInd = 0;
            containerfiltervaluesInd = containerfiltervalues.length;
            while (containerfiltervaluesInd--) {
                containerfiltervalue = containerfiltervalues[containerfiltervaluesInd];
                containerfiltervalueId = containerfiltervalue.id;
                filtervaluesInd = filtervalues.length;
                while (filtervaluesInd--) {
                    if (filtervalues[filtervaluesInd].id == containerfiltervalueId) {
                        break;
                    }
                }
                if (filtervaluesInd === -1) {
                    filtervalues.push({
                        id: containerfiltervalue.id,
                        type: containerfiltervalue.type,
                        reset: true
                    });
                }
            }
        }

        if (filtervalues.length > 0) {
            initAdvansedFilter(null, $container, filtervalues, null, nonetrigger);
        }
    }

    function initAdvansedFilter(opts, $this, filtervalues, sortervalues, nonetrigger) {
        var
          wasCallTrigger = false,
          changeSorter = false,
          changeOptions = false,
          wasAdded = false,
          $container = $this.filter(':first'),
          containerfiltervalues = $container.length > 0 ? $container.data('filtervalues') || [] : [],
          containersortervalues = $container.length > 0 ? $container.data('sortervalues') || [] : [],
          containerfiltervaluesInd = 0,
          containersortervaluesInd = 0,
          filtervalue = null,
          sortervalue = null;

        changeOptions = false;
        if (opts) {
            if (!$container.hasClass('no-button') && opts.hasButton === false || $container.hasClass('no-button') && (typeof (opts.hasButton) == 'undefined' || opts.hasButton === true)) {
                changeOptions = true;
            }
            $container[opts.hasButton === false ? 'addClass' : 'removeClass']('no-button');
        }

        // d'ohhh
        if (sortervalues === null) {
            sortervalues = [];
            var filtervaluesInd = filtervalues.length;
            while (filtervaluesInd--) {
                if (filtervalues[filtervaluesInd].id === 'sorter' && filtervalues[filtervaluesInd].params) {
                    filtervalue = filtervalues[filtervaluesInd];
                    sortervalue = { id: filtervalue.params.id, title: filtervalue.params.title, dsc: filtervalue.params.dsc, sortOrder: filtervalue.params.sortOrder, selected: filtervalue.selected === true };
                    sortervalues.push(sortervalue);
                    break;
                }
            }
        }

        opts = opts || {};
        lazyTrigger = true;
        wasCallTrigger = false;

        changeSorter = false;
        var selItem = sortervalues.find(function(item) { return item.selected });
        for (var i = 0, n = sortervalues.length; i < n; i++) {
            sortervalue = sortervalues[i];
            if (sortervalue.visible === true) {
                enableUserSorter($container, sortervalue.id, true);
            }
            if (sortervalue.visible === false) {
                if (disableUserSorter($container, sortervalue.id, true)) {
                    changeSorter = true;
                }
            }
            if (sortervalue.selected === true) {
                //containersortervaluesInd = containersortervalues.length;
                //while (containersortervaluesInd--) {
                //  if (sortervalue.id == containersortervalues[containersortervaluesInd].id) {
                //    break;
                //  }
                //}
                //if (containersortervaluesInd !== -1) {
                //  extendItemValue(sortervalue, containersortervalues[containerfiltervaluesInd]);
                //}
                if (setUserSorter($container, sortervalue.id, { dsc: sortervalue.dsc === true || sortervalue.sortOrder === 'descending' }, true)) {
                    changeSorter = true;
                    break;
                }
            }
            if (!selItem && sortervalue.def === true) {
                setUserSorter($container, sortervalue.id, { dsc: sortervalue.dsc === true || sortervalue.sortOrder === 'descending' }, true);
                //break;
            }
        }

        var $availablesorteritems = $container.find('li.item-item.sorter-item').not('.hidden-item');
        if ($availablesorteritems.length === 1) {
            $container.find('.advansed-filter-sort-container:first').addClass('sorter-nochange');
        }

        wasAdded = false;
        
        var $filterItems = $container.find('li.item-item.filter-item');
        var $selectedFilters = $container.find('div.advansed-filter-filters:first div.filter-item');
        for (var i = 0, n = filtervalues.length; i < n; i++) {
            filtervalue = filtervalues[i];

            var $filterItem, $selectedfilterItem;
            if (filtervalue.hasOwnProperty("visible") || filtervalue.hasOwnProperty("enable") ||
                filtervalue.hasOwnProperty("reset") || filtervalue.hasOwnProperty('params')) {
                $filterItem = $filterItems.filter('[data-id="' + filtervalue.id + '"]');
                $selectedfilterItem = $selectedFilters.filter('[data-id="' + filtervalue.id + '"]');
            }

            if (filtervalue.visible === true) {
                showUserFilterByOption($filterItem);
            } else if (filtervalue.visible === false) {
                if (hideUserFilterByOption($container, $selectedfilterItem, $filterItem, true)) {
                    wasAdded = true;
                }
            }

            if (filtervalue.enable === true) {
                enableUserFilterByOption($filterItem);
            } else if (filtervalue.enable === false) {
                if (disableUserFilterByOption($container, $selectedfilterItem, $filterItem, true)) {
                    wasAdded = true;
                }
            }

            if (filtervalue.type === 'combobox' && filtervalue.hasOwnProperty('options')) {
                containerfiltervaluesInd = containerfiltervalues.length;
                while (containerfiltervaluesInd--) {
                    if (filtervalue.id === containerfiltervalues[containerfiltervaluesInd].id) {
                        break;
                    }
                }
                if (containerfiltervaluesInd !== -1) {
                    var containerfiltervalue = containerfiltervalues[containerfiltervaluesInd];
                    containerfiltervalue.options = filtervalue.options.slice(0);
                    // d'ohhh
                    var defaultvalue = '-1',
                        defaulttitle = null;

                    defaultvalue = typeof filtervalue.defaultvalue === 'string' && filtervalue.defaultvalue.length > 0 ? filtervalue.defaultvalue : defaultvalue;
                    defaulttitle = typeof filtervalue.defaulttitle === 'string' && filtervalue.defaulttitle.length > 0 ? filtervalue.defaulttitle : defaulttitle;
                    defaulttitle = typeof containerfiltervalue.defaulttitle === 'string' && containerfiltervalue.defaulttitle.length > 0 ? containerfiltervalue.defaulttitle : defaulttitle;
                    if (defaulttitle) {
                        containerfiltervalue.options.unshift({ value: defaultvalue, classname: 'default-value', title: defaulttitle, def: true });
                    }
                }
            }

            if (filtervalue.visible !== false && filtervalue.hasOwnProperty('params') && filtervalue.params) {
                containerfiltervaluesInd = containerfiltervalues.length;
                while (containerfiltervaluesInd--) {
                    if (filtervalue.id !== 'sorter' && filtervalue.id == containerfiltervalues[containerfiltervaluesInd].id) {
                        break;
                    }
                }
                if (containerfiltervaluesInd !== -1) {
                    if (addUserFilter($container, containerfiltervalues[containerfiltervaluesInd], filtervalue.params, true)) {
                        wasAdded = true;
                    }
                }
            }

            if (filtervalue.reset === true || (filtervalue.hasOwnProperty('params') && filtervalue.params === null)) {
                if (resetUserFilterByOption($container, $selectedfilterItem, true)) {
                    wasAdded = true;
                }
            }
        }

        if (filtervalue.hasOwnProperty("visible") || filtervalue.hasOwnProperty("enable")) {
            updateFiltersList($container);
        }

        if (opts.store === true) {
            if (!$container.hasClass('is-init')) {
                readLastState(opts, $container, true);
                if (opts.inhash === true) {
                    try {
                        ASC.Controls.AnchorController.bind((function (opts, $container) {
                            return function (hash) {
                                onChangeHash(opts, $container, hash);
                            };
                        })(opts, $container));
                    } catch (err) { }
                }
            }
        }
        lazyTrigger = false;

        if (!$container.hasClass('is-init')) {

            if (nonetrigger !== true) {
                resizeContainer($container);
                $container.addClass('is-init');
                callSetFilterTrigger($container);
                wasCallTrigger = true;
            }
        }

        if (changeOptions == true) {
            onBodyClick(true);
            resizeUserFilterContainer($container);
        }
        if (nonetrigger !== true && wasCallTrigger !== true && (wasAdded === true || changeSorter === true)) {
            wasCallTrigger = true;
            callSetFilterTrigger($container);
        }
        $container.trigger('adv-ready', [$container, opts, nonetrigger]);
    }

    function setAdvansedFilter($this, id, params) {
        var
          $container = $this.filter(':first'),
          containerfiltervalues = $container.length > 0 ? $container.data('filtervalues') || [] : [],
          containerfiltervaluesInd = 0;

        containerfiltervaluesInd = containerfiltervalues.length;
        while (containerfiltervaluesInd--) {
            if (id == containerfiltervalues[containerfiltervaluesInd].id) {
                break;
            }
        }
        if (containerfiltervaluesInd !== -1) {
            setFilterItem($container, null, containerfiltervalues[containerfiltervaluesInd], params);
        }
    }

    function getAdvansedFilter($this) {
        var
          $container = $this.filter(':first'),
          $filters = null,
          filterid = null,
          filtervalue = null,
          filtervalues = $container.data('filtervalues'),
          filtervaluesInd = 0,
          selectedfilters = [];

        if (!filtervalues || filtervalues.length === 0) {
            return selectedfilters;
        }

        updateTextFilter($container, true);

        filtervaluesInd = filtervalues.length;
        while (filtervaluesInd--) {
            if (filtervalues[filtervaluesInd].isset === true) {
                selectedfilters.unshift(filtervalues[filtervaluesInd]);
            }
        }

        return selectedfilters;
    };

    function clearAdvansedFilter($this) {
        var
          wasRemover = false,
          $container = $this.filter(':first'),
          filtervalues = $container.length > 0 ? $container.data('filtervalues') || [] : [],
          $filters = $container.find('div.advansed-filter-filters:first div.filter-item'),
          $filter = null,
          filtersInd = 0,
          filtervaluesInd = 0;

        lazyTrigger = true;
        $container.removeClass('has-filters')
          .find('div.advansed-filter-input:first').removeClass('has-value')
            .find('input.advansed-filter-input:first').val('');
        filtervaluesInd = filtervalues ? filtervalues.length : 0;
        while (filtervaluesInd--) {
            filtervalue = filtervalues[filtervaluesInd];
            if (filtervalue.id === 'text' && filtervalue.isset === true) {
                wasRemover = true;
                $container.find('input.advansed-filter-input:first').val('');
                unsetFilterItem($container, null, filtervalue);
            }
        }
        filtersInd = $filters.length;
        while (filtersInd--) {
            wasRemover = true;
            $filter = jQuery($filters[filtersInd]);
            removeUserFilterByObject($container, $filter, true);
        }
        lazyTrigger = false;
        if (wasRemover === true) {
            callSetFilterTrigger($container);
        }
    };


    function initHint($container, hintHtml) {
        var popupId = Math.floor(Math.random() * 1000000);
        $container.find('div.advansed-filter-hint-popup:first').attr('id', popupId).html(hintHtml);

        $container.addClass('has-hint').find('label.advansed-filter-hint:first').attr('data-popupid', popupId).click(function () {
            jQuery(this).helper({ BlockHelperID: jQuery(this).attr('data-popupid') });
            // check position
            var $hint = jQuery('#' + jQuery(this).attr('data-popupid')),
            top = $hint.offset().top;
            if ($hint.offset().top > $hint.outerHeight() + 20) {
                $hint.removeClass('valign-bottom').addClass('valign-top')
                .parents('div.advansed-filter-hint-popup-helper:first').removeClass('valign-bottom').addClass('valign-top')
                .find('div.cornerHelpBlock:first').removeClass('pos_bottom').addClass('pos_top');
            } else {
                $hint.removeClass('valign-top').addClass('valign-bottom')
                .parents('div.advansed-filter-hint-popup-helper:first').removeClass('valign-top').addClass('valign-bottom')
                .find('div.cornerHelpBlock:first').removeClass('pos_top').addClass('pos_bottom');
            }
        });
    };


    function updateEmptyInputs($els, filtervalues, sortervalues, opts, customdata) {
        var
          needIndex = opts.hasOwnProperty('zindex') ? opts.zindex === true : false,
          $template = null,
          $containers = $(),
          $container = null,
          elsInd = 0,
          $el = null;

        $template = $(createAdvansedFilter(filtervalues, sortervalues, opts));
        updateAdvansedFilter(opts, $template, filtervalues, sortervalues);
        setEvents($template, opts);

        customdata = customdata && typeof customdata === 'object' ? customdata : null;
        elsInd = $els.length;
        while (elsInd--) {
            $el = $($els[elsInd]).val('');
            if (($container = $el.is('div.advansed-filter') ? $el : $el.parents('div.advansed-filter:first')).length > 0) {
                if (needIndex === true) {
                    $container.css('z-index', 100 - elsInd);
                }
                continue;
            }
            $container = $template.clone(true);
            //$container.insertBefore($el).find('input.advansed-filter-complete:first').attr('id', $el.attr('id') || null);
            $container.insertBefore($el).attr('id', $el.attr('id') || null);
            $el.remove();
            $container = $container.hasClass('advansed-filter') ? $container : $container.find('div.advansed-filter:first');

            if (needIndex === true) {
                $container.css('z-index', 100 - elsInd);
            }

            $container.addClass('has-events').data('filtervalues', filtervalues).data('sortervalues', sortervalues).data('customdata', customdata).data('filteroptions', opts);

            if (opts.hasOwnProperty('help')) {
                $container.addClass('has-help').find('div.advansed-filter-helper:first')
                    .html([
                            '<label class="advansed-filter-helper-label"></label>',
                            opts.help
                    ]
                    .join(''));
            }

            if (!opts.hintDefaultDisable && opts.hasOwnProperty('hint')) {
                initHint($container, opts.hint);
            }

            $containers = $containers.add($container);
        }

        return $containers;
    }

    function updateControlInputs($els, filtervalues, sortervalues, opts, customdata) {
        var
          needIndex = opts.hasOwnProperty('zindex') ? opts.zindex === true : false,
          $containers = $(),
          $container = null,
          elsInd = 0,
          $el = null;

        customdata = customdata && typeof customdata === 'object' ? customdata : null;
        elsInd = $els.length;
        while (elsInd--) {
            $el = $($els[elsInd]).val('');
            if (($container = $el.is('div.advansed-filter') ? $el : $el.parents('div.advansed-filter:first')).length === 0) {
                continue;
            }

            if (!$container.hasClass('has-events')) {
                $container.find('input.advansed-filter:first').val('').attr('maxlength', opts.hasOwnProperty('maxlength') ? opts.maxlength : null);

                updateAdvansedFilter(opts, $container, filtervalues, sortervalues);
                setEvents($container, opts);

                if (needIndex === true) {
                    $container.css('z-index', 100 - elsInd);
                }

                $container.addClass('has-events').data('filtervalues', filtervalues).data('sortervalues', sortervalues).data('customdata', customdata).data('filteroptions', opts);
                if (opts.hasOwnProperty('help')) {
                    $container.addClass('has-help').find('div.advansed-filter-helper:first')
                    .html([
                            '<label class="advansed-filter-helper-label"></label>',
                            opts.help
                    ]
                    .join(''));
                }

                if (!opts.hintDefaultDisable && opts.hasOwnProperty('hint')) {
                    initHint($container, opts.hint);
                }
            }
            $containers = $containers.add($container);
        }
        return $containers;
    }

    $.fn.advansedFilter = $.fn.advansedfilter = function (opts) {
        if (arguments.length === 0) {
            return getAdvansedFilter($(this));
        }

        //if (arguments.length === 2) {
        //  return setAdvansedFilter($(this), arguments[0], arguments[1]);
        //}

        if (opts === null) {
            return clearAdvansedFilter($(this));
        }

        if (opts && typeof opts === 'string') {
            var
              cmd = opts,
              $container = $(this).filter(':first');

            switch (cmd) {
                case 'sort':
                    toggleSorterBlock($container, arguments.length > 1 ? arguments[1] === true : true);

                    resizeUserSorterContainer($container);
                    resizeContainer($container);
                    resizeUserFilterContainer($container);
                    return undefined;
                case 'filters':
                    return getContainerFilters($container);
                case 'hash':
                    return getStorageHash($container);
                case 'storage':
                    return getLocalStorageFilters();
                case 'resetText':
                    return resetTextFilter($container);
                case 'resize':
                    if ($container.is(":visible")) {
                        onBodyClick();
                        resizeUserSorterContainer($container);
                        resizeContainer($container);
                        resizeUserFilterContainer($container);
                     }
                    return undefined;
                default:
                    return setAdvansedFilter($container, arguments[0], arguments[1]);
            }
            return undefined;
        }

        var
          customdata = null,
          colcount = 1,
          opts = opts && typeof opts === 'object' ? opts : {},
          filtervalues = opts.hasOwnProperty('filters') ? opts.filters : [],
          sortervalues = opts.hasOwnProperty('sorters') ? opts.sorters : [],
          resources = opts.hasOwnProperty('resources') ? opts.resources : {},
          maxfilters = opts.hasOwnProperty('maxfilters') ? isFinite(+opts.maxfilters) && +opts.maxfilters >= -1 ? +opts.maxfilters : -1 : -1,
          $containers = null,
          $this = $(this);

        if ($this.length === 0) {
            return $this;
        }

        for (var fld in resources) {
            if (resources.hasOwnProperty(fld)) {
                Resources[fld] = resources[fld];
            }
        }

        opts.colcount = opts.hasOwnProperty('colcount') && isFinite(+opts.colcount) ? +opts.colcount : colcount;
        opts.colcount = opts.colcount > 4 ? 4 : opts.colcount;

        if (!opts.hintDefaultDisable && ASC.Resources.Master.FilterHelpCenterLink) {
        opts.hint = opts.hasOwnProperty('hint') ? opts.hint : ASC.Resources.Master.ResourceJS.AdvansedFilterInfoText.format(
                                '<b>',
                                '</b>',
                                '<br/><br/><a href="' + ASC.Resources.Master.FilterHelpCenterLink + '" target="_blank">',
                                '</a>');
        }

        customdata = { maxfilters: maxfilters };
        filtervalues = extendItemValues(filtervalues, jQuery.parseJSON(jQuery.toJSON(filterValues)));
        sortervalues = extendItemValues(sortervalues, jQuery.parseJSON(jQuery.toJSON(sorterValues)));

        if (($containers = updateControlInputs($this, filtervalues, sortervalues, opts, customdata)).length === $this.length) {
            addReadyEvent(initAdvansedFilter, [opts, $containers, filtervalues, sortervalues, opts.nonetrigger]);
            return $containers;
        }
        $containers = updateEmptyInputs($this, filtervalues, sortervalues, opts, customdata);
        addReadyEvent(initAdvansedFilter, [opts, $containers, filtervalues, sortervalues, opts.nonetrigger]);
        return $containers;
    };
})(jQuery, window, document, document.body);


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SMTP/Server/old/SmtpServerReply.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace LumiSoft.Net.SMTP.Server
{
	/// <summary>
	/// SMTP server reply info. This class specifies smtp reply what is returned to connected client.
	/// </summary>
	public class SmtpServerReply
	{
		private bool   m_ErrorReply    = false;
		private int    m_SmtpReplyCode = -1;
		private string m_ReplyText     = "";

		/// <summary>
		/// Default consttuctor.
		/// </summary>
		public SmtpServerReply()
		{
		}


		#region method ToSmtpReply

		internal string ToSmtpReply(string defaultSmtpRelyCode,string defaultReplyText)
		{
			string replyText = "";
			if(this.SmtpReplyCode == -1){
				replyText = defaultSmtpRelyCode + " ";
			}
			else{
				replyText = this.SmtpReplyCode.ToString() + " ";
			}

			if(this.ReplyText == ""){
				replyText += defaultReplyText;
			}
			else{
				replyText += this.ReplyText;
			}

			return replyText;
		}

		#endregion


		#region Properties Implementation

		/// <summary>
		/// Gets or sets if CustomReply is error or ok reply.
		/// </summary>
		public bool ErrorReply
		{
			get{ return m_ErrorReply; }

			set{ m_ErrorReply = value; }
		}

		/// <summary>
		/// Gets or sets SMTP reply code (250,500,500, ...). Value -1 means that SMTP reply code isn't specified and server uses it's defult error code. 
		/// </summary>
		public int SmtpReplyCode
		{
			get{ return m_SmtpReplyCode; }

			set{ m_SmtpReplyCode = value; }
		}

		/// <summary>
		/// Gets or sets reply text what is shown to connected client. 
		/// Note: Maximum lenth of reply text is 500 chars and text can contain only ASCII chars 
		/// without CR or LF.  
		/// </summary>
		public string ReplyText
		{
			get{ return m_ReplyText; }

			set{				
				if(!Core.IsAscii(value)){
					throw new Exception("Reply text can contian only ASCII chars !");
				}
				if(value.Length > 500){
					value = value.Substring(0,500);
				}
				value = value.Replace("\r","").Replace("\n","");

				m_ReplyText = value;
			}
		}

		#endregion

	}
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Services/NotifyService/NotifyConstants.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using ASC.Notify.Model;

#endregion

namespace ASC.Projects.Core.Services.NotifyService
{
    public static class NotifyConstants
    {
        public static INotifyAction Event_NewCommentForMessage = new NotifyAction("NewCommentForMessage", "new comment for message");
        public static INotifyAction Event_EditedCommentForMessage = new NotifyAction("EditedCommentForMessage", "Edited comment for message");

        public static INotifyAction Event_NewCommentForTask = new NotifyAction("NewCommentForTask", "new comment for task");
        public static INotifyAction Event_EditedCommentForTask = new NotifyAction("EditedCommentForTask", "Edited comment for task");

        public static INotifyAction Event_NewFileForDiscussion = new NotifyAction("NewFileForDiscussion", "new file for discussion");
        public static INotifyAction Event_NewFileForTask = new NotifyAction("NewFileForTask", "new file for task");

        public static INotifyAction Event_TaskEdited = new NotifyAction("TaskEdited", "task edited");
        public static INotifyAction Event_TaskClosed = new NotifyAction("TaskClosed", "task closed");
        public static INotifyAction Event_TaskCreated = new NotifyAction("TaskCreated", "task created");
        public static INotifyAction Event_TaskDeleted = new NotifyAction("TaskDeleted", "task deleted");
        public static INotifyAction Event_TaskResumed = new NotifyAction("TaskResumed", "task resumed");
        public static INotifyAction Event_TaskMovedToMilestone = new NotifyAction("TaskMovedToMilestone", "task moved to milestone");
        public static INotifyAction Event_TaskMovedFromMilestone = new NotifyAction("TaskMovedFromMilestone", "task moved from milestone");
        public static INotifyAction Event_MilestoneDeadline = new NotifyAction("MilestoneDeadline", "milestone deadline");
        public static INotifyAction Event_ResponsibleForProject = new NotifyAction("ResponsibleForProject", "responsible for project");
        public static INotifyAction Event_ResponsibleForTask = new NotifyAction("ResponsibleForTask", "responsible for task");
        public static INotifyAction Event_RemoveResponsibleForTask = new NotifyAction("RemoveResponsibleForTask", "remove responsible for task");
        public static INotifyAction Event_ReminderAboutTask = new NotifyAction("ReminderAboutTask", "reminder about task");
        public static INotifyAction Event_ReminderAboutTaskDeadline = new NotifyAction("ReminderAboutTaskDeadline", "reminder about task deadline");
        public static INotifyAction Event_InviteToProject = new NotifyAction("InviteToProject", "invite to project");
        public static INotifyAction Event_RemoveFromProject = new NotifyAction("RemoveFromProject", "remove from project");

        public static INotifyAction Event_MilestoneCreated = new NotifyAction("MilestoneCreated", "milestone created");
        public static INotifyAction Event_MilestoneEdited = new NotifyAction("MilestoneEdited", "milestone edited");
        public static INotifyAction Event_MilestoneClosed = new NotifyAction("MilestoneClosed", "milestone closed");
        public static INotifyAction Event_MilestoneDeleted = new NotifyAction("MilestoneDeleted", "milestone deleted");
        public static INotifyAction Event_MilestoneResumed = new NotifyAction("MilestoneResumed", "milestone resumed");
        public static INotifyAction Event_ResponsibleForMilestone = new NotifyAction("ResponsibleForMilestone", "responsible for milestone");

        public static INotifyAction Event_MessageCreated = new NotifyAction("NewMessage", "message created");
        public static INotifyAction Event_MessageEdited = new NotifyAction("EditMessage", "message edited");
        public static INotifyAction Event_MessageDeleted = new NotifyAction("MessageDeleted", "message deleted");

        public static INotifyAction Event_ImportData = new NotifyAction("ImportData", "import data");

        public static INotifyAction Event_ResponsibleForSubTask = new NotifyAction("ResponsibleForSubTask", "responsible for subtask");
        public static INotifyAction Event_SubTaskCreated = new NotifyAction("SubTaskCreated", "subtask created");
        public static INotifyAction Event_SubTaskEdited = new NotifyAction("SubTaskEdited", "subtask edited");
        public static INotifyAction Event_SubTaskResumed = new NotifyAction("SubTaskResumed", "subtask resumed");
        public static INotifyAction Event_SubTaskClosed = new NotifyAction("SubTaskClosed", "subtask closed");
        public static INotifyAction Event_SubTaskDeleted = new NotifyAction("SubTaskDeleted", "subtask deleted");

        public static INotifyAction Event_ProjectDeleted = new NotifyAction("ProjectDeleted", "project deleted");

        public static string Tag_ProjectTitle = "ProjectTitle";
        public static string Tag_ProjectID = "ProjectID";
        public static string Tag_AdditionalData = "AdditionalData";
        public static string Tag_EntityID = "EntityID";
        public static string Tag_EntityTitle = "EntityTitle";
        public static string Tag_SubEntityTitle = "SubEntityTitle";
        public static string Tag_EventType = "EventType";
        public static string Tag_Responsible = "Responsible";
        public static string Tag_Priority = "Priority";
        public static string Tag_CommentID = "CommentID";
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Test/BaseTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Web.Core;
using ASC.Web.Projects.Core;

using Autofac;

using NUnit.Framework;

namespace ASC.Web.Projects.Test
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using ASC.Core;
    using ASC.Projects.Core.Domain;
    using ASC.Projects.Engine;

    [TestFixture]
    public class BaseTest
    {
        protected ILifetimeScope Scope { get; set; }
        protected TagEngine TagEngine { get; set; }
        protected TaskEngine TaskEngine { get; set; }
        protected SubtaskEngine SubtaskEngine { get; set; }
        protected MilestoneEngine MilestoneEngine { get; set; }
        protected MessageEngine MessageEngine { get; set; }
        protected TimeTrackingEngine TimeTrackingEngine { get; set; }
        protected ProjectEngine ProjectEngine { get; set; }
        protected ParticipantEngine ParticipantEngine { get; set; }
        protected DataGenerator DataGenerator { get; set; }

        private Project Project { get; set; }

        public static Guid UserInTeam = new Guid("809a74fd-2f52-4284-a267-f512fb60ce9e");
        public static Guid ProjectManager = new Guid("8a911318-129e-48b0-8414-04f49b308a9c");
        public static Guid UserNotInTeam = new Guid("ce90d596-9c6c-490f-b538-e8d3ccc12a72");
        public static Guid Guest = new Guid("f4381b0a-694a-4ab7-bfdb-6a6d25df65f8");
        public static Guid Admin = new Guid("f412903b-9601-42e9-91f2-1bd31f6da9e3");
        public static Guid Owner = new Guid("23f101b0-bc41-11e8-b696-9cb6d0fc71d8");

        [OneTimeSetUp]
        public void Init()
        {
            WebItemManager.Instance.LoadItems();

            CoreContext.TenantManager.SetCurrentTenant(CoreContext.TenantManager.GetTenants().First());
            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            SecurityContext.AuthenticateMe(tenant.OwnerId);

            Scope = DIHelper.Resolve(true);

            var engineFactory = Scope.Resolve<EngineFactory>();
            Scope.Resolve<ProjectSecurity>();
            ProjectEngine = engineFactory.ProjectEngine;
            ParticipantEngine = engineFactory.ParticipantEngine;
            TaskEngine = engineFactory.TaskEngine;
            SubtaskEngine = engineFactory.SubtaskEngine;
            MilestoneEngine = engineFactory.MilestoneEngine;
            MessageEngine = engineFactory.MessageEngine;
            TimeTrackingEngine = engineFactory.TimeTrackingEngine;
            TagEngine = engineFactory.TagEngine;
            DataGenerator = new DataGenerator();

            var team = new List<Guid>(2) { ProjectManager, UserInTeam, Guest };

            Project = SaveOrUpdate(GenerateProject(ProjectManager));
            AddTeamToProject(Project, team);
        }

        [OneTimeTearDown]
        public void Cleanup()
        {
            Delete(Project);

            if (Scope != null)
            {
                Scope.Dispose();
            }
        }

        protected Project GenerateProject(Guid userId)
        {
            return DataGenerator.GenerateProject(userId);
        }

        protected Project SaveOrUpdate(Project project)
        {
            return ProjectEngine.SaveOrUpdate(project, false);
        }

        protected Project Get(Project project)
        {
            return ProjectEngine.GetByID(project.ID);
        }

        protected void AddTeamToProject(Project project, List<Guid> team)
        {
            foreach (var user in team.Select(r => ParticipantEngine.GetByID(r)))
            {
                ProjectEngine.AddToTeam(project, user, false);
            }
        }

        protected List<Guid> GetTeam(int projectId)
        {
            return ProjectEngine.GetTeam(projectId).Select(r => r.ID).ToList();
        }

        protected void Delete(Project project)
        {
            ProjectEngine.Delete(project.ID);
        }


        protected Task GenerateTask()
        {
            return DataGenerator.GenerateTask(Project);
        }

        protected Task SaveOrUpdate(Task task)
        {
            return TaskEngine.SaveOrUpdate(task, new List<int>(), false);
        }

        protected Task Get(Task task)
        {
            return TaskEngine.GetByID(task.ID);
        }

        protected void Delete(Task task)
        {
            TaskEngine.Delete(task);
        }

        protected Milestone GenerateMilestone()
        {
            return DataGenerator.GenerateMilestone(Project);
        }

        protected Milestone SaveOrUpdate(Milestone milestone)
        {
            return MilestoneEngine.SaveOrUpdate(milestone);
        }

        protected Milestone Get(Milestone milestone)
        {
            return MilestoneEngine.GetByID(milestone.ID);
        }

        protected void Delete(Milestone milestone)
        {
            MilestoneEngine.Delete(milestone);
        }


        protected Message GenerateMessage()
        {
            return DataGenerator.GenerateMessage(Project);
        }

        protected Message SaveOrUpdate(Message message)
        {
            return MessageEngine.SaveOrUpdate(message, false, new List<Guid>());
        }

        protected Message Get(Message message)
        {
            return MessageEngine.GetByID(message.ID);
        }

        protected void Delete(Message message)
        {
            MessageEngine.Delete(message);
        }

        protected TimeSpend GenerateTimeTracking()
        {
            var task = SaveOrUpdate(GenerateTask());
            return DataGenerator.GenerateTimeTracking(task);
        }

        protected TimeSpend SaveOrUpdate(TimeSpend timeSpend)
        {
            return TimeTrackingEngine.SaveOrUpdate(timeSpend);
        }

        protected TimeSpend Get(TimeSpend timeSpend)
        {
            return TimeTrackingEngine.GetByID(timeSpend.ID);
        }

        protected void Delete(TimeSpend timeSpend)
        {
            TimeTrackingEngine.Delete(timeSpend);
        }

        protected void ChangeProjectPrivate(bool @private)
        {
            SecurityContext.AuthenticateMe(Owner);
            Project.Private = @private;
            SaveOrUpdate(Project);
        }

        protected void ChangeProjectStatus(ProjectStatus status)
        {
            SecurityContext.AuthenticateMe(Owner);
            Project.Status = status;
            SaveOrUpdate(Project);
        }

        protected void RestrictAccess(Guid userID, ProjectTeamSecurity projectTeamSecurity, bool visible)
        {
            SecurityContext.AuthenticateMe(Owner);
            ProjectEngine.SetTeamSecurity(Project, ParticipantEngine.GetByID(userID), projectTeamSecurity, visible);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Model/Domain/Reports/ReportTemplate.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;

using ASC.Projects.Engine;
using ASC.Web.Files.Services.DocumentService;
using ASC.Web.Files.Utils;
using ASC.Web.Projects;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Projects.Core.Domain.Reports
{
    public class ReportTemplate
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public ReportType ReportType { get; private set; }

        public TaskFilter Filter { get; set; }

        public string Cron { get; set; }

        public Guid CreateBy { get; set; }

        public DateTime CreateOn { get; set; }

        public bool AutoGenerated { get; set; }

        public int Tenant { get; set; }


        public ReportTemplate(ReportType reportType)
        {
            ReportType = reportType;
            AutoGenerated = false;
        }

        public override string ToString()
        {
            return Name;
        }

        public override bool Equals(object obj)
        {
            var t = obj as ReportTemplate;
            return t != null && Id.Equals(t.Id);
        }

        public override int GetHashCode()
        {
            return Id.GetHashCode();
        }

        internal void SaveDocbuilderReport(ReportState state, string url)
        {
            var data = new System.Net.WebClient().DownloadData(url);

            using (var memStream = new MemoryStream(data))
            {
                Action<Stream> action = stream =>
                {
                    var file = FileUploader.Exec(ProjectsCommonSettings.LoadForCurrentUser().FolderId.ToString(), state.FileName, stream.Length, stream, true);
                    state.FileId = (int)file.ID;
                };

                try
                {
                    action(memStream);
                }
                catch (DirectoryNotFoundException)
                {
                    var settings = ProjectsCommonSettings.LoadForCurrentUser();
                    settings.FolderId = Web.Files.Classes.Global.FolderMy;
                    settings.SaveForCurrentUser();

                    action(memStream);
                }
            }

            using (var scope = DIHelper.Resolve())
            {
                scope.Resolve<EngineFactory>().ReportEngine.Save(new ReportFile
                {
                    FileId = state.FileId,
                    Name = Name,
                    ReportType = ReportType
                });
            }
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailCommonSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;

namespace ASC.Mail.Data.Contracts
{
    [Serializable]
    [DataContract]
    public class MailCommonSettings : BaseSettings<MailCommonSettings>
    {
        [DataMember(Name = "EnableConversations")]
        public bool EnableConversationsSetting { get; set; }

        [DataMember(Name = "AlwaysDisplayImages")]
        public bool AlwaysDisplayImagesSetting { get; set; }

        [DataMember(Name = "CacheUnreadMessages")]
        public bool CacheUnreadMessagesSetting { get; set; }

        [DataMember(Name = "EnableGoNextAfterMove")]
        public bool EnableGoNextAfterMoveSetting { get; set; }

        [DataMember(Name = "ReplaceMessageBody")]
        public bool ReplaceMessageBodySetting { get; set; }

        public override ISettings GetDefault()
        {
            return new MailCommonSettings
            {
                EnableConversationsSetting = true,
                AlwaysDisplayImagesSetting = false,
                CacheUnreadMessagesSetting = false, //TODO: Change cache algoritnm and restore it back
                EnableGoNextAfterMoveSetting = false,
                ReplaceMessageBodySetting = false
            };
        }

        public override Guid ID
        {
            get { return new Guid("{AA4E16A0-B9F5-402A-A71E-9A1EC6E6B57A}"); }
        }

        public static bool EnableConversations
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.EnableConversationsSetting = value;
                setting.SaveForCurrentUser();
            }
            get
            {
                return LoadForCurrentUser().EnableConversationsSetting;
            }
        }

        public static bool AlwaysDisplayImages
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.AlwaysDisplayImagesSetting = value;
                setting.SaveForCurrentUser();
            }
            get
            {
                return LoadForCurrentUser().AlwaysDisplayImagesSetting;
            }
        }

        public static bool CacheUnreadMessages
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.CacheUnreadMessagesSetting = value;
                setting.SaveForCurrentUser();
            }
            get
            {
                return LoadForCurrentUser().CacheUnreadMessagesSetting;
            }
        }

        public static bool GoNextAfterMove
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.EnableGoNextAfterMoveSetting = value;
                setting.SaveForCurrentUser();
            }
            get
            {
                return LoadForCurrentUser().EnableGoNextAfterMoveSetting;
            }
        }

        public static bool ReplaceMessageBody
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.ReplaceMessageBodySetting = value;
                setting.SaveForCurrentUser();
            }
            get
            {
                return LoadForCurrentUser().ReplaceMessageBodySetting;
            }
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Specific/ASCBearerAuthorization.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Net;
using System.Web;

using ASC.Api.Interfaces;
using ASC.Common.Logging;
using ASC.Core;


namespace ASC.Specific
{

    public class AscBearerAuthorization : IApiAuthorization
    {
        private readonly ILog log;


        public AscBearerAuthorization()
        {

        }

        public AscBearerAuthorization(ILog log)
        {
            this.log = log;
        }


        public bool Authorize(HttpContextBase context)
        {
            if (!SecurityContext.IsAuthenticated)
            {
                try
                {
                    var authorization = context.Request.Headers["Authorization"];
                    if (string.IsNullOrEmpty(authorization))
                    {
                        return false;
                    }
                    authorization = authorization.Trim();
                    if (authorization.IndexOf(',') != -1)
                        authorization = authorization.Substring(0, authorization.IndexOf(',')).Trim();

                    if (authorization.IndexOf("Bearer", 0, StringComparison.Ordinal) != 0)
                    {
                        return false;
                    }

                    SecurityContext.AuthenticateMe(authorization.Substring(7));
                }
                catch (Exception e)
                {
                    log.Error("ASC bearer auth error", e);
                }
            }
            return SecurityContext.IsAuthenticated;
        }

        public bool OnAuthorizationFailed(HttpContextBase context)
        {
            if (!string.IsNullOrEmpty(context.Request.Headers["Authorization"]))
            {
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                context.Response.StatusDescription = HttpStatusCode.Unauthorized.ToString();
                var realm = String.Format("Bearer Realm=\"{0}\"", context.Request.GetUrlRewriter().Host);
                context.Response.AppendHeader("WWW-Authenticate", realm);
                return true;
            }
            return false;
        }
    }
}

<|start_filename|>common/ASC.Common/Utils/MimeHeaderUtils.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Text;

namespace ASC.Common.Utils
{
    public static class MimeHeaderUtils
    {
        public static string EncodeMime(string mimeHeaderValue)
        {
            return EncodeMime(mimeHeaderValue, Encoding.UTF8, false);
        }

        public static string EncodeMime(string mimeHeaderValue, Encoding charset, bool split)
        {
            if (MustEncode(mimeHeaderValue))
            {
                var result = new StringBuilder();
                var data = charset.GetBytes(mimeHeaderValue);
                var maxEncodedTextSize = split ? 75 - ("=?" + charset.WebName + "?" + "B"/*Base64 encode*/ + "?" + "?=").Length : int.MaxValue;

                result.Append("=?" + charset.WebName + "?B?");
                var stored = 0;
                var base64 = Convert.ToBase64String(data);
                for (var i = 0; i < base64.Length; i += 4)
                {
                    // Encoding buffer full, create new encoded-word.
                    if (stored + 4 > maxEncodedTextSize)
                    {
                        result.Append("?=\r\n =?" + charset.WebName + "?B?");
                        stored = 0;
                    }

                    result.Append(base64, i, 4);
                    stored += 4;
                }
                result.Append("?=");
                return result.ToString();
            }
            return mimeHeaderValue;
        }

        public static bool MustEncode(string text)
        {
            return !string.IsNullOrEmpty(text) && text.Any(c => c > 127);
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/IMAP_BODY.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP
{
    #region usings

    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using Mime;

    #endregion

    /// <summary>
    /// IMAP BODYSTRUCTURE. Defined in RFC 3501 7.4.2.
    /// </summary>
    public class IMAP_BODY
    {
        #region Members

        private IMAP_BODY_Entity m_pMainEntity;

        #endregion

        #region Properties

        /// <summary>
        /// Gets main entity.
        /// </summary>
        public IMAP_BODY_Entity MainEntity
        {
            get { return m_pMainEntity; }
        }

        /// <summary>
        /// Gets all entities contained in BODYSTRUCTURE, including child entities.
        /// </summary>
        public IMAP_BODY_Entity[] Entities
        {
            get
            {
                List<IMAP_BODY_Entity> allEntities = new List<IMAP_BODY_Entity>();
                allEntities.Add(m_pMainEntity);
                GetEntities(m_pMainEntity.ChildEntities, allEntities);

                return allEntities.ToArray();
            }
        }

        /// <summary>
        /// Gets attachment entities. Entity is considered as attachmnet if:<p/>
        ///     *) Content-Type: name = "" is specified  (old RFC 822 message)<p/>
        /// </summary>
        public IMAP_BODY_Entity[] Attachmnets
        {
            // Cant use these at moment, we need to use extended BODYSTRUCTURE fo that    
            //     *) Content-Disposition: attachment (RFC 2822 message)<p/>
            //     *) Content-Disposition: filename = "" is specified  (RFC 2822 message)<p/>

            get
            {
                List<IMAP_BODY_Entity> attachments = new List<IMAP_BODY_Entity>();
                IMAP_BODY_Entity[] entities = Entities;
                foreach (IMAP_BODY_Entity entity in entities)
                {
                    if (entity.ContentType_Paramters != null)
                    {
                        foreach (HeaderFieldParameter parameter in entity.ContentType_Paramters)
                        {
                            if (parameter.Name.ToLower() == "name")
                            {
                                attachments.Add(entity);
                                break;
                            }
                        }
                    }
                }

                return attachments.ToArray();
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        public IMAP_BODY()
        {
            m_pMainEntity = new IMAP_BODY_Entity();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Constructs FETCH BODY and BODYSTRUCTURE response.
        /// </summary>
        /// <param name="mime">Mime message.</param>
        /// <param name="bodystructure">Specifies if to construct BODY or BODYSTRUCTURE.</param>
        /// <returns></returns>
        public static string ConstructBodyStructure(Mime mime, bool bodystructure)
        {
            if (bodystructure)
            {
                return "BODYSTRUCTURE " + ConstructParts(mime.MainEntity, bodystructure);
            }
            else
            {
                return "BODY " + ConstructParts(mime.MainEntity, bodystructure);
            }
        }

        /// <summary>
        /// Parses IMAP BODYSTRUCTURE from body structure string.
        /// </summary>
        /// <param name="bodyStructureString">Body structure string</param>
        public void Parse(string bodyStructureString)
        {
            m_pMainEntity = new IMAP_BODY_Entity();
            m_pMainEntity.Parse(bodyStructureString);
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// Constructs specified entity and it's childentities bodystructure string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <param name="bodystructure">Specifies if to construct BODY or BODYSTRUCTURE.</param>
        /// <returns></returns>
        private static string ConstructParts(MimeEntity entity, bool bodystructure)
        {
            /* RFC 3501 7.4.2 BODYSTRUCTURE
							  BODY A form of BODYSTRUCTURE without extension data.
			  
				A parenthesized list that describes the [MIME-IMB] body
				structure of a message.  This is computed by the server by
				parsing the [MIME-IMB] header fields, defaulting various fields
				as necessary.

				For example, a simple text message of 48 lines and 2279 octets
				can have a body structure of: ("TEXT" "PLAIN" ("CHARSET"
				"US-ASCII") NIL NIL "7BIT" 2279 48)

				Multiple parts are indicated by parenthesis nesting.  Instead
				of a body type as the first element of the parenthesized list,
				there is a sequence of one or more nested body structures.  The
				second element of the parenthesized list is the multipart
				subtype (mixed, digest, parallel, alternative, etc.).
					
				For example, a two part message consisting of a text and a
				BASE64-encoded text attachment can have a body structure of:
				(("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
				23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
				"<960723163407.<EMAIL>>" "Compiler diff"
				"BASE64" 4554 73) "MIXED")

				Extension data follows the multipart subtype.  Extension data
				is never returned with the BODY fetch, but can be returned with
				a BODYSTRUCTURE fetch.  Extension data, if present, MUST be in
				the defined order.  The extension data of a multipart body part
				are in the following order:

				body parameter parenthesized list
					A parenthesized list of attribute/value pairs [e.g., ("foo"
					"bar" "baz" "rag") where "bar" is the value of "foo", and
					"rag" is the value of "baz"] as defined in [MIME-IMB].

				body disposition
					A parenthesized list, consisting of a disposition type
					string, followed by a parenthesized list of disposition
					attribute/value pairs as defined in [DISPOSITION].

				body language
					A string or parenthesized list giving the body language
					value as defined in [LANGUAGE-TAGS].

				body location
					A string list giving the body content URI as defined in [LOCATION].

				Any following extension data are not yet defined in this
				version of the protocol.  Such extension data can consist of
				zero or more NILs, strings, numbers, or potentially nested
				parenthesized lists of such data.  Client implementations that
				do a BODYSTRUCTURE fetch MUST be prepared to accept such
				extension data.  Server implementations MUST NOT send such
				extension data until it has been defined by a revision of this
				protocol.

				The basic fields of a non-multipart body part are in the
				following order:

				body type
					A string giving the content media type name as defined in [MIME-IMB].
				
				body subtype
					 A string giving the content subtype name as defined in [MIME-IMB].

				body parameter parenthesized list
					A parenthesized list of attribute/value pairs [e.g., ("foo"
					"bar" "baz" "rag") where "bar" is the value of "foo" and
					"rag" is the value of "baz"] as defined in [MIME-IMB].

				body id
					A string giving the content id as defined in [MIME-IMB].

				body description
					A string giving the content description as defined in [MIME-IMB].

				body encoding
					A string giving the content transfer encoding as defined in	[MIME-IMB].

				body size
					A number giving the size of the body in octets.  Note that
					this size is the size in its transfer encoding and not the
					resulting size after any decoding.

				A body type of type MESSAGE and subtype RFC822 contains,
				immediately after the basic fields, the envelope structure,
				body structure, and size in text lines of the encapsulated
				message.

				A body type of type TEXT contains, immediately after the basic
				fields, the size of the body in text lines.  Note that this
				size is the size in its content transfer encoding and not the
				resulting size after any decoding.

				Extension data follows the basic fields and the type-specific
				fields listed above.  Extension data is never returned with the
				BODY fetch, but can be returned with a BODYSTRUCTURE fetch.
				Extension data, if present, MUST be in the defined order.

				The extension data of a non-multipart body part are in the
				following order:

				body MD5
					A string giving the body MD5 value as defined in [MD5].
					
				body disposition
					A parenthesized list with the same content and function as
					the body disposition for a multipart body part.

				body language
					A string or parenthesized list giving the body language
					value as defined in [LANGUAGE-TAGS].

				body location
					A string list giving the body content URI as defined in [LOCATION].

				Any following extension data are not yet defined in this
				version of the protocol, and would be as described above under
				multipart extension data.
			
			
				// We don't construct extention fields like rfc says:
					Server implementations MUST NOT send such
					extension data until it has been defined by a revision of this
					protocol.
			
										
				contentTypeMainMediaType - Example: 'TEXT'
				contentTypeSubMediaType  - Example: 'PLAIN'
				conentTypeParameters     - Example: '("CHARSET" "iso-8859-1" ...)'
				contentID                - Content-ID: header field value.
				contentDescription       - Content-Description: header field value.
				contentEncoding          - Content-Transfer-Encoding: header field value.
				contentSize              - mimeEntity ENCODED data size
				[envelope]               - NOTE: included only if contentType = "message" !!!
				[contentLines]           - number of ENCODED data lines. NOTE: included only if contentType = "text" !!!
									   			
				// Basic fields for multipart
				(nestedMimeEntries) contentTypeSubMediaType
												
				// Basic fields for non-multipart
				contentTypeMainMediaType contentTypeSubMediaType (conentTypeParameters) contentID contentDescription contentEncoding contentSize [envelope] [contentLine]

			*/

            StringBuilder retVal = new StringBuilder();
            // Multipart message
            if ((entity.ContentType & MediaType_enum.Multipart) != 0)
            {
                retVal.Append("(");

                // Construct child entities.
                foreach (MimeEntity childEntity in entity.ChildEntities)
                {
                    // Construct child entity. This can be multipart or non multipart.
                    retVal.Append(ConstructParts(childEntity, bodystructure));
                }

                // Add contentTypeSubMediaType
                string contentType = entity.ContentTypeString.Split(';')[0];
                if (contentType.Split('/').Length == 2)
                {
                    retVal.Append(" \"" + contentType.Split('/')[1].Replace(";", "") + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                retVal.Append(")");
            }
                // Single part message
            else
            {
                retVal.Append("(");

                // NOTE: all header fields and parameters must in ENCODED form !!!

                // Add contentTypeMainMediaType
                if (entity.ContentTypeString != null)
                {
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if (contentType.Split('/').Length == 2)
                    {
                        retVal.Append("\"" + entity.ContentTypeString.Split('/')[0] + "\"");
                    }
                    else
                    {
                        retVal.Append("NIL");
                    }
                }
                else
                {
                    retVal.Append("NIL");
                }

                // contentTypeSubMediaType
                if (entity.ContentTypeString != null)
                {
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if (contentType.Split('/').Length == 2)
                    {
                        retVal.Append(" \"" + contentType.Split('/')[1].Replace(";", "") + "\"");
                    }
                    else
                    {
                        retVal.Append(" NIL");
                    }
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // conentTypeParameters - Syntax: {("name" SP "value" *(SP "name" SP "value"))}
                if (entity.ContentTypeString != null)
                {
                    ParametizedHeaderField contentTypeParameters =
                        new ParametizedHeaderField(entity.Header.GetFirst("Content-Type:"));
                    if (contentTypeParameters.Parameters.Count > 0)
                    {
                        retVal.Append(" (");

                        bool first = true;
                        foreach (HeaderFieldParameter param in contentTypeParameters.Parameters)
                        {
                            // For first item, don't add SP
                            if (!first)
                            {
                                retVal.Append(" ");
                            }
                            else
                            {
                                // Clear first flag
                                first = false;
                            }

                            retVal.Append("\"" + param.Name + "\" \"" +
                                          MimeUtils.EncodeHeaderField(param.Value) + "\"");
                        }

                        retVal.Append(")");
                    }
                    else
                    {
                        retVal.Append(" NIL");
                    }
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentID
                string contentID = entity.ContentID;
                if (contentID != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentID) + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentDescription
                string contentDescription = entity.ContentDescription;
                if (contentDescription != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentDescription) + "\"");
                }
                else
                {
                    retVal.Append(" NIL");
                }

                // contentEncoding
                HeaderField contentEncoding = entity.Header.GetFirst("Content-Transfer-Encoding:");
                if (contentEncoding != null)
                {
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentEncoding.Value) + "\"");
                }
                else
                {
                    // If not specified, then must be 7bit.
                    retVal.Append(" \"7bit\"");
                }

                // contentSize
                if (entity.DataEncoded != null)
                {
                    retVal.Append(" " + entity.DataEncoded.Length);
                }
                else
                {
                    retVal.Append(" 0");
                }

                // envelope ---> FOR ContentType: message/rfc822 ONLY ###
                if ((entity.ContentType & MediaType_enum.Message_rfc822) != 0)
                {
                    retVal.Append(" " + IMAP_Envelope.ConstructEnvelope(entity));

                    // TODO: BODYSTRUCTURE,LINES
                }

                // contentLines ---> FOR ContentType: text/xxx ONLY ###
                if ((entity.ContentType & MediaType_enum.Text) != 0)
                {
                    if (entity.DataEncoded != null)
                    {
                        long lineCount = 0;
                        StreamLineReader r = new StreamLineReader(new MemoryStream(entity.DataEncoded));
                        byte[] line = r.ReadLine();
                        while (line != null)
                        {
                            lineCount++;

                            line = r.ReadLine();
                        }

                        retVal.Append(" " + lineCount);
                    }
                    else
                    {
                        retVal.Append(" 0");
                    }
                }

                retVal.Append(")");
            }

            return retVal.ToString();
        }

        /// <summary>
        /// Gets mime entities, including nested entries. 
        /// </summary>
        /// <param name="entities"></param>
        /// <param name="allEntries"></param>
        private void GetEntities(IMAP_BODY_Entity[] entities, List<IMAP_BODY_Entity> allEntries)
        {
            if (entities != null)
            {
                foreach (IMAP_BODY_Entity ent in entities)
                {
                    allEntries.Add(ent);

                    // Add child entities, if any
                    if (ent.ChildEntities.Length > 0)
                    {
                        GetEntities(ent.ChildEntities, allEntries);
                    }
                }
            }
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/Multilang/IMLangStringWStr.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#pragma warning disable 0108

namespace MultiLanguage
{
    using System;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Security;

    [ComImport, InterfaceType((short) 1), ComConversionLoss, Guid("C04D65D0-B70D-11D0-B188-00AA0038C969")]
    public interface IMLangStringWStr : IMLangString
    {
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void Sync([In] int fNoAccess);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        int GetLength();
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void SetMLStr([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pSrcMLStr, [In] int lSrcPos, [In] int lSrcLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void GetMLStr([In] int lSrcPos, [In] int lSrcLen, [In, MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter, [In] uint dwClsContext, [In] ref Guid piid, [MarshalAs(UnmanagedType.IUnknown)] out object ppDestMLStr, out int plDestPos, out int plDestLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void SetWStr([In] int lDestPos, [In] int lDestLen, [In] ref ushort pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void SetStrBufW([In] int lDestPos, [In] int lDestLen, [In, MarshalAs(UnmanagedType.Interface)] IMLangStringBufW pSrcBuf, out int pcchActual, out int plActualLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void GetWStr([In] int lSrcPos, [In] int lSrcLen, out ushort pszDest, [In] int cchDest, out int pcchActual, out int plActualLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void GetStrBufW([In] int lSrcPos, [In] int lSrcMaxLen, [MarshalAs(UnmanagedType.Interface)] out IMLangStringBufW ppDestBuf, out int plDestLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void LockWStr([In] int lSrcPos, [In] int lSrcLen, [In] int lFlags, [In] int cchRequest, [Out] IntPtr ppszDest, out int pcchDest, out int plDestLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void UnlockWStr([In] ref ushort pszSrc, [In] int cchSrc, out int pcchActual, out int plActualLen);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void SetLocale([In] int lDestPos, [In] int lDestLen, [In] uint locale);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)]
        void GetLocale([In] int lSrcPos, [In] int lSrcMaxLen, out uint plocale, out int plLocalePos, out int plLocaleLen);
    }
}

#pragma warning restore 0108

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Core/Data/BlogsStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Data;

namespace ASC.Blogs.Core.Data
{
    public class BlogsStorage : IDisposable
    {
        readonly DbManager _db;
        readonly int _tenant;
        readonly IPostDao _postDao;


        public BlogsStorage(string dbId, int tenant)
        {
            _db = new DbManager(dbId);
            _tenant = tenant;
            _postDao = new DbPostDao(_db, _tenant);
        }


        public IPostDao GetPostDao()
        {
            return _postDao;
        }

        public void Dispose()
        {
            _db.Dispose();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/js/projectaction.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.Projects.ProjectAction = (function() {
    var projectId,
        activeTasksCount = 0,
        activeMilestonesCount = 0,
        opportunityId = undefined,
        contactId = undefined,
        teamIds = new Array(),
        currentUserId,
        projectResponsible,
        $projectManagerSelector,
        $projectTeamSelector,
        $projectStatusContainer,
        $projectStatus,
        $projectTag,
        $projectParticipants,
        $notifyManagerCheckbox,
        $followingProjectCheckbox,
        $notifyProjectCheckbox,
        $projectTitle,
        $projectDescription,
        $projectParticipantsContainer,
        $projectPrivacyCheckbox;

    var disabledAttr = "disabled",
        checkedProp = "checked",
        readonlyAttr = "readonly",
        requiredFieldErrorClass = "requiredFieldError",
        requiredInputErrorClass = "requiredInputError",
        itemsDisplayListClass = ".items-display-list";

    var teamlab, loadingBanner, project, team = [], tagsId = [], master;

    var init = function () {
        teamlab = Teamlab;
        loadingBanner = LoadingBanner;
        currentUserId = teamlab.profile.id;
        var param = jq.getURLParam("opportunityID");
        opportunityId = param ? param : undefined;
        param = jq.getURLParam("contactID");
        contactId = param ? param : undefined;
        projectId = jq.getURLParam("prjID");
        master = ASC.Projects.Master;

        if (!projectId) {
            teamlab.getPrjTemplates({}, { success: onGetTemplates });
        } else {
            teamlab.getPrjProject({}, projectId, { success: onGetProject });
        }
    };

    function initObjects() {
        if (project) {
            activeTasksCount = project.taskCount;
            activeMilestonesCount = project.milestoneCount;
        }

        $projectManagerSelector = jq("#projectManagerSelector"),
        $projectTeamSelector = jq("#projectTeamSelector");
        $projectStatusContainer = jq("#projectStatusContainer");
        $projectStatus = jq("#projectStatus");
        $projectTag = jq("#tags");
        $projectParticipants = jq("#projectParticipants");
        $notifyManagerCheckbox = jq("#notifyManagerCheckbox");
        $followingProjectCheckbox = jq("#followingProjectCheckbox");
        $notifyProjectCheckbox = jq("#notifyProjectCheckbox");
        $projectTitle = jq("[id$=projectTitle]");
        $projectDescription = jq("[id$=projectDescription]");
        $projectParticipantsContainer = jq("#projectParticipantsContainer");
        $projectPrivacyCheckbox = jq("#projectPrivacyCkeckbox");

        if (isProjectsCreatedFromCRM()) {
            ASC.CRM.ListContactView.removeMember = removeContactFromProject;
            getCRMParams();
        } else {
            $projectTitle.focus();
            if (!projectId) {
                clearFields();
            }
        }


        var selectedProjectManager = $projectManagerSelector.attr("data-id");
        $projectManagerSelector.useradvancedSelector({
            itemsSelectedIds: selectedProjectManager.length ? [selectedProjectManager] : [],
            withGuests: false,
            showGroups: true,
            onechosen: true
        }).on("showList", onChooseProjectManager);

        $projectTeamSelector.useradvancedSelector({
            itemsDisabledIds: projectId ? [$projectManagerSelector.attr("data-id")] : [],
            itemsSelectedIds: projectId ? teamIds : [],
            showGroups: true
        }).on("showList", onChooseProjectTeam);

        var itemsSelectedIds = [];

        if (projectId) {
            var findTag = function (tagToFind) {
                return function (item) {
                    return tagToFind === Encoder.htmlDecode(item.title);
                };
            };

            for (var i = 0; i < project.tags.length; i++) {
                var tag = master.Tags.filter(findTag(project.tags[i])).map(function (item) { return item.value; });
                itemsSelectedIds = itemsSelectedIds.concat(tag);
            }
        }

        $projectTag.tagsadvancedSelector({
            canadd: true,
            itemsChoose: master.Tags.map(function (item) { return { id: item.value, title: item.title } }),
            itemsSelectedIds:itemsSelectedIds
        }).on("showList", function (event, items) {
            tagsId = items.map(function(item) {
                return item.id;
            });
            var titles = items.map(function (item) {
                return Encoder.htmlEncode(item.title);
            });
            var selectedTags = titles.length ? titles.reduce(function (previousValue, currentValue) {
                return previousValue + ", " + currentValue;
            }) : "";
            jq("#tagsContainer").html(selectedTags);
        });

        if (project) {
            projectResponsible = project.responsible.id;
            var statuses = ASC.Projects.Resources.ProjectStatus;

            $projectStatus.advancedSelector({
                itemsSelectedIds: project.status,
                onechosen: true,
                showSearch: false,
                itemsChoose: statuses,
                sortMethod: function () {
                    return 0;
                }
            }).on("showList", function (event, item) {
                $projectStatusContainer.find(".selected-before").removeClass("selected-before");
                $projectStatus.attr("data-id", item.id).text(item.title).attr("title", item.title);
                showCloseQuestion(item.id);
            });

            team = master.Team.filter(function (item) {
                return item.id !== projectResponsible;
            });
            if ($projectManagerSelector.attr("data-id") == currentUserId) {
                $projectManagerSelector.useradvancedSelector("selectBeforeShow", { id: currentUserId, title: ASC.Resources.Master.ResourceJS.MeLabel });
            }
            displayProjectTeam();
        }
    }

    function initEvents() {
        jq("[id$=inputUserName]").keyup(function (eventObject) {
            if (eventObject.which == 13) {
                var id = jq("#login").attr("value");
                if (id != -1) {
                    jq("#projectManagerContainer").removeClass(requiredFieldErrorClass);
                    $projectManagerSelector.find(".borderBase").removeClass(requiredInputErrorClass);
                }
                if (id == currentUserId || (projectResponsible && id == projectResponsible)) {
                    $notifyManagerCheckbox.prop(checkedProp, false).attr(disabledAttr, disabledAttr);
                } else {
                    $notifyManagerCheckbox.removeAttr(disabledAttr).prop(checkedProp, true);
                }
            }
        });

        // title
        $projectTitle.keyup(function () {
            if (jq.trim($projectTitle.val()) != "") {
                jq("#projectTitleContainer").removeClass(requiredFieldErrorClass);
            }
        });

        // popup and other button

        var oldTeam = jq.map(team, function (user) { return user.id; });
        jq("#projectActionButton").click(function () {
            if (!validateProjectData() || jq(this).hasClass("disable")) return;

            jq(this).addClass("disable");
            var project = getProjectData();

            lockProjectActionPageElements();

            if (projectId) {
                var needDelete = oldTeam.filter(function (userId) {
                    return jq.map(team, function (user) { return user.id; }).indexOf(userId) < 0;
                });
                needDelete.forEach(function (user) {
                    teamlab.removeCaldavProjectCalendar(projectId, user);
                });
                updateProject(projectId, project);
            } else {
                addProject(project);
            }
        });

        jq("#projectDeleteButton").click(function () {
            ASC.Projects.Base.showCommonPopup("projectRemoveWarning",
                function () {
                    lockProjectActionPageElements();
                    teamlab.removePrjProject(projectId, { success: onDeleteProject, error: onError });
                });
        });

        jq("#cancelEditProject").click(function () {
            if (jq(this).hasClass("disable")) return;
            window.onbeforeunload = null;
            document.location.replace(location.pathname.substring(0, location.pathname.lastIndexOf("/") + 1));
        });

        $projectParticipantsContainer.on("click", ".reset-action", function () {
            var $tr = jq(this).parents("tr.pm-projectTeam-participantContainer");
            var id = $tr.attr("data-partisipantid");
            deleteItemInArray(teamIds, id);
            team = team.filter(function (item) { return item.id !== id; });

            if (teamIds.length == 0) {
                $projectParticipantsContainer.hide();
            }
            
            $tr.remove();
            $projectTeamSelector.useradvancedSelector("undisable", [id]).useradvancedSelector("unselect", [id]);

            ASC.Projects.CreateProjectStructure.onResetAction(id);
        });

        $projectParticipantsContainer.on("click", ".right-checker", function () {
            var checker = jq(this);
            if (checker.closest("tr").hasClass("disable") || checker.hasClass("no-dotted")) {
                return;
            }

            var onClass = "pm-projectTeam-modulePermissionOn",
                offClass = "pm-projectTeam-modulePermissionOff";

            if (checker.hasClass(offClass)) {
                checker.removeClass(offClass).addClass(onClass);
            } else if (checker.hasClass(onClass)) {
                checker.removeClass(onClass).addClass(offClass);
            }

            var id = checker.parents("tr.pm-projectTeam-participantContainer").attr("data-partisipantid");
            team.find(function(item) { return item.id === id; })[checker.attr("data-flag")] = checker.hasClass(onClass);
        });


        if (!projectId && ASC.Projects.MilestoneContainer) {
            ASC.Projects.MilestoneContainer.init();
            jq(document).bind("chooseResp", function (event, data) {
                showNotifyProjectCheckbox();
            });
            jq(document).bind("unchooseResp", function (event, data) {
                hideNotifyProjectCheckbox();
            });
        }
        jq.confirmBeforeUnload(confirmBeforeUnloadCheck);

        $projectPrivacyCheckbox.on("change", function(e) {
            displayProjectTeam();
        });
    }

    function onChooseProjectTeam(e, items) {
        teamIds = [];

        var findInTeam = function(i) {
            return function(item) { return item.id === items[i].id; };
        };
        var newTeam = [];
        for (var i = 0, j = items.length; i < j; i++) {
            var exist = team.find(findInTeam(i));
            if (exist) {
                newTeam.push(exist);
            } else {
                newTeam.push(items[i]);
            }
        }

        team = newTeam;
        displayProjectTeam();
        return false;
    };

    function onChooseProjectManager(e, item) {
        var id = item.id,
            name = item.title;

        $projectManagerSelector.html(name).attr("data-id", id).removeClass("plus");

        if (id == currentUserId) {
            $notifyManagerCheckbox.prop(checkedProp, false).attr(disabledAttr, disabledAttr);
            $followingProjectCheckbox.prop(checkedProp, false).attr(disabledAttr, disabledAttr);
        } else {
            $notifyManagerCheckbox.removeAttr(disabledAttr).prop(checkedProp, true);
            $followingProjectCheckbox.removeAttr(disabledAttr);
        }

        if (projectResponsible) {
            $projectTeamSelector.useradvancedSelector("undisable", [projectResponsible]);
        }
        projectResponsible = id;
        $projectParticipantsContainer.find("tr[data-partisipantid='" + id + "'] .reset-action").click();
        $projectTeamSelector.useradvancedSelector("disable", [id]);
    };

    function confirmBeforeUnloadCheck() {
        var project = getProjectData();
        return project.title.length ||
            project.responsibleid ||
            project.notify ||
            project.description.length ||
            tagsId.length ||
            (project.milestones && project.milestones.length) ||
            (project.tasks && project.tasks.length) ||
            (project.participants && project.participants.length);
    };

    function displayProjectTeam() {
        teamIds = team.map(function (item) { return item.id; });

        var projectManagerId = $projectManagerSelector.attr("data-id");

        if (team.length > 0) {
            var teamForTemplate = team.map(function(item) {
                return jq.extend({}, item, window.UserManager.getUser(item.id));
            });

            var data = jq.tmpl('member_template_without_photo',
            {
                team: teamForTemplate.map(mapTeamMember),
                project: {
                    canEditTeam: true,
                    isPrivate: $projectPrivacyCheckbox.is(":" + checkedProp)
                }
            });

            $projectParticipantsContainer.html(data);

            if (projectManagerId) {
                $projectParticipantsContainer.find("li[participantId=" + projectManagerId + "] .reset-action")
                    .addClass("hidden");
            }
            $projectParticipantsContainer.show();
            $projectTeamSelector.useradvancedSelector("select", teamIds);
            if (!project) {
                showNotifyProjectCheckbox();
            }
        } else {
            $projectParticipantsContainer.empty().hide();
        }
    };

    function showNotifyProjectCheckbox() {
        $notifyProjectCheckbox.show();
        $notifyProjectCheckbox.removeAttr(disabledAttr);
    }

    function hideNotifyProjectCheckbox() {
        $notifyProjectCheckbox.attr(disabledAttr, disabledAttr);
    }

    function mapTeamMember(item) {
        var resources = ASC.Projects.Resources;
        item.isManager = projectResponsible === item.id;
        item.isAdmin = item.isAdmin || (item.groups && item.groups.indexOf(master.ProjectsProductID) > -1);
        return jq.extend({
                security: [
                    security(item, "canReadMessages", resources.MessageResource.Messages),
                    security(item, "canReadFiles", resources.ProjectsFileResource.Documents),
                    security(item, "canReadTasks", resources.TaskResource.AllTasks),
                    security(item, "canReadMilestones", resources.MilestoneResource.Milestones),
                    security(item, "canReadContacts", resources.ProjectsCommonResource.ModuleContacts, item.isVisitor)
                ]
            }, item);
    }

    function security(item, flag, title, defaultDisabled) {
        var result = { check: getPropertyOrDefault(item, flag, defaultDisabled), flag: flag, title: title };
        if (typeof defaultDisabled === "boolean") {
            result.defaultDisabled = defaultDisabled;
        }
        return result;
    }

    function clearFields() {
        $projectTitle.add($projectDescription).val("");
        $notifyManagerCheckbox.add($followingProjectCheckbox).prop(checkedProp, false);
    };

    function validateProjectData() {
        jq("#projectTitleContainer , #projectManagerContainer, #projectStatusContainer").removeClass(requiredFieldErrorClass);
        $projectManagerSelector.find(".borderBase").removeClass(requiredInputErrorClass);

        var title = jq.trim($projectTitle.val()),
            responsibleid = $projectManagerSelector.attr("data-id"),
            status = $projectStatus.attr("data-id"),
            isError = false,
            scrollTo = "";

        if (!title) {
            jq("#projectTitleContainer").addClass(requiredFieldErrorClass);
            isError = true;
            scrollTo = "#projectTitleContainer";
        }
        if (!responsibleid) {
            jq("#projectManagerContainer").addClass(requiredFieldErrorClass);
            $projectManagerSelector.find(".borderBase").addClass(requiredInputErrorClass);
            isError = true;
            scrollTo = scrollTo || "#projectManagerContainer";
        }
        if (projectId && status == 1 && showCloseQuestion(status)) {
            $projectStatusContainer.addClass(requiredFieldErrorClass);
            isError = true;
            scrollTo = scrollTo || "#projectStatusContainer";
        }
        if (isError) {
            jq("body").scrollTo(scrollTo);
            return false;
        }
        return true;
    };

    function getProjectData() {
        var project =
        {
            title: jq.trim($projectTitle.val()),
            responsibleid: projectResponsible,
            notify: $notifyManagerCheckbox.is(":" + checkedProp),
            description: $projectDescription.val(),
            'private': $projectPrivacyCheckbox.is(":" + checkedProp),
            templateProjectId: jq("#SelectedTemplateID").val()
        };

        var projStructure = ASC.Projects.CreateProjectStructure;
        if (projStructure) {
            project.milestones = projStructure.getProjMilestones();
            project.tasks = projStructure.getProjTasks();
        }

        if (projectId) {
            project.status = $projectStatus.attr("data-id");
        }
        if (team) {
            project.participants = team.map(function (item) {
                return {
                    ID: item.id,
                    CanReadMessages: getPropertyOrDefault(item, "canReadMessages"),
                    CanReadFiles: getPropertyOrDefault(item, "canReadFiles"),
                    CanReadTasks: getPropertyOrDefault(item, "canReadTasks"),
                    CanReadMilestones: getPropertyOrDefault(item, "canReadMilestones"),
                    CanReadContacts: getPropertyOrDefault(item, "canReadContacts")
                };
            });
            project.notifyResponsibles = $notifyProjectCheckbox.is(":" + checkedProp);
        }
        return project;
    };

    function getPropertyOrDefault(item, property, defaultDisabled) {
        return item.hasOwnProperty(property) ? item[property] : !defaultDisabled;
    }

    function removeContactFromProject(contactid) {
        var contactContainer = jq("#contactTable");
        contactContainer.find("tr[id='contactItem_" + contactid + "']").remove();
        if (!contactContainer.find("tr").length) {
            jq("#projectContactsContainer .no-linked-contacts").show();
        }
    };

    function deleteItemInArray(array, item) {
        for (var i = 0; i < array.length; i++) {
            if (array[i] == item) {
                array.splice(i, 1);
                return;
            }
        }
    };

    function isProjectsCreatedFromCRM() {
        if (opportunityId || contactId) {
            return true;
        } else {
            return false;
        }
    };

    function getCRMParams() {
        if (opportunityId) {
            teamlab.getCrmOpportunity({}, opportunityId, { success: onGetCRMOpportunity });
            teamlab.getCrmEntityMembers({}, "opportunity", opportunityId, { success: onGetCRMContacts });
        }
        if (contactId) {
            teamlab.getCrmContact({}, contactId, { success: onGetCRMContact });
        }
    };

    function addUsersToCommand(users) {
        var userIds = [],
            usersCount = users.length;
        if (!usersCount) return;
        for (var i = 0; i < usersCount; i++) {
            userIds.push(users[i].id);
        }
        $projectTeamSelector.useradvancedSelector("select", [userIds]);
    };

    function appendContacts(project) {
        var contacts = jq("#contactTable tr");
        var contactsCount = contacts.length;
        if (contactsCount == 0) {
            checkFollowProj(project);
            return;
        };
        var contactsIds = [];
        for (var i = 0; i < contactsCount; i++) {
            var id = jq(contacts[i]).attr("id").split("_")[1];
            contactsIds.push(parseInt(id));
        }
        teamlab.addCrmContactsForProject({ project: project }, project.id, { contactid: contactsIds }, { success: onAddCRMContacts });
    };

    function checkFollowProj(project) {
        var following = $followingProjectCheckbox.is(":" + checkedProp);

        var isManager = project.responsible.id == currentUserId;
        var isInTeam = getArrayIndex(currentUserId, teamIds) != -1;
        if (following && !isInTeam & !isManager) {
            teamlab.followingPrjProject({}, project.id, { projectId: project.id }, { success: onFollowingProject });
        } else {
            window.onbeforeunload = null;
            document.location.replace("Tasks.aspx?prjID=" + project.id + "#sortBy=sort_order&sortOrder=ascending");
        }
    };

    function getArrayIndex(value, array) {
        var index = -1;
        for (var i = 0; i < array.length; i++) {
            if (array[i] === value) {
                index = i;
                break;
            }
        }
        return index;
    };

    function showCloseQuestion(status) {
        if (status == 1) {
            var moduleLocationPath = StudioManager.getLocationPathToModule("Projects");
            if (activeTasksCount > 0) {
                ASC.Projects.Base.showCommonPopup("projectOpenTaskWarning", function () {
                    location.href = jq.format('{0}Tasks.aspx?prjID={1}#sortBy=deadline&sortOrder=ascending&status=open', moduleLocationPath, projectId);
                });
                $projectStatusContainer.addClass(requiredFieldErrorClass);
            }
            else if (activeMilestonesCount > 0) {
                ASC.Projects.Base.showCommonPopup("projectOpenMilestoneWarning", function () {
                    location.href = jq.format('{0}Milestones.aspx?prjID={1}#sortBy=deadline&sortOrder=ascending&status=open', moduleLocationPath, projectId);
                });
                $projectStatusContainer.addClass(requiredFieldErrorClass);
            }
        } else {
            $projectStatusContainer.removeClass(requiredFieldErrorClass);
            return false;
        }
        return activeTasksCount > 0 || activeMilestonesCount > 0;
    };

    //lock fields

    function lockProjectActionPageElements() {
        loadingBanner.displayLoading();
        $projectTitle.attr(readonlyAttr, readonlyAttr).addClass(disabledAttr);
        $projectDescription.attr(readonlyAttr, readonlyAttr).addClass(disabledAttr);
        jq(".inputUserName").attr(disabledAttr, disabledAttr);
        $projectManagerSelector.find("td:last").css({ 'display': "none" });
        $projectParticipantsContainer.find(itemsDisplayListClass).removeClass("canedit");
        $projectStatus.attr(disabledAttr, disabledAttr).addClass(disabledAttr);
        $notifyManagerCheckbox.attr(disabledAttr, disabledAttr);
        $projectPrivacyCheckbox.attr(disabledAttr, disabledAttr);
        $followingProjectCheckbox.attr(disabledAttr, disabledAttr);
        jq("#TemplatesComboboxContainer").hide();
        jq("#projectTeamContainer .headerPanel").off();
    };

    function unlockProjectActionPageElements() {
        $projectTitle.removeAttr(readonlyAttr).removeClass(disabledAttr);
        $projectDescription.removeAttr(readonlyAttr).removeClass(disabledAttr);
        jq(".inputUserName").removeAttr(disabledAttr);
        $projectManagerSelector.find("td:last").css({ 'display': "table-cell" });
        $projectParticipantsContainer.find(itemsDisplayListClass).addClass("canedit");
        $projectStatus.removeAttr(disabledAttr).removeClass(disabledAttr);
        $notifyManagerCheckbox.removeAttr(disabledAttr);
        $projectPrivacyCheckbox.removeAttr(disabledAttr);
        $followingProjectCheckbox.removeAttr(disabledAttr);
        jq("#TemplatesComboboxContainer").show();
        loadingBanner.hideLoading();
    };

    function onError(params, error) {
        ASC.Projects.Common.displayInfoPanel(error, true);
        unlockProjectActionPageElements();
    }
    // actions
    function addProject(project) {
        var params = {};
        if (isProjectsCreatedFromCRM()) {
            params.isProjectsCreatedFromCRM = true;
        }
        teamlab.addPrjProject(params, project, { success: onAddProject, error: onError });
    };

    function updateProject(projectId, project) {
        teamlab.updatePrjProject({}, projectId, project, { success: onUpdateProject, error: onError });
    };

    //handlers
    function onAddProject(params) {
        project = this.__responses[0];

        teamlab.updatePrjProjectTags(project.id, { tags: tagsId }, {
            success: function() {
                if (params.isProjectsCreatedFromCRM) {
                    appendContacts(project);
                } else {
                    checkFollowProj(project);
                }
            }
        });
    };

    function onUpdateProject(params, project) {
        teamlab.updatePrjProjectTags(project.id, { tags: tagsId },
            {
                success: function() {
                    window.onbeforeunload = null;
                    document.location.replace("Tasks.aspx?prjID=" + project.id);
                }
            });
    };

    function onDeleteProject() {
        window.onbeforeunload = null;
        document.location.replace("Projects.aspx");
    };

    function onFollowingProject(params, project) {
        window.onbeforeunload = null;
        document.location.replace("Tasks.aspx?prjID=" + project.id + "#sortBy=sort_order&sortOrder=ascending");
    };

    function onGetCRMOpportunity(params, opportunity) {
        $projectTitle.val(opportunity.title);
        $projectDescription.val(opportunity.description);

        if (opportunity.responsible.id !== "4a515a15-d4d6-4b8e-828e-e0586f18f3a3") {
            $projectManagerSelector.useradvancedSelector("select", [opportunity.responsible.id]);
            $projectManagerSelector.html(Encoder.htmlDecode(opportunity.responsible.displayName)).attr("data-id", opportunity.responsible.id).removeClass("plus");
        }

        if (opportunity.responsible.id == currentUserId) {
            $notifyManagerCheckbox.prop(checkedProp, false).attr(disabledAttr, disabledAttr);
            $followingProjectCheckbox.prop(checkedProp, false).attr(disabledAttr, disabledAttr);
        }
        if (opportunity.isPrivate) {
            $projectPrivacyCheckbox.prop(checkedProp, true);
            addUsersToCommand(opportunity.accessList);
        }
    };

    function onGetCRMContacts(params, contacts) {
        var contactsCount = contacts.length;
        if (contactsCount > 0) {
            ASC.CRM.ListContactView.CallbackMethods.render_simple_content({}, contacts);
        } else {
            jq("#projectContactsContainer .no-linked-contacts").show();
        }

    };

    function onGetCRMContact(params, contact) {
        onGetCRMContacts({}, [contact]);
    };
    
    function onAddCRMContacts (params) {
        checkFollowProj(params.project);
    };

    function onGetTemplates(params, data) {
        jq("#projectActionPage").html(jq.tmpl("projects_action_create",
        {
            IsProjectCreatedFromCrm: isProjectsCreatedFromCRM(),
            hideChooseTeam: Object.keys(window.UserManager.getAllUsers(true)).length === 1,
            showTemplates: data.length > 0,
            pageTitle: ASC.Projects.Resources.ProjectResource.CreateNewProject,
            IsPrivateDisabled: false,
            project: {
                title: "",
                description: "",
                manager: {
                    id: "",
                    name: ASC.Projects.Resources.ProjectResource.AddProjectManager
                },
                "private": true,
                canDelete: true,
                tags: []
            },
            actionButton: ASC.Projects.Resources.ProjectResource.AddNewProject
        }));
        initObjects();
        initEvents();

        jq("#templateContainer").removeClass("display-none");
        var templateSelect = jq("#templateSelect");
        templateSelect.projectadvancedSelector(
            {
                itemsChoose: data,
                onechosen: true
            }
        );
        
        templateSelect.on("showList", function (event, item) {
            templateSelect.text(item.title).attr("title", item.title);
            ASC.Projects.CreateProjectStructure.onGetTemplate({}, item);
        });
        
        var tmplid = jq.getURLParam("tmplid");
        if (tmplid) {
            var tmpl = data.find(function (item) { return item.id == tmplid; });
            if (tmpl)
                templateSelect.projectadvancedSelector("selectBeforeShow", tmpl);
        }
    };

    function onGetProject(params, data) {
        project = data;
        tagsId = master.Tags
            .filter(function (item) { return data.tags.indexOf(item.title) > -1; })
            .map(function (item) { return item.value });

        jq("#projectActionPage").html(jq.tmpl("projects_action_create",
            {
                IsProjectCreatedFromCrm: isProjectsCreatedFromCRM(),
                hideChooseTeam: Object.keys(window.UserManager.getAllUsers(true)).length === 1,
                showTemplates: false,
                pageTitle: ASC.Projects.Resources.ProjectResource.EditProject,
                IsPrivateDisabled: false,
                project: {
                    title: data.title,
                    description: data.description,
                    manager: {
                        id: data.responsible.id,
                        name: data.responsible.displayName
                    },
                    status: ASC.Projects.Resources.ProjectStatus.find(function(item) {
                        return item.id === data.status;
                    }),
                    "private": data.isPrivate,
                    canDelete: data.canDelete,
                    url: "Tasks.aspx?prjID=" + data.id,
                    tags: data.tags.length ? data.tags.reduce(function (previousValue, currentValue) {
                        return previousValue + ", " + currentValue;
                    }) : ""
                },
                actionButton: ASC.Projects.Resources.ProjectResource.SaveProject
            }));
        initObjects();
        initEvents();
    }

    return {
        init: init
    };
})();


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_Value.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    /// <summary>
    /// This base class for all SIP data types.
    /// </summary>
    public abstract class SIP_t_Value
    {
        #region Methods

        /// <summary>
        /// Parses single value from specified reader.
        /// </summary>
        /// <param name="reader">Reader what contains </param>
        public abstract void Parse(StringReader reader);

        /// <summary>
        /// Convert this to string value.
        /// </summary>
        /// <returns>Returns this as string value.</returns>
        public abstract string ToStringValue();

        #endregion
    }
}

<|start_filename|>common/ASC.Core.Common/Contracts/BackupServiceClient.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Module;

namespace ASC.Core.Common.Contracts
{
    public class BackupServiceClient : BaseWcfClient<IBackupService>, IBackupService
    {
        public BackupProgress StartBackup(StartBackupRequest request)
        {
            return Channel.StartBackup(request);
        }

        public BackupProgress GetBackupProgress(int tenantId)
        {
            return Channel.GetBackupProgress(tenantId);
        }

        public void DeleteBackup(Guid backupId)
        {
            Channel.DeleteBackup(backupId);
        }

        public void DeleteAllBackups(int tenantId)
        {
            Channel.DeleteAllBackups(tenantId);
        }

        public List<BackupHistoryRecord> GetBackupHistory(int tenantId)
        {
            return Channel.GetBackupHistory(tenantId);
        }

        public BackupProgress StartTransfer(StartTransferRequest request)
        {
            return Channel.StartTransfer(request);
        }

        public BackupProgress GetTransferProgress(int tenantID)
        {
            return Channel.GetTransferProgress(tenantID);
        }

        public List<TransferRegion> GetTransferRegions()
        {
            return Channel.GetTransferRegions();
        }

        public BackupProgress StartRestore(StartRestoreRequest request)
        {
            return Channel.StartRestore(request);
        }

        public BackupProgress GetRestoreProgress(int tenantId)
        {
            return Channel.GetRestoreProgress(tenantId);
        }

        public string GetTmpFolder()
        {
            return Channel.GetTmpFolder();
        }

        public void CreateSchedule(CreateScheduleRequest request)
        {
            Channel.CreateSchedule(request);
        }

        public void DeleteSchedule(int tenantId)
        {
            Channel.DeleteSchedule(tenantId);
        }

        public ScheduleResponse GetSchedule(int tenantId)
        {
            return Channel.GetSchedule(tenantId);
        }
    }
}

<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/EncryptionLoginProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.FederatedLogin;
using ASC.FederatedLogin.Profile;
using ASC.Security.Cryptography;

using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Web.Studio.Core
{
    public static class EncryptionLoginProvider
    {
        public static void SetKeys(Guid userId, string keys)
        {
            if (string.IsNullOrEmpty(keys)) return;

            var loginProfile = new LoginProfile
            {
                Provider = ProviderConstants.Encryption,
                Name = InstanceCrypto.Encrypt(keys),
            };

            var linker = new AccountLinker("webstudio");
            linker.AddLink(userId.ToString(), loginProfile);
        }


        public static string GetKeys()
        {
            return GetKeys(SecurityContext.CurrentAccount.ID);
        }

        public static string GetKeys(Guid userId)
        {
            var linker = new AccountLinker("webstudio");
            var profile = linker.GetLinkedProfiles(userId.ToString(), ProviderConstants.Encryption).FirstOrDefault();
            if (profile == null) return null;

            var keys = InstanceCrypto.Decrypt(profile.Name);
            return keys;
        }
    }
}

<|start_filename|>common/ASC.Common/Data/Sql/SqlInstructionDebuggerDisplay.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;

namespace ASC.Common.Data.Sql
{
    class SqlInstructionDebuggerDisplay
    {
        private readonly ISqlInstruction i;


        public SqlInstructionDebuggerDisplay(ISqlInstruction i)
        {
            this.i = i;
        }

        public override string ToString()
        {
            if (i == null) return null;

            var parts = i.ToString().Split('?');
            var result = new StringBuilder(parts[0]);
            var counter = 0;
            foreach (var p in i.GetParameters())
            {
                counter++;
                if (p == null)
                {
                    result.Append("null");
                }
                else
                {
                    var format = "{0}";
                    if (p is DateTime || p is Guid || p is string) format = "'{0}'";
                    result.AppendFormat(format, p);
                }
                if (counter < parts.Length) result.Append(parts[counter]);
            }
            return result.ToString();
        }
    }
}


<|start_filename|>module/ASC.Api/ASC.Api.CRM/CRMApi.ContactInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.Collections;
using ASC.Api.CRM.Wrappers;
using ASC.Api.Exceptions;
using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.ElasticSearch;
using ASC.MessagingSystem;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Core.Search;

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace ASC.Api.CRM
{
    public partial class CRMApi
    {
        /// <summary>
        ///   Returns the list of all available contact categories
        /// </summary>
        /// <param name="infoType">
        ///    Contact information type
        /// </param>
        /// <short>Get all categories</short> 
        /// <category>Contacts</category>
        /// <returns>
        ///   List of all available contact categories
        /// </returns>
        [Read(@"contact/data/{infoType}/category")]
        public IEnumerable<string> GetContactInfoCategory(ContactInfoType infoType)
        {
            return Enum.GetNames(ContactInfo.GetCategory(infoType)).ToItemList();
        }

        /// <summary>
        ///   Returns the list of all available contact information types
        /// </summary>
        /// <short>Get all contact info types</short> 
        /// <category>Contacts</category>
        /// <returns></returns>
        [Read(@"contact/data/infoType")]
        public IEnumerable<string> GetContactInfoType()
        {
            return Enum.GetNames(typeof(ContactInfoType)).ToItemList();
        }

        /// <summary>
        ///    Returns the detailed information for the contact
        /// </summary>
        /// <param name="contactid">Contact ID</param>
        /// <short>Get contact information</short> 
        /// <category>Contacts</category>
        /// <returns>
        ///   Contact information
        /// </returns>
        [Read(@"contact/{contactid:[0-9]+}/data")]
        public IEnumerable<ContactInfoWrapper> GetContactInfo(int contactid)
        {
            if (contactid <= 0) throw new ArgumentException();

            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null || !CRMSecurity.CanAccessTo(contact)) throw new ItemNotFoundException();

            return DaoFactory.ContactInfoDao.GetList(contactid, null, null, null)
                .OrderByDescending(info => info.ID)
                .ToList()
                .ConvertAll(ToContactInfoWrapper);
        }

        /// <summary>
        ///   Returns the detailed list of all information available for the contact with the ID specified in the request
        /// </summary>
        /// <param name="contactid">Contact ID</param>
        /// <param name="id">Contact information ID</param>
        /// <short>Get contact info</short> 
        /// <category>Contacts</category>
        /// <returns>Contact information</returns>
        ///<exception cref="ArgumentException"></exception>
        [Read(@"contact/{contactid:[0-9]+}/data/{id:[0-9]+}")]
        public ContactInfoWrapper GetContactInfoByID(int contactid, int id)
        {
            if (contactid <= 0 || id <= 0) throw new ArgumentException();

            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null || !CRMSecurity.CanAccessTo(contact)) throw new ItemNotFoundException();

            var contactInfo = DaoFactory.ContactInfoDao.GetByID(id);

            if (contactInfo == null || contactInfo.ContactID != contactid) throw new ArgumentException();

            return ToContactInfoWrapper(contactInfo);
        }

        /// <summary>
        ///    Adds the information with the parameters specified in the request to the contact with the selected ID
        /// </summary>
        ///<param name="contactid">Contact ID</param>
        ///<param name="infoType">Contact information type</param>
        ///<param name="data">Data</param>
        ///<param name="isPrimary">Contact importance: primary or not</param>
        ///<param   name="category">Category</param>
        ///<short> Add contact info</short> 
        ///<category>Contacts</category>
        /// <seealso cref="GetContactInfoType"/>
        /// <seealso cref="GetContactInfoCategory"/>
        /// <returns>
        ///    Contact information
        /// </returns> 
        ///<exception cref="ArgumentException"></exception>
        [Create(@"contact/{contactid:[0-9]+}/data")]
        public ContactInfoWrapper CreateContactInfo(int contactid, ContactInfoType infoType, string data, bool isPrimary, string category)
        {
            if (string.IsNullOrEmpty(data) || contactid <= 0) throw new ArgumentException();
            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null) throw new ItemNotFoundException();

            if (infoType == ContactInfoType.Twitter)
            {
                if (!CRMSecurity.CanAccessTo(contact)) throw new ItemNotFoundException();
            }
            else
            {
                if (!CRMSecurity.CanEdit(contact)) throw new ItemNotFoundException();
            }

            var categoryType = ContactInfo.GetCategory(infoType);
            if (!Enum.IsDefined(categoryType, category)) throw new ArgumentException();


            var contactInfo = new ContactInfo
            {
                Data = data,
                InfoType = infoType,
                ContactID = contactid,
                IsPrimary = isPrimary,
                Category = (int)Enum.Parse(categoryType, category)
            };

            if (contactInfo.InfoType == ContactInfoType.Address)
            {
                Address res;
                if (!Address.TryParse(contactInfo, out res))
                    throw new ArgumentException();
            }

            var contactInfoID = DaoFactory.ContactInfoDao.Save(contactInfo);

            var messageAction = contact is Company ? MessageAction.CompanyUpdatedPrincipalInfo : MessageAction.PersonUpdatedPrincipalInfo;
            MessageService.Send(Request, messageAction, MessageTarget.Create(contact.ID), contact.GetTitle());

            var contactInfoWrapper = ToContactInfoWrapper(contactInfo);
            contactInfoWrapper.ID = contactInfoID;
            return contactInfoWrapper;
        }

        /// <summary>
        ///    Adds the address information to the contact with the selected ID
        /// </summary>
        /// <param name="contactid">Contact ID</param>
        /// <param name="address">Address data</param>
        /// <short>Add address info</short> 
        /// <category>Contacts</category>
        /// <seealso cref="GetContactInfoType"/>
        /// <seealso cref="GetContactInfoCategory"/>
        /// <returns>
        ///    Contact information
        /// </returns> 
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ItemNotFoundException"></exception>
        [Create(@"contact/{contactid:[0-9]+}/addressdata")]
        public ContactInfoWrapper CreateContactInfoAddress(int contactid, Address address)
        {
            if (contactid <= 0) throw new ArgumentException("Invalid value", "contactid");

            var contact = DaoFactory.ContactDao.GetByID(contactid);

            if (contact == null || !CRMSecurity.CanEdit(contact)) throw new ItemNotFoundException();

            if (address == null) throw new ArgumentException("Value cannot be null", "address");

            if (!Enum.IsDefined(typeof(AddressCategory), address.Category)) throw new ArgumentException("Value does not fall within the expected range.", "address.Category");

            address.CategoryName = ((AddressCategory)address.Category).ToLocalizedString();

            var settings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                },
                Formatting = Formatting.Indented
            };

            var contactInfo = new ContactInfo
            {
                InfoType = ContactInfoType.Address,
                ContactID = contactid,
                IsPrimary = address.IsPrimary,
                Category = address.Category,
                Data = JsonConvert.SerializeObject(address, settings)
            };

            contactInfo.ID = DaoFactory.ContactInfoDao.Save(contactInfo);

            var messageAction = contact is Company ? MessageAction.CompanyUpdatedPrincipalInfo : MessageAction.PersonUpdatedPrincipalInfo;
            MessageService.Send(Request, messageAction, MessageTarget.Create(contact.ID), contact.GetTitle());

            return ToContactInfoWrapper(contactInfo);
        }

        /// <summary>
        ///  Creates contact information (add new information to the old list) with the parameters specified in the request for the contact with the selected ID
        /// </summary>
        ///<short>Group contact info</short> 
        /// <param name="contactid">Contact ID</param>
        /// <param name="items">Contact information</param>
        /// <remarks>
        /// <![CDATA[
        ///  items has format
        ///  [{infoType : 1, category : 1, categoryName : 'work', data : "<EMAIL>", isPrimary : true}, {infoType : 0, category : 0, categoryName : 'home', data : "+8999111999111", isPrimary : true}]
        /// ]]>
        /// </remarks>
        /// <category>Contacts</category>
        /// <exception cref="ArgumentException"></exception>
        /// <returns>
        ///   Contact information
        /// </returns>
        /// <visible>false</visible>
        [Create(@"contact/{contactid:[0-9]+}/batch")]
        public IEnumerable<ContactInfoWrapper> CreateBatchContactInfo(int contactid, IEnumerable<ContactInfoWrapper> items)
        {
            if (contactid <= 0) throw new ArgumentException();

            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null || !CRMSecurity.CanEdit(contact)) throw new ItemNotFoundException();

            var itemsList = items != null ? items.ToList() : new List<ContactInfoWrapper>();
            var contactInfoList = itemsList.Select(FromContactInfoWrapper).ToList();

            foreach (var contactInfo in contactInfoList)
            {
                if (contactInfo.InfoType == ContactInfoType.Address)
                {
                    Address res;
                    if (!Address.TryParse(contactInfo, out res))
                        throw new ArgumentException();
                }
                contactInfo.ContactID = contactid;
            }

            var ids = DaoFactory.ContactInfoDao.SaveList(contactInfoList, contact);

            for (var index = 0; index < itemsList.Count; index++)
            {
                var infoWrapper = itemsList[index];
                infoWrapper.ID = ids[index];
            }
            return itemsList;
        }

        /// <summary>
        ///   Updates the information with the parameters specified in the request for the contact with the selected ID
        /// </summary>
        ///<param name="id">Contact information record ID</param>
        ///<param name="contactid">Contact ID</param>
        ///<param optional="true" name="infoType">Contact information type</param>
        ///<param name="data">Data</param>
        ///<param optional="true" name="isPrimary">Contact importance: primary or not</param>
        ///<param optional="true" name="category">Contact information category</param>
        ///<short>Update contact info</short> 
        ///<category>Contacts</category>
        ///<exception cref="ArgumentException"></exception>
        /// <returns>
        ///   Contact information
        /// </returns>
        [Update(@"contact/{contactid:[0-9]+}/data/{id:[0-9]+}")]
        public ContactInfoWrapper UpdateContactInfo(int id, int contactid, ContactInfoType? infoType, string data, bool? isPrimary, string category)
        {
            if (id <= 0 || string.IsNullOrEmpty(data) || contactid <= 0) throw new ArgumentException();

            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null || !CRMSecurity.CanEdit(contact)) throw new ItemNotFoundException();

            var contactInfo = DaoFactory.ContactInfoDao.GetByID(id);

            if (infoType != null)
            {
                var categoryType = ContactInfo.GetCategory(infoType.Value);

                if (!string.IsNullOrEmpty(category) && Enum.IsDefined(categoryType, category))
                {
                    contactInfo.Category = (int)Enum.Parse(categoryType, category);
                }

                contactInfo.InfoType = infoType.Value;
            }

            contactInfo.ContactID = contactid;

            if (isPrimary != null)
            {
                contactInfo.IsPrimary = isPrimary.Value;
            }

            contactInfo.Data = data;

            if (contactInfo.InfoType == ContactInfoType.Address)
            {
                Address res;
                if (!Address.TryParse(contactInfo, out res))
                    throw new ArgumentException();
            }

            DaoFactory.ContactInfoDao.Update(contactInfo);

            var messageAction = contact is Company ? MessageAction.CompanyUpdatedPrincipalInfo : MessageAction.PersonUpdatedPrincipalInfo;
            MessageService.Send(Request, messageAction, MessageTarget.Create(contact.ID), contact.GetTitle());

            var contactInfoWrapper = ToContactInfoWrapper(contactInfo);
            return contactInfoWrapper;
        }

        /// <summary>
        ///   Updates the address information with the parameters specified in the request for the contact with the selected ID
        /// </summary>
        /// <param name="id">Contact information record ID</param>
        /// <param name="contactid">Contact ID</param>
        /// <param name="address">Address data</param>
        /// <short>Update address info</short> 
        /// <category>Contacts</category>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ItemNotFoundException"></exception>
        /// <returns>
        ///   Contact information
        /// </returns>
        [Update(@"contact/{contactid:[0-9]+}/addressdata/{id:[0-9]+}")]
        public ContactInfoWrapper UpdateContactInfoAddress(int id, int contactid, Address address)
        {
            if (id <= 0) throw new ArgumentException("Invalid value", "id");

            var contactInfo = DaoFactory.ContactInfoDao.GetByID(id);

            if (contactInfo == null || contactInfo.InfoType != ContactInfoType.Address) throw new ItemNotFoundException();

            if (contactid <= 0) throw new ArgumentException("Invalid value", "contactid");

            var contact = DaoFactory.ContactDao.GetByID(contactid);

            if (contact == null || !CRMSecurity.CanEdit(contact) || contactInfo.ContactID != contactid) throw new ItemNotFoundException();

            if (address == null) throw new ArgumentException("Value cannot be null", "address");

            if (!Enum.IsDefined(typeof(AddressCategory), address.Category)) throw new ArgumentException("Value does not fall within the expected range.", "address.Category");

            address.CategoryName = ((AddressCategory)address.Category).ToLocalizedString();

            var settings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                },
                Formatting = Formatting.Indented
            };

            contactInfo.IsPrimary = address.IsPrimary;
            contactInfo.Category = address.Category;
            contactInfo.Data = JsonConvert.SerializeObject(address, settings);

            DaoFactory.ContactInfoDao.Update(contactInfo);

            var messageAction = contact is Company ? MessageAction.CompanyUpdatedPrincipalInfo : MessageAction.PersonUpdatedPrincipalInfo;
            MessageService.Send(Request, messageAction, MessageTarget.Create(contact.ID), contact.GetTitle());

            return ToContactInfoWrapper(contactInfo);
        }

        /// <summary>
        ///  Updates contact information (delete old information and add new list) with the parameters specified in the request for the contact with the selected ID
        /// </summary>
        ///<short>Group contact info update</short> 
        ///<param name="contactid">Contact ID</param>
        ///<param name="items">Contact information</param>
        /// <![CDATA[
        ///  items has format
        ///  [{infoType : 1, category : 1, categoryName : 'work', data : "<EMAIL>", isPrimary : true}, {infoType : 0, category : 0, categoryName : 'home', data : "+8999111999111", isPrimary : true}]
        /// ]]>
        ///<category>Contacts</category>
        ///<exception cref="ArgumentException"></exception>
        /// <returns>
        ///   Contact information
        /// </returns>
        /// <visible>false</visible>
        [Update(@"contact/{contactid:[0-9]+}/batch")]
        public IEnumerable<ContactInfoWrapper> UpdateBatchContactInfo(int contactid, IEnumerable<ContactInfoWrapper> items)
        {
            if (contactid <= 0) throw new ArgumentException();

            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null || !CRMSecurity.CanEdit(contact)) throw new ItemNotFoundException();

            var itemsList = items != null ? items.ToList() : new List<ContactInfoWrapper>();
            var contactInfoList = itemsList.Select(FromContactInfoWrapper).ToList();

            foreach (var contactInfo in contactInfoList)
            {
                if (contactInfo.InfoType == ContactInfoType.Address)
                {
                    Address res;
                    if (!Address.TryParse(contactInfo, out res))
                        throw new ArgumentException();
                }
                contactInfo.ContactID = contactid;
            }

            DaoFactory.ContactInfoDao.DeleteByContact(contactid);
            var ids = DaoFactory.ContactInfoDao.SaveList(contactInfoList, contact);

            for (var index = 0; index < itemsList.Count; index++)
            {
                var infoWrapper = itemsList[index];
                infoWrapper.ID = ids[index];
            }
            return itemsList;
        }

        /// <summary>
        ///    Returns the detailed information for the contact with the selected ID by the information type specified in the request
        /// </summary>
        /// <param name="contactid">Contact ID</param>
        /// <param name="infoType">Contact information type</param>
        /// <short>Get contact information by type</short> 
        /// <category>Contacts</category>
        /// <returns>
        ///   Contact information
        /// </returns>
        [Read(@"contact/{contactid:[0-9]+}/data/{infoType}")]
        public IEnumerable<string> GetContactInfo(int contactid, ContactInfoType infoType)
        {
            if (contactid <= 0) throw new ArgumentException();

            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null || !CRMSecurity.CanAccessTo(contact)) throw new ItemNotFoundException();

            return DaoFactory.ContactInfoDao.GetListData(contactid, infoType);
        }


        /// <summary>
        ///   Deletes the contact information for the contact with the ID specified in the request
        /// </summary>
        /// <param name="contactid">Contact ID</param>
        /// <param name="id">Contact information record ID</param>
        /// <short>Delete contact info</short> 
        /// <category>Contacts</category>
        /// <exception cref="ArgumentException"></exception>
        /// <exception cref="ItemNotFoundException"></exception>
        /// <returns>
        ///   Contact information
        /// </returns>
        [Delete(@"contact/{contactid:[0-9]+}/data/{id:[0-9]+}")]
        public ContactInfoWrapper DeleteContactInfo(int contactid, int id)
        {
            if (id <= 0 || contactid <= 0) throw new ArgumentException();

            var contact = DaoFactory.ContactDao.GetByID(contactid);
            if (contact == null || !CRMSecurity.CanEdit(contact)) throw new ItemNotFoundException();

            var contactInfo = DaoFactory.ContactInfoDao.GetByID(id);
            if (contactInfo == null) throw new ItemNotFoundException();

            var wrapper = ToContactInfoWrapper(contactInfo);

            DaoFactory.ContactInfoDao.Delete(id);

            var messageAction = contact is Company ? MessageAction.CompanyUpdatedPrincipalInfo : MessageAction.PersonUpdatedPrincipalInfo;
            MessageService.Send(Request, messageAction, MessageTarget.Create(contact.ID), contact.GetTitle());

            if (contactInfo.InfoType == ContactInfoType.Email)
            {
                FactoryIndexer<EmailWrapper>.DeleteAsync(EmailWrapper.ToEmailWrapper(contact, new List<ContactInfo> { contactInfo }));
            }
            FactoryIndexer<InfoWrapper>.DeleteAsync(contactInfo);

            return wrapper;
        }


        private static ContactInfoWrapper ToContactInfoWrapper(ContactInfo contactInfo)
        {
            return new ContactInfoWrapper(contactInfo);
        }

        private static ContactInfo FromContactInfoWrapper(ContactInfoWrapper contactInfoWrapper)
        {
            return new ContactInfo
            {
                ID = contactInfoWrapper.ID,
                Category = contactInfoWrapper.Category,
                Data = contactInfoWrapper.Data,
                InfoType = contactInfoWrapper.InfoType,
                IsPrimary = contactInfoWrapper.IsPrimary
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Helpers/DocuSignHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Security;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Users;
using ASC.FederatedLogin;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.Files.Core;
using ASC.MessagingSystem;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.HttpHandlers;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Services.WCFService;
using ASC.Web.Files.ThirdPartyApp;
using ASC.Web.Files.Utils;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

using DocuSign.eSign.Api;
using DocuSign.eSign.Client;
using DocuSign.eSign.Model;

using Newtonsoft.Json;

using File = ASC.Files.Core.File;
using Folder = ASC.Files.Core.Folder;
using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Web.Files.Helpers
{
    public class DocuSignToken
    {
        public static ILog Log = Global.Logger;

        public const string AppAttr = "docusign";

        public static OAuth20Token GetToken()
        {
            return Token.GetToken(AppAttr);
        }

        public static void DeleteToken(Guid? userId = null)
        {
            Token.DeleteToken(AppAttr, userId);
        }

        public static void SaveToken(OAuth20Token token)
        {
            if (token == null) throw new ArgumentNullException("token");

            Token.SaveToken(new Token(token, AppAttr));
        }

        internal static string GetRefreshedToken(OAuth20Token token)
        {
            if (token.IsExpired)
            {
                try
                {
                    Log.Info("DocuSign refresh token for user " + SecurityContext.CurrentAccount.ID);

                    var refreshed = DocuSignLoginProvider.Instance.RefreshToken(token.RefreshToken);

                    if (refreshed != null)
                    {
                        token.AccessToken = <PASSWORD>reshed.AccessToken;
                        token.RefreshToken = refreshed.RefreshToken;
                        token.ExpiresIn = refreshed.ExpiresIn;
                        token.Timestamp = DateTime.UtcNow;

                        SaveToken(token);
                    }
                }
                catch (Exception ex)
                {
                    Log.Error("DocuSign refresh token for user " + SecurityContext.CurrentAccount.ID, ex);
                }
            }
            return token.AccessToken;
        }
    }

    public class DocuSignHelper
    {
        public static ILog Log = Global.Logger;

        public const string UserField = "userId";

        public static readonly List<string> SupportedFormats = new List<string>
            {
                ".as", ".asl", ".doc", ".docm", ".docx", ".dot", ".dotm", ".dotx", ".htm", ".html", ".msg", ".pdf", ".pdx", ".rtf", ".txt", ".wpd", ".wps", ".wpt", ".xps",
                ".emz", ".svg", ".svgz", ".vdx", ".vss", ".vst",
                ".bmp", ".cdr", ".dcx", ".gif", ".ico", ".jpg", ".jpeg", ".pct", ".pic", ".png", ".rgb", ".sam", ".tga", ".tif", ".tiff", ".wpg",
                ".dps", ".dpt", ".pot", ".potx", ".pps", ".ppt", ".pptm", ".pptx",
                ".csv", ".et", ".ett", ".xls", ".xlsm", ".xlsx", ".xlt"
            };

        public static long MaxFileSize = 25L * 1024L * 1024L;

        public static int MaxEmailLength = 10000;

        public static bool ValidateToken(OAuth20Token token)
        {
            GetDocuSignAccount(token);
            return true;
        }

        public static string SendDocuSign(object fileId, DocuSignData docuSignData, Dictionary<string, string> requestHeaders)
        {
            if (docuSignData == null) throw new ArgumentNullException("docuSignData");
            var token = DocuSignToken.GetToken();
            var account = GetDocuSignAccount(token);

            var configuration = GetConfiguration(account, token);
            File sourceFile;
            var document = CreateDocument(fileId, docuSignData.Name, docuSignData.FolderId, out sourceFile);

            var url = CreateEnvelope(account.AccountId, document, docuSignData, configuration);

            FilesMessageService.Send(sourceFile, requestHeaders, MessageAction.DocumentSendToSign, "DocuSign", sourceFile.Title);

            return url;
        }

        private static DocuSignAccount GetDocuSignAccount(OAuth20Token token)
        {
            if (token == null) throw new ArgumentNullException("token");

            var userInfoString = RequestHelper.PerformRequest(DocuSignLoginProvider.Instance.DocuSignHost + "/oauth/userinfo",
                                                              headers: new Dictionary<string, string> { { "Authorization", "Bearer " + DocuSignToken.GetRefreshedToken(token) } });

            Log.Debug("DocuSing userInfo: " + userInfoString);

            var userInfo = (DocuSignUserInfo)JsonConvert.DeserializeObject(userInfoString, typeof(DocuSignUserInfo));

            if (userInfo.Accounts == null || userInfo.Accounts.Count == 0) throw new Exception("Account is null");

            var account = userInfo.Accounts[0];
            return account;
        }

        private static DocuSign.eSign.Client.Configuration GetConfiguration(DocuSignAccount account, OAuth20Token token)
        {
            if (account == null) throw new ArgumentNullException("account");
            if (token == null) throw new ArgumentNullException("token");

            var apiClient = new ApiClient(account.BaseUri + "/restapi");

            var configuration = new DocuSign.eSign.Client.Configuration { ApiClient = apiClient };
            configuration.AddDefaultHeader("Authorization", "Bearer " + DocuSignToken.GetRefreshedToken(token));

            return configuration;
        }

        private static Document CreateDocument(object fileId, string documentName, string folderId, out File file)
        {
            using (var fileDao = Global.DaoFactory.GetFileDao())
            {
                file = fileDao.GetFile(fileId);
                if (file == null) throw new Exception(FilesCommonResource.ErrorMassage_FileNotFound);
                if (!Global.GetFilesSecurity().CanRead(file)) throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
                if (!SupportedFormats.Contains(FileUtility.GetFileExtension(file.Title))) throw new ArgumentException(FilesCommonResource.ErrorMassage_NotSupportedFormat);
                if (file.ContentLength > MaxFileSize) throw new Exception(FileSizeComment.GetFileSizeExceptionString(MaxFileSize));

                byte[] fileBytes;
                using (var stream = fileDao.GetFileStream(file))
                {
                    var buffer = new byte[16 * 1024];
                    using (var ms = new MemoryStream())
                    {
                        int read;
                        while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            ms.Write(buffer, 0, read);
                        }
                        fileBytes = ms.ToArray();
                    }
                }

                if (string.IsNullOrEmpty(documentName))
                {
                    documentName = file.Title;
                }

                var document = new Document
                {
                    DocumentBase64 = Convert.ToBase64String(fileBytes),
                    DocumentFields = new List<NameValue>
                            {
                                new NameValue {Name = FilesLinkUtility.FolderId, Value = folderId},
                                new NameValue {Name = FilesLinkUtility.FileTitle, Value = file.Title},
                            },
                    DocumentId = "1", //file.ID.ToString(),
                    FileExtension = FileUtility.GetFileExtension(file.Title),
                    Name = documentName,
                };

                return document;
            }
        }

        private static string CreateEnvelope(string accountId, Document document, DocuSignData docuSignData, DocuSign.eSign.Client.Configuration configuration)
        {
            var eventNotification = new EventNotification
            {
                EnvelopeEvents = new List<EnvelopeEvent>
                        {
                            //new EnvelopeEvent {EnvelopeEventStatusCode = DocuSignStatus.Sent.ToString()},
                            //new EnvelopeEvent {EnvelopeEventStatusCode = DocuSignStatus.Delivered.ToString()},
                            new EnvelopeEvent {EnvelopeEventStatusCode = DocuSignStatus.Completed.ToString()},
                            new EnvelopeEvent {EnvelopeEventStatusCode = DocuSignStatus.Declined.ToString()},
                            new EnvelopeEvent {EnvelopeEventStatusCode = DocuSignStatus.Voided.ToString()},
                        },
                IncludeDocumentFields = "true",
                //RecipientEvents = new List<RecipientEvent>
                //    {
                //        new RecipientEvent {RecipientEventStatusCode = "Sent"},
                //        new RecipientEvent {RecipientEventStatusCode = "Delivered"},
                //        new RecipientEvent {RecipientEventStatusCode = "Completed"},
                //        new RecipientEvent {RecipientEventStatusCode = "Declined"},
                //        new RecipientEvent {RecipientEventStatusCode = "AuthenticationFailed"},
                //        new RecipientEvent {RecipientEventStatusCode = "AutoResponded"},
                //    },
                Url = CommonLinkUtility.GetFullAbsolutePath(DocuSignHandler.Path + "?" + FilesLinkUtility.Action + "=webhook"),
            };
            Global.Logger.Debug("DocuSign hook url: " + eventNotification.Url);

            var signers = new List<Signer>();
            docuSignData.Users.ForEach(uid =>
                {
                    try
                    {
                        var user = CoreContext.UserManager.GetUsers(uid);
                        signers.Add(new Signer
                        {
                            Email = user.Email,
                            Name = user.DisplayUserName(false),
                            RecipientId = user.ID.ToString(),
                        });
                    }
                    catch (Exception ex)
                    {
                        Log.Error("Signer is undefined", ex);
                    }
                });

            var envelopeDefinition = new EnvelopeDefinition
            {
                CustomFields = new CustomFields
                {
                    TextCustomFields = new List<TextCustomField>
                                {
                                    new TextCustomField {Name = UserField, Value = SecurityContext.CurrentAccount.ID.ToString()},
                                }
                },
                Documents = new List<Document> { document },
                EmailBlurb = docuSignData.Message,
                EmailSubject = docuSignData.Name,
                EventNotification = eventNotification,
                Recipients = new Recipients
                {
                    Signers = signers,
                },
                Status = "created",
            };

            var envelopesApi = new EnvelopesApi(configuration);
            var envelopeSummary = envelopesApi.CreateEnvelope(accountId, envelopeDefinition);

            Global.Logger.Debug("DocuSign createdEnvelope: " + envelopeSummary.EnvelopeId);

            var envelopeId = envelopeSummary.EnvelopeId;
            var url = envelopesApi.CreateSenderView(accountId, envelopeId, new ReturnUrlRequest
            {
                ReturnUrl = CommonLinkUtility.GetFullAbsolutePath(DocuSignHandler.Path + "?" + FilesLinkUtility.Action + "=redirect")
            });
            Global.Logger.Debug("DocuSign senderView: " + url.Url);

            return url.Url;
        }

        public static File SaveDocument(string envelopeId, string documentId, string documentName, object folderId)
        {
            if (string.IsNullOrEmpty(envelopeId)) throw new ArgumentNullException("envelopeId");
            if (string.IsNullOrEmpty(documentId)) throw new ArgumentNullException("documentId");

            var token = DocuSignToken.GetToken();
            var account = GetDocuSignAccount(token);
            var configuration = GetConfiguration(account, token);

            using (var fileDao = Global.DaoFactory.GetFileDao())
            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                if (string.IsNullOrEmpty(documentName))
                {
                    documentName = "new.pdf";
                }

                Folder folder;
                if (folderId == null
                    || (folder = folderDao.GetFolder(folderId)) == null
                    || folder.RootFolderType == FolderType.TRASH
                    || !Global.GetFilesSecurity().CanCreate(folder))
                {
                    if (Global.FolderMy != null)
                    {
                        folderId = Global.FolderMy;
                    }
                    else
                    {
                        throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_Create);
                    }
                }

                var file = new File
                {
                    FolderID = folderId,
                    Comment = FilesCommonResource.CommentCreateByDocuSign,
                    Title = FileUtility.ReplaceFileExtension(documentName, ".pdf"),
                };

                var envelopesApi = new EnvelopesApi(configuration);
                Log.Info("DocuSign webhook get stream: " + documentId);
                using (var stream = envelopesApi.GetDocument(account.AccountId, envelopeId, documentId))
                {
                    file.ContentLength = stream.Length;
                    file = fileDao.SaveFile(file, stream);
                }

                FilesMessageService.Send(file, MessageInitiator.ThirdPartyProvider, MessageAction.DocumentSignComplete, "DocuSign", file.Title);

                FileMarker.MarkAsNew(file);

                return file;
            }
        }


        [DataContract]
        [DebuggerDisplay("{AccountId} {BaseUri}")]
        private class DocuSignAccount
        {
            [DataMember(Name = "account_id", EmitDefaultValue = false)]
            public string AccountId { get; set; }

            [DataMember(Name = "base_uri", EmitDefaultValue = false)]
            public string BaseUri { get; set; }
        }

        [DataContract]
        private class DocuSignUserInfo
        {
            [DataMember(Name = "accounts", EmitDefaultValue = false)]
            public List<DocuSignAccount> Accounts { get; set; }
        }
    }

    [DataContract(Name = "docusign_data", Namespace = "")]
    [DebuggerDisplay("{Name}")]
    public class DocuSignData
    {
        [DataMember(Name = "folderId")]
        public string FolderId { get; set; }

        [DataMember(Name = "message")]
        public string Message { get; set; }

        [DataMember(Name = "name", IsRequired = true, EmitDefaultValue = false)]
        public string Name { get; set; }

        [DataMember(Name = "users")]
        public ItemList<Guid> Users { get; set; }
    }

    public enum DocuSignStatus
    {
        Draft,
        Sent,
        Delivered,
        Completed,
        Declined,
        Voided,
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/AdminMessageSettings/js/admmess.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var AdmMess = new function() {
    this.SaveSettings = function (btnObj) {

        if (jq(btnObj).hasClass("disable")) return;

        AjaxPro.onLoading = function(b) {
            if (b)
                LoadingBanner.showLoaderBtn("#studio_admMessSettings");
            else
                LoadingBanner.hideLoaderBtn("#studio_admMessSettings");
        };

        AdmMessController.SaveSettings(jq("#chk_studio_admMess").is(":checked"), function(result) {
            var res = result.value;
            LoadingBanner.showMesInfoBtn("#studio_admMessSettings", res.Message, res.Status == 1 ? "success" : "error");
        });
    }
}

<|start_filename|>common/ASC.Core.Common/Notify/Telegram/TelegramHelper.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Security.Cryptography;

using ASC.Core.Common.Configuration;
using ASC.Core.Common.Notify.Telegram;
using ASC.Notify.Messages;

namespace ASC.Core.Common.Notify
{
    public class TelegramHelper
    {
        private TelegramServiceClient Client
        {
            get
            {
                return new TelegramServiceClient();
            }
        }

        private static TelegramHelper _instance;
        public static TelegramHelper Instance
        {
            get
            {
                if (_instance != null) return _instance;

                _instance = new TelegramHelper();
                return _instance;
            }
        }

        public enum RegStatus
        {
            NotRegistered,
            Registered,
            AwaitingConfirmation
        }

        public string RegisterUser(Guid userId, int tenantId)
        {
            var token = GenerateToken(userId);

            using (var client = Client)
            {
                client.RegisterUser(userId.ToString(), tenantId, token);
            }

            return GetLink(token);
        }

        public void SendMessage(NotifyMessage msg)
        {
            using (var client = Client)
            {
                client.SendMessage(msg);
            }
        }

        public bool CheckConnection(int tenantId, string token, int tokenLifespan, string proxy)
        {
            using (var client = Client)
            {
                return client.CheckConnection(tenantId, token, tokenLifespan, proxy);
            }
        }

        public RegStatus UserIsConnected(Guid userId, int tenantId)
        {
            if (CachedTelegramDao.Instance.GetUser(userId, tenantId) != null) return RegStatus.Registered;

            return IsAwaitingRegistration(userId, tenantId) ? RegStatus.AwaitingConfirmation : RegStatus.NotRegistered;
        }

        public string CurrentRegistrationLink(Guid userId, int tenantId)
        {
            var token = GetCurrentToken(userId, tenantId);
            if (token == null) return "";

            return GetLink(token);
        }

        public void Disconnect(Guid userId, int tenantId)
        {
            CachedTelegramDao.Instance.Delete(userId, tenantId);
        }

        private bool IsAwaitingRegistration(Guid userId, int tenantId)
        {
            return GetCurrentToken(userId, tenantId) == null ? false : true;
        }

        private string GetCurrentToken(Guid userId, int tenantId)
        {
            using (var client = Client)
            {
                return client.RegistrationToken(userId.ToString(), tenantId);
            }
        }

        private string GenerateToken(Guid userId)
        {
            var id = userId.ToByteArray();
            var d = BitConverter.GetBytes(DateTime.Now.Ticks);

            var buf = id.Concat(d).ToArray();

            using (var sha = new SHA256CryptoServiceProvider())
            {
                return Convert.ToBase64String(sha.ComputeHash(buf))
                    .Replace('+', '-').Replace('/', '_').Replace("=", ""); // make base64 url safe
            }
        }

        private string GetLink(string token)
        {
            var tgProvider = (ITelegramLoginProvider)ConsumerFactory.GetByName("Telegram");
            var botname = tgProvider == null ? default(string) : tgProvider.TelegramBotName;
            if (string.IsNullOrEmpty(botname)) return null;

            return string.Format("t.me/{0}?start={1}", botname, token);
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/DNS/Client/RCODE.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Dns.Client
{
    /// <summary>
    /// Dns server reply codes.
    /// </summary>
    public enum RCODE
    {
        /// <summary>
        /// No error condition.
        /// </summary>
        NO_ERROR = 0,

        /// <summary>
        /// Format error - The name server was unable to interpret the query.
        /// </summary>
        FORMAT_ERRROR = 1,

        /// <summary>
        /// Server failure - The name server was unable to process this query due to a problem with the name server.
        /// </summary>
        SERVER_FAILURE = 2,

        /// <summary>
        /// Name Error - Meaningful only for responses from an authoritative name server, this code signifies that the
        /// domain name referenced in the query does not exist.
        /// </summary>
        NAME_ERROR = 3,

        /// <summary>
        /// Not Implemented - The name server does not support the requested kind of query.
        /// </summary>
        NOT_IMPLEMENTED = 4,

        /// <summary>
        /// Refused - The name server refuses to perform the specified operation for policy reasons.
        /// </summary>
        REFUSED = 5,
    }
}

<|start_filename|>module/ASC.VoipService/Dao/CachedVoipDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

using ASC.Common.Caching;

namespace ASC.VoipService.Dao
{
    public class CachedVoipDao : VoipDao
    {
        private static readonly ICache cache = AscCache.Memory;
        private static readonly ICacheNotify notify = AscCache.Notify;
        private static readonly TimeSpan timeout = TimeSpan.FromDays(1);


        static CachedVoipDao()
        {
            try
            {
                notify.Subscribe<CachedVoipItem>((c, a) => ResetCache(c.Tenant));
            }
            catch (Exception)
            {
            }
        }


        public CachedVoipDao(int tenantID)
            : base(tenantID)
        {
        }

        public override VoipPhone SaveOrUpdateNumber(VoipPhone phone)
        {
            var result = base.SaveOrUpdateNumber(phone);
            notify.Publish(new CachedVoipItem { Tenant = TenantID }, CacheNotifyAction.InsertOrUpdate);
            return result;
        }

        public override void DeleteNumber(string phoneId = "")
        {
            base.DeleteNumber(phoneId);
            notify.Publish(new CachedVoipItem { Tenant = TenantID }, CacheNotifyAction.Remove);
        }

        public override IEnumerable<VoipPhone> GetNumbers(params object[] ids)
        {
            var numbers = cache.Get<List<VoipPhone>>(GetCacheKey(TenantID));
            if (numbers == null)
            {
                numbers = new List<VoipPhone>(base.GetNumbers());
                cache.Insert(GetCacheKey(TenantID), numbers, DateTime.UtcNow.Add(timeout));
            }

            return ids.Any() ? numbers.Where(r => ids.Contains(r.Id) || ids.Contains(r.Number)).ToList() : numbers;
        }


        private static void ResetCache(int tenant)
        {
            cache.Remove(GetCacheKey(tenant));
        }

        private static string GetCacheKey(int tenant)
        {
            return "voip" + tenant.ToString(CultureInfo.InvariantCulture);
        }

        [Serializable]
        class CachedVoipItem
        {
            public int Tenant { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/CurrencyInfoDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;

#endregion

namespace ASC.CRM.Core.Dao
{
    public class CurrencyInfoDao : AbstractDao
    {
        public CurrencyInfoDao(int tenantID)
            : base(tenantID)
        {
        }

        public virtual List<CurrencyInfo> GetAll()
        {
            return Db.ExecuteList(GetSqlQuery(null)).ConvertAll(ToCurrencyInfo);
        }

        public virtual CurrencyInfo GetByAbbreviation(string abbreviation)
        {
            var currencies = Db.ExecuteList(GetSqlQuery(Exp.Eq("abbreviation", abbreviation))).ConvertAll(ToCurrencyInfo);

            return currencies.Count > 0 ? currencies[0] : null;
        }

        public List<CurrencyInfo> GetBasic()
        {
            return Db.ExecuteList(GetSqlQuery(Exp.Eq("is_basic", true))).ConvertAll(ToCurrencyInfo);
        }

        public List<CurrencyInfo> GetOther()
        {
            return Db.ExecuteList(GetSqlQuery(Exp.Eq("is_basic", false))).ConvertAll(ToCurrencyInfo);
        }

        private SqlQuery GetSqlQuery(Exp where)
        {
            var sqlQuery = new SqlQuery("crm_currency_info")
                .Select("resource_key",
                        "abbreviation",
                        "symbol",
                        "culture_name",
                        "is_convertable",
                        "is_basic");

            if (where != null)
                sqlQuery.Where(where);

            return sqlQuery;
        }

        private static CurrencyInfo ToCurrencyInfo(object[] row)
        {
            return new CurrencyInfo(
                    Convert.ToString(row[0]),
                    Convert.ToString(row[1]),
                    Convert.ToString(row[2]),
                    Convert.ToString(row[3]),
                    Convert.ToBoolean(row[4]),
                    Convert.ToBoolean(row[5])
                );
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/js/actionmanager.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.ASC.Files.Actions = (function () {
    var isInit = false;
    var clipGetLink = null;
    var clipGetExternalLink = null;

    var currentEntryData = null;

    var init = function () {
        if (isInit === false) {
            isInit = true;

            jq(document).click(function (event) {
                jq.dropdownToggle().registerAutoHide(event, "#filesActionsPanel", "#filesActionsPanel",
                    function () {
                        ASC.Files.Mouse.disableHover = false;
                    });
                jq.dropdownToggle().registerAutoHide(event, ".row-selected .menu-small", "#filesActionPanel",
                    function () {
                        jq(".row-selected .menu-small.active").removeClass("active");
                        jq(".row-selected.row-lonely-select").removeClass("row-lonely-select");
                        ASC.Files.Mouse.disableHover = false;
                    });
            });

            jq.dropdownToggle(
                {
                    switcherSelector: "#mainContentHeader .menuActionSelectAll",
                    dropdownID: "filesSelectorPanel",
                    anchorSelector: ".menuActionSelectAll",
                    addTop: 4
                });

            jq.dropdownToggle({
                addLeft: 4,
                addTop: -4,
                dropdownID: "filesVersionPanel",
                sideToggle: true,
                switcherSelector: "#filesVersion",
                toggleOnOver: true,
            });

            jq.dropdownToggle({
                addLeft: 4,
                addTop: -4,
                dropdownID: "filesMovePanel",
                sideToggle: true,
                switcherSelector: "#filesMove",
                toggleOnOver: true,
            });

            jq.dropdownToggle({
                addLeft: 4,
                addTop: -4,
                dropdownID: "foldersMovePanel",
                sideToggle: true,
                switcherSelector: "#foldersMove",
                toggleOnOver: true,
            });

            ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.GetFileSharedInfo, onGetFileSharedInfo);

            ASC.Files.ServiceManager.bind(ASC.Files.ServiceManager.events.SetAceFileLink, onSetAceFileLink);
        }
    };

    /* Methods*/

    var afterShowFunction = function (dropdownPanel) {
        showSeporators(dropdownPanel);
        createClipboardLinks();
    };

    var showSeporators = function(dropdownPanel) {
        var first = !!dropdownPanel.find(".dropdown-item.first-section:visible").length;
        var second = !!dropdownPanel.find(".dropdown-item.second-section:visible").length;
        var third = !!dropdownPanel.find(".dropdown-item.third-section:visible").length;
        var fourth = !!dropdownPanel.find(".dropdown-item.fourth-section:visible").length;

        dropdownPanel.find(".dropdown-item-seporator.first-section").toggle(first && (second || third || fourth));
        dropdownPanel.find(".dropdown-item-seporator.second-section").toggle(second && (third || fourth));
        dropdownPanel.find(".dropdown-item-seporator.third-section").toggle(third && fourth);
    };

    var resizeDropdownPanel = function (dropdownPanel) {
        var contents = dropdownPanel.find(".dropdown-content:not(.display-none)").filter(function(index, item) {
            return item.style.display != "none";
        });

        var content = contents.length > 0 ? contents[0] : null;

        if (!content) return;
        if (content.style.minWidth) return;

        var tmpDropdownPanel = dropdownPanel.clone().appendTo('body');
        tmpDropdownPanel.show().removeClass("display-none");
        var tmpContent = tmpDropdownPanel.find(".dropdown-content:visible");
        tmpContent.css({overflow: "auto", maxHeight: "none"});
        tmpContent.find("li").show().removeClass("display-none");
        jq(content).css({ minWidth: tmpContent.width() });
        tmpDropdownPanel.remove();
    };

    var createClipboardLinks = function () {
        var link = jq("#filesGetLink:visible, #foldersGetLink:visible").first();

        if (link.length) {
            createClipboardLink(link.attr("id"));
        }

        if (jq("#filesGetExternalLink").is(":visible")) {
            getFileSharedInfo();
        }
    };

    var createClipboardLink = function (id) {
        var url = ASC.Files.Actions.currentEntryData.entryObject.find(".entry-title .name a").prop("href");

        ASC.Files.Actions.clipGetLink = ASC.Clipboard.destroy(ASC.Files.Actions.clipGetLink);

        ASC.Files.Actions.clipGetLink = ASC.Clipboard.create(url, id, {
            onComplete: function () {
                ASC.Files.UI.displayInfoPanel(ASC.Resources.Master.ResourceJS.LinkCopySuccess);
                ASC.Files.Actions.hideAllActionPanels();
            }
        });
    };

    var getFileSharedInfo = function () {
        ASC.Files.ServiceManager.getSharedInfo(ASC.Files.ServiceManager.events.GetFileSharedInfo,
            {
                showLoading: true,
            },
            {
                stringList: {
                    entry: [ASC.Files.Actions.currentEntryData.entryType + "_" + ASC.Files.Actions.currentEntryData.id]
                }
            });
    };

    var onGetFileSharedInfo = function (jsonData, params, errorMessage) {
        if (errorMessage) {
            ASC.Files.UI.displayInfoPanel(errorMessage, true);
            return;
        }

        var data = jsonData[0];

        var toggleSwitcher = jq("#filesGetExternalLink .toggle");

        toggleSwitcher.toggleClass("off", data.ace_status == 3);

        ASC.Files.Actions.clipGetExternalLink = ASC.Clipboard.destroy(ASC.Files.Actions.clipGetExternalLink);

        ASC.Files.Actions.clipGetExternalLink = ASC.Clipboard.create(data.link, "filesGetExternalLink", {
            onComplete: function () {
                if (toggleSwitcher.hasClass("off")) {
                    ASC.Files.Actions.setAceFileLink();
                }

                ASC.Files.UI.displayInfoPanel(ASC.Resources.Master.ResourceJS.LinkCopySuccess);

                if (!ASC.Files.Actions.clipGetExternalLink.fromToggleBtn) {
                    ASC.Files.Actions.hideAllActionPanels();
                }

                ASC.Files.Actions.clipGetExternalLink.fromToggleBtn = false;
            }
        });
    };

    var setAceFileLink = function () {
        ASC.Files.ServiceManager.setAceLink(ASC.Files.ServiceManager.events.SetAceFileLink, {
            showLoading: true,
            fileId: ASC.Files.Actions.currentEntryData.entryId,
            share: jq("#filesGetExternalLink .toggle").hasClass("off") ? ASC.Files.Constants.AceStatusEnum.Read : ASC.Files.Constants.AceStatusEnum.Restrict
        });
    };

    var onSetAceFileLink = function (jsonData, params, errorMessage) {
        if (errorMessage) {
            ASC.Files.UI.displayInfoPanel(errorMessage, true);
            return;
        }

        jq("#filesGetExternalLink .toggle").toggleClass("off");
        ASC.Files.Actions.currentEntryData.entryObject.toggleClass("__active", jsonData);
    };


    var showActionsViewPanel = function (event) {
        jq("#buttonUnsubscribe, #buttonDelete, #buttonMoveto, #buttonCopyto, #buttonShare, #buttonMarkRead, #buttonSendInEmail, #buttonAddFaforite").hide();
        jq("#mainContentHeader .unlockAction").removeClass("unlockAction");
        var count = jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):has(.checkbox input:checked)").length;
        var filesCount = jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):not(.folder-row):has(.checkbox input:checked)").length;

        var countNotFavorite = 0;
        if (ASC.Files.Tree.displayFavorites()
            && ASC.Files.Folders.folderContainer != "trash"
            && ASC.Files.Folders.folderContainer != "privacy") {
            countNotFavorite = jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):not(.on-favorite):not(.folder-row):has(.checkbox input:checked)").length;
        }

        var countWithRights = count;
        var countIsNew = 0;
        var onlyThirdParty = (ASC.Files.ThirdParty && !ASC.Files.ThirdParty.isThirdParty());
        var countThirdParty = 0;
        var canConvert = false;
        var countCanShare = 0;

        jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):has(.checkbox input:checked)").each(function () {
            var entryObj = jq(this);

            if (ASC.Files.UI.editingFile(entryObj) || !ASC.Files.UI.accessDelete(entryObj) || ASC.Files.UI.lockedForMe(entryObj)) {
                countWithRights--;
            }

            if (entryObj.find(".is-new:visible").length > 0) {
                countIsNew++;
            }

            var entryData = ASC.Files.UI.getObjectData(entryObj);
            if (ASC.Files.ThirdParty) {
                if (!ASC.Files.ThirdParty.isThirdParty() && ASC.Files.ThirdParty.isThirdParty(entryData)) {
                    countThirdParty++;
                } else {
                    onlyThirdParty = false;
                }
            } else {
                onlyThirdParty = false;
            }

            if (!canConvert && !entryObj.hasClass("folder-row")) {
                var entryTitle = entryData.title;
                var formats = ASC.Files.Utility.GetConvertFormats(entryTitle);
                canConvert = formats.length > 0 && !entryData.encrypted && entryData.content_length <= ASC.Files.Constants.AvailableFileSize;
            }

            if (!ASC.Resources.Master.Personal && entryObj.is(":not(.without-share)")
                && ASC.Files.Share && ASC.Files.Folders.currentFolder.shareable
                && (!entryData.encrypted
                    || ASC.Files.Folders.folderContainer == "privacy"
                        && ASC.Files.Utility.CanWebEncrypt(entryData.title)
                        && ASC.Desktop && ASC.Desktop.setAccess)) {
                countCanShare++;
            }
        });

        if (count > 0) {
            jq("#buttonDownload, #buttonRemoveFavorite, #buttonRemoveTemplate, #buttonUnsubscribe, #buttonRestore, #buttonCopyto").show().find("span").html(count);
            jq("#mainDownload, #mainRemoveFavorite, #mainRemoveTemplate, #mainUnsubscribe, #mainRestore, #mainCopy").addClass("unlockAction");
            if (ASC.Files.Folders.folderContainer == "privacy") {
                jq("#buttonCopyto").hide();
            }
            if (ASC.Files.Folders.folderContainer != "forme") {
                jq("#buttonUnsubscribe").hide();
            }
            if (ASC.Files.Folders.folderContainer == "favorites") {
                jq("#buttonMoveto").hide();
            } else {
                jq("#buttonRemoveFavorite").hide();
            }
            if (ASC.Files.Folders.folderContainer == "templates") {
                jq("#buttonMoveto").hide();
            } else {
                jq("#buttonRemoveTemplate").hide();
            }
        }

        if (filesCount > 0 && countCanShare > 0 || ASC.Files.Folders.folderContainer == "project" && filesCount > 0) {
            jq("#buttonSendInEmail").show().find("span").html(filesCount);
        }

        if (countNotFavorite > 0) {
            jq("#buttonAddFavorite").show().find("span").html(countNotFavorite);
        } else {
            jq("#buttonAddFavorite").hide();
        }

        if (canConvert) {
            jq("#buttonConvert").show().find("span").html(count);
        } else {
            jq("#buttonConvert").hide();
        }
        jq("#mainConvert").toggleClass("unlockAction", canConvert);

        if (countIsNew > 0) {
            jq("#buttonMarkRead").show().find("span").html(countIsNew);
            jq("#mainMarkRead").addClass("unlockAction");
        }

        if (countWithRights > 0) {
            jq("#buttonDelete, #buttonMoveto").show().find("span").html(countWithRights - countThirdParty);
            jq("#mainDelete, #mainMove").addClass("unlockAction");
        }

        if (ASC.Files.Folders.folderContainer == "trash") {
            jq("#buttonDelete, #buttonMoveto, #buttonCopyto, #buttonMarkRead").hide();
            jq("#mainDelete, #mainMove, #mainCopy").removeClass("unlockAction");
        }

        jq("#buttonRestore, #buttonEmptyTrash").hide();
        jq("#mainRestore, #mainEmptyTrash").removeClass("unlockAction");
        if (ASC.Files.Folders.folderContainer == "trash") {
            if (count > 0) {
                jq("#buttonDownload, #buttonDelete, #buttonRestore").show();
                jq("#mainDownload, #mainDelete, #mainRestore").addClass("unlockAction");
            } else {
                jq("#buttonDownload, #buttonConvert").hide();
                jq("#mainDownload, #mainConvert").removeClass("unlockAction");
            }
            jq("#buttonEmptyTrash").show();
            jq("#mainEmptyTrash").addClass("unlockAction");
        } else if (ASC.Files.Folders.folderContainer != "project"
            && ASC.Files.Folders.folderContainer != "privacy"
            && countCanShare > 0) {
            jq("#buttonShare").show().find("span").html(countCanShare);
            jq("#mainShare").addClass("unlockAction");
        }

        if (onlyThirdParty) {
            jq("#buttonDelete, #buttonMoveto").hide();
            jq("#mainDelete, #mainMove").removeClass("unlockAction");
        }

        if (typeof event != "undefined") {
            var e = jq.fixEvent(event),
                dropdownItem = jq("#filesActionsPanel"),
                correctionX = document.body.clientWidth - (e.pageX - pageXOffset + dropdownItem.innerWidth()) > 0 ? 0 : dropdownItem.innerWidth(),
                correctionY = document.body.clientHeight - (e.pageY - pageYOffset + dropdownItem.innerHeight()) > 0 ? 0 : dropdownItem.innerHeight();

            dropdownItem.css({
                "top": e.pageY - correctionY,
                "left": e.pageX - correctionX
            });

            resizeDropdownPanel(dropdownItem);
            dropdownItem.toggle();
            afterShowFunction(dropdownItem);
            ASC.Files.Mouse.disableHover = true;
        }
    };

    var showActionsPanel = function (event, entryData) {
        ASC.Files.Actions.clipGetLink = ASC.Clipboard.destroy(ASC.Files.Actions.clipGetLink);

        var e = jq.fixEvent(event);

        var target = jq(e.srcElement || e.target);
        if (target.hasClass("active")) {
            ASC.Files.Actions.hideAllActionPanels();
            return true;
        }

        entryData = entryData || ASC.Files.UI.getObjectData(target);

        var entryObj = entryData.entryObject;
        if (entryObj.is(".loading")) {
            return true;
        }

        ASC.Files.Actions.currentEntryData = entryData;

        ASC.Files.UI.checkSelectAll(false);
        ASC.Files.UI.selectRow(entryObj, true);
        ASC.Files.UI.updateMainContentHeader();

        var accessibleObj = ASC.Files.UI.accessEdit(entryData, entryObj);
        var accessAdminObj = ASC.Files.UI.accessDelete(entryObj);
        var isVisitor = Teamlab.profile.isVisitor === true;

        jq("#actionPanelFolders, #actionPanelFiles").hide();
        if (entryData.entryType === "file") {
            jq("#filesOpen,\
                #filesGotoParent,\
                #filesEdit,\
                #filesByTemplate,\
                #filesConvert,\
                #filesDownload,\
                #filesGetLink,\
                #filesShareAccess,\
                #filesGetExternalLink,\
                #filesChangeOwner,\
                #filesSendInEmail,\
                #filesLock,\
                #filesUnlock,\
                #filesDocuSign,\
                #filesUnsubscribe,\
                #filesVersion,\
                #filesCompleteVersion,\
                #filesVersions,\
                #filesMove,\
                #filesMoveto,\
                #filesCopyto,\
                #filesCopy,\
                #filesMarkRead,\
                #filesAddFavorite,\
                #filesRemoveFavorite,\
                #filesAddTemplate,\
                #filesRemoveTemplate,\
                #filesRename,\
                #filesRestore,\
                #filesRemove").show().removeClass("display-none");

            var entryTitle = entryData.title;

            if (!ASC.Files.Utility.GetConvertFormats(entryTitle).length || entryData.encrypted || entryData.content_length > ASC.Files.Constants.AvailableFileSize) {
                jq("#filesConvert").hide().addClass("display-none");
            }

            if (!ASC.Files.Utility.CanWebView(entryTitle)
                && (typeof ASC.Files.ImageViewer == "undefined" || !ASC.Files.Utility.CanImageView(entryTitle))
                && (typeof ASC.Files.MediaPlayer == "undefined" || !ASC.Files.MediaPlayer.canPlay(entryTitle, true))) {
                jq("#filesOpen").hide().addClass("display-none");
            }

            if (!ASC.Files.ThirdParty || !ASC.Files.ThirdParty.thirdpartyAvailable()
                || jq.inArray(ASC.Files.Utility.GetFileExtension(entryTitle), ASC.Files.Constants.DocuSignFormats) == -1
                || entryData.encrypted) {
                jq("#filesDocuSign").hide();
            }

            if (entryObj.find("#contentVersions").length != 0
                || ASC.Files.ThirdParty && ASC.Files.ThirdParty.isThirdParty()) {
                jq("#filesVersions").hide().addClass("display-none");
            }

            var editingFile = ASC.Files.UI.editingFile(entryObj);
            if (editingFile) {
                jq("#filesCompleteVersion,\
                    #filesMoveto,\
                    #filesRemove").hide().addClass("display-none");

                if (ASC.Files.ThirdParty && ASC.Files.ThirdParty.isThirdParty()) {
                    jq("#filesRename").hide();
                }
            }

            if (entryObj.hasClass("on-favorite")) {
                jq("#filesAddFavorite").hide().addClass("display-none");
            } else {
                jq("#filesRemoveFavorite").hide().addClass("display-none");

                if (!ASC.Files.Tree.displayFavorites()) {
                    jq("#filesAddFavorite").hide().addClass("display-none");
                }
            }

            if (ASC.Files.Folders.folderContainer == "favorites") {
                jq("#filesMoveto,\
                    #filesRemove").hide().addClass("display-none");
            }

            if (entryObj.hasClass("is-template")) {
                jq("#filesAddTemplate").hide().addClass("display-none");
            } else {
                jq("#filesByTemplate, #filesRemoveTemplate").hide().addClass("display-none");

                if (!ASC.Files.Tree.displayTemplates()
                    || !ASC.Files.Utility.CanBeTemplate(entryTitle)) {
                    jq("#filesAddTemplate").hide().addClass("display-none");
                }
            }

            if (ASC.Files.Folders.folderContainer == "templates") {
                jq("#filesMoveto,\
                    #filesRemove").hide().addClass("display-none");
            }

            var lockedForMe = ASC.Files.UI.lockedForMe(entryObj);
            if (!ASC.Files.UI.editableFile(entryData)
                || editingFile && (!ASC.Files.Utility.CanCoAuhtoring(entryTitle) || entryObj.hasClass("on-edit-alone"))
                || lockedForMe) {
                jq("#filesEdit").hide().addClass("display-none");
            }

            if (entryData.encrypted) {
                jq("#filesEdit,\
                    #filesOpen,\
                    #filesGetLink,\
                    #filesGetExternalLink,\
                    #filesSendInEmail,\
                    #filesCompleteVersion,\
                    #filesLock,\
                    #filesUnlock,\
                    #filesAddTemplate,\
                    #filesCopyto,\
                    #filesCopy,\
                    #filesByTemplate,\
                    #filesAddFavorite").hide().addClass("display-none");
            }

            if (entryObj.hasClass("file-locked")) {
                jq("#filesLock").hide().addClass("display-none");
            } else {
                jq("#filesUnlock").hide().addClass("display-none");
            }

            if (ASC.Files.Folders.folderContainer == "trash") {
                jq("#filesOpen,\
                    #filesGotoParent,\
                    #filesEdit,\
                    #filesByTemplate,\
                    #filesGetLink,\
                    #filesShareAccess,\
                    #filesGetExternalLink,\
                    #filesSendInEmail,\
                    #filesCompleteVersion,\
                    #filesLock,\
                    #filesUnlock,\
                    #filesDocuSign,\
                    #filesVersions,\
                    #filesMoveto,\
                    #filesCopyto,\
                    #filesMarkRead,\
                    #filesAddFavorite,\
                    #filesRemoveFavorite,\
                    #filesAddTemplate,\
                    #filesRemoveTemplate,\
                    #filesRename").hide().addClass("display-none");
            } else {
                jq("#filesRestore").hide().addClass("display-none");
            }

            if (!accessibleObj || lockedForMe) {
                jq("#filesCompleteVersion,\
                    #filesRename,\
                    #filesLock").hide().addClass("display-none");

                if (!ASC.Files.Constants.ADMIN && ASC.Files.Folders.folderContainer != "my") {
                    jq("#filesUnlock").hide().addClass("display-none");
                }
            }

            if (isVisitor) {
                jq("#filesByTemplate,\
                    #filesLock,\
                    #filesDocuSign,\
                    #filesCompleteVersion,\
                    #filesAddFavorite,\
                    #filesRemoveFavorite,\
                    #filesAddTemplate,\
                    #filesRemoveTemplate").hide().addClass("display-none");
                if (!accessAdminObj) {
                    jq("#filesRename").hide().addClass("display-none");
                }
            }

            if (ASC.Files.Folders.folderContainer != "corporate") {
                jq("#filesChangeOwner").hide().addClass("display-none");
            }

            if (ASC.Files.ThirdParty && ASC.Files.ThirdParty.isThirdParty(entryData)) {
                jq("#filesChangeOwner,\
                    #filesCompleteVersion,\
                    #filesCopy").hide().addClass("display-none");
            }

            if (!accessAdminObj || lockedForMe) {
                jq("#filesChangeOwner,\
                    #filesMoveto,\
                    #filesRemove").hide().addClass("display-none");
            }

            if (entryObj.is(".without-share *, .without-share")) {
                jq("#filesShareAccess").hide().addClass("display-none");
                jq("#filesGetExternalLink").hide().addClass("display-none");
            } else if (jq("#filesGetExternalLink").data("trial")
                && !ASC.Files.Utility.CanWebView(entryTitle)) {
                jq("#filesGetExternalLink").hide().addClass("display-none");
            }

            if (entryObj.find(".is-new:visible").length == 0) {
                jq("#filesMarkRead").hide().addClass("display-none");
            }

            if (ASC.Files.Folders.folderContainer != "forme"
                && (ASC.Files.Folders.folderContainer != "privacy"
                    || accessAdminObj)) {
                jq("#filesUnsubscribe").hide().addClass("display-none");
            }

            if (!ASC.Files.UI.accessEdit()) {
                jq("#filesCopy").hide().addClass("display-none");
            }

            if (ASC.Files.Folders.folderContainer != "favorites"
                && ASC.Files.Folders.folderContainer != "templates"
                && ASC.Files.Folders.folderContainer != "recent"
                && (!ASC.Files.Filter || !ASC.Files.Filter.getFilterSettings().isSet
                    || ASC.Files.ThirdParty && ASC.Files.ThirdParty.isThirdParty())) {
                jq("#filesGotoParent").hide().addClass("display-none");
            }

            if (!jq("#filesVersionPanel li:not(.display-none)").length) {
                jq("#filesVersion").hide().addClass("display-none");
            }

            if (!jq("#filesMovePanel li:not(.display-none)").length) {
                jq("#filesMove").hide().addClass("display-none");
            }

            jq("#actionPanelFiles").show();

        } else {
            jq("#foldersOpen,\
                #foldersGotoParent,\
                #foldersDownload,\
                #foldersGetLink,\
                #foldersShareAccess,\
                #foldersChangeOwner,\
                #foldersUnsubscribe,\
                #foldersMove,\
                #foldersMoveto,\
                #foldersCopyto,\
                #foldersMarkRead,\
                #foldersRename,\
                #foldersRestore,\
                #foldersRemove,\
                #foldersRemoveThirdparty,\
                #foldersChangeThirdparty").show().removeClass("display-none");

            if (ASC.Files.Folders.folderContainer == "privacy") {
                jq("#foldersCopyto").hide().addClass("display-none");
            }

            if (ASC.Files.Folders.folderContainer == "trash") {
                jq("#foldersOpen,\
                    #foldersGotoParent,\
                    #foldersGetLink,\
                    #foldersShareAccess,\
                    #foldersMove,\
                    #foldersMoveto,\
                    #foldersCopyto,\
                    #foldersMarkRead,\
                    #foldersRename").hide().addClass("display-none");
            } else {
                jq("#foldersRestore").hide().addClass("display-none");
            }

            if (!accessibleObj || ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_PROJECT) {
                jq("#foldersRename,\
                    #foldersRemoveThirdparty,\
                    #foldersChangeThirdparty").hide().addClass("display-none");
            }

            if (ASC.Files.Folders.folderContainer != "corporate") {
                jq("#foldersChangeOwner").hide().addClass("display-none");
            }

            if (!accessAdminObj) {
                jq("#foldersChangeOwner,\
                    #foldersMoveto,\
                    #foldersRemove,\
                    #foldersRemoveThirdparty,\
                    #foldersChangeThirdparty").hide().addClass("display-none");
                if (isVisitor) {
                    jq("#foldersRename").hide().addClass("display-none");
                }
            }

            if (entryObj.is(".without-share *, .without-share")) {
                jq("#foldersShareAccess").hide().addClass("display-none");
            }

            if (entryObj.find(".is-new:visible").length == 0) {
                jq("#foldersMarkRead").hide().addClass("display-none");
            }

            if (ASC.Files.Folders.folderContainer != "forme") {
                jq("#foldersUnsubscribe").hide().addClass("display-none");
            }

            if (ASC.Files.ThirdParty && ASC.Files.ThirdParty.isThirdParty(entryData)) {
                jq("#foldersChangeOwner").hide().addClass("display-none");

                if (ASC.Files.ThirdParty.isThirdParty()
                    || ASC.Files.Folders.currentFolder.id == ASC.Files.Constants.FOLDER_ID_SHARE) {
                    jq("#foldersRemoveThirdparty,\
                        #foldersChangeThirdparty").hide().addClass("display-none");
                } else {
                    if (ASC.Desktop) {
                        jq("#foldersRemoveThirdparty,\
                        #foldersChangeThirdparty").hide().addClass("display-none");
                    }

                    if (entryData.create_by_id != Teamlab.profile.id) {
                        jq("#foldersChangeThirdparty").hide().addClass("display-none");
                    }

                    jq("#foldersRemove,\
                        #foldersMoveto").hide().addClass("display-none");

                    if (entryData.error) {
                        jq("#foldersOpen,\
                            #foldersDownload,\
                            #foldersCopyto,\
                            #foldersRename").hide().addClass("display-none");
                    }
                }
            } else {
                jq("#foldersRemoveThirdparty,\
                    #foldersChangeThirdparty").hide().addClass("display-none");
            }

            if (!ASC.Files.Filter || !ASC.Files.Filter.getFilterSettings().isSet
                || ASC.Files.ThirdParty && ASC.Files.ThirdParty.isThirdParty()) {
                jq("#foldersGotoParent").hide().addClass("display-none");
            }

            if (!jq("#foldersMovePanel li:not(.display-none)").length) {
                jq("#foldersMove").hide().addClass("display-none");
            }

            jq("#actionPanelFolders").show();
        }

        if (!ASC.Clipboard.enable) {
            jq("#filesGetLink, #foldersGetLink").remove();
        }

        var dropdownItem = jq("#filesActionPanel");

        resizeDropdownPanel(dropdownItem);

        jq.showDropDownByContext(e, target, dropdownItem, function () {
            ASC.Files.Mouse.disableHover = true;
        });

        afterShowFunction(dropdownItem);

        if (target.is(".menu-small")) {
            entryObj.addClass("row-lonely-select");
        }

        return true;
    };

    var onContextMenu = function (event) {
        var e = jq.fixEvent(event);

        if (typeof e == "undefined" || !e) {
            return true;
        }

        var target = jq(e.srcElement || e.target);
        if (target.is("input[type=text]")) {
            return true;
        }

        if (target.parents(".studio-action-panel").length) {
            return !ASC.Desktop;
        }

        ASC.Files.Actions.hideAllActionPanels();

        if (!target.parents("#filesMainContent").length) {
            return !ASC.Desktop;
        }

        var entryData = ASC.Files.UI.getObjectData(target);
        if (!entryData) {
            if (target.is("a[href]")) {
                return true;
            }
            return false;
        }
        var entryObj = entryData.entryObject;

        if (entryObj.hasClass("new-folder") || entryObj.hasClass("row-rename") || entryObj.hasClass("error-entry")) {
            return true;
        }

        jq("#filesMainContent .row-hover").removeClass("row-hover");
        jq("#filesMainContent .row-lonely-select").removeClass("row-lonely-select");
        jq("#filesMainContent .menu-small").removeClass("active");
        var count = jq("#filesMainContent .file-row.row-selected").length;

        if (count > 1 && entryObj.hasClass("row-selected")) {
            ASC.Files.Actions.showActionsViewPanel(event);
        } else {
            ASC.Files.Actions.showActionsPanel(event, entryData);
        }

        return false;
    };

    var hideAllActionPanels = function () {
        ASC.Files.Actions.clipGetLink = ASC.Clipboard.destroy(ASC.Files.Actions.clipGetLink);

        jq(".studio-action-panel:visible").hide();
        jq("#filesMainContent .file-row.row-lonely-select").removeClass("row-lonely-select");
        jq("#filesMainContent .file-row .menu-small").removeClass("active");
        ASC.Files.UI.hideEntryTooltip();

        ASC.Files.Mouse.disableHover = false;
    };

    var checkEditFile = function (fileId, winEditor) {
        var fileObj = ASC.Files.UI.getEntryObject("file", fileId);
        ASC.Files.UI.lockEditFile(fileObj, true);

        var url = ASC.Files.Utility.GetFileWebEditorUrl(fileId);

        if (winEditor && winEditor.location) {
            winEditor.location.href = url;
        } else {
            winEditor = window.open(url, "_blank");
        }

        var onloadFunction = function () {
            var fileIdLocal = fileId;
            if (fileIdLocal) {
                ASC.Files.UI.lockEditFileById(fileIdLocal, true);
                ASC.Files.UI.checkEditing();
                ASC.Files.Socket.subscribeChangeEditors(fileIdLocal);
            }
        };

        if (winEditor == undefined) {

            ASC.Files.UI.lockEditFile(fileObj, true);
            ASC.Files.Socket.subscribeChangeEditors(fileId);

            ASC.Files.UI.checkEditingDefer();

        } else {

            try {
                winEditor.onload = onloadFunction;

                if (jq.browser.msie) {
                    var bodyIe;
                    var checkIeLoaded = function () {
                        bodyIe = winEditor.document.getElementsByTagName("body");
                        if (bodyIe[0] == null) {
                            setTimeout(checkIeLoaded, 10);
                        } else {
                            onloadFunction();
                        }
                    };
                    checkIeLoaded();
                }
            } catch (ex) {
            }

            try {
                winEditor.onunload = function () {
                    if (fileId) {
                        ASC.Files.UI.checkEditing();
                    }
                };
            } catch (ex) {
            }
        }

        return ASC.Files.Marker.removeNewIcon("file", fileId);
    };

    var showMoveToSelector = function (isCopy) {
        ASC.Files.Folders.isCopyTo = (isCopy === true);
        ASC.Files.Actions.hideAllActionPanels();

        if (ASC.Files.Folders.folderContainer != "trash"
            && !ASC.Files.Folders.isCopyTo) {
            if (!ASC.Files.UI.accessEdit()) {
                var listWithAccess = jq.grep(jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):has(.checkbox input:checked)"), function (item) {
                    return ASC.Files.UI.accessDelete(item);
                });

                if (!listWithAccess.length) {
                    ASC.Files.UI.displayInfoPanel(ASC.Files.FilesJSResource.InfoMoveGroup.format(0));
                    return;
                }
            }
        }

        ASC.Files.Tree.updateTreePath();

        if (!isCopy
            && jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):not(.on-edit):has(.checkbox input:checked)").length == 0) {
            ASC.Files.UI.displayInfoPanel(ASC.Files.FilesJSResource.InfoMoveGroup.format(0));
            return;
        }

        if (ASC.Files.ThirdParty
            && !ASC.Files.Folders.isCopyTo
            && !ASC.Files.ThirdParty.isThirdParty()
            && jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):not(.third-party-entry):has(.checkbox input:checked)").length == 0) {
            ASC.Files.UI.displayInfoPanel(ASC.Files.FilesJSResource.InfoMoveGroup.format(0));
            return;
        }

        if (jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):has(.checkbox input:checked)").length == 0) {
            return;
        }

        jq("#treeViewPanelSelector").removeClass("without-third-party");

        if (!jq("#treeViewPanelSelector").next().is("#mainContentHeader")) {
            jq("#treeViewPanelSelector").insertBefore("#mainContentHeader");
        }

        ASC.Files.Tree.showSelect(ASC.Files.Folders.currentFolder.id);
        jq.dropdownToggle().toggle(".menuActionSelectAll", "treeViewPanelSelector");

        jq("#treeViewPanelSelector").scrollTo(jq("#treeViewPanelSelector").find(".tree-node" + ASC.Files.UI.getSelectorId(ASC.Files.Folders.currentFolder.id)));

        jq("body").bind("click", ASC.Files.Actions.registerHideTree);
    };

    var registerHideTree = function (event) {
        if (!jq((event.target) ? event.target : event.srcElement).parents().addBack()
            .is("#treeViewPanelSelector, #foldersMoveto, #filesMoveto, #foldersCopyto, #filesCopyto,\
                 #foldersRestore, #filesRestore, #buttonMoveto, #buttonCopyto, #buttonRestore,\
                 #mainMove, #mainCopy, #mainRestore")) {
            ASC.Files.Actions.hideAllActionPanels();
            jq("body").unbind("click", ASC.Files.Actions.registerHideTree);
        }
    };

    return {
        init: init,
        showActionsViewPanel: showActionsViewPanel,
        showActionsPanel: showActionsPanel,
        onContextMenu: onContextMenu,

        checkEditFile: checkEditFile,

        hideAllActionPanels: hideAllActionPanels,

        clipGetLink: clipGetLink,
        clipGetExternalLink: clipGetExternalLink,

        currentEntryData: currentEntryData,

        showMoveToSelector: showMoveToSelector,
        registerHideTree: registerHideTree,

        setAceFileLink: setAceFileLink
    };
})();

(function ($) {
    ASC.Files.Actions.init();
    $(function () {

        jq("#filesSelectAll").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.UI.checkSelectAll(true);
        });

        jq("#filesSelectFile, #filesSelectFolder, #filesSelectDocument,\
            #filesSelectPresentation, #filesSelectSpreadsheet, #filesSelectImage, #filesSelectMedia, #filesSelectArchive").click(function () {
            var filter = this.id.replace("filesSelect", "").toLowerCase();
            ASC.Files.UI.checkSelect(filter);
        });

        jq("#filesDownload, #foldersDownload").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.download(ASC.Files.Actions.currentEntryData.entryType, ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesRename, #foldersRename").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.rename(ASC.Files.Actions.currentEntryData.entryType, ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesAddFavorite, #filesRemoveFavorite").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.toggleFavorite(ASC.Files.Actions.currentEntryData.entryObject);
        });

        jq("#filesAddTemplate, #filesRemoveTemplate").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.toggleTemplate(ASC.Files.Actions.currentEntryData.entryObject);
        });

        jq("#filesRemove, #foldersRemove").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.deleteItem(ASC.Files.Actions.currentEntryData.entryType, ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesShareAccess, #foldersShareAccess").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Share.getSharedInfo(ASC.Files.Actions.currentEntryData.entryType + "_" + ASC.Files.Actions.currentEntryData.id, ASC.Files.Actions.currentEntryData.title);
        });

        jq("#filesGetExternalLink .toggle").click(function(e) {
            if (jq(this).hasClass("off")) {
                ASC.Files.Actions.clipGetExternalLink.fromToggleBtn = true;
            } else {
                e.stopPropagation();
                ASC.Files.Actions.setAceFileLink();
            }
        });

        jq("#filesMarkRead, #foldersMarkRead").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Marker.markAsRead(ASC.Files.Actions.currentEntryData);
        });

        jq("#filesChangeOwner, #foldersChangeOwner").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.changeOwnerDialog(ASC.Files.Actions.currentEntryData);
        });

        jq("#filesSendInEmail").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            window.location.href = ASC.Mail.Utility.GetDraftUrl(ASC.Files.Actions.currentEntryData.entryId);
        });

        jq("#studioPageContent").on("click", "#buttonSendInEmail", function () {
            ASC.Files.Actions.hideAllActionPanels();

            var fileIds = jq("#filesMainContent .file-row:not(.checkloading):not(.new-folder):not(.new-file):not(.error-entry):not(.folder-row):has(.checkbox input:checked)").map(function () {
                var entryRowData = ASC.Files.UI.getObjectData(this);
                var entryRowId = entryRowData.entryId;

                return entryRowId;
            });

            window.location.href = ASC.Mail.Utility.GetDraftUrl(fileIds.get());
        });

        jq("#filesUnsubscribe, #foldersUnsubscribe").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Share.unSubscribeMe(ASC.Files.Actions.currentEntryData.entryType, ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesConvert").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Converter.showToConvert(ASC.Files.Actions.currentEntryData.entryObject);
        });

        jq("#filesOpen").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.clickOnFile(ASC.Files.Actions.currentEntryData, false);
            return false;
        });

        jq("#filesLock, #filesUnlock").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.lockFile(ASC.Files.Actions.currentEntryData.entryObject, ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesLock .toggle, #filesUnlock .toggle").click(function (e) {
            e.stopPropagation();
            jq("#filesLock, #filesUnlock").toggle();
            ASC.Files.Folders.lockFile(ASC.Files.Actions.currentEntryData.entryObject, ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesCompleteVersion").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.versionComplete(ASC.Files.Actions.currentEntryData.id, 0, false);
        });

        jq("#filesVersions").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.showVersions(ASC.Files.Actions.currentEntryData.entryObject, ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesEdit").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.clickOnFile(ASC.Files.Actions.currentEntryData, true);
        });

        jq("#filesByTemplate").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.createNewDoc(ASC.Files.Actions.currentEntryData);
        });

        jq("#filesCopy").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.createDuplicate(ASC.Files.Actions.currentEntryData);
        });

        jq("#foldersOpen").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.clickOnFolder(ASC.Files.Actions.currentEntryData.id);
        });

        jq("#filesGotoParent, #foldersGotoParent").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.Folders.clickOnFolder(ASC.Files.Actions.currentEntryData.folder_id);
        });

        jq("#foldersRemoveThirdparty").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.ThirdParty.showDeleteDialog(null, null, null, ASC.Files.Actions.currentEntryData.title, ASC.Files.Actions.currentEntryData);
        });

        jq("#foldersChangeThirdparty").click(function () {
            ASC.Files.Actions.hideAllActionPanels();
            ASC.Files.ThirdParty.showChangeDialog(ASC.Files.Actions.currentEntryData);
        });

        jq("body").bind("contextmenu", function (event) {
            return ASC.Files.Actions.onContextMenu(event);
        });

        jq("#filesMainContent").on("click", ".menu-small", ASC.Files.Actions.showActionsPanel);

        jq("#studioPageContent").on("click",
            "#buttonMoveto, #buttonCopyto, #buttonRestore,\
            #mainMove.unlockAction, #mainCopy.unlockAction, #mainRestore.unlockAction,\
            #filesMoveto, #filesRestore, #filesCopyto,\
            #foldersMoveto, #foldersRestore, #foldersCopyto",
            function () {
                ASC.Files.Actions.showMoveToSelector(this.id == "buttonCopyto" || this.id == "mainCopy" || this.id == "filesCopyto" || this.id == "foldersCopyto");
            });

        jq("#filesDocuSign").click(function () {
            ASC.Files.ThirdParty.showDocuSignDialog(ASC.Files.Actions.currentEntryData);
            ASC.Files.Actions.hideAllActionPanels();
            return false;
        });
    });
})(jQuery);

<|start_filename|>common/ASC.Common/Utils/HttpRequestExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Specialized;
using System.Globalization;
using System.Reflection;

namespace System.Web
{
    public static class HttpRequestExtensions
    {
        public static readonly string UrlRewriterHeader = "X-REWRITER-URL";


        public static Uri GetUrlRewriter(this HttpRequest request)
        {
            return request != null ? GetUrlRewriter(request.Headers, request.Url) : null;
        }

        public static Uri GetUrlRewriter(this HttpRequestBase request)
        {
            return request != null ? GetUrlRewriter(request.Headers, request.Url) : null;
        }

        public static Uri GetUrlRewriter(NameValueCollection headers, Uri requestUri)
        {
            if (requestUri == null)
            {
                return null;
            }

            if (!string.IsNullOrEmpty(requestUri.Query))
            {
                var urlRewriterQuery = HttpUtility.ParseQueryString(requestUri.Query);
                var rewriterUri = ParseRewriterUrl(urlRewriterQuery[UrlRewriterHeader]);
                if (rewriterUri != null)
                {
                    var result = new UriBuilder(requestUri)
                    {
                        Scheme = rewriterUri.Scheme,
                        Host = rewriterUri.Host,
                        Port = rewriterUri.Port
                    };
                    return result.Uri;
                }
            }

            if (headers != null && !string.IsNullOrEmpty(headers[UrlRewriterHeader]))
            {
                var rewriterUri = ParseRewriterUrl(headers[UrlRewriterHeader]);
                if (rewriterUri != null)
                {
                    var result = new UriBuilder(requestUri)
                    {
                        Scheme = rewriterUri.Scheme,
                        Host = rewriterUri.Host,
                        Port = rewriterUri.Port
                    };
                    return result.Uri;
                }
            }

            return requestUri;
        }

        public static Uri PushRewritenUri(this HttpContext context)
        {
            return context != null ? PushRewritenUri(context, GetUrlRewriter(context.Request)) : null;
        }

        public static Uri PushRewritenUri(this HttpContext context, Uri rewrittenUri)
        {
            Uri oldUri = null;
            if (context != null)
            {
                var request = context.Request;

                if (request.Url != rewrittenUri)
                {
                    var requestUri = request.Url;
                    try
                    {
                        //Push it
                        request.ServerVariables.Set("HTTPS", rewrittenUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase) ? "on" : "off");
                        request.ServerVariables.Set("SERVER_NAME", rewrittenUri.Host);
                        request.ServerVariables.Set("SERVER_PORT",
                                                    rewrittenUri.Port.ToString(CultureInfo.InvariantCulture));

                        if (rewrittenUri.IsDefaultPort)
                        {
                            request.ServerVariables.Set("HTTP_HOST",
                                                        rewrittenUri.Host);
                        }
                        else
                        {
                            request.ServerVariables.Set("HTTP_HOST",
                                                        rewrittenUri.Host + ":" + requestUri.Port);
                        }
                        //Hack:
                        typeof(HttpRequest).InvokeMember("_url",
                                                          BindingFlags.NonPublic | BindingFlags.SetField |
                                                          BindingFlags.Instance,
                                                          null, HttpContext.Current.Request,
                                                          new object[] { null });
                        oldUri = requestUri;
                        context.Items["oldUri"] = oldUri;

                    }
                    catch (Exception)
                    {
                    }
                }
            }
            return oldUri;
        }

        public static Uri PopRewritenUri(this HttpContext context)
        {
            if (context != null && context.Items["oldUri"] != null)
            {
                var rewriteTo = context.Items["oldUri"] as Uri;
                if (rewriteTo != null)
                {
                    return PushRewritenUri(context, rewriteTo);
                }
            }
            return null;
        }

        public static bool DesktopApp(this HttpRequest request)
        {
            return request != null
                && (!string.IsNullOrEmpty(request["desktop"])
                    || (request.UserAgent ?? "").Contains("AscDesktopEditor"));
        }

        public static bool SailfishApp(this HttpRequest request)
        {
            return request != null
                   && (!string.IsNullOrEmpty(request["sailfish"])
                       || !string.IsNullOrEmpty(request.UserAgent) && request.UserAgent.Contains("SailfishOS"));
        }


        private static Uri ParseRewriterUrl(string s)
        {
            if (string.IsNullOrEmpty(s))
            {
                return null;
            }

            const StringComparison cmp = StringComparison.OrdinalIgnoreCase;
            if (0 < s.Length && (s.StartsWith("0", cmp)))
            {
                s = Uri.UriSchemeHttp + s.Substring(1);
            }
            else if (3 < s.Length && s.StartsWith("OFF", cmp))
            {
                s = Uri.UriSchemeHttp + s.Substring(3);
            }
            else if (0 < s.Length && (s.StartsWith("1", cmp)))
            {
                s = Uri.UriSchemeHttps + s.Substring(1);
            }
            else if (2 < s.Length && s.StartsWith("ON", cmp))
            {
                s = Uri.UriSchemeHttps + s.Substring(2);
            }
            else if (s.StartsWith(Uri.UriSchemeHttp + "%3A%2F%2F", cmp) || s.StartsWith(Uri.UriSchemeHttps + "%3A%2F%2F", cmp))
            {
                s = HttpUtility.UrlDecode(s);
            }

            Uri result;
            Uri.TryCreate(s, UriKind.Absolute, out result);
            return result;
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Proxy/SIP_ProxyContext.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Proxy
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Timers;
    using Message;
    using Stack;

    #endregion

    /// <summary>
    /// Implements SIP 'proxy context'. Defined in RFC 3261.
    /// </summary>
    /// <remarks>Proxy context is bridge between caller and calee. 
    /// Proxy context job is to forward request to contact(s) and send received responses back to caller.</remarks>
    public class SIP_ProxyContext : IDisposable
    {
        #region Nested type: TargetHandler

        /// <summary>
        /// This class is responsible for sending <b>request</b> to target(HOPs) and processing responses.
        /// </summary>
        private class TargetHandler : IDisposable
        {
            #region Members

            private readonly bool m_AddRecordRoute = true;
            private readonly bool m_IsRecursed;
            private readonly SIP_Flow m_pFlow;
            private readonly object m_pLock = new object();
            private bool m_HasReceivedResponse;
            private bool m_IsCompleted;
            private bool m_IsDisposed;
            private bool m_IsStarted;
            private Queue<SIP_Hop> m_pHops;
            private SIP_ProxyContext m_pOwner;
            private SIP_Request m_pRequest;
            private SIP_Uri m_pTargetUri;
            private TimerEx m_pTimerC;
            private SIP_ClientTransaction m_pTransaction;

            #endregion

            #region Properties

            /// <summary>
            /// Gets if this object is disposed.
            /// </summary>
            public bool IsDisposed
            {
                get { return m_IsDisposed; }
            }

            /// <summary>
            /// Gets if this target processing has been started.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
            public bool IsStarted
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    return m_IsStarted;
                }
            }

            /// <summary>
            /// Gets if request sender has completed.
            /// </summary>
            public bool IsCompleted
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    return m_IsCompleted;
                }
            }

            /// <summary>
            /// Gets SIP request what this <b>Target</b> is sending.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
            public SIP_Request Request
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    return m_pRequest;
                }
            }

            /// <summary>
            /// Gets target URI where request is being sent.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
            public SIP_Uri TargetUri
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    return m_pTargetUri;
                }
            }

            /// <summary>
            /// Gets if this target is recording routing(By adding Record-Route header field to forwarded requests).
            /// </summary>
            public bool IsRecordingRoute
            {
                get { return m_AddRecordRoute; }
            }

            /// <summary>
            /// Gets if this target is redirected by proxy context.
            /// </summary>
            public bool IsRecursed
            {
                get { return m_IsRecursed; }
            }

            /// <summary>
            /// Gets if this handler has received any response from target.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
            public bool HasReceivedResponse
            {
                get
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    return m_HasReceivedResponse;
                }
            }

            #endregion

            #region Constructor

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="owner">Owner proxy context.</param>
            /// <param name="flow">Data flow to use for sending. Value null means system will choose it.</param>
            /// <param name="targetUri">Target URI where to send request.</param>
            /// <param name="addRecordRoute">If true, handler will add Record-Route header to forwarded message.</param>
            /// <param name="isRecursed">If true then this target is redirected by proxy context.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>targetURI</b> is null reference.</exception>
            public TargetHandler(SIP_ProxyContext owner,
                                 SIP_Flow flow,
                                 SIP_Uri targetUri,
                                 bool addRecordRoute,
                                 bool isRecursed)
            {
                if (owner == null)
                {
                    throw new ArgumentNullException("owner");
                }
                if (targetUri == null)
                {
                    throw new ArgumentNullException("targetUri");
                }

                m_pOwner = owner;
                m_pFlow = flow;
                m_pTargetUri = targetUri;
                m_AddRecordRoute = addRecordRoute;
                m_IsRecursed = isRecursed;

                m_pHops = new Queue<SIP_Hop>();
            }

            #endregion

            #region Methods

            /// <summary>
            /// Cleans up any resources being used.
            /// </summary>
            public void Dispose()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    m_IsDisposed = true;

                    m_pOwner.TargetHandler_Disposed(this);

                    m_pOwner = null;
                    m_pRequest = null;
                    m_pTargetUri = null;
                    m_pHops = null;
                    if (m_pTransaction != null)
                    {
                        m_pTransaction.Dispose();
                        m_pTransaction = null;
                    }
                    if (m_pTimerC != null)
                    {
                        m_pTimerC.Dispose();
                        m_pTimerC = null;
                    }
                }
            }

            /// <summary>
            /// Starts target processing.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
            /// <exception cref="InvalidOperationException">Is raised when <b>Start</b> method is already called and this method is called.</exception>
            public void Start()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }
                    if (m_IsStarted)
                    {
                        throw new InvalidOperationException("Start has already called.");
                    }
                    m_IsStarted = true;

                    Init();

                    // No hops for target. Invalid target domain name,dns server down,target won't support needed target.
                    if (m_pHops.Count == 0)
                    {
                        m_pOwner.ProcessResponse(this,
                                                 m_pTransaction,
                                                 m_pOwner.Proxy.Stack.CreateResponse(
                                                     SIP_ResponseCodes.x503_Service_Unavailable +
                                                     ": No hop(s) for target.",
                                                     m_pTransaction.Request));
                        Dispose();
                        return;
                    }
                    else
                    {
                        if (m_pFlow != null)
                        {
                            SendToFlow(m_pFlow, m_pRequest.Copy());
                        }
                        else
                        {
                            SendToNextHop();
                        }
                    }
                }
            }

            /// <summary>
            /// Cancels target processing.
            /// </summary>
            /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
            public void Cancel()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        throw new ObjectDisposedException(GetType().Name);
                    }

                    if (m_IsStarted)
                    {
                        m_pTransaction.Cancel();
                    }
                    else
                    {
                        Dispose();
                    }
                }
            }

            #endregion

            #region Event handlers

            /// <summary>
            /// Is called when client transactions receives response.
            /// </summary>
            /// <param name="sender">Sender.</param>
            /// <param name="e">Event data.</param>
            private void ClientTransaction_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
            {
                lock (m_pLock)
                {
                    m_HasReceivedResponse = true;

                    /* RFC 3261 16.7 Response Processing.
                        1.  Find the appropriate response context
                        2.  Update timer C for provisional responses
                 
                        Steps 3 - 10 done in ProxyContext.ProcessResponse method.
                    */

                    #region 1. Find Context

                    // Done, m_pOwner is it.

                    #endregion

                    #region 2. Update timer C for provisional responses

                    /* For an INVITE transaction, if the response is a provisional
                       response with status codes 101 to 199 inclusive (i.e., anything
                       but 100), the proxy MUST reset timer C for that client
                       transaction.  The timer MAY be reset to a different value, but
                       this value MUST be greater than 3 minutes.
                    */
                    if (m_pTimerC != null && e.Response.StatusCode >= 101 && e.Response.StatusCode <= 199)
                    {
                        m_pTimerC.Interval = 3*60*1000;
                    }

                    #endregion

                    /*
                    // If 401 or 407 (Authentication required), see i we have specified realm(s) credentials, 
                    // if so try to authenticate.
                    if(e.Response.StatusCode == 401 || e.Response.StatusCode == 407){
                        SIP_t_Challenge[] challanges = null;
                        if(e.Response.StatusCode == 401){
                            challanges = e.Response.WWWAuthenticate.GetAllValues();
                        }
                        else{
                            challanges = e.Response.ProxyAuthenticate.GetAllValues();
                        }

                        // TODO: Porbably we need to auth only if we can provide authentication data to all realms ?

                        SIP_Request request = m_pServerTransaction.Request.Copy();
                        request.CSeq.SequenceNumber++;
                        bool hasAny = false;
                        foreach(SIP_t_Challenge challange in challanges){
                            Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,m_pServerTransaction.Request.Method);
                            NetworkCredential credential = GetCredential(authDigest.Realm);
                            if(credential != null){
                                // Don't authenticate again, if we tried already once and failed.
                                // FIX ME: if user passed authorization, then works wrong.
                                if(e.ClientTransaction.Request.Authorization.Count == 0 && e.ClientTransaction.Request.ProxyAuthorization.Count == 0){
                                    authDigest.RequestMethod = m_pServerTransaction.Request.Method;
                                    authDigest.Uri           = e.ClientTransaction.Request.Uri;
                                    authDigest.Realm         = credential.Domain;
                                    authDigest.UserName      = credential.UserName;
                                    authDigest.Password      = <PASSWORD>;
                                    authDigest.CNonce        = Auth_HttpDigest.CreateNonce();
                                    authDigest.Qop           = authDigest.Qop;
                                    authDigest.Opaque        = authDigest.Opaque;
                                    authDigest.Algorithm     = authDigest.Algorithm;
                                    if(e.Response.StatusCode == 401){
                                        request.Authorization.Add(authDigest.ToAuthorization());
                                    }
                                    else{
                                        request.ProxyAuthorization.Add(authDigest.ToAuthorization());
                                    }
                                    hasAny = true;
                                }
                            }
                        }
                        if(hasAny){
                            // CreateClientTransaction((SIP_Target)e.ClientTransaction.Tag,request);
                            return;
                        }
                    }*/

                    if (e.Response.StatusCodeType != SIP_StatusCodeType.Provisional)
                    {
                        m_IsCompleted = true;
                    }

                    m_pOwner.ProcessResponse(this, m_pTransaction, e.Response);
                }
            }

            /// <summary>
            /// Is called when client transaction has timed out.
            /// </summary>
            /// <param name="sender">Sender.</param>
            /// <param name="e">Event data.</param>
            private void ClientTransaction_TimedOut(object sender, EventArgs e)
            {
                lock (m_pLock)
                {
                    /* RFC 3263 4.3.
                        For SIP requests, failure occurs if the transaction layer reports a
                        503 error response or a transport failure of some sort (generally,
                        due to fatal ICMP errors in UDP or connection failures in TCP).
                        Failure also occurs if the transaction layer times out without ever
                        having received any response, provisional or final (i.e., timer B or
                        timer F in RFC 3261 [1] fires). If a failure occurs, the client
                        SHOULD create a new request, which is identical to the previous, but
                        has a different value of the Via branch ID than the previous (and
                        therefore constitutes a new SIP transaction).  That request is sent
                        to the next element in the list as specified by RFC 2782.
                    */
                    if (m_pHops.Count > 0)
                    {
                        CleanUpActiveHop();
                        SendToNextHop();
                    }
                        /* RFC 3161 16.6.7.
                        If the ordered set is exhausted, the request cannot be forwarded to this element in
                        the target set. The proxy does not need to place anything in the response context, 
                        but otherwise acts as if this element of the target set returned a 
                        408 (Request Timeout) final response.
                    */
                    else
                    {
                        m_IsCompleted = true;
                        m_pOwner.ProcessResponse(this,
                                                 m_pTransaction,
                                                 m_pOwner.Proxy.Stack.CreateResponse(
                                                     SIP_ResponseCodes.x408_Request_Timeout,
                                                     m_pTransaction.Request));
                        Dispose();
                    }
                }
            }

            /// <summary>
            /// Is called when client transaction encountered transport error.
            /// </summary>
            /// <param name="sender">Sender.</param>
            /// <param name="e">Event data.</param>
            private void ClientTransaction_TransportError(object sender, ExceptionEventArgs e)
            {
                lock (m_pLock)
                {
                    /* RFC 3263 4.3.
                        For SIP requests, failure occurs if the transaction layer reports a
                        503 error response or a transport failure of some sort (generally,
                        due to fatal ICMP errors in UDP or connection failures in TCP).
                        Failure also occurs if the transaction layer times out without ever
                        having received any response, provisional or final (i.e., timer B or
                        timer F in RFC 3261 [1] fires). If a failure occurs, the client
                        SHOULD create a new request, which is identical to the previous, but
                        has a different value of the Via branch ID than the previous (and
                        therefore constitutes a new SIP transaction).  That request is sent
                        to the next element in the list as specified by RFC 2782.
                    */
                    if (m_pHops.Count > 0)
                    {
                        CleanUpActiveHop();
                        SendToNextHop();
                    }
                        /* RFC 3161 16.6.7.
                        If the ordered set is exhausted, the request cannot be forwarded to this element in
                        the target set.  The proxy does not need to place anything in the response context, 
                        but otherwise acts as if this element of the target set returned a 
                        408 (Request Timeout) final response.
                    */
                    else
                    {
                        m_IsCompleted = true;
                        m_pOwner.ProcessResponse(this,
                                                 m_pTransaction,
                                                 m_pOwner.Proxy.Stack.CreateResponse(
                                                     SIP_ResponseCodes.x408_Request_Timeout,
                                                     m_pTransaction.Request));
                        Dispose();
                    }
                }
            }

            /// <summary>
            /// This method is called when client transaction has disposed.
            /// </summary>
            /// <param name="sender">Sender.</param>
            /// <param name="e">Event data.</param>
            private void m_pTransaction_Disposed(object sender, EventArgs e)
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }

                    // If we have got any response from any client transaction, then all done.
                    if (HasReceivedResponse)
                    {
                        Dispose();
                    }
                }
            }

            private void m_pTimerC_Elapsed(object sender, ElapsedEventArgs e)
            {
                lock (m_pLock)
                {
                    /* RFC 3261 16.8 Processing Timer C.
                        If the client transaction has received a provisional response, the proxy
                        MUST generate a CANCEL request matching that transaction.  If the client 
                        transaction has not received a provisional response, the proxy MUST behave 
                        as if the transaction received a 408 (Request Timeout) response.
                    */

                    if (m_pTransaction.HasProvisionalResponse)
                    {
                        m_pTransaction.Cancel();
                    }
                    else
                    {
                        m_pOwner.ProcessResponse(this,
                                                 m_pTransaction,
                                                 m_pOwner.Proxy.Stack.CreateResponse(
                                                     SIP_ResponseCodes.x408_Request_Timeout,
                                                     m_pTransaction.Request));
                        Dispose();
                    }
                }
            }

            #endregion

            #region Utility methods

            /// <summary>
            /// Initializes target.
            /// </summary>
            private void Init()
            {
                /* RFC 3261 16.6 Request Forwarding.
                For each target, the proxy forwards the request following these steps:
                    1.  Make a copy of the received request
                    2.  Update the Request-URI
                    3.  Update the Max-Forwards header field
                    4.  Optionally add a Record-route header field value
                    5.  Optionally add additional header fields
                    6.  Postprocess routing information
                    7.  Determine the next-hop address, port, and transport
                */

                bool isStrictRoute = false;

                #region 1. Make a copy of the received request.

                // 1. Make a copy of the received request.
                m_pRequest = m_pOwner.Request.Copy();

                #endregion

                #region 2. Update the Request-URI.

                // 2. Update the Request-URI.
                m_pRequest.RequestLine.Uri = m_pTargetUri;

                #endregion

                #region 3. Update the Max-Forwards header field.

                // 3. Update the Max-Forwards header field.
                m_pRequest.MaxForwards--;

                #endregion

                #region 5. Optionally add additional header fields.

                // 5. Optionally add additional header fields.
                //    Skip.

                #endregion

                #region 6. Postprocess routing information.

                /* 6. Postprocess routing information.
             
                    If the copy contains a Route header field, the proxy MUST inspect the URI in its first value.  
                    If that URI does not contain an lr parameter, the proxy MUST modify the copy as follows:             
                        - The proxy MUST place the Request-URI into the Route header
                          field as the last value.
             
                        - The proxy MUST then place the first Route header field value
                          into the Request-URI and remove that value from the Route header field.
                */
                if (m_pRequest.Route.GetAllValues().Length > 0 &&
                    !m_pRequest.Route.GetTopMostValue().Parameters.Contains("lr"))
                {
                    m_pRequest.Route.Add(m_pRequest.RequestLine.Uri.ToString());

                    m_pRequest.RequestLine.Uri =
                        SIP_Utils.UriToRequestUri(m_pRequest.Route.GetTopMostValue().Address.Uri);
                    m_pRequest.Route.RemoveTopMostValue();

                    isStrictRoute = true;
                }

                #endregion

                #region 7. Determine the next-hop address, port, and transport.

                /* 7. Determine the next-hop address, port, and transport.
                      The proxy MAY have a local policy to send the request to a
                      specific IP address, port, and transport, independent of the
                      values of the Route and Request-URI.  Such a policy MUST NOT be
                      used if the proxy is not certain that the IP address, port, and
                      transport correspond to a server that is a loose router.
                      However, this mechanism for sending the request through a
                      specific next hop is NOT RECOMMENDED; instead a Route header
                      field should be used for that purpose as described above.
             
                      In the absence of such an overriding mechanism, the proxy
                      applies the procedures listed in [4] as follows to determine
                      where to send the request.  If the proxy has reformatted the
                      request to send to a strict-routing element as described in
                      step 6 above, the proxy MUST apply those procedures to the
                      Request-URI of the request.  Otherwise, the proxy MUST apply
                      the procedures to the first value in the Route header field, if
                      present, else the Request-URI.  The procedures will produce an
                      ordered set of (address, port, transport) tuples.
                      Independently of which URI is being used as input to the
                      procedures of [4], if the Request-URI specifies a SIPS
                      resource, the proxy MUST follow the procedures of [4] as if the
                      input URI were a SIPS URI.

                      As described in [4], the proxy MUST attempt to deliver the
                      message to the first tuple in that set, and proceed through the
                      set in order until the delivery attempt succeeds.

                      For each tuple attempted, the proxy MUST format the message as
                      appropriate for the tuple and send the request using a new
                      client transaction as detailed in steps 8 through 10.
             
                      Since each attempt uses a new client transaction, it represents
                      a new branch.  Thus, the branch parameter provided with the Via
                      header field inserted in step 8 MUST be different for each
                      attempt.

                      If the client transaction reports failure to send the request
                      or a timeout from its state machine, the proxy continues to the
                      next address in that ordered set.  If the ordered set is
                      exhausted, the request cannot be forwarded to this element in
                      the target set.  The proxy does not need to place anything in
                      the response context, but otherwise acts as if this element of
                      the target set returned a 408 (Request Timeout) final response.
                */
                SIP_Uri uri = null;
                if (isStrictRoute)
                {
                    uri = (SIP_Uri) m_pRequest.RequestLine.Uri;
                }
                else if (m_pRequest.Route.GetTopMostValue() != null)
                {
                    uri = (SIP_Uri) m_pRequest.Route.GetTopMostValue().Address.Uri;
                }
                else
                {
                    uri = (SIP_Uri) m_pRequest.RequestLine.Uri;
                }

                // Queue hops.
                foreach (
                    SIP_Hop hop in
                        m_pOwner.Proxy.Stack.GetHops(uri,
                                                     m_pRequest.ToByteData().Length,
                                                     ((SIP_Uri) m_pRequest.RequestLine.Uri).IsSecure))
                {
                    m_pHops.Enqueue(hop);
                }

                #endregion

                #region 4. Optionally add a Record-route header field value.

                // We need to do step 4 after step 7, because then transport in known.
                // Each transport can have own host-name, otherwise we don't know what to put into Record-Route.

                /*
                    If the Request-URI contains a SIPS URI, or the topmost Route header
                    field value (after the post processing of bullet 6) contains a SIPS URI,                 
                    the URI placed into the Record-Route header field MUST be a SIPS URI.
                    Furthermore, if the request was not received over TLS, the proxy MUST 
                    insert a Record-Route header field. In a similar fashion, a proxy that 
                    receives a request over TLS, but generates a request without a SIPS URI 
                    in the Request-URI or topmost Route header field value (after the post
                    processing of bullet 6), MUST insert a Record-Route header field that 
                    is not a SIPS URI.
                */

                // NOTE: ACK don't add Record-route header.
                if (m_pHops.Count > 0 && m_AddRecordRoute && m_pRequest.RequestLine.Method != SIP_Methods.ACK)
                {
                    string recordRoute =
                        m_pOwner.Proxy.Stack.TransportLayer.GetRecordRoute(m_pHops.Peek().Transport);
                    if (recordRoute != null)
                    {
                        m_pRequest.RecordRoute.Add(recordRoute);
                    }
                }

                #endregion
            }

            /// <summary>
            /// Starts sending request to next hop in queue.
            /// </summary>
            /// <exception cref="InvalidOperationException">Is raised when no next hop available(m_pHops.Count == 0) and this method is accessed.</exception>
            private void SendToNextHop()
            {
                if (m_pHops.Count == 0)
                {
                    throw new InvalidOperationException("No more hop(s).");
                }

                SIP_Hop hop = m_pHops.Dequeue();

                SendToFlow(
                    m_pOwner.Proxy.Stack.TransportLayer.GetOrCreateFlow(hop.Transport, null, hop.EndPoint),
                    m_pRequest.Copy());
            }

            /// <summary>
            /// Sends specified request to the specified data flow.
            /// </summary>
            /// <param name="flow">SIP data flow.</param>
            /// <param name="request">SIP request to send.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
            private void SendToFlow(SIP_Flow flow, SIP_Request request)
            {
                if (flow == null)
                {
                    throw new ArgumentNullException("flow");
                }
                if (request == null)
                {
                    throw new ArgumentNullException("request");
                }

                /* NAT traversal.
                    When we do record routing, store request sender flow info and request target flow info.
                    Now the tricky part, how proxy later which flow is target (because both sides can send requests).
                      Sender-flow will store from-tag to flow and target-flow will store flowID only (Because we don't know to-tag).
                      Later if request to-tag matches(incoming request), use that flow, otherwise(outgoing request) other flow.
                 
                    flowInfo: sender-flow "/" target-flow
                              sender-flow = from-tag ":" flowID
                              target-flow = flowID                        
                */
                if (m_AddRecordRoute && request.From.Tag != null)
                {
                    string flowInfo = request.From.Tag + ":" + m_pOwner.ServerTransaction.Flow.ID + "/" +
                                      flow.ID;
                    ((SIP_Uri) request.RecordRoute.GetTopMostValue().Address.Uri).Parameters.Add("flowInfo",
                                                                                                 flowInfo);
                }

                /* RFC 3261 16.6 Request Forwarding.
                        Common Steps 1 - 7 are done in target Init().
                                                  
                        8.  Add a Via header field value
                        9.  Add a Content-Length header field if necessary
                        10. Forward the new request
                        11. Set timer C
                */

                #region 8.  Add a Via header field value

                // Skip, Client transaction will add it.

                #endregion

                #region 9.  Add a Content-Length header field if necessary

                // Skip, our SIP_Message class is smart and do it when ever it's needed.

                #endregion

                #region 10. Forward the new request

                m_pTransaction = m_pOwner.Proxy.Stack.TransactionLayer.CreateClientTransaction(flow,
                                                                                               request,
                                                                                               true);
                m_pTransaction.ResponseReceived += ClientTransaction_ResponseReceived;
                m_pTransaction.TimedOut += ClientTransaction_TimedOut;
                m_pTransaction.TransportError += ClientTransaction_TransportError;
                m_pTransaction.Disposed += m_pTransaction_Disposed;

                // Start transaction processing.
                m_pTransaction.Start();

                #endregion

                #region 11. Set timer C

                /* 11. Set timer C
                    In order to handle the case where an INVITE request never
                    generates a final response, the TU uses a timer which is called
                    timer C.  Timer C MUST be set for each client transaction when
                    an INVITE request is proxied.  The timer MUST be larger than 3
                    minutes.  Section 16.7 bullet 2 discusses how this timer is
                    updated with provisional responses, and Section 16.8 discusses
                    processing when it fires.
                */
                if (request.RequestLine.Method == SIP_Methods.INVITE)
                {
                    m_pTimerC = new TimerEx();
                    m_pTimerC.AutoReset = false;
                    m_pTimerC.Interval = 3*60*1000;
                    m_pTimerC.Elapsed += m_pTimerC_Elapsed;
                }

                #endregion
            }

            /// <summary>
            /// Cleans up acitve hop resources.
            /// </summary>
            private void CleanUpActiveHop()
            {
                if (m_pTimerC != null)
                {
                    m_pTimerC.Dispose();
                    m_pTimerC = null;
                }
                if (m_pTransaction != null)
                {
                    m_pTransaction.Dispose();
                    m_pTransaction = null;
                }
            }

            #endregion
        }

        #endregion

        #region Members

        private readonly bool m_AddRecordRoute;
        private readonly DateTime m_CreateTime;
        private readonly SIP_ForkingMode m_ForkingMode = SIP_ForkingMode.Parallel;
        private readonly string m_ID = "";
        private readonly bool m_IsB2BUA = true;
        private readonly bool m_NoCancel;
        private readonly bool m_NoRecurse = true;
        private readonly List<NetworkCredential> m_pCredentials;
        private readonly object m_pLock = new object();
        private readonly SIP_Request m_pRequest;
        private bool m_IsDisposed;
        private bool m_IsFinalResponseSent;
        private bool m_IsStarted;
        private SIP_ProxyCore m_pProxy;
        private List<SIP_Response> m_pResponses;
        private SIP_ServerTransaction m_pServerTransaction;
        private Queue<TargetHandler> m_pTargets;
        private List<TargetHandler> m_pTargetsHandlers;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get { return m_IsDisposed; }
        }

        /// <summary>
        /// Gets owner SIP proxy server.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public SIP_ProxyCore Proxy
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return m_pProxy;
            }
        }

        /// <summary>
        /// Gets proxy context ID.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public string ID
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_ID;
            }
        }

        /// <summary>
        /// Gets time when proxy context was created.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public DateTime CreateTime
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_CreateTime;
            }
        }

        /// <summary>
        /// Gets forking mode used by this 'proxy context'.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public SIP_ForkingMode ForkingMode
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_ForkingMode;
            }
        }

        /// <summary>
        /// Gets if proxy cancels forked requests what are not needed any more. If true, 
        /// requests not canceled, otherwise canceled.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public bool NoCancel
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_NoCancel;
            }
        }

        /// <summary>
        /// Gets what proxy server does when it gets 3xx response. If true proxy will forward
        /// request to new specified address if false, proxy will return 3xx response to caller.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public bool Recurse
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return !m_NoRecurse;
            }
        }

        /// <summary>
        /// Gets server transaction what is responsible for sending responses to caller.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public SIP_ServerTransaction ServerTransaction
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_pServerTransaction;
            }
        }

        /// <summary>
        /// Gets request what is forwarded by proxy context.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this property is accessed.</exception>
        public SIP_Request Request
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_pRequest;
            }
        }

        /*
        /// <summary>
        /// Gets active client transactions that will handle forward request. 
        /// There may be more than 1 active client transaction if parallel forking.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public SIP_ClientTransaction[] ClientTransactions
        {
            get{
                if(m_IsDisposed){
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_pClientTransactions.ToArray(); 
            }
        } */

        /// <summary>
        /// Gets all responses what proxy context has received.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public SIP_Response[] Responses
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SIP_ProxyContext");
                }

                return m_pResponses.ToArray();
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="proxy">Owner proxy.</param>
        /// <param name="transaction">Server transaction what is used to send SIP responses back to caller.</param>
        /// <param name="request">Request to forward.</param>
        /// <param name="addRecordRoute">If true, Record-Route header field will be added.</param>
        /// <param name="forkingMode">Specifies how proxy context must handle forking.</param>
        /// <param name="isB2BUA">Specifies if proxy context is in B2BUA or just transaction satefull mode.</param>
        /// <param name="noCancel">Specifies if proxy should not send Cancel to forked requests.</param>
        /// <param name="noRecurse">Specifies what proxy server does when it gets 3xx response. If true proxy will forward
        /// request to new specified address if false, proxy will return 3xx response to caller.</param>
        /// <param name="targets">Possible remote targets. NOTE: These values must be in priority order !</param>
        /// <param name="credentials">Target set credentials.</param>
        /// <exception cref="ArgumentNullException">Is raised when any of the reference type prameters is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        internal SIP_ProxyContext(SIP_ProxyCore proxy,
                                  SIP_ServerTransaction transaction,
                                  SIP_Request request,
                                  bool addRecordRoute,
                                  SIP_ForkingMode forkingMode,
                                  bool isB2BUA,
                                  bool noCancel,
                                  bool noRecurse,
                                  SIP_ProxyTarget[] targets,
                                  NetworkCredential[] credentials)
        {
            if (proxy == null)
            {
                throw new ArgumentNullException("proxy");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (targets == null)
            {
                throw new ArgumentNullException("targets");
            }
            if (targets.Length == 0)
            {
                throw new ArgumentException("Argumnet 'targets' must contain at least 1 value.");
            }

            m_pProxy = proxy;

            m_pServerTransaction = transaction;
            m_pServerTransaction.Canceled += m_pServerTransaction_Canceled;
            m_pServerTransaction.Disposed += m_pServerTransaction_Disposed;

            m_pRequest = request;
            m_AddRecordRoute = addRecordRoute;
            m_ForkingMode = forkingMode;
            m_IsB2BUA = isB2BUA;
            m_NoCancel = noCancel;
            m_NoRecurse = noRecurse;

            m_pTargetsHandlers = new List<TargetHandler>();
            m_pResponses = new List<SIP_Response>();
            m_ID = Guid.NewGuid().ToString();
            m_CreateTime = DateTime.Now;

            // Queue targets up, higest to lowest.
            m_pTargets = new Queue<TargetHandler>();
            foreach (SIP_ProxyTarget target in targets)
            {
                m_pTargets.Enqueue(new TargetHandler(this,
                                                     target.Flow,
                                                     target.TargetUri,
                                                     m_AddRecordRoute,
                                                     false));
            }

            m_pCredentials = new List<NetworkCredential>();
            m_pCredentials.AddRange(credentials);

            /*  RFC 3841 9.1.
                The Request-Disposition header field specifies caller preferences for
                how a server should process a request.
              
                Override SIP proxy default value.
            */
            foreach (SIP_t_Directive directive in request.RequestDisposition.GetAllValues())
            {
                if (directive.Directive == SIP_t_Directive.DirectiveType.NoFork)
                {
                    m_ForkingMode = SIP_ForkingMode.None;
                }
                else if (directive.Directive == SIP_t_Directive.DirectiveType.Parallel)
                {
                    m_ForkingMode = SIP_ForkingMode.Parallel;
                }
                else if (directive.Directive == SIP_t_Directive.DirectiveType.Sequential)
                {
                    m_ForkingMode = SIP_ForkingMode.Sequential;
                }
                else if (directive.Directive == SIP_t_Directive.DirectiveType.NoCancel)
                {
                    m_NoCancel = true;
                }
                else if (directive.Directive == SIP_t_Directive.DirectiveType.NoRecurse)
                {
                    m_NoRecurse = true;
                }
            }

            m_pProxy.Stack.Logger.AddText("ProxyContext(id='" + m_ID + "') created.");
        }

        #endregion

        #region Methods

        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            lock (m_pLock)
            {
                if (m_IsDisposed)
                {
                    return;
                }
                m_IsDisposed = true;

                m_pProxy.Stack.Logger.AddText("ProxyContext(id='" + m_ID + "') disposed.");

                m_pProxy.m_pProxyContexts.Remove(this);

                m_pProxy = null;
                m_pServerTransaction = null;
                m_pTargetsHandlers = null;
                m_pResponses = null;
                m_pTargets = null;
            }
        }

        /// <summary>
        /// Starts processing.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when this method is called more than once.</exception>
        public void Start()
        {
            lock (m_pLock)
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (m_IsStarted)
                {
                    throw new InvalidOperationException("Start has already called.");
                }
                m_IsStarted = true;

                // Only use destination with the highest q value.
                // We already have ordered highest to lowest, so just get first destination.
                if (m_ForkingMode == SIP_ForkingMode.None)
                {
                    TargetHandler handler = m_pTargets.Dequeue();
                    m_pTargetsHandlers.Add(handler);
                    handler.Start();
                }
                    // Use all destinations at same time.
                else if (m_ForkingMode == SIP_ForkingMode.Parallel)
                {
                    // NOTE: If target count == 1 and transport exception, target may Dispose proxy context., so we need to handle it.
                    while (!m_IsDisposed && m_pTargets.Count > 0)
                    {
                        TargetHandler handler = m_pTargets.Dequeue();
                        m_pTargetsHandlers.Add(handler);
                        handler.Start();
                    }
                }
                    // Start processing destinations with highest q value to lowest.
                else if (m_ForkingMode == SIP_ForkingMode.Sequential)
                {
                    TargetHandler handler = m_pTargets.Dequeue();
                    m_pTargetsHandlers.Add(handler);
                    handler.Start();
                }
            }
        }

        /// <summary>
        /// Cancels proxy context processing. All client transactions and owner server transaction will be canceled,
        /// proxy context will be disposed. 
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when <b>Start</b> method is not called and this method is accessed.</exception>
        public void Cancel()
        {
            lock (m_pLock)
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (!m_IsStarted)
                {
                    throw new InvalidOperationException("Start method is not called, nothing to cancel.");
                }

                m_pServerTransaction.Cancel();

                // Server transaction raised Cancled event, we dispose active targets there.
            }
        }

        #endregion

        #region Event handlers

        /// <summary>
        /// Is called when server transaction has canceled.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pServerTransaction_Canceled(object sender, EventArgs e)
        {
            lock (m_pLock)
            {
                CancelAllTargets();

                // We dont need to Dispose proxy context, server transaction will call Terminated event
                // after cancel, there we dispose it.
            }
        }

        /// <summary>
        /// This method is called when server transaction has disposed.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pServerTransaction_Disposed(object sender, EventArgs e)
        {
            // All done, just dispose proxy context.
            Dispose();
        }

        #endregion

        #region Utility methods

        /// <summary>
        /// This method is called when specified target handler has disposed.
        /// </summary>
        /// <param name="handler">TargetHandler what disposed.</param>
        private void TargetHandler_Disposed(TargetHandler handler)
        {
            lock (m_pLock)
            {
                m_pTargetsHandlers.Remove(handler);

                // All targets are processed.
                if (m_pTargets.Count == 0 && m_pTargetsHandlers.Count == 0)
                {
                    Dispose();
                }
            }
        }

        /// <summary>
        /// Processes received response.
        /// </summary>
        /// <param name="handler">Target handler what received response.</param>
        /// <param name="transaction">Client transaction what response it is.</param>
        /// <param name="response">Response received.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>handler</b>,<b>transaction</b> or <b>response</b> is null reference.</exception>
        private void ProcessResponse(TargetHandler handler,
                                     SIP_ClientTransaction transaction,
                                     SIP_Response response)
        {
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            /* RFC 3261 16.7 Response Processing.
                Steps 1 - 2 handled in TargetHandler.
             
                3.  Remove the topmost Via
                4.  Add the response to the response context
                5.  Check to see if this response should be forwarded immediately
                6.  When necessary, choose the best final response from the response context.
                    If no final response has been forwarded after every client
                    transaction associated with the response context has been terminated,
                    the proxy must choose and forward the "best" response from those it
                    has seen so far.

                The following processing MUST be performed on each response that is
                forwarded.  It is likely that more than one response to each request
                will be forwarded: at least each provisional and one final response.

                7.  Aggregate authorization header field values if necessary
                8.  Optionally rewrite Record-Route header field values
                9.  Forward the response
                10. Generate any necessary CANCEL requests
            */

            bool forwardResponse = false;

            lock (m_pLock)
            {
                #region 3.  Remove the topmost Via

                /* 
                    The proxy removes the topmost Via header field value from the
                    response.
                 
                    If no Via header field values remain in the response, the
                    response was meant for this element and MUST NOT be forwarded.
                    The remainder of the processing described in this section is
                    not performed on this message, the UAC processing rules
                    described in Section 8.1.3 are followed instead (transport
                    layer processing has already occurred).

                    This will happen, for instance, when the element generates
                    CANCEL requests as described in Section 10.
                 
                    NOTE: We MAY NOT do it for B2BUA, skip it for B2BUA
                */
                if (!m_IsB2BUA)
                {
                    response.Via.RemoveTopMostValue();
                    if (response.Via.GetAllValues().Length == 0)
                    {
                        return;
                    }
                }

                #endregion

                #region 4.  Add the response to the response context

                /*
                    Final responses received are stored in the response context
                    until a final response is generated on the server transaction
                    associated with this context.  The response may be a candidate
                    for the best final response to be returned on that server
                    transaction.  Information from this response may be needed in
                    forming the best response, even if this response is not chosen.
 
                    If the proxy chooses to recurse on any contacts in a 3xx
                    response by adding them to the target set, it MUST remove them
                    from the response before adding the response to the response
                    context.  However, a proxy SHOULD NOT recurse to a non-SIPS URI
                    if the Request-URI of the original request was a SIPS URI.  If
                    the proxy recurses on all of the contacts in a 3xx response,
                    the proxy SHOULD NOT add the resulting contactless response to
                    the response context.
                  
                    Removing the contact before adding the response to the response
                    context prevents the next element upstream from retrying a
                    location this proxy has already attempted.

                    3xx responses may contain a mixture of SIP, SIPS, and non-SIP
                    URIs.  A proxy may choose to recurse on the SIP and SIPS URIs
                    and place the remainder into the response context to be
                    returned, potentially in the final response.
                */

                if (response.StatusCodeType == SIP_StatusCodeType.Redirection && !m_NoRecurse &&
                    !handler.IsRecursed)
                {
                    // Get SIP contacts and remove them from response.
                    SIP_t_ContactParam[] contacts = response.Contact.GetAllValues();
                    // Remove all contacts from response, we add non-SIP URIs back.
                    response.Contact.RemoveAll();
                    foreach (SIP_t_ContactParam contact in contacts)
                    {
                        // SIP URI add it to fork list.
                        if (contact.Address.IsSipOrSipsUri)
                        {
                            m_pTargets.Enqueue(new TargetHandler(this,
                                                                 null,
                                                                 (SIP_Uri) contact.Address.Uri,
                                                                 m_AddRecordRoute,
                                                                 true));
                        }
                            // Add specified URI back to response.
                        else
                        {
                            response.Contact.Add(contact.ToStringValue());
                        }
                    }

                    // There are remaining non-SIP contacts, so we need to add the response to reponses collection.
                    if (response.Contact.GetAllValues().Length > 0)
                    {
                        m_pResponses.Add(response);
                    }

                    // Handle forking
                    if (m_pTargets.Count > 0)
                    {
                        if (m_ForkingMode == SIP_ForkingMode.Parallel)
                        {
                            while (m_pTargets.Count > 0)
                            {
                                TargetHandler h = m_pTargets.Dequeue();
                                m_pTargetsHandlers.Add(handler);
                                h.Start();
                            }
                        }
                            // Just fork next.
                        else
                        {
                            TargetHandler h = m_pTargets.Dequeue();
                            m_pTargetsHandlers.Add(handler);
                            h.Start();
                        }

                        // Because we forked request to new target(s), we don't need to do steps 5 - 10.
                        return;
                    }
                }
                    // Not 3xx response or recursing disabled.
                else
                {
                    m_pResponses.Add(response);
                }

                #endregion

                #region 5.  Check to see if this response should be forwarded immediately

                /*
                    Until a final response has been sent on the server transaction,
                    the following responses MUST be forwarded immediately:

                    -  Any provisional response other than 100 (Trying)

                    -  Any 2xx response

                    If a 6xx response is received, it is not immediately forwarded,
                    but the stateful proxy SHOULD cancel all client pending
                    transactions as described in Section 10, and it MUST NOT create
                    any new branches in this context.
                 
                    After a final response has been sent on the server transaction,
                    the following responses MUST be forwarded immediately:

                    -  Any 2xx response to an INVITE request
                */

                if (!m_IsFinalResponseSent)
                {
                    if (response.StatusCodeType == SIP_StatusCodeType.Provisional &&
                        response.StatusCode != 100)
                    {
                        forwardResponse = true;
                    }
                    else if (response.StatusCodeType == SIP_StatusCodeType.Success)
                    {
                        forwardResponse = true;
                    }
                    else if (response.StatusCodeType == SIP_StatusCodeType.GlobalFailure)
                    {
                        CancelAllTargets();
                    }
                }
                else
                {
                    if (response.StatusCodeType == SIP_StatusCodeType.Success &&
                        m_pServerTransaction.Request.RequestLine.Method == SIP_Methods.INVITE)
                    {
                        forwardResponse = true;
                    }
                }

                #endregion

                #region x.  Handle sequential forking

                /*
                    Sequential Search: In a sequential search, a proxy server attempts
                    each contact address in sequence, proceeding to the next one
                    only after the previous has generated a final response.  A 2xx
                    or 6xx class final response always terminates a sequential
                    search.
                */
                if (m_ForkingMode == SIP_ForkingMode.Sequential &&
                    response.StatusCodeType != SIP_StatusCodeType.Provisional)
                {
                    if (response.StatusCodeType == SIP_StatusCodeType.Success)
                    {
                        // Do nothing, 2xx will be always forwarded and step 10. Cancels all targets.
                    }
                    else if (response.StatusCodeType == SIP_StatusCodeType.GlobalFailure)
                    {
                        // Do nothing, 6xx is already handled in setp 5.
                    }
                    else if (m_pTargets.Count > 0)
                    {
                        TargetHandler h = m_pTargets.Dequeue();
                        m_pTargetsHandlers.Add(handler);
                        h.Start();

                        // Skip all next steps, we will get new responses from new target.
                        return;
                    }
                }

                #endregion

                #region 6.  When necessary, choose the best final response from the response context

                /* 
                    A stateful proxy MUST send a final response to a response
                    context's server transaction if no final responses have been
                    immediately forwarded by the above rules and all client
                    transactions in this response context have been terminated.

                    The stateful proxy MUST choose the "best" final response among
                    those received and stored in the response context.

                    If there are no final responses in the context, the proxy MUST
                    send a 408 (Request Timeout) response to the server
                    transaction.

                */

                if (!m_IsFinalResponseSent && !forwardResponse && m_pTargets.Count == 0)
                {
                    bool mustChooseBestFinalResponse = true;
                    // Check if all transactions terminated.
                    foreach (TargetHandler h in m_pTargetsHandlers)
                    {
                        if (!h.IsCompleted)
                        {
                            mustChooseBestFinalResponse = false;
                            break;
                        }
                    }

                    if (mustChooseBestFinalResponse)
                    {
                        response = GetBestFinalResponse();
                        if (response == null)
                        {
                            response = Proxy.Stack.CreateResponse(SIP_ResponseCodes.x408_Request_Timeout,
                                                                  m_pServerTransaction.Request);
                        }

                        forwardResponse = true;
                    }
                }

                #endregion

                if (forwardResponse)
                {
                    #region 7.  Aggregate authorization header field values if necessary

                    /* 
                        If the selected response is a 401 (Unauthorized) or 407 (Proxy Authentication Required), 
                        the proxy MUST collect any WWW-Authenticate and Proxy-Authenticate header field values 
                        from all other 401 (Unauthorized) and 407 (Proxy Authentication Required) responses 
                        received so far in this response context and add them to this response without 
                        modification before forwarding. The resulting 401 (Unauthorized) or 407 (Proxy
                        Authentication Required) response could have several WWW-Authenticate AND 
                        Proxy-Authenticate header field values.

                        This is necessary because any or all of the destinations the request was forwarded to 
                        may have requested credentials.  The client needs to receive all of those challenges and 
                        supply credentials for each of them when it retries the request.
                    */
                    if (response.StatusCode == 401 || response.StatusCode == 407)
                    {
                        foreach (SIP_Response resp in m_pResponses.ToArray())
                        {
                            if (response != resp && (resp.StatusCode == 401 || resp.StatusCode == 407))
                            {
                                // WWW-Authenticate
                                foreach (SIP_HeaderField hf in resp.WWWAuthenticate.HeaderFields)
                                {
                                    resp.WWWAuthenticate.Add(hf.Value);
                                }
                                // Proxy-Authenticate
                                foreach (SIP_HeaderField hf in resp.ProxyAuthenticate.HeaderFields)
                                {
                                    resp.ProxyAuthenticate.Add(hf.Value);
                                }
                            }
                        }
                    }

                    #endregion

                    #region 8.  Optionally rewrite Record-Route header field values

                    // This is optional so we currently won't do that.

                    #endregion

                    #region 9.  Forward the response

                    SendResponse(transaction, response);
                    if (response.StatusCodeType != SIP_StatusCodeType.Provisional)
                    {
                        m_IsFinalResponseSent = true;
                    }

                    #endregion

                    #region 10. Generate any necessary CANCEL requests

                    /* 
                        If the forwarded response was a final response, the proxy MUST
                        generate a CANCEL request for all pending client transactions
                        associated with this response context.
                    */
                    if (response.StatusCodeType != SIP_StatusCodeType.Provisional)
                    {
                        CancelAllTargets();
                    }

                    #endregion
                }
            }
        }

        /// <summary>
        /// Sends SIP response to caller. If proxy context is in B2BUA mode, new response is generated 
        /// as needed.
        /// </summary>
        /// <param name="transaction">Client transaction what response it is.</param>
        /// <param name="response">Response to send.</param>
        private void SendResponse(SIP_ClientTransaction transaction, SIP_Response response)
        {
            if (m_IsB2BUA)
            {
                /* draft-marjou-sipping-b2bua-00 4.1.3.
                    When the UAC side of the B2BUA receives the downstream SIP response
                    of a forwarded request, its associated UAS creates an upstream
                    response (except for 100 responses).  The creation of the Via, Max-
                    Forwards, Call-Id, CSeq, Record-Route and Contact header fields
                    follows the rules of [2].  The Record-Route header fields of the
                    downstream response are not copied in the new upstream response, as
                    Record-Route is meaningful for the downstream dialog.  The UAS SHOULD
                    copy other header fields and body from the downstream response into
                    this upstream response before sending it.
                */

                SIP_Request originalRequest = m_pServerTransaction.Request;

                // We need to use caller original request to construct response from proxied response.
                SIP_Response b2buaResponse = response.Copy();
                b2buaResponse.Via.RemoveAll();
                b2buaResponse.Via.AddToTop(originalRequest.Via.GetTopMostValue().ToStringValue());
                b2buaResponse.CallID = originalRequest.CallID;
                b2buaResponse.CSeq = originalRequest.CSeq;
                b2buaResponse.Contact.RemoveAll();
                //b2buaResponse.Contact.Add(m_pProxy.CreateContact(originalRequest.From.Address).ToStringValue());
                b2buaResponse.RecordRoute.RemoveAll();

                b2buaResponse.Allow.RemoveAll();
                b2buaResponse.Supported.RemoveAll();
                // Accept to non ACK,BYE request.
                if (originalRequest.RequestLine.Method != SIP_Methods.ACK &&
                    originalRequest.RequestLine.Method != SIP_Methods.BYE)
                {
                    b2buaResponse.Allow.Add("INVITE,ACK,OPTIONS,CANCEL,BYE,PRACK");
                }
                // Supported to non ACK request. 
                if (originalRequest.RequestLine.Method != SIP_Methods.ACK)
                {
                    b2buaResponse.Supported.Add("100rel,timer");
                }
                // Remove Require: header.
                b2buaResponse.Require.RemoveAll();

                m_pServerTransaction.SendResponse(b2buaResponse);

                // If INVITE 2xx response do call here.
                if (response.CSeq.RequestMethod.ToUpper() == SIP_Methods.INVITE &&
                    response.StatusCodeType == SIP_StatusCodeType.Success)
                {
                    m_pProxy.B2BUA.AddCall(m_pServerTransaction.Dialog, transaction.Dialog);
                }
            }
            else
            {
                m_pServerTransaction.SendResponse(response);
            }
        }

        /// <summary>
        /// Cancels all targets processing.
        /// </summary>
        private void CancelAllTargets()
        {
            if (!m_NoCancel)
            {
                m_pTargets.Clear();

                foreach (TargetHandler target in m_pTargetsHandlers.ToArray())
                {
                    target.Cancel();
                }
            }
        }

        /// <summary>
        /// Gets best final response. If no final response in responses collection, null is returned.
        /// </summary>
        /// <returns>Resturns best final response or  null if no final response.</returns>
        private SIP_Response GetBestFinalResponse()
        {
            // 6xx -> 2xx -> 3xx -> 4xx -> 5xx

            // 6xx
            foreach (SIP_Response resp in m_pResponses.ToArray())
            {
                if (resp.StatusCodeType == SIP_StatusCodeType.GlobalFailure)
                {
                    return resp;
                }
            }
            // 2xx
            foreach (SIP_Response resp in m_pResponses.ToArray())
            {
                if (resp.StatusCodeType == SIP_StatusCodeType.Success)
                {
                    return resp;
                }
            }
            // 3xx
            foreach (SIP_Response resp in m_pResponses.ToArray())
            {
                if (resp.StatusCodeType == SIP_StatusCodeType.Redirection)
                {
                    return resp;
                }
            }
            // 4xx
            foreach (SIP_Response resp in m_pResponses.ToArray())
            {
                if (resp.StatusCodeType == SIP_StatusCodeType.RequestFailure)
                {
                    return resp;
                }
            }
            // 5xx
            foreach (SIP_Response resp in m_pResponses.ToArray())
            {
                if (resp.StatusCodeType == SIP_StatusCodeType.ServerFailure)
                {
                    return resp;
                }
            }

            return null;
        }

        /// <summary>
        /// Gets credentials for specified realm. Returns null if none such credentials.
        /// </summary>
        /// <param name="realm">Realm which credentials to get.</param>
        /// <returns>Returns specified realm credentials or null in none.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>realm</b> is null reference.</exception>
        private NetworkCredential GetCredential(string realm)
        {
            if (realm == null)
            {
                throw new ArgumentNullException("realm");
            }

            foreach (NetworkCredential c in m_pCredentials)
            {
                if (c.Domain.ToLower() == realm.ToLower())
                {
                    return c;
                }
            }
            return null;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Mail/MailApi.Attachments.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.IO;
using System.Threading;
using System.Web;

using ASC.Api.Attributes;
using ASC.Mail.Core.Engine;
using ASC.Mail.Core.Engine.Operations.Base;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Utils;

// ReSharper disable InconsistentNaming

namespace ASC.Api.Mail
{
    public partial class MailApi
    {
        /// <summary>
        /// Export all message's attachments to MyDocuments
        /// </summary>
        /// <param name="id_message">Id of any message</param>
        /// <param name="id_folder" optional="true">Id of Documents folder (if empty then @My)</param>
        /// <returns>Count of exported attachments</returns>
        /// <category>Messages</category>
        [Update(@"messages/attachments/export")]
        public int ExportAttachmentsToDocuments(int id_message, string id_folder = null)
        {
            if (id_message < 1)
                throw new ArgumentException(@"Invalid message id", "id_message");

            if (string.IsNullOrEmpty(id_folder))
                id_folder = DocumentsEngine.MY_DOCS_FOLDER_ID;

            var scheme = HttpContext.Current == null ? Uri.UriSchemeHttp : HttpContext.Current.Request.GetUrlRewriter().Scheme;
            var documentsDal = new DocumentsEngine(TenantId, Username, scheme);
            var savedAttachmentsList = documentsDal.StoreAttachmentsToDocuments(id_message, id_folder);

            return savedAttachmentsList.Count;
        }

        /// <summary>
        /// Export attachment to MyDocuments
        /// </summary>
        /// <param name="id_attachment">Id of any attachment from the message</param>
        /// <param name="id_folder" optional="true">Id of Documents folder (if empty then @My)</param>
        /// <returns>Id document in My Documents</returns>
        /// <category>Messages</category>
        [Update(@"messages/attachment/export")]
        public object ExportAttachmentToDocuments(int id_attachment, string id_folder = null)
        {
            if (id_attachment < 1)
                throw new ArgumentException(@"Invalid attachment id", "id_attachment");

            if (string.IsNullOrEmpty(id_folder))
                id_folder = DocumentsEngine.MY_DOCS_FOLDER_ID;

            var scheme = HttpContext.Current == null ? Uri.UriSchemeHttp : HttpContext.Current.Request.GetUrlRewriter().Scheme;

            var documentsDal = new DocumentsEngine(TenantId, Username, scheme);
            var documentId = documentsDal.StoreAttachmentToDocuments(id_attachment, id_folder);
            return documentId;
        }

        /// <summary>
        /// Add attachment to draft
        /// </summary>
        /// <param name="id_message">Id of any message</param>
        /// <param name="name">File name</param>
        /// <param name="file">File stream</param>
        /// <param name="content_type">File content type</param>
        /// <returns>MailAttachment</returns>
        /// <category>Messages</category>
        [Create(@"messages/attachment/add")]
        public MailAttachmentData AddAttachment(int id_message, string name, Stream file, string content_type)
        {
            var attachment = MailEngineFactory.AttachmentEngine
                .AttachFileToDraft(TenantId, Username, id_message, name, file, file.Length, content_type);

            return attachment;
        }

        /// <summary>
        /// Add attachment to draft
        /// </summary>
        /// <param name="id_message">Id of any message</param>
        /// <param name="ical_body">File name</param>
        /// <returns>MailAttachment</returns>
        /// <category>Messages</category>
        [Create(@"messages/calendarbody/add")]
        public MailAttachmentData AddCalendarBody(int id_message, string ical_body)
        {
            if (string.IsNullOrEmpty(ical_body))
                throw new ArgumentException(@"Empty calendar body", "ical_body");

            var calendar = MailUtil.ParseValidCalendar(ical_body, _log);

            if (calendar == null)
                throw new ArgumentException(@"Invalid calendar body", "ical_body");

            using (var ms = new MemoryStream())
            {
                using (var writer = new StreamWriter(ms))
                {
                    writer.Write(ical_body);
                    writer.Flush();
                    ms.Position = 0;

                    var attachment = MailEngineFactory.AttachmentEngine
                        .AttachFileToDraft(TenantId, Username, id_message, calendar.Method.ToLowerInvariant() + ".ics",
                            ms, ms.Length, "text/calendar");

                    return attachment;
                }
            }
        }

        /// <summary>
        /// Download all attachments from message
        /// </summary>
        /// <short>
        /// Download all attachments from message
        /// </short>
        /// <param name="messageId">Id of message</param>
        /// <returns>Attachment Archive</returns>
        [Update(@"messages/attachment/downloadall/{messageId}")]
        public MailOperationStatus DownloadAllAttachments(int messageId)
        {
            Thread.CurrentThread.CurrentCulture = CurrentCulture;
            Thread.CurrentThread.CurrentUICulture = CurrentCulture;

            return MailEngineFactory.OperationEngine.DownloadAllAttachments(messageId, TranslateMailOperationStatus);
        }
    }
}


<|start_filename|>common/ASC.Common/Geolocation/GeolocationHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Web;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Common.Logging;

namespace ASC.Geolocation
{
    public class GeolocationHelper
    {
        private static readonly ILog log = LogManager.GetLogger("ASC.Geo");

        private readonly string dbid;


        public GeolocationHelper(string dbid)
        {
            this.dbid = dbid;
        }


        public IPGeolocationInfo GetIPGeolocation(string ip)
        {
            try
            {
                var ipformatted = FormatIP(ip);
                using (var db = new DbManager(dbid))
                {
                    var q = new SqlQuery("dbip_location")
                        .Select("ip_start", "ip_end", "country", "city", "timezone_offset", "timezone_name")
                        .Where(Exp.Le("ip_start", ipformatted))
                        .OrderBy("ip_start", false)
                        .SetMaxResults(1);
                    return db
                        .ExecuteList(q)
                        .Select(r => new IPGeolocationInfo()
                        {
                            IPStart = Convert.ToString(r[0]),
                            IPEnd = Convert.ToString(r[1]),
                            Key = Convert.ToString(r[2]),
                            City = Convert.ToString(r[3]),
                            TimezoneOffset = Convert.ToDouble(r[4]),
                            TimezoneName = Convert.ToString(r[5])
                        })
                        .SingleOrDefault(i => ipformatted.CompareTo(i.IPEnd) <= 0) ??
                        IPGeolocationInfo.Default;
                }
            }
            catch (Exception error)
            {
                log.Error(error);
            }
            return IPGeolocationInfo.Default;
        }

        public IPGeolocationInfo GetIPGeolocationFromHttpContext()
        {
            return GetIPGeolocationFromHttpContext(HttpContext.Current);
        }

        public IPGeolocationInfo GetIPGeolocationFromHttpContext(HttpContext context)
        {
            if (context != null && context.Request != null)
            {
                var ip = context.Request.Headers["X-Forwarded-For"] ?? context.Request.ServerVariables["REMOTE_ADDR"];
                if (!string.IsNullOrWhiteSpace(ip))
                {
                    return GetIPGeolocation(ip);
                }
            }
            return IPGeolocationInfo.Default;
        }

        private static string FormatIP(string ip)
        {
            ip = (ip ?? "").Trim();
            if (ip.Contains('.'))
            {
                //ip v4
                if (ip.Length == 15)
                {
                    return ip;
                }
                return string.Join(".", ip.Split(':')[0].Split('.').Select(s => ("00" + s).Substring(s.Length - 1)).ToArray());
            }
            else if (ip.Contains(':'))
            {
                //ip v6
                if (ip.Length == 39)
                {
                    return ip;
                }
                var index = ip.IndexOf("::");
                if (0 <= index)
                {
                    ip = ip.Insert(index + 2, new String(':', 8 - ip.Split(':').Length));
                }
                return string.Join(":", ip.Split(':').Select(s => ("0000" + s).Substring(s.Length)).ToArray());
            }
            else
            {
                throw new ArgumentException("Unknown ip " + ip);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/contacts/contacts.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.contactsManager = (function() {
    var initFlag = false,
        teamlabContacts = [],
        crmContacts = [],
        personalContacts = [];

    var init = function() {
        if (!initFlag) {
            initFlag = true;
            updateTlContacts();
            setInterval(function () {
                crmContacts = [];
                personalContacts = [];
                updateTlContacts();
            }, ASC.Mail.Constants.CHECK_NEWS_TIMEOUT * 10);
        }
    };

    var onGetFullTlContacts = function(params, contacts) {
        var count = contacts.length;
        for (var i = 0; i < count; i++) {
            if (contacts[i].email != undefined && contacts[i].email != '') {
                teamlabContacts.push({ 'firstName': contacts[i].firstName, 'lastName': contacts[i].lastName, 'email': contacts[i].email, 'id': contacts[i].id, 'displayName': contacts[i].displayName });
            }
        }
    };

    var updateTlContacts = function() {
        serviceManager.getProfiles({}, { success: onGetFullTlContacts });
    };

    var getTlContacts = function() {
        return teamlabContacts;
    };

    var getTlContactsByEmail = function(email) {
        var result = null;
        var count = teamlabContacts.length;
        for (var i = 0; i < count; i++) {
            if (teamlabContacts[i].email.toLowerCase() == email.toLowerCase()) {
                result = teamlabContacts[i];
                break;
            }
        }
        return result;
    };

    function searchResult(contacts, email) {
        return jq.grep(contacts, function(c) {
            return c.email === email;
        });
    }

    function searchResultIndex(contacts, email) {
        for (var i = 0, n = contacts.length; i < n; i++) {
            if (contacts[i].email === email) {
                return i;
            }
        }

        return -1;
    }

    function inCrmContacts(email) {
        var d = jq.Deferred();
        var result = {
            email: email,
            exists: false
        };

        try {
            if (!ASC.Mail.Constants.CRM_AVAILABLE) {
                d.resolve(result);
                return d.promise(); 
            }

            var found = searchResult(crmContacts, email);
            if (found.length) {
                d.resolve(found[0]);
                return d.promise();
            }

            Teamlab.getContactsByContactInfo({ address: email }, { infoType: 1, data: email }, {
                success: function (params, contacts) {
                    result.email = params.address;
                    result.exists = contacts.length > 0;
                    crmContacts.push(result);
                    d.resolve(result);
                },
                error: function (e) {
                    console.error("Teamlab.getContactsByContactInfo", e);
                },
                async: true
            });


        } catch (e) {
            console.error("inCrmContacts", e);
            d.resolve(result);
        }
        return d.promise();
    }

    function inPersonalContacts(email) {
        var d = jq.Deferred();
        var result = {
            email: email,
            exists: false
        };

        try {
            var found = searchResult(personalContacts, email);
            if (found.length) {
                d.resolve(found[0]);
                return d.promise();
            }

            Teamlab.getMailContactsByInfo({ address: email }, { infoType: 1, data: email }, {
                success: function (params, contacts) {
                    result.email = params.address;
                    result.exists = contacts.length > 0;
                    personalContacts.push(result);
                    d.resolve(result);
                },
                error: function (e) {
                    console.error("Teamlab.getMailContactsByInfo", e);
                    d.resolve(result);
                },
                async: true
            });
        } catch (e) {
            console.error("inPersonalContacts", e);
            d.resolve(result);
        }
        return d.promise();
    }

    function forgetCrmContact(email) {
        var index = searchResultIndex(crmContacts, email);
        if (index > -1) {
            crmContacts.splice(index, 1);
        }
    }

    function forgetPersonalContact(email) {
        var index = searchResultIndex(personalContacts, email);
        if (index > -1) {
            personalContacts.splice(index, 1);
        }
    }

    return {
        init: init,

        updateTlContact: updateTlContacts,
        getTLContacts: getTlContacts,
        getTLContactsByEmail: getTlContactsByEmail,
        inCrmContacts: inCrmContacts,
        inPersonalContacts: inPersonalContacts,
        forgetCrmContact: forgetCrmContact,
        forgetPersonalContact: forgetPersonalContact
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Code/CommentDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core.Tenants;

namespace ASC.Web.UserControls.Wiki.Data
{
    class CommentDao : BaseDao
    {
        public CommentDao(string dbid, int tenant)
            : base(dbid, tenant)
        {
        }


        public List<Comment> GetComments(string pageName)
        {
            var q = Query("wiki_comments")
                .Select("Id", "ParentId", "PageName", "Body", "UserId", "Date", "Inactive")
                .Where("PageName", pageName)
                .OrderBy("Date", true);

            return db.ExecuteList(q)
                .ConvertAll(r => ToComment(r));
        }

        public Comment GetComment(Guid id)
        {
            var q = Query("wiki_comments")
                .Select("Id", "ParentId", "PageName", "Body", "UserId", "Date", "Inactive")
                .Where("Id", id.ToString());

            return db.ExecuteList(q)
                .ConvertAll(r => ToComment(r))
                .SingleOrDefault();
        }

        public Comment SaveComment(Comment comment)
        {
            if (comment == null) throw new NotImplementedException("comment");

            if (comment.Id == Guid.Empty) comment.Id = Guid.NewGuid();
            var i = Insert("wiki_comments")
                .InColumnValue("id", comment.Id.ToString())
                .InColumnValue("ParentId", comment.ParentId.ToString())
                .InColumnValue("PageName", comment.PageName)
                .InColumnValue("Body", comment.Body)
                .InColumnValue("UserId", comment.UserId.ToString())
                .InColumnValue("Date", TenantUtil.DateTimeToUtc(comment.Date))
                .InColumnValue("Inactive", comment.Inactive);

            db.ExecuteNonQuery(i);

            return comment;
        }

        public void RemoveComment(Guid id)
        {
            var d = Delete("wiki_comments").Where("id", id.ToString());
            db.ExecuteNonQuery(d);
        }


        private Comment ToComment(object[] r)
        {
            return new Comment
            {
                Id = new Guid((string)r[0]),
                ParentId = new Guid((string)r[1]),
                PageName = (string)r[2],
                Body = (string)r[3],
                UserId = new Guid((string)r[4]),
                Date = TenantUtil.DateTimeFromUtc((DateTime)r[5]),
                Inactive = Convert.ToBoolean(r[6]),
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Default.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

using AjaxPro;

using ASC.Core;
using ASC.ElasticSearch;
using ASC.Notify.Recipients;
using ASC.Web.Community.Modules.Wiki.Resources;
using ASC.Web.Community.Product;
using ASC.Web.Community.Search;
using ASC.Web.Community.Wiki.Common;
using ASC.Web.Core.Mobile;
using ASC.Web.Core.Users;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.UserControls.Common.Comments;
using ASC.Web.Studio.Utility;
using ASC.Web.Studio.Utility.HtmlUtility;
using ASC.Web.UserControls.Wiki;
using ASC.Web.UserControls.Wiki.Data;
using ASC.Web.UserControls.Wiki.Handlers;
using ASC.Web.UserControls.Wiki.UC;

namespace ASC.Web.Community.Wiki
{
    [AjaxNamespace("_Default")]
    public partial class _Default : WikiBasePage, IContextInitializer
    {
        protected string WikiPageName { get; set; }
        private bool _isEmptyPage;

        protected int Version
        {
            get
            {
                int result;
                if (Request["ver"] == null || !int.TryParse(Request["ver"], out result))
                    return 0;

                return result;
            }
        }

        protected bool m_IsCategory
        {
            get { return Action == ActionOnPage.CategoryView || Action == ActionOnPage.CategoryEdit; }
        }

        private string _categoryName;

        protected string m_categoryName
        {
            get
            {
                if (_categoryName == null)
                {
                    _categoryName = string.Empty;
                    if (m_IsCategory)
                    {
                        var str = PageNameUtil.Decode(WikiPage);
                        _categoryName = str.Substring(str.IndexOf(':') + 1).Trim();
                    }
                }

                return _categoryName;
            }
        }

        protected string PrintPageName
        {
            get
            {
                var pageName = PageNameUtil.Decode(WikiPage);
                if (string.IsNullOrEmpty(pageName))
                {
                    pageName = WikiResource.MainWikiCaption;
                }
                return pageName;
            }
        }

        protected string PrintPageNameEncoded
        {
            get { return HttpUtility.HtmlEncode(PrintPageName); }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            wikiViewPage.TenantId = wikiViewFile.TenantId = wikiEditFile.TenantId = wikiEditPage.TenantId = TenantId;
        }

        private void CheckSpetialSymbols()
        {
            var spetialName = PrintPageName;
            if (!spetialName.Contains(":"))
                return;

            var spetial = spetialName.Split(':')[0];
            spetialName = spetialName.Split(':')[1];

            /*if (spetial.Equals(ASC.Web.UserControls.Wiki.Resources.WikiResource.wikiCategoryKeyCaption, StringComparison.InvariantCultureIgnoreCase))
            {
                Response.RedirectLC(string.Format("ListPages.aspx?cat={0}", spetialName.Trim()), this);
            }
            else*/
            if (spetial.Equals(UserControls.Wiki.Constants.WikiInternalKeyCaption, StringComparison.InvariantCultureIgnoreCase))
            {
                spetialName = spetialName.Trim();
                var anchors = spetialName;
                if (spetialName.Contains("#"))
                {
                    spetialName = spetialName.Split('#')[0];
                    anchors = anchors.Remove(0, spetialName.Length).TrimStart('#');
                }
                else
                {
                    anchors = string.Empty;
                }

                if (spetialName.Equals(UserControls.Wiki.Constants.WikiInternalIndexKey, StringComparison.InvariantCultureIgnoreCase))
                {
                    Response.RedirectLC("ListPages.aspx", this);
                }
                else if (spetialName.Equals(UserControls.Wiki.Constants.WikiInternalCategoriesKey, StringComparison.InvariantCultureIgnoreCase))
                {
                    Response.RedirectLC("ListCategories.aspx", this);
                }
                else if (spetialName.Equals(UserControls.Wiki.Constants.WikiInternalFilesKey, StringComparison.InvariantCultureIgnoreCase))
                {
                    Response.RedirectLC("ListFiles.aspx", this);
                }

                else if (spetialName.Equals(UserControls.Wiki.Constants.WikiInternalHomeKey, StringComparison.InvariantCultureIgnoreCase))
                {
                    if (string.IsNullOrEmpty(anchors))
                    {
                        Response.RedirectLC("Default.aspx", this);
                    }
                    else
                    {
                        Response.RedirectLC(string.Format(@"Default.aspx?page=#{0}", anchors), this);
                    }
                }
                else if (spetialName.Equals(UserControls.Wiki.Constants.WikiInternalNewPagesKey, StringComparison.InvariantCultureIgnoreCase))
                {
                    Response.RedirectLC("ListPages.aspx?n=", this);
                }
                else if (spetialName.Equals(UserControls.Wiki.Constants.WikiInternalRecentlyKey, StringComparison.InvariantCultureIgnoreCase))
                {
                    Response.RedirectLC("ListPages.aspx?f=", this);
                }
                else if (spetialName.Equals(UserControls.Wiki.Constants.WikiInternalHelpKey, StringComparison.InvariantCultureIgnoreCase))
                {
                    if (string.IsNullOrEmpty(anchors))
                    {
                        Response.RedirectLC(string.Format(@"Default.aspx?page={0}", WikiUCResource.HelpPageCaption), this);
                    }
                    else
                    {
                        Response.RedirectLC(string.Format(@"Default.aspx?page={0}#{1}", WikiUCResource.HelpPageCaption, anchors), this);
                    }
                }
            }
        }

        protected void wikiEditPage_SetNewFCKMode(bool isWysiwygDefault)
        {
            WikiModuleSettings.SetIsWysiwygDefault(isWysiwygDefault);
        }

        protected string wikiEditPage_GetUserFriendlySizeFormat(long size)
        {
            return GetFileLengthToString(size);
        }

        protected void cmdDelete_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(WikiPage) || IsFile) return;
                var pageName = PageNameUtil.Decode(WikiPage);

                var page = Wiki.GetPage(pageName);
                CommunitySecurity.DemandPermissions(new WikiObjectsSecurityObject(page), Common.Constants.Action_RemovePage);

                foreach (var cat in Wiki.GetCategoriesRemovedWithPage(pageName))
                {
                    WikiNotifySource.Instance.GetSubscriptionProvider().UnSubscribe(Common.Constants.AddPageToCat, cat.CategoryName);
                }

                Wiki.RemoveCategories(pageName);

                WikiNotifySource.Instance.GetSubscriptionProvider().UnSubscribe(Common.Constants.EditPage, pageName);

                foreach (var comment in Wiki.GetComments(pageName))
                {
                    CommonControlsConfigurer.FCKUploadsRemoveForItem("wiki_comments", comment.Id.ToString());
                }
                Wiki.RemovePage(pageName);

                FactoryIndexer<WikiWrapper>.DeleteAsync(page);

                Response.RedirectLC("Default.aspx", this);
            }
            catch (Exception err)
            {
                WikiMaster.PrintInfoMessage(err.Message, InfoType.Alert);
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            WikiPageName = PrintPageName;
            (Master as WikiMaster).GetDelUniqId += new WikiMaster.GetDelUniqIdHandle(_Default_GetDelUniqId);

            Utility.RegisterTypeForAjax(typeof(_Default), Page);
            RegisterInlineScript();
            LoadViews();

            if (IsPostBack) return;

            if (IsFile)
            {
                Response.RedirectLC(string.Format(WikiSection.Section.ImageHangler.UrlFormat, WikiPage, TenantId), this);
            }

            pCredits.Visible = Action.Equals(ActionOnPage.View) || Action.Equals(ActionOnPage.CategoryView);

            CheckSpetialSymbols();

            wikiEditPage.mainPath = this.ResolveUrlLC("Default.aspx");
            InitEditsLink();

            var mainStudioCss = WebSkin.BaseCSSFileAbsoluteWebPath;

            wikiEditPage.CanUploadFiles = CommunitySecurity.CheckPermissions(Common.Constants.Action_UploadFile);
            wikiEditPage.MainCssFile = mainStudioCss;

            if (Action == ActionOnPage.CategoryView)
            {
                BindPagesByCategory();
            }
        }

        private void RegisterInlineScript()
        {
            var script = @"
                    window.scrollPreview = function() {
                        jq.scrollTo(jq('#_PrevContainer').position().top, { speed: 500 });
                    }
                    window.HidePreview = function() {
                        jq('#_PrevContainer').hide();
                        jq.scrollTo(jq('#edit_container').position().top, { speed: 500 });
                    }
                    window.WikiEditBtns = function() {
                        window.checkUnload=false;
                        LoadingBanner.showLoaderBtn('#actionWikiPage');
                    }
                    window.checkUnload=true;
                    window.checkUnloadFunc = function() {
                        return checkUnload;
                    }
                    window.panelEditBtnsID = '" + pEditButtons.ClientID + @"';
                    jq.dropdownToggle({
                        dropdownID: 'WikiActionsMenuPanel',
                        switcherSelector: '.WikiHeaderBlock .menu-small',
                        addLeft: -11,
                        showFunction: function (switcherObj, dropdownItem) {
                            jq('.WikiHeaderBlock .menu-small.active').removeClass('active');
                            if (dropdownItem.is(':hidden')) {
                                switcherObj.addClass('active');
                            }
                        },
                        hideFunction: function () {
                            jq('.WikiHeaderBlock .menu-small.active').removeClass('active');
                        }
                    });
                    if (jq('#WikiActionsMenuPanel .dropdown-content a').length == 0) {
                        jq('span.menu-small').hide();
                    }
                    jq('input[id$=txtPageName]').focus();";

            if (Action == ActionOnPage.AddNew || Action == ActionOnPage.Edit)
                script += "jq.confirmBeforeUnload(window.checkUnloadFunc);";

            Page.RegisterInlineScript(script);
        }

        private IWikiObjectOwner _wikiObjOwner;

        protected void InitPageActionPanel()
        {
            var sb = new StringBuilder();
            var canEdit = false;
            var canDelete = false;
            var subscribed = false;

            if (_wikiObjOwner != null)
            {
                var secObj = new WikiObjectsSecurityObject(_wikiObjOwner);
                canEdit = CommunitySecurity.CheckPermissions(secObj, Common.Constants.Action_EditPage);
                canDelete = CommunitySecurity.CheckPermissions(secObj, Common.Constants.Action_RemovePage) &&
                            !string.IsNullOrEmpty(_wikiObjOwner.GetObjectId().ToString());
            }

            if (SecurityContext.IsAuthenticated && (Action.Equals(ActionOnPage.CategoryView) || Action.Equals(ActionOnPage.View)))
            {
                var subscriptionProvider = WikiNotifySource.Instance.GetSubscriptionProvider();
                var userList = new List<string>();
                var IAmAsRecipient = (IDirectRecipient)WikiNotifySource.Instance.GetRecipientsProvider().GetRecipient(SecurityContext.CurrentAccount.ID.ToString());

                if (IAmAsRecipient != null)
                {
                    userList = new List<string>(
                        subscriptionProvider.GetSubscriptions(
                            Community.Wiki.Common.Constants.EditPage,
                            IAmAsRecipient)
                        );
                }

                var pageName = WikiPage ?? string.Empty;
                subscribed = userList.Exists(s => string.Compare(s, pageName, StringComparison.InvariantCultureIgnoreCase) == 0 || (s == null && string.Empty.Equals(pageName)));
                var SubscribeTopicLink = string.Format(CultureInfo.CurrentCulture, string.Format(CultureInfo.CurrentCulture,
                                                                                                 "<a id=\"statusSubscribe\" class=\"follow-status " +
                                                                                                 (subscribed ? "subscribed" : "unsubscribed") +
                                                                                                 "\" title=\"{0}\" href=\"#\"></a>",
                                                                                                 !subscribed ? WikiResource.NotifyOnEditPage : WikiResource.UnNotifyOnEditPage));

                SubscribeLinkBlock.Text = SubscribeTopicLink;
            }

            var delURL = string.Format(@"javascript:if(confirm('{0}')) __doPostBack('{1}', '');", WikiResource.cfmDeletePage, _Default_GetDelUniqId());

            sb.Append("<div id=\"WikiActionsMenuPanel\" class=\"studio-action-panel\">");
            sb.Append("<ul class=\"dropdown-content\">");
            sb.AppendFormat("<li><a class=\"dropdown-item\" href=\"{0}\">{1}</a></li>",
                            ActionHelper.GetViewPagePath(this.ResolveUrlLC("pagehistorylist.aspx"), WikiPage),
                            WikiResource.menu_ShowVersions);

            sb.AppendFormat("<li><a class=\"dropdown-item\" href=\"javascript:window.print();\">{0}</a></li>", WikiResource.menu_PrintThePage);

            if (canEdit)
                sb.AppendFormat("<li><a class=\"dropdown-item\" href=\"{0}\">{1}</a></li>",
                                ActionHelper.GetEditPagePath(this.ResolveUrlLC("Default.aspx"), WikiPage),
                                WikiResource.menu_EditThePage);

            if (canDelete)
                sb.AppendFormat("<li><a class=\"dropdown-item\" href=\"{0}\">{1}</a></li>", delURL, WikiResource.menu_DeleteThePage);

            sb.Append("</ul>");
            sb.Append("</div>");

            ActionPanel.Text = sb.ToString();

            var script = String.Format("ASC.Community.Wiki.BindSubscribeEvent({0}, \"{1}\", \"{2}\", \"{3}\")",
                subscribed.ToString().ToLower(CultureInfo.CurrentCulture),
                HttpUtility.HtmlEncode((Page as WikiBasePage).WikiPage).EscapeString(),
                WikiResource.NotifyOnEditPage,
                WikiResource.UnNotifyOnEditPage
                );

            Page.RegisterInlineScript(script);
        }

        protected void InitCategoryActionPanel()
        {
            var sb = new StringBuilder();

            sb.Append("<div id=\"WikiActionsMenuPanel\" class=\"studio-action-panel\">");
            sb.Append("<ul class=\"dropdown-content\">");

            sb.AppendFormat("<li><a class=\"dropdown-item\" href=\"{0}\">{1}</a></li>",
                            ActionHelper.GetEditPagePath(this.ResolveUrlLC("Default.aspx"), WikiPage),
                            WikiResource.cmdEdit);

            sb.Append("</ul>");
            sb.Append("</div>");

            ActionPanel.Text = sb.ToString();
        }

        protected void wikiViewPage_WikiPageLoaded(bool isNew, IWikiObjectOwner owner)
        {
            _wikiObjOwner = owner;
            wikiViewPage.CanEditPage = CommunitySecurity.CheckPermissions(new WikiObjectsSecurityObject(_wikiObjOwner), Common.Constants.Action_EditPage);
            UpdateEditDeleteVisible(owner);
            //WikiMaster.UpdateNavigationItems();
            InitPageActionPanel();
        }

        protected void wikiEditPage_WikiPageLoaded(bool isNew, IWikiObjectOwner owner)
        {
            if (!isNew)
            {
                _wikiObjOwner = owner;
            }

            if ((isNew && !CommunitySecurity.CheckPermissions(Common.Constants.Action_AddPage))
                ||
                (!isNew && !(CommunitySecurity.CheckPermissions(new WikiObjectsSecurityObject(owner), Common.Constants.Action_EditPage))))
            {
                Response.RedirectLC("Default.aspx", this);
            }
        }

        protected void wikiEditPage_SaveNewCategoriesAdded(object sender, List<string> categories, string pageName)
        {
            //var authorId = SecurityContext.CurrentAccount.ID.ToString();
            //foreach (var catName in categories)
            //{
            //    WikiNotifyClient.SendNoticeAsync(
            //        authorId,
            //        Common.Constants.AddPageToCat,
            //        catName,
            //        null,
            //        GetListOfTagValForCategoryNotify(catName, pageName));
            //}
        }

        private string _Default_GetDelUniqId()
        {
            return cmdDelete.UniqueID;
        }

        internal string GetCategoryName()
        {
            return m_categoryName;
        }

        protected void OnPageEmpty(object sender, EventArgs e)
        {
            var pageName = PageNameUtil.Decode(WikiPage);

            wikiViewPage.Visible = false;
            wikiEditPage.Visible = false;
            wikiViewFile.Visible = false;
            wikiEditFile.Visible = false;
            pPageIsNotExists.Visible = true;

            if (!(Action.Equals(ActionOnPage.CategoryView) || Action.Equals(ActionOnPage.CategoryEdit)))
            {
                if (IsFile)
                {
                    txtPageEmptyLabel.Text = PrepereEmptyString(WikiResource.MainWikiFileIsNotExists, true, false);
                }
                else
                {
                    if (Wiki.SearchPagesByName(pageName).Count > 0)
                    {
                        txtPageEmptyLabel.Text = PrepereEmptyString(WikiResource.MainWikiPageIsNotExists, false, true);
                    }
                    else
                    {
                        txtPageEmptyLabel.Text = PrepereEmptyString(WikiResource.MainWikiPageIsNotExists, false, false);
                    }
                }
            }

            _isEmptyPage = true;
            InitEditsLink();
            //WikiMaster.UpdateNavigationItems();
        }

        private string PrepereEmptyString(string format, bool isFile, bool isSearchResultExists)
        {
            commentList.Visible = false;
            var mainOptions = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant;
            var rxLinkCreatePlace = new Regex(@"{0([\s\S]+?)}", mainOptions);
            var rxLinkSearchResult = new Regex(@"{1([\s\S]+?)}", mainOptions);
            var rxSearchResultParth = new Regex(@"\[\[([\s\S]+?)\]\]", mainOptions);
            var result = format;

            foreach (Match match in rxLinkCreatePlace.Matches(format))
            {
                if (isFile)
                {
                    if (CommunitySecurity.CheckPermissions(Common.Constants.Action_UploadFile))
                    {
                        result = result.Replace(match.Value, string.Format(@"<a href=""{0}"">{1}</a>", ActionHelper.GetEditFilePath(this.ResolveUrlLC("Default.aspx"), PageNameUtil.Decode(WikiPage)), match.Groups[1].Value));
                    }
                }
                else
                {
                    if (CommunitySecurity.CheckPermissions(Common.Constants.Action_AddPage))
                    {
                        result = result.Replace(match.Value, string.Format(@"<a href=""{0}"">{1}</a>", ActionHelper.GetEditPagePath(this.ResolveUrlLC("Default.aspx"), PageNameUtil.Decode(WikiPage)), match.Groups[1].Value));
                    }
                    else
                    {
                        result = result.Replace(match.Value, match.Groups[1].Value);
                    }
                }
            }

            if (isSearchResultExists && !isFile)
            {
                result = rxSearchResultParth.Replace(result, SearchResultParthMatchEvaluator);

                foreach (Match match in rxLinkSearchResult.Matches(format))
                {
                    result = result.Replace(match.Value, string.Format(@"<a href=""{0}"">{1}</a>", this.ResolveUrlLC(string.Format("Search.aspx?Search={0}&pn=", HttpUtility.UrlEncode(PageNameUtil.Decode(WikiPage)))), match.Groups[1].Value));
                }
            }
            else
            {
                result = rxSearchResultParth.Replace(result, string.Empty);
            }

            return result;
        }

        private string SearchResultParthMatchEvaluator(Match match)
        {
            return match.Groups[1].Value;
        }

        private string GetAbsolutePath(string relative)
        {
            return string.Format(@"{0}://{1}{2}{3}",
                                 Request.GetUrlRewriter().Scheme,
                                 Request.GetUrlRewriter().Host,
                                 (Request.GetUrlRewriter().Port != 80 ? string.Format(":{0}", Request.GetUrlRewriter().Port) : string.Empty),
                                 this.ResolveUrlLC(relative));
        }

        private void LoadViews()
        {
            wikiEditPage.AlaxUploaderPath = GetAbsolutePath("~/js/uploader/ajaxupload.js");
            wikiEditPage.JQPath = GetAbsolutePath("~/js/third-party/jquery/jquery.core.js");

            wikiEditPage.CurrentUserId = SecurityContext.CurrentAccount.ID;
            wikiViewPage.Visible = false;
            wikiEditPage.Visible = false;
            wikiViewFile.Visible = false;
            wikiEditFile.Visible = false;
            pPageIsNotExists.Visible = false;
            pView.Visible = false;
            PrintHeader.Visible = false;
            phCategoryResult.Visible = Action == ActionOnPage.CategoryView;

            var pageName = PrintPageName;
            var _mobileVer = MobileDetector.IsMobile;


            //fix for IE 10
            var browser = HttpContext.Current.Request.Browser.Browser;

            var userAgent = Context.Request.Headers["User-Agent"];
            var regExp = new Regex("MSIE 10.0", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            var regExpIe11 = new Regex("(?=.*Trident.*rv:11.0).+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
            if (browser == "IE" && regExp.Match(userAgent).Success || regExpIe11.Match(userAgent).Success)
            {
                _mobileVer = true;
            }

            switch (Action)
            {
                case ActionOnPage.AddNew:
                    pageName = WikiResource.MainWikiAddNewPage;
                    wikiEditPage.IsWysiwygDefault = !_mobileVer && WikiModuleSettings.GetIsWysiwygDefault();
                    wikiEditPage.Visible = true;
                    wikiEditPage.IsNew = true;
                    WikiPageName = pageName;
                    break;
                case ActionOnPage.AddNewFile:
                    pageName = WikiResource.MainWikiAddNewFile;
                    wikiEditFile.Visible = true;
                    WikiPageName = pageName;
                    break;
                case ActionOnPage.Edit:
                case ActionOnPage.CategoryEdit:
                    if (IsFile)
                    {
                        wikiEditFile.FileName = WikiPage;
                        wikiEditFile.Visible = true;
                        WikiPageName = WikiResource.MainWikiEditFile;
                    }
                    else
                    {
                        wikiEditPage.PageName = WikiPage;
                        wikiEditPage.IsWysiwygDefault = !_mobileVer && WikiModuleSettings.GetIsWysiwygDefault();
                        wikiEditPage.Visible = true;
                        if (m_IsCategory)
                            wikiEditPage.IsSpecialName = true;

                        WikiPageName = WikiResource.MainWikiEditPage;
                    }
                    break;
                case ActionOnPage.View:
                case ActionOnPage.CategoryView:
                    pView.Visible = true;
                    if (IsFile)
                    {
                        wikiViewFile.FileName = WikiPage;
                        wikiViewFile.Visible = true;
                    }
                    else
                    {
                        PrintHeader.Visible = true;
                        wikiViewPage.PageName = WikiPage;
                        wikiViewPage.Version = Version;
                        if (Version == 0)
                        {
                            if (m_IsCategory)
                            {
                                var name = HttpUtility.HtmlDecode(m_categoryName);
                                WikiPageName = string.Format(WikiResource.menu_ListPagesCatFormat, name);
                            }
                        }
                        else
                        {
                            if (m_IsCategory)
                            {
                                var name = HttpUtility.HtmlDecode(m_categoryName);
                                WikiPageName = string.Format(WikiResource.menu_ListPagesCatFormat, name);
                            }
                            WikiMaster.CurrentPageCaption = string.Format("{0}{1}", WikiResource.wikiVersionCaption, Version);
                        }
                        wikiViewPage.Visible = true;
                    }
                    InitCommentsView();
                    break;
            }
            if (SecurityContext.IsAuthenticated && (Action.Equals(ActionOnPage.CategoryView) || Action.Equals(ActionOnPage.View)))
            {
                var subscriptionProvider = WikiNotifySource.Instance.GetSubscriptionProvider();
                var userList = new List<string>();
                var IAmAsRecipient = (IDirectRecipient)WikiNotifySource.Instance.GetRecipientsProvider().GetRecipient(SecurityContext.CurrentAccount.ID.ToString());
                if (IAmAsRecipient != null)
                {
                    userList = new List<string>(
                        subscriptionProvider.GetSubscriptions(
                            Community.Wiki.Common.Constants.EditPage,
                            IAmAsRecipient)
                        );
                }

                pageName = WikiPage ?? string.Empty;
                var subscribed = userList.Exists(s => string.Compare(s, pageName, StringComparison.InvariantCultureIgnoreCase) == 0 || (s == null && string.Empty.Equals(pageName)));
                var SubscribeTopicLink = string.Format(CultureInfo.CurrentCulture, string.Format(CultureInfo.CurrentCulture,
                                                                                                 "<a id=\"statusSubscribe\" class=\"follow-status " +
                                                                                                 (subscribed ? "subscribed" : "unsubscribed") +
                                                                                                 "\" title=\"{0}\" href=\"#\"></a>",
                                                                                                 !subscribed ? WikiResource.NotifyOnEditPage : WikiResource.UnNotifyOnEditPage));

                SubscribeLinkBlock.Text = SubscribeTopicLink;
            }

        }

        protected void BindPagesByCategory()
        {
            if (Action != ActionOnPage.CategoryView || string.IsNullOrEmpty(m_categoryName))
                return;

            var result = Wiki.GetPages(m_categoryName);

            result.RemoveAll(pemp => string.IsNullOrEmpty(pemp.PageName));

            var letters = new List<string>(WikiResource.wikiCategoryAlfaList.Split(','));

            var otherSymbol = string.Empty;
            if (letters.Count > 0)
            {
                otherSymbol = letters[0];
                letters.Remove(otherSymbol);
            }

            var dictList = new List<PageDictionary>();
            foreach (var page in result)
            {
                var firstLetter = new string(page.PageName[0], 1);

                if (!letters.Exists(lt => lt.Equals(firstLetter, StringComparison.InvariantCultureIgnoreCase)))
                {
                    firstLetter = otherSymbol;
                }

                PageDictionary pageDic;
                if (!dictList.Exists(dl => dl.HeadName.Equals(firstLetter, StringComparison.InvariantCultureIgnoreCase)))
                {
                    pageDic = new PageDictionary { HeadName = firstLetter };
                    pageDic.Pages.Add(page);
                    dictList.Add(pageDic);
                }
                else
                {
                    pageDic = dictList.Find(dl => dl.HeadName.Equals(firstLetter, StringComparison.InvariantCultureIgnoreCase));
                    pageDic.Pages.Add(page);
                }
            }

            dictList.Sort(SortPageDict);

            var countAll = dictList.Count * 3 + result.Count; //1 letter is like 2 links to category
            var perColumn = (int)(Math.Round((decimal)countAll / 3));

            var mainDictList = new List<List<PageDictionary>>();

            int index = 0, lastIndex = 0, count = 0;

            for (var i = 0; i < dictList.Count; i++)
            {
                var p = dictList[i];

                count += 3;
                count += p.Pages.Count;
                index++;
                if (count >= perColumn || i == dictList.Count - 1)
                {
                    count = count - perColumn;
                    mainDictList.Add(dictList.GetRange(lastIndex, index - lastIndex));
                    lastIndex = index;
                }
            }

            rptCategoryPageList.DataSource = mainDictList;
            rptCategoryPageList.DataBind();
        }


        private int SortPageDict(PageDictionary cd1, PageDictionary cd2)
        {
            return cd1.HeadName.CompareTo(cd2.HeadName);
        }

        protected void On_PublishVersionInfo(object sender, VersionEventArgs e)
        {
            if (!e.UserID.Equals(Guid.Empty))
            {
                litAuthorInfo.Text = GetPageInfo(PageNameUtil.Decode(WikiPage), e.UserID, e.Date);
            }
            else
            {
                litAuthorInfo.Text = string.Empty;
            }

            hlVersionPage.Text = string.Format(WikiResource.cmdVersionTemplate, e.Version);
            hlVersionPage.NavigateUrl = ActionHelper.GetViewPagePath(this.ResolveUrlLC("PageHistoryList.aspx"), PageNameUtil.Decode(WikiPage));
            hlVersionPage.Visible = Action.Equals(ActionOnPage.View) || Action.Equals(ActionOnPage.CategoryView);
            //litVersionSeparator.Visible = hlEditPage.Visible;
        }

        protected void cmdCancel_Click(object sender, EventArgs e)
        {
            if (!IsFile)
            {
                Response.RedirectLC(ActionHelper.GetViewPagePath(this.ResolveUrlLC("Default.aspx"), PageNameUtil.Decode(WikiPage)), this);
            }
            else
            {
                Response.RedirectLC(ActionHelper.GetViewFilePath(this.ResolveUrlLC("Default.aspx"), PageNameUtil.Decode(WikiPage)), this);
            }
        }

        protected void cmdSave_Click(object sender, EventArgs e)
        {
            SaveResult result;
            string pageName;
            if (IsFile || Action.Equals(ActionOnPage.AddNewFile))
            {
                result = wikiEditFile.Save(SecurityContext.CurrentAccount.ID, out pageName);
            }
            else
            {
                result = wikiEditPage.Save(SecurityContext.CurrentAccount.ID, out pageName);
            }

            PrintResultBySave(result, pageName);
            if (result == SaveResult.OkPageRename)
            {
                //Redirect
                Response.RedirectLC(ActionHelper.GetViewPagePath(this.ResolveUrlLC("Default.aspx"), PageNameUtil.Decode(pageName)), this);
            }
        }

        private void PrintInfoMessage(string info, InfoType type)
        {
            WikiMaster.PrintInfoMessage(info, type);
        }

        private void PrintResultBySave(SaveResult result, string pageName)
        {
            var infoType = InfoType.Info;
            if (!result.Equals(SaveResult.Ok) && !result.Equals(SaveResult.NoChanges))
            {
                infoType = InfoType.Alert;
            }

            switch (result)
            {
                case SaveResult.SectionUpdate:
                    Response.RedirectLC(ActionHelper.GetViewPagePath(this.ResolveUrlLC("Default.aspx"), pageName), this);
                    break;
                case SaveResult.OkPageRename:
                case SaveResult.Ok:
                    PrintInfoMessage(WikiResource.msgSaveSucess, infoType);
                    if (Action.Equals(ActionOnPage.AddNew) || Action.Equals(ActionOnPage.Edit))
                    {
                        Response.RedirectLC(ActionHelper.GetViewPagePath(this.ResolveUrlLC("Default.aspx"), pageName), this);
                    }
                    else if (Action.Equals(ActionOnPage.AddNewFile))
                    {
                        Response.RedirectLC(ActionHelper.GetEditFilePath(this.ResolveUrlLC("Default.aspx"), pageName), this);
                    }
                    break;
                case SaveResult.FileEmpty:
                    PrintInfoMessage(WikiResource.msgFileEmpty, infoType);
                    break;
                case SaveResult.FileSizeExceeded:
                    PrintInfoMessage(FileSizeComment.GetFileSizeExceptionString(FileUploader.MaxUploadSize), infoType);
                    break;
                case SaveResult.NoChanges:
                    PrintInfoMessage(WikiResource.msgNoChanges, infoType);
                    break;
                case SaveResult.PageNameIsEmpty:
                    PrintInfoMessage(WikiResource.msgPageNameEmpty, infoType);
                    break;
                case SaveResult.PageNameIsIncorrect:
                    PrintInfoMessage(WikiResource.msgPageNameIncorrect, infoType);
                    break;
                case SaveResult.SamePageExists:
                    PrintInfoMessage(WikiResource.msgSamePageExists, infoType);
                    break;
                case SaveResult.UserIdIsEmpty:
                    PrintInfoMessage(WikiResource.msgInternalError, infoType);
                    break;
                case SaveResult.OldVersion:
                    PrintInfoMessage(WikiResource.msgOldVersion, infoType);
                    break;
                case SaveResult.Error:
                    PrintInfoMessage(WikiResource.msgMarkupError, InfoType.Alert);
                    break;
                case SaveResult.PageTextIsEmpty:
                    PrintInfoMessage(WikiResource.msgPageTextEmpty, infoType);
                    break;
            }
        }

        private void InitEditsLink()
        {
            //hlEditPage.Text = WikiResource.cmdEdit;
            cmdSave.Text = WikiResource.cmdPublish;
            hlPreview.Text = WikiResource.cmdPreview;
            hlPreview.Attributes["onclick"] = string.Format("{0}();return false;", wikiEditPage.GetShowPrevFunctionName());
            //hlPreview.NavigateUrl = string.Format("javascript:{0}();", wikiEditPage.GetShowPrevFunctionName());
            hlPreview.NavigateUrl = string.Format("javascript:void(0);");
            cmdCancel.Text = WikiResource.cmdCancel;
            cmdCancel.Attributes["name"] = wikiEditPage.WikiFckClientId;
            cmdDelete.Text = WikiResource.cmdDelete;
            cmdDelete.OnClientClick = string.Format("javascript:return confirm(\"{0}\");", WikiResource.cfmDeletePage);

            hlPreview.Visible = Action.Equals(ActionOnPage.AddNew) || Action.Equals(ActionOnPage.Edit) || Action.Equals(ActionOnPage.CategoryEdit);

            if (_isEmptyPage)
            {
                //hlEditPage.Visible = pEditButtons.Visible = false;
                cmdDelete.Visible = false;
                if (Action.Equals(ActionOnPage.CategoryView))
                {
                    //hlEditPage.Visible = true;
                    InitCategoryActionPanel();
                }
            }
            else
            {
                UpdateEditDeleteVisible(_wikiObjOwner);
            }

            litVersionSeparatorDel.Visible = cmdDelete.Visible;
        }

        private void UpdateEditDeleteVisible(IWikiObjectOwner obj)
        {
            var canDelete = false;
            var editVisible = Action.Equals(ActionOnPage.View) || Action.Equals(ActionOnPage.CategoryView);
            if (obj != null)
            {
                var secObj = new WikiObjectsSecurityObject(obj);
                canDelete = CommunitySecurity.CheckPermissions(secObj, Common.Constants.Action_RemovePage) &&
                            !string.IsNullOrEmpty(obj.GetObjectId().ToString());
            }

            pEditButtons.Visible = !editVisible;
            //hlEditPage.Visible = editVisible && canEdit;

            if (Version > 0 && (Action.Equals(ActionOnPage.View) || Action.Equals(ActionOnPage.CategoryView)))
            {
                //hlEditPage.Visible = pEditButtons.Visible = false;
            }

            cmdDelete.Visible = editVisible && canDelete;
            litVersionSeparatorDel.Visible = cmdDelete.Visible;
        }

        #region Comments Functions

        private void InitCommentsView()
        {
            if (m_IsCategory) return;

            int totalCount;
            var pageName = PageNameUtil.Decode(WikiPage);
            commentList.Visible = true;

            commentList.Items = GetCommentsList(pageName, out totalCount);
            ConfigureComments(commentList);
            commentList.TotalCount = totalCount;
        }

        private IList<CommentInfo> GetCommentsList(string pageName, out int totalCount)
        {
            var comments = Wiki.GetComments(pageName);
            totalCount = comments.Count;

            return BuildCommentsList(comments);
        }

        private List<CommentInfo> BuildCommentsList(List<Comment> loaded)
        {
            return BuildCommentsList(loaded, Guid.Empty);
        }

        private List<CommentInfo> BuildCommentsList(List<Comment> loaded, Guid parentId)
        {
            var result = new List<CommentInfo>();
            foreach (var comment in SelectChildLevel(parentId, loaded))
            {
                var info = GetCommentInfo(comment);
                info.CommentList = BuildCommentsList(loaded, comment.Id);
                result.Add(info);
            }
            return result;
        }

        private static List<Comment> SelectChildLevel(Guid forParentId, List<Comment> from)
        {
            return from.FindAll(comm => comm.ParentId == forParentId);
        }

        private static void ConfigureComments(CommentsList commentList)
        {
            CommonControlsConfigurer.CommentsConfigure(commentList);

            commentList.BehaviorID = "_commentsWikiObj";
            commentList.IsShowAddCommentBtn = CommunitySecurity.CheckPermissions(Common.Constants.Action_AddComment);
            commentList.ModuleName = "wiki";
            commentList.FckDomainName = "wiki_comments";
            commentList.ObjectID = "wiki_page";
        }

        public CommentInfo GetCommentInfo(Comment comment)
        {
            var info = new CommentInfo
            {
                CommentID = comment.Id.ToString(),
                UserID = comment.UserId,
                TimeStamp = comment.Date,
                TimeStampStr = comment.Date.Ago(),
                IsRead = true,
                Inactive = comment.Inactive,
                CommentBody = HtmlUtility.GetFull(comment.Body),
                UserFullName = DisplayUserSettings.GetFullUserName(comment.UserId),
                UserProfileLink = CommonLinkUtility.GetUserProfile(comment.UserId),
                UserAvatarPath = UserPhotoManager.GetBigPhotoURL(comment.UserId),
                IsEditPermissions = CommunitySecurity.CheckPermissions(new WikiObjectsSecurityObject(comment), Common.Constants.Action_EditRemoveComment),
                IsResponsePermissions = CommunitySecurity.CheckPermissions(Common.Constants.Action_AddComment),
                UserPost = CoreContext.UserManager.GetUsers(comment.UserId).Title
            };

            return info;
        }

        #region Ajax functions for comments management

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public string ConvertWikiToHtml(string pageName, string wikiValue, string appRelativeCurrentExecutionFilePath,
                                        string imageHandlerUrl)
        {
            return EditPage.ConvertWikiToHtml(pageName, wikiValue, appRelativeCurrentExecutionFilePath,
                                              imageHandlerUrl, TenantId);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public string ConvertWikiToHtmlWysiwyg(string pageName, string wikiValue, string appRelativeCurrentExecutionFilePath,
                                               string imageHandlerUrl)
        {
            return EditPage.ConvertWikiToHtmlWysiwyg(pageName, wikiValue, appRelativeCurrentExecutionFilePath,
                                                     imageHandlerUrl, TenantId);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public string CreateImageFromWiki(string pageName, string wikiValue, string appRelativeCurrentExecutionFilePath,
                                          string imageHandlerUrl)
        {
            return EditPage.CreateImageFromWiki(pageName, wikiValue, appRelativeCurrentExecutionFilePath,
                                                imageHandlerUrl, TenantId);
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public string UpdateTempImage(string fileName, string UserId, string tempFileName)
        {
            string outFileName;
            EditFile.MoveContentFromTemp(new Guid(UserId), tempFileName, fileName, ConfigLocation, PageWikiSection, TenantId, HttpContext.Current, RootPath, out outFileName);
            return outFileName;
        }

        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public void CancelUpdateImage(string UserId, string tempFileName)
        {
            EditFile.DeleteTempContent(tempFileName, ConfigLocation, PageWikiSection, TenantId, HttpContext.Current);
        }

        #endregion

        #endregion

        #region IContextInitializer Members

        public void InitializeContext(HttpContext context)
        {
            _rootPath = context.Server.MapPath("~");
            _wikiSection = WikiSection.Section;
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Autoreply/ParameterResolvers/TaskResponsiblesResolver.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using ASC.Core;
using ASC.Core.Users;
using ASC.Mail.Autoreply.Utility;
using ASC.Mail.Net.Mail;

namespace ASC.Mail.Autoreply.ParameterResolvers
{
    internal class TaskResponsiblesResolver : IParameterResolver
    {
        public static readonly Regex Pattern = new Regex(@"@\w+\s+\w+", RegexOptions.CultureInvariant | RegexOptions.Compiled);

        public object ResolveParameterValue(Mail_Message mailMessage)
        {
            if (!Pattern.IsMatch(mailMessage.Subject))
                return null;

            var users = new List<object>();
            foreach (Match match in Pattern.Matches(mailMessage.Subject))
            {
                var words = match.Value.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
                Guid user;
                if (TryGetUser(words[0], words[1], out user))
                {
                    users.Add(user);
                }
            }

            return users;
        }

        private static bool TryGetUser(string word1, string word2, out Guid userId)
        {
            userId = Guid.Empty;

            var users = CoreContext.UserManager.GetUsers()
                                  .GroupBy(u => GetDistance(u, word1, word2))
                                  .OrderBy(g => g.Key)
                                  .FirstOrDefault(g => g.Key < 3);

            if (users != null && users.Count() == 1)
            {
                userId = users.First().ID;
                return true;
            }

            return false;
        }

        private static int GetDistance(UserInfo user, string word1, string word2)
        {
            var distance1 = StringDistance.LevenshteinDistance(user.FirstName, word1) + StringDistance.LevenshteinDistance(user.LastName, word2);
            var distance2 = StringDistance.LevenshteinDistance(user.FirstName, word2) + StringDistance.LevenshteinDistance(user.LastName, word1);
            return Math.Min(distance1, distance2);
        }
    }

    internal class TaskResponsibleResolver : IParameterResolver
    {
        public object ResolveParameterValue(Mail_Message mailMessage)
        {
            var responsibles = new TaskResponsiblesResolver().ResolveParameterValue(mailMessage) as List<object>;

            return responsibles != null ? responsibles.FirstOrDefault() : null;
        }
    }
}


<|start_filename|>common/ASC.Data.Backup/Tasks/Modules/FilesModuleSpecifics.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

using ASC.Common.Logging;
using ASC.Data.Backup.Tasks.Data;

namespace ASC.Data.Backup.Tasks.Modules
{
    class FilesModuleSpecifics : ModuleSpecificsBase
    {
        private static readonly Regex RegexIsInteger = new Regex(@"^\d+$", RegexOptions.Compiled);
        private const string BunchRightNodeStartProject = "projects/project/";
        private const string BunchRightNodeStartCrmOpportunity = "crm/opportunity/";
        private const string BunchRightNodeStartMy = "files/my/";
        private const string BunchRightNodeStartTrash = "files/trash/";

        private readonly TableInfo[] _tables = new[]
            {
                new TableInfo("files_bunch_objects", "tenant_id"),
                new TableInfo("files_file", "tenant_id", "id", IdType.Integer)
                    {
                        UserIDColumns = new[] {"create_by", "modified_by"},
                        DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"modified_on", false}}
                    },
                new TableInfo("files_folder", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"create_by", "modified_by"},
                        DateColumns = new Dictionary<string, bool> {{"create_on", false}, {"modified_on", false}}
                    },
                new TableInfo("files_folder_tree"),
                new TableInfo("files_security", "tenant_id") {UserIDColumns = new[] {"owner"}},
                new TableInfo("files_thirdparty_account", "tenant_id", "id")
                    {
                        UserIDColumns = new[] {"user_id"},
                        DateColumns = new Dictionary<string, bool> {{"create_on", false}}
                    },
                new TableInfo("files_thirdparty_id_mapping", "tenant_id")
            };

        private readonly RelationInfo[] _tableRelations = new[]
            {
                new RelationInfo("core_user", "id", "files_bunch_objects", "right_node", typeof(TenantsModuleSpecifics),
                                 x =>
                                     {
                                         var rightNode = Convert.ToString(x["right_node"]);
                                         return rightNode.StartsWith(BunchRightNodeStartMy) || rightNode.StartsWith(BunchRightNodeStartTrash);
                                     }),

                new RelationInfo("core_user", "id", "files_security", "subject", typeof(TenantsModuleSpecifics)),

                new RelationInfo("core_group", "id", "files_security", "subject", typeof(TenantsModuleSpecifics)),

                new RelationInfo("crm_deal", "id", "files_bunch_objects", "right_node", typeof(CrmModuleSpecifics),
                                 x => Convert.ToString(x["right_node"]).StartsWith(BunchRightNodeStartCrmOpportunity)),

                new RelationInfo("projects_projects", "id", "files_bunch_objects", "right_node", typeof(ProjectsModuleSpecifics),
                                 x => Convert.ToString(x["right_node"]).StartsWith(BunchRightNodeStartProject, StringComparison.InvariantCultureIgnoreCase)),

                new RelationInfo("files_folder", "id", "files_bunch_objects", "left_node"),

                new RelationInfo("files_folder", "id", "files_file", "folder_id"),

                new RelationInfo("files_folder", "id", "files_folder", "parent_id"),

                new RelationInfo("files_folder", "id", "files_folder_tree", "folder_id"),

                new RelationInfo("files_folder", "id", "files_folder_tree", "parent_id"),

                new RelationInfo("files_file", "id", "files_security", "entry_id",
                                 x => Convert.ToInt32(x["entry_type"]) == 2 && RegexIsInteger.IsMatch(Convert.ToString(x["entry_id"]))),

                new RelationInfo("files_folder", "id", "files_security", "entry_id",
                                 x => Convert.ToInt32(x["entry_type"]) == 1 && RegexIsInteger.IsMatch(Convert.ToString(x["entry_id"]))),

                new RelationInfo("files_thirdparty_id_mapping", "hash_id", "files_security", "entry_id",
                                 x => !RegexIsInteger.IsMatch(Convert.ToString(x["entry_id"]))),

                new RelationInfo("files_thirdparty_account", "id", "files_thirdparty_id_mapping", "id"),

                new RelationInfo("files_thirdparty_account", "id", "files_thirdparty_id_mapping", "hash_id")
            };

        public override ModuleName ModuleName
        {
            get { return ModuleName.Files; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return _tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return _tableRelations; }
        }

        public override bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
        {
            var match = Regex.Match(filePath.Replace('\\', '/'), @"^folder_\d+/file_(?'fileId'\d+)/(?'versionExtension'v\d+/[\.\w]+)$", RegexOptions.Compiled);
            if (match.Success)
            {
                var fileId = columnMapper.GetMapping("files_file", "id", match.Groups["fileId"].Value);
                if (fileId == null)
                {
                    if (!dump)
                    {
                        return false;
                    }

                    fileId = match.Groups["fileId"].Value;
                }

                filePath = string.Format("folder_{0}/file_{1}/{2}", (Convert.ToInt32(fileId) / 1000 + 1) * 1000, fileId, match.Groups["versionExtension"].Value);
                return true;
            }

            return false;
        }

        protected override string GetSelectCommandConditionText(int tenantId, TableInfo table)
        {
            if (table.Name == "files_folder_tree")
            {
                return "inner join files_folder as t1 on t1.id = t.folder_id where t1.tenant_id = " + tenantId;
            }
            if (table.Name == "files_file")
            {
                // do not backup previus backup files
                return "where not exists(select 1 from backup_backup b where b.tenant_id = t.tenant_id and b.storage_path = t.id) and t.tenant_id = " + tenantId;
            }
            return base.GetSelectCommandConditionText(tenantId, table);
        }

        protected override bool TryPrepareRow(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, DataRowInfo row, out Dictionary<string, object> preparedRow)
        {
            if (row.TableName == "files_thirdparty_id_mapping")
            {
                //todo: think...
                preparedRow = new Dictionary<string, object>();

                object folderId = null;

                var sboxId = Regex.Replace(row[1].ToString(), @"(?<=(?:sbox-|box-|dropbox-|spoint-|drive-|onedrive-))\d+", match =>
                {
                    folderId = columnMapper.GetMapping("files_thirdparty_account", "id", match.Value);
                    return Convert.ToString(folderId);
                }, RegexOptions.Compiled);

                if (folderId == null)
                    return false;

                var hashBytes = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(sboxId));
                var hashedId = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();

                preparedRow.Add("hash_id", hashedId);
                preparedRow.Add("id", sboxId);
                preparedRow.Add("tenant_id", columnMapper.GetTenantMapping());

                columnMapper.SetMapping("files_thirdparty_id_mapping", "hash_id", row["hash_id"], hashedId);

                return true;
            }

            return base.TryPrepareRow(dump, connection, columnMapper, table, row, out preparedRow);
        }

        protected override bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
        {
            var relationList = relations.ToList();
            if (relationList.All(x => x.ChildTable == "files_security" && x.ChildColumn == "subject"))
            {
                //note: value could be ShareForEveryoneID and in that case result should be always false
                var strVal = Convert.ToString(value);
                if (Helpers.IsEmptyOrSystemUser(strVal) || Helpers.IsEmptyOrSystemGroup(strVal))
                    return true;

                foreach (var relation in relationList)
                {
                    var mapping = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, value);
                    if (mapping != null)
                    {
                        value = mapping;
                        return true;
                    }
                }
                return false;
            }

            return base.TryPrepareValue(dump, connection, columnMapper, table, columnName, relationList, ref value);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
        {
            if (relation.ChildTable == "files_bunch_objects" && relation.ChildColumn == "right_node")
            {
                var strValue = Convert.ToString(value);

                string start = GetStart(strValue);
                if (start == null)
                    return false;

                var entityId = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, strValue.Substring(start.Length));
                if (entityId == null)
                    return false;

                value = strValue.Substring(0, start.Length) + entityId;
                return true;
            }

            return base.TryPrepareValue(connection, columnMapper, relation, ref value);
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
        {
            if (table.Name == "files_thirdparty_account" && (columnName == "password" || columnName == "token") && value != null)
            {
                try
                {
                    value = Helpers.CreateHash(value as string); // save original hash
                }
                catch (Exception err)
                {
                    LogManager.GetLogger("ASC").ErrorFormat("Can not prepare value {0}: {1}", value, err);
                    value = null;
                }
                return true;
            }
            if (table.Name == "files_folder" && (columnName == "create_by" || columnName == "modified_by"))
            {
                base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
                return true;
            }

            return base.TryPrepareValue(connection, columnMapper, table, columnName, ref value);
        }

        public override void PrepareData(DataTable data)
        {
            if (data.TableName == "files_thirdparty_account")
            {
                var providerColumn = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "provider");
                var pwdColumn = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "password");
                var tokenColumn = data.Columns.Cast<DataColumn>().Single(c => c.ColumnName == "token");
                for (var i = 0; i < data.Rows.Count; i++)
                {
                    var row = data.Rows[i];
                    try
                    {
                        row[pwdColumn] = Helpers.CreateHash2(row[pwdColumn] as string);
                        row[tokenColumn] = Helpers.CreateHash2(row[tokenColumn] as string);
                    }
                    catch (Exception ex)
                    {
                        LogManager.GetLogger("ASC").ErrorFormat("Can not prepare data {0}: {1}", row[providerColumn] as string, ex);
                        data.Rows.Remove(row);
                        i--;
                    }
                }
            }
        }

        private static string GetStart(string value)
        {
            var allStarts = new[] { BunchRightNodeStartProject, BunchRightNodeStartMy, BunchRightNodeStartTrash, BunchRightNodeStartCrmOpportunity };
            return allStarts.FirstOrDefault(value.StartsWith);
        }
    }


    class FilesModuleSpecifics2 : ModuleSpecificsBase
    {
        private static readonly Regex RegexIsInteger = new Regex(@"^\d+$", RegexOptions.Compiled);
        private const string TagStartMessage = "Message";
        private const string TagStartTask = "Task";
        private const string TagStartProject = "Project";
        private const string TagStartRelationshipEvent = "RelationshipEvent_";

        private readonly TableInfo[] tables = new[]
            {
                new TableInfo("files_tag", "tenant_id", "id") {UserIDColumns = new[] {"owner"}},
                new TableInfo("files_tag_link", "tenant_id")
                    {
                        UserIDColumns = new[] {"create_by"},
                        DateColumns = new Dictionary<string, bool> {{"create_on", false}}
                    },
            };

        private readonly RelationInfo[] rels = new[]
            {
                new RelationInfo("projects_messages", "id", "files_tag", "name", typeof(ProjectsModuleSpecifics),
                    x => Convert.ToString(x["name"]).StartsWith(TagStartMessage, StringComparison.InvariantCultureIgnoreCase)),

                new RelationInfo("projects_tasks", "id", "files_tag", "name", typeof(ProjectsModuleSpecifics),
                    x => Convert.ToString(x["name"]).StartsWith(TagStartTask, StringComparison.InvariantCultureIgnoreCase)),

                new RelationInfo("projects_projects", "id", "files_tag", "name", typeof(ProjectsModuleSpecifics),
                    x => Convert.ToString(x["name"]).StartsWith(TagStartProject, StringComparison.InvariantCultureIgnoreCase)),

                new RelationInfo("crm_relationship_event", "id", "files_tag", "name", typeof(CrmModuleSpecifics2),
                    x => Convert.ToString(x["name"]).StartsWith(TagStartRelationshipEvent, StringComparison.InvariantCultureIgnoreCase)),

                new RelationInfo("files_tag", "id", "files_tag_link", "tag_id", typeof(FilesModuleSpecifics)),

                new RelationInfo("files_file", "id", "files_tag_link", "entry_id", typeof(FilesModuleSpecifics),
                    x => Convert.ToInt32(x["entry_type"]) == 2 && RegexIsInteger.IsMatch(Convert.ToString(x["entry_id"]))),

                new RelationInfo("files_folder", "id", "files_tag_link", "entry_id",typeof(FilesModuleSpecifics),
                    x => Convert.ToInt32(x["entry_type"]) == 1 && RegexIsInteger.IsMatch(Convert.ToString(x["entry_id"]))),

                new RelationInfo("files_thirdparty_id_mapping", "hash_id", "files_tag_link", "entry_id", typeof(FilesModuleSpecifics),
                    x => !RegexIsInteger.IsMatch(Convert.ToString(x["entry_id"]))),
            };

        public override ModuleName ModuleName
        {
            get { return ModuleName.Files2; }
        }

        public override IEnumerable<TableInfo> Tables
        {
            get { return tables; }
        }

        public override IEnumerable<RelationInfo> TableRelations
        {
            get { return rels; }
        }

        protected override bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
        {
            if (relation.ChildTable == "files_tag" && relation.ChildColumn == "name")
            {
                var str = Convert.ToString(value);
                var start = GetStart(str);
                if (start == null)
                {
                    return false;
                }
                var entityId = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, str.Substring(start.Length));
                if (entityId == null)
                {
                    return false;
                }
                value = str.Substring(0, start.Length) + entityId;
                return true;
            }
            return base.TryPrepareValue(connection, columnMapper, relation, ref value);
        }

        private static string GetStart(string value)
        {
            var allStarts = new[] { TagStartMessage, TagStartTask, TagStartRelationshipEvent, TagStartProject, };
            return allStarts.FirstOrDefault(value.StartsWith);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/App_Themes/default/blogstyle.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


table.MainBlogsTable
{
    width: 100%;
    border-bottom: 1px dotted #D1D1D1;
}
table.MainBlogsTable td.avatarContainer
{
    width: 85px;
}

.ContentMainBlog
{
    margin: 12px 8px 0;
}

.TagsMainBlog
{
    margin: 20px 8px 0;
}
.TagsImgMainBlog
{
    margin-bottom:-2px;
    margin-right:2px;
}

.BlogsBodyBlock {
    padding-left: 0px; 
}

#tableForNavigation {
    height: 24px;
    width: 100%;
}

.navigationLinkBox .tl-combobox {
    background: url("images/comboarrow_bottom.png") no-repeat scroll right center transparent;
    margin-bottom: 1px;
    vertical-align: middle;
}

.navigationLinkBox .tl-combobox .combobox-title .inner-text {
    border-bottom: 1px dotted #666666;
    color: #666666;
}
.table-border-dotted {
     border-bottom: 1px dotted #D1D1D1;
}

.MainBlogsTable .author-title {
    display: inline-block;
}
.MainBlogsTable .author-name {
    display: inline-block;
    margin-left: 12px;
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/TopStudioPanel/VoipPhoneControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Web.Core.Client.Bundling;
using ASC.Web.Core.Client.HttpHandlers;

namespace ASC.Web.Studio.UserControls.Common
{
    public partial class VoipPhoneControl : UserControl, IStaticBundle
    {
        public static string Location
        {
            get { return "~/UserControls/Common/TopStudioPanel/VoipPhoneControl.ascx"; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterStaticScripts(GetStaticJavaScript())
                .RegisterBodyScripts(
                        "~/js/third-party/socket.io.js",
                        "~/js/asc/core/asc.socketio.js")
                .RegisterClientScript(new VoipNumberData());
        }

        public ScriptBundleData GetStaticJavaScript()
        {
            var result = new ScriptBundleData("voip", "studio");
            result.AddSource(ResolveUrl, new ClientTemplateResources());
            result.AddSource(ResolveUrl,
                "~/js/asc/core/voip.countries.js",
                "~/js/asc/core/voip.phone.js");
            return result;
        }

        public StyleBundleData GetStaticStyleSheet()
        {
            return null;
        }
    }

    public class ClientTemplateResources : ClientScriptTemplate
    {
        protected override string[] Links
        {
            get
            {
                return new[]
                {
                    "~/Templates/VoipTemplate.html"
                };
            }
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.CRM/Wrappers/RelationshipEventWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

using ASC.Api.Documents;
using ASC.Api.Employee;
using ASC.CRM.Core;
using ASC.CRM.Core.Entities;
using ASC.Specific;

namespace ASC.Api.CRM.Wrappers
{
    [DataContract(Name = "entity", Namespace = "")]
    public class EntityWrapper
    {
        [DataMember]
        public String EntityType { get; set; }

        [DataMember]
        public int EntityId { get; set; }

        [DataMember]
        public String EntityTitle { get; set; }

        public static EntityWrapper GetSample()
        {
            return new EntityWrapper
            {
                EntityId = 123445,
                EntityType = "opportunity",
                EntityTitle = "Household appliances internet shop"
            };
        }
    }


    [DataContract(Name = "historyEvent", Namespace = "")]
    public class RelationshipEventWrapper :
        ObjectWrapperBase
    {
        public RelationshipEventWrapper() :
            base(0)
        {
        }

        public RelationshipEventWrapper(RelationshipEvent relationshipEvent)
            : base(relationshipEvent.ID)
        {
            CreateBy = EmployeeWraper.Get(relationshipEvent.CreateBy);
            Created = (ApiDateTime)relationshipEvent.CreateOn;
            Content = relationshipEvent.Content;
            Files = new List<FileWrapper>();
            CanEdit = CRMSecurity.CanEdit(relationshipEvent);
        }

        [DataMember(IsRequired = false, EmitDefaultValue = false)]
        public EmployeeWraper CreateBy { get; set; }

        [DataMember(IsRequired = true, EmitDefaultValue = false)]
        public ApiDateTime Created { get; set; }

        [DataMember(IsRequired = true, EmitDefaultValue = false)]
        public String Content { get; set; }

        [DataMember(IsRequired = true, EmitDefaultValue = false)]
        public HistoryCategoryBaseWrapper Category { get; set; }

        [DataMember(IsRequired = false, EmitDefaultValue = false)]
        public ContactBaseWrapper Contact { get; set; }

        [DataMember]
        public EntityWrapper Entity { get; set; }

        [DataMember(IsRequired = false, EmitDefaultValue = false)]
        public bool CanEdit { get; set; }

        [DataMember(IsRequired = false, EmitDefaultValue = false)]
        public IEnumerable<FileWrapper> Files { get; set; }

        public static RelationshipEventWrapper GetSample()
        {
            return new RelationshipEventWrapper
            {
                CanEdit = true,
                Category = HistoryCategoryBaseWrapper.GetSample(),
                Entity = EntityWrapper.GetSample(),
                Contact = ContactBaseWrapper.GetSample(),
                Created = ApiDateTime.GetSample(),
                CreateBy = EmployeeWraper.GetSample(),
                Files = new[] { FileWrapper.GetSample() },
                Content = @"Agreed to meet at lunch and discuss the client commercial offer"
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TfaControls/ConfirmTfa.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Security.Cryptography;
using ASC.Web.Core;
using ASC.Web.Core.Security;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.TFA;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Common;
using ASC.Web.Studio.Utility;

using Google.Authenticator;

namespace ASC.Web.Studio.UserControls.Management
{
    [AjaxNamespace("AjaxPro.TfaActivationController")]
    public partial class TfaActivation : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/TfaControls/ConfirmTfa.ascx"; }
        }

        public UserInfo User { get; set; }

        public bool Activation { get; set; }

        public SetupCode SetupCode { get; set; }

        protected string Country = "US";

        protected override void OnPreRender(EventArgs e)
        {
            if (Activation) return;
            if (SecurityContext.IsAuthenticated) Response.Redirect(GetRefererURL());
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (SecurityContext.IsAuthenticated && User.ID != SecurityContext.CurrentAccount.ID)
            {
                Response.Redirect(GetRefererURL(), true);
                return;
            }
            if (!TfaAppAuthSettings.IsVisibleSettings || !TfaAppAuthSettings.Enable)
            {
                Response.Redirect(GetRefererURL(), true);
                return;
            }
            if (!Activation && !TfaAppUserSettings.EnableForUser(User.ID))
            {
                Response.Redirect(GetRefererURL(), true);
                return;
            }

            var authCommunications = (AuthCommunications)LoadControl(AuthCommunications.Location);
            authCommunications.DisableJoin = true;
            _communitations.Controls.Add(authCommunications);

            AjaxPro.Utility.RegisterTypeForAjax(GetType());

            Page.RegisterBodyScripts("~/UserControls/Management/TfaControls/js/confirmtfa.js")
                .RegisterStyle("~/UserControls/Management/TfaControls/css/confirmtfa.less");

            if (Activation)
            {
                SetupCode = User.GenerateSetupCode();
            }
        }

        private static UserInfo GetUser(string query)
        {
            if (SecurityContext.IsAuthenticated)
            {
                return CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
            }

            var queryString = HttpUtility.ParseQueryString(query);

            var email = (queryString["email"] ?? "").Trim();
            var type = typeof(ConfirmType).TryParseEnum(queryString["type"] ?? "", ConfirmType.EmpInvite);
            var checkKeyResult = EmailValidationKeyProvider.ValidateEmailKey(email + type, queryString["key"], SetupInfo.ValidAuthKeyInterval);

            if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Expired)
            {
                throw new Exception(Resource.ErrorExpiredActivationLink);
            }

            if (checkKeyResult == EmailValidationKeyProvider.ValidationResult.Invalid)
            {
                throw new Exception(Resource.ErrorConfirmURLError);
            }

            var user = CoreContext.UserManager.GetUserByEmail(email);
            return user;
        }

        private string GetRefererURL()
        {
            var refererURL = (string)Context.Session["refererURL"];
            Context.Session["refererURL"] = null;

            if (string.IsNullOrEmpty(refererURL))
                refererURL = CommonLinkUtility.GetDefault();

            return refererURL;
        }

        [SecurityPassthrough]
        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object ValidateTfaCode(string query, string code)
        {
            var user = GetUser(query);
            bool newBackupCodes;

            try
            {
                newBackupCodes = user.ValidateAuthCode(code, !Activation);

                MessageService.Send(HttpContext.Current.Request, MessageAction.LoginSuccesViaTfaApp);
            }
            catch (Authorize.BruteForceCredentialException)
            {
                MessageService.Send(HttpContext.Current.Request, user.DisplayUserName(false), MessageAction.LoginFailBruteForce);
                throw;
            }
            catch
            {
                MessageService.Send(HttpContext.Current.Request, user.DisplayUserName(false), MessageAction.LoginFailViaTfaApp, MessageTarget.Create(user.ID));
                throw;
            }

            var refererUrl = GetRefererURL();

            if (newBackupCodes)
            {
                MessageService.Send(HttpContext.Current.Request, MessageAction.UserConnectedTfaApp, MessageTarget.Create(user.ID));

                refererUrl = CommonLinkUtility.GetUserProfile(user.ID) + "#codes";
            }

            if (query.Contains("desktop=true"))
            {
                refererUrl = CommonLinkUtility.GetFullAbsolutePath(WebItemManager.Instance[WebItemManager.DocumentsProductID].StartURL + "?desktop=true");
            }

            return new { RefererURL = refererUrl };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/mail.cache.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.mailCache = (function($) {
    var cache = [],
        cacheLimit = 25,
        inLoad = [];

    function loadToCache(ids) {
        if (inLoad.length === 0)
            inLoad = ids.slice();
        else
            return;

        var needItems = cacheLimit - cache.length;
        if (needItems.length > 0 && ids.length > needItems)
            ids = ids.slice(0, needItems);

        if (cache.length >= cacheLimit) {
            forgetOldest(ids.length);
        }

        async.each(ids, function (id, callback) {
            var data = { loadAll: false, markRead: false };
            console.log("%s is loading to cache", id);
            async.parallel([
                function (cb) {

                    if (commonSettingsPage.isConversationsEnabled()) {
                        Teamlab.getMailConversation({ skipIO: true },
                            id,
                            data,
                            {
                                success: function(params, messages) {
                                    cb(null, messages);
                                },
                                error: function(err) {
                                    cb(err);
                                },
                                async: true
                            });
                    } else {
                        Teamlab.getMailMessage({ skipIO: true },
                            id,
                            data,
                            {
                                success: function (params, messages) {
                                    cb(null, messages);
                                },
                                error: function (err) {
                                    cb(err);
                                },
                                async: true
                            });
                    }
                },
                function (cb) {
                    if (ASC.Mail.Constants.CRM_AVAILABLE) {
                        Teamlab.isConversationLinkedWithCrm(null, id,
                        {
                            success: function (params, status) {
                                cb(null, status);
                            },
                            error: function (params, e) {
                                cb(null, { isLinked: false });
                                console.error(e);
                            },
                            async: true
                        });
                    } else {
                        cb(null, { isLinked: false });
                    }
                }
            ], function (err, data) {
                if (err) {
                    callback(err);
                } else {
                    var content = $.extend(true, {}, { messages: commonSettingsPage.isConversationsEnabled() ? data[0] : [data[0]], hasLinked: data[1].isLinked });
                    set(id, content);
                    callback();
                }
            });
        }, function (err) {
            if (err) {
                console.error("Failed loadToCache", arguments);
            } else {
                console.info("Success loadToCache (%d items). Cache length %d", ids.length, cache.length);
            }
            inLoad = [];
        });
    }

    function getCacheItem(id) {
        id = parseInt(id);

        var cacheItem = null;
        for (var i = 0, n = cache.length; i < n; i++) {
            if (cache[i].id == id) {
                cacheItem = cache[i];
                break;
            }
        }

        return cacheItem;
    }

    function getCacheIndex(id) {
        id = parseInt(id);

        for (var i = 0, n = cache.length; i < n; i++) {
            if (cache[i].id == id) {
                return i;
            }
        }

        return -1;
    }

    function searchMessage(id, messages) {
        for (var i = 0, n = messages.length; i < n; i++) {
            var message = messages[i];
            if (message.id == id) {
                return message;
            }
        }

        return null;
    }

    function getRootMessage(id) {
        var item = getCacheItem(id);
        return item ? item.root : null;
    }

    function getMessage(id) {
        var item = getCacheItemByMessageId(id);
        if (!item)
            return null;

        var message = null,
            rootId = item.id;

        for (var i = 0, n = item.content.messages.length; i < n; i++) {
            var m = item.content.messages[i];
            if (m.id == rootId) {
                message = m;
                break;
            }
        }

        return message;
    }

    function get(id) {
        var cacheItem = getCacheItem(id);
        if (cacheItem && cacheItem.content) {
            return cacheItem.content;
        }

        return undefined;
    }

    function getCacheItemByMessageId(id) {
        for (var i = 0, n = cache.length; i < n; i++) {
            var messages = cache[i].content.messages;
            for (var j = 0, m = messages.length; j < m; j++) {
                if (messages[j].id == id)
                    return cache[i];
            }
        }

        return undefined;
    }

    function getByMessageId(id) {
        var item = getCacheItemByMessageId(id);
        return item ? item.content : undefined;
    }

    function getAll() {
        return cache;
    }

    function getAllMessagesIds(distinct) {
        var ids = [];
        for (var i = 0, n = cache.length; i < n; i++) {
            var messages = cache[i].content.messages;
            if (messages.length > 0) {
                ids = ids.concat(messages.map(function(vM) {
                    return vM.id;
                }));
            }
        }

        return ids.length > 1
            ? (distinct
                ? $.unique(ids.sort())
                : ids.sort())
            : ids;
    }

    function findMissingIds(ids) {
        var allCachedIds = getAllMessagesIds(true),
            missingIds = [];

        if (allCachedIds.length === 0)
            return ids;

        for (var i = 0, n = ids.length; i < n; i++) {
            if ($.inArray(ids[i], allCachedIds) === -1) {
                missingIds.push(ids[i]);
            }
        }

        return missingIds;
    }

    function forgetOldest(count) {
        var oldItems = [];

        var allUnread = $.grep(cache, function (item) {
            return item.unread === false;
        });

        if (allUnread.length > 0) {
            allUnread.sort(function(a, b) {
                if (a.date.isBefore(b.start))
                    return 1;
                if (a.date.isAfter(b.start))
                    return -1;
                return 0;
            });
            oldItems = allUnread.slice(0, count);
        } else {
            var tmp = cache.slice();
            tmp.sort(function (a, b) {
                if (a.date.isBefore(b.date))
                    return -1;
                if (a.date.isAfter(b.date))
                    return 1;
                return 0;
            });

            oldItems = tmp.slice(0, count);
        }

        var forgetIds = oldItems.map(function(v) { return v.id });

        remove(forgetIds);
    }

    function set(id, content) {
        if (!content.hasOwnProperty("messages") ||
            !$.isArray(content.messages) ||
            content.messages.length === 0)
            return;

        var cacheItem = getCacheItem(id);
        if (cacheItem) {
            cacheItem.content = content;
        } else {
            var root;
            if (content.messages.length > 1) {
                root = searchMessage(id, content.messages);
                for (var i = 0, n = content.messages.length; i < n; i++) {
                    var messageId = content.messages[i].id;
                    var oldRoot = getCacheItem(messageId);
                    if (oldRoot) {
                        remove([oldRoot.id]); //TODO: no need to remove, but copy to the new conversation
                        break;
                    }
                }
            } else {
                root = content.messages[0];
            }

            if (cache.length >= cacheLimit) {
                forgetOldest(1);
            }

            id = parseInt(id);

            cache.push({
                id: id,
                content: content,
                date: moment(new Date(root.date)),
                root: root,
                unread: root.wasNew
            });

            console.log("%s was cached. Cache length %d", id, cache.length);
        }
    }

    function setHasLinked(id, hasLinked) {
        var content = get(id);
        if (content) {
            content.hasLinked = hasLinked;
            set(id, content);
        }
    }

    function setImportant(ids, important) {
        if (!ids) return;

        if (!(ids instanceof Array)) {
            ids = [ids];
        }

        for (var i = 0, n = ids.length; i < n; i++) {
            var id = ids[i];

            var content = get(id);
            if (content) {
                for (var j = 0, m = content.messages.length; j < m; j++) {
                    var msg = content.messages[j];
                    if (msg.important !== important) {
                        msg.important = important;
                    }
                }
            }
        }
    }

    function setRead(ids, isRead) {
        if (!ids) return;

        if (!(ids instanceof Array)) {
            ids = [ids];
        }

        for (var i = 0, n = ids.length; i < n; i++) {
            var id = ids[i];
            var item = getCacheItem(id);
            if (item) {
                var needUpdate = false;
                var messages = item.content.messages;
                for (var j = 0, m = messages.length; j < m; j++) {
                    var msg = messages[j];
                    if (msg.wasNew !== !isRead) {
                        msg.wasNew = !isRead;
                        needUpdate = true;
                    }
                }
                if (needUpdate)
                    item.unread = !isRead;
            }
        }
    }

    function setTag(id, tagId, remove) {
        var content = get(id);
        if (content) {
            tagId = parseInt(tagId);
            var needUpdate = false;
            for (var i = 0, n = content.messages.length; i < n; i++) {
                var msg = content.messages[i];
                if (msg.tagIds && msg.tagIds.length > 0) {
                    var index = $.inArray(tagId, msg.tagIds);
                    if (index > -1) {
                        if (remove) {
                            msg.tagIds.splice(index, 1);
                            needUpdate = true;
                        }
                    } else {
                        if (!remove) {
                            msg.tagIds.push(tagId);
                            needUpdate = true;
                        }
                    }
                    
                } else {
                    if (!remove) {
                        msg.tagIds = [tagId];
                        needUpdate = true;
                    }
                }
            }
            if (needUpdate)
                set(id, content);
        }
    }

    function setFolder(ids, folder, userFolderId) {
        for (var i = 0, n = ids.length; i < n; i++) {
            var id = ids[i];
            var content = get(id);
            if (content) {
                var needUpdate = false;
                for (var j = 0, m = content.messages.length; j < m; j++) {
                    var msg = content.messages[j];
                    if (msg.folder != folder) {
                        msg.folder = folder;
                        needUpdate = true;
                    }

                    if (msg.userFolderId != userFolderId) {
                        msg.userFolderId = userFolderId;
                        needUpdate = true;
                    }
                }
                if (needUpdate)
                    set(id, content);
            }
        }
    }

    function setFolderToMessage(id, folder) {
        //TODO: create method for remove message in chain
    }

    function updateMessage(id, newMessage) {
        var item = getCacheItemByMessageId(id);
        if (!item)
            return;

        var content = item.content;
        for (var i = 0, n = content.messages.length; i < n; i++) {
            var message = content.messages[i];

            if (message.id == id) {
                content.messages[i] = newMessage;
                break;
            }
        }
    }

    function remove(ids) {
        for (var i = 0, n = ids.length; i < n; i++) {
            var id = parseInt(ids[i]);
            var cacheIndex = getCacheIndex(id);
            if (cacheIndex > -1) {
                cache.splice(cacheIndex, 1);
                console.log("%s removed from cache. Cache length %d", id, cache.length);
            }
        }
    }

    function clear() {
        cache = [];
    }

    return {
        loadToCache: loadToCache,
        get: get,
        getAll: getAll,
        getAllMessagesIds: getAllMessagesIds,
        getRootMessage: getRootMessage,
        getMessage: getMessage,
        getByMessageId: getByMessageId,
        findMissingIds: findMissingIds,
        set: set,
        setHasLinked: setHasLinked,
        setImportant: setImportant,
        setTag: setTag,
        setRead: setRead,
        setFolder: setFolder,
        updateMessage: updateMessage,
        remove: remove,
        clear: clear
    };

})(jQuery);

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/DbSchema/Tables/ImapFlagsTable.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


// ReSharper disable InconsistentNaming

using System.Collections.Generic;

using ASC.Mail.Core.DbSchema.Interfaces;

namespace ASC.Mail.Core.DbSchema.Tables
{
    public class ImapFlagsTable : ITable
    {
        public const string TABLE_NAME = "mail_imap_flags";

        public static class Columns
        {
            public const string FlagName = "name";
            public const string FolderId = "folder_id";
            public const string Skip = "skip";
        }

        public string Name
        {
            get { return TABLE_NAME; }
        }

        public IEnumerable<string> OrderedColumnCollection { get; private set; }

        public ImapFlagsTable()
        {
            OrderedColumnCollection = new List<string>
            {
                Columns.FolderId,
                Columns.FlagName,
                Columns.Skip
            };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/js/talk.default.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof window.console === 'undefined') {
  window.console = {};
}

//window.console._log = function () {
//  console.log.apply(this, arguments);
//}

/* (function () {
  var
    consoleId = 'console-' + Math.floor(Math.random() * 1000000),
    _log = [];

  if (typeof window.console == 'undefined') {
    window.console = {};
  }
  if (typeof window.console.log === 'undefined') {
    window.console.log = function (message) {
      return undefined;
      var console = document.getElementById(consoleId);
      if (!console) {
        console = document.createElement('textarea');
        document.body.appendChild(console);
        console.id = consoleId;
        console.setAttribute('readonly', 'readonly');
        console.style.position = 'absolute';
        console.style.zIndex = '6666';
        console.style.left = '0';
        console.style.bottom = '0';
        console.style.width = '50%';
        console.style.height = '200px';
        console.style.overflowY = 'scroll';
        console.style.whiteSpace = 'pre';
        console.style.background = '#FFF';
        console.style.border = '0';
      }
      console.value += message + '\n';
    };
  }

  window.console._log = function (msg) {
    _log.push(msg);
  };
  window.console._printLog = function () {
    for (var i = 0, n = _log.length; i < n; i++) {
      window.console.log(_log[i]);
    }
    _log = [];
  };
})(); */

window.TMTalk = (function ($) {
  var
    isInit = false,
    $body = null,
    onblurTimeoutHandler = 0,
    maxlengthMessage = 50,
    setDefaultIcon = false,
    originalTitle = '',
    indicatorTitle = '***',
    postfixTitle = '',
    unreadMessageCount = 0,
    maxIndicatorLength = 3,
    dialogsQueue = [],
    properties = {
      focused : false
    },
    customEvents = {
      pageKeyup : 'onpagekeyup',
      pageBlur : 'onpageblur',
      pageFocus : 'onpagefocus'
    },
    eventManager = new CustomEvent(customEvents);

  var init = function () {

    if (isInit === true) {
      return undefined;
    }
    isInit = true;

    // TODO
    //properties.focused = true;
    originalTitle = document.title;
    if (!window.name) {
      try {window.name = ASC.Controls.JabberClient.winName} catch (err) {}
    }

    postfixTitle = ASC.TMTalk.TalkResource.LabelNewMessage || '';

    if (window.moment) {
        window.moment.locale(ASC.Resources.Master.TwoLetterISOLanguageName);
    }
    var
      fld = '',
      engine = {},
      browser = {},
      version = -1,
      $body = $(document.body),
      ua = navigator.userAgent;

    version = (ua.match(/.+(?:rv|it|ra|ie|ox|me|on|id|os)[\/:\s]([\d._]+)/i)||[0,'0'])[1].replace('_', '');
    version = isFinite(parseFloat(version)) ? parseFloat(version) : version;
    engine = {
      'engn-ios'      : /iphone|ipad/i.test(ua),
      'engn-android'  : /android/i.test(ua),
      'engn-gecko'    : /gecko/i.test(ua) && !/webkit/i.test(ua),
      'engn-webkit'   : /webkit/i.test(ua)
    };
    browser = {
      'brwr-msie'     : '\v' == 'v' || /msie/i.test(ua),
      'brwr-opera'    : window.opera ? true : false,
      'brwr-chrome'   : window.chrome ? true : false,
      'brwr-safari'   : /safari/i.test(ua) && !window.chrome,
      'brwr-firefox'  : /firefox/i.test(ua)
    };
    for (fld in engine) {
      if (engine.hasOwnProperty(fld)) {
        if (engine[fld]) {
          $body.addClass(fld);
        }
      }
    }
    for (fld in browser) {
      if (browser.hasOwnProperty(fld)) {
        if (browser[fld]) {
          $body.addClass(fld);
          $body.addClass(fld + '-' + version);
        }
      }
    }

    ASC.TMTalk.mucManager.bind(ASC.TMTalk.mucManager.events.recvInvite, onRecvInvite);
    ASC.TMTalk.mucManager.bind(ASC.TMTalk.mucManager.events.acceptInvite, onCloseInvite);
    ASC.TMTalk.mucManager.bind(ASC.TMTalk.mucManager.events.declineInvite, onCloseInvite);

    ASC.TMTalk.messagesManager.bind(ASC.TMTalk.messagesManager.events.recvMessageFromChat, onRecvMessageFromChat);

    ASC.TMTalk.mucManager.bind(ASC.TMTalk.mucManager.events.createRoom, onCreateConference);

    ASC.TMTalk.roomsManager.bind(ASC.TMTalk.roomsManager.events.openRoom, onOpenRoom);
    ASC.TMTalk.roomsManager.bind(ASC.TMTalk.roomsManager.events.closeRoom, onCloseRoom);

    ASC.TMTalk.connectionManager.bind(ASC.TMTalk.connectionManager.events.connected, onClientConnected);
    ASC.TMTalk.connectionManager.bind(ASC.TMTalk.connectionManager.events.disconnected, onClientDisconnected);
    ASC.TMTalk.connectionManager.bind(ASC.TMTalk.connectionManager.events.connectingFailed, onClientConnectingFailed);

    TMTalk.bind(TMTalk.events.pageFocus, onPageFocus);

    ASC.TMTalk.indicator.bind(ASC.TMTalk.indicator.events.start, onStartIndicator);
    ASC.TMTalk.indicator.bind(ASC.TMTalk.indicator.events.show, onShowIndicator);
    ASC.TMTalk.indicator.bind(ASC.TMTalk.indicator.events.stop, onStopIndicator);
      
    if (document.getElementById('talkHtmlSoundsContainer') == null) {
        ASC.TMTalk.sounds.initHtml();
    }
  };

  var bind = function (eventName, handler, params) {
    return eventManager.bind(eventName, handler, params);
  };

  var unbind = function (handlerId) {
    return eventManager.unbind(handlerId);
  };

  var blur = function (evt) {
    clearTimeout(onblurTimeoutHandler);
    onblurTimeoutHandler = setTimeout(TMTalk.blurcallback, 1);
  };

  var focus = function (evt) {
    clearTimeout(onblurTimeoutHandler);

    if (properties.focused === false) {
      properties.focused = true;
      eventManager.call(customEvents.pageFocus, window, [evt]);
    }
  };

  var blurcallback = function (evt) {
    if (properties.focused === true) {
      properties.focused = false;
      eventManager.call(customEvents.pageBlur, window, [evt]);
    }
  };

  var click = function (evt) {
    clearTimeout(onblurTimeoutHandler);
    setTimeout(TMTalk.focus, 2);
  };

  var clickcallback = function (evt) {
    if (window.getSelection) {
      window.getSelection().removeAllRanges();
    }

    $(document).trigger('click');
  };

  var keyup = function (evt) {
    eventManager.call(customEvents.pageKeyup, window, [evt]);
  };

  var onStartIndicator = function () {
    setDefaultIcon = true;
  };

  var onShowIndicator = function () {
    //var currenttitle = document.title;
    //if (currenttitle !== indicatorTitle + ' ' + originalTitle) { 
    //  originalTitle = currenttitle;
    //}
    indicatorTitle += indicatorTitle.charAt(0);
    if (indicatorTitle.length > maxIndicatorLength) {
      indicatorTitle = indicatorTitle.charAt(0);
    }
    unreadMessageCount = window.ASC.TMTalk.contactsContainer.getUnreadMessageCount();
    document.title = indicatorTitle + "(" + unreadMessageCount+ ") -" + ' ' + originalTitle;

    if (setDefaultIcon) {
        ASC.TMTalk.iconManager.set(ASC.TMTalk.Icons.iconNewMessage);
        setDefaultIcon = !setDefaultIcon;
    }
  };

  var onStopIndicator = function () {
    indicatorTitle = '***';
    document.title = originalTitle;
    ASC.TMTalk.iconManager.reset();
    setDefaultIcon = true;
  };

  var onPageFocus = function () {
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (currentRoomData !== null && currentRoomData.type === 'chat') {
      ASC.TMTalk.notifications.hide(currentRoomData.id);
    }

  };
    var openRoom = function(key, inBackground) {
        setTimeout(function() {
            ASC.TMTalk.contactsContainer.openRoom(key, inBackground);
        }, 300);
    };
    var reopenOpenedRooms = function (openedRooms) {
        for (key in openedRooms) {
            if (ASC.TMTalk.contactsManager.getContact(key) != null) {
                if (openedRooms[key].type == 'chat') {
                    if (ASC.TMTalk.roomsManager.getRoomDataById(key) == null) {
                        openRoom(key, openedRooms[key].inBackground);
                    }
                }
            } else {
                setTimeout(function () {
                    reopenOpenedRooms(openedRooms);
                }, 300);
                break;
            }
        }
    };

  var onClientConnected = function () {
      $(document.body).addClass('connected');
      var openedRooms = localStorageManager.getItem("openedRooms");

      if (openedRooms != undefined) {
          reopenOpenedRooms(openedRooms);
      }
  };

  var onClientDisconnected = function () {
    $(document.body).removeClass('connected');
  };

  var onClientConnectingFailed = function () {
    $(document.body).removeClass('connected');
  };

  var onCreateConference = function (roomjid, room) {
    ASC.TMTalk.mucManager.setSubject(roomjid, ASC.TMTalk.stringFormat(ASC.TMTalk.TalkResource.DefaultConferenceSubjectTemplate, room.name));
  };

  var onOpenRoom = function (roomId, data, inBackground) {
    if (inBackground !== true) {
      if (TMTalk.properties.focused && data.type === 'chat') {
          ASC.TMTalk.notifications.hide(data.id);
      }

      $('#talkContentContainer').removeClass('disabled');
      TMTalk.disableFileUploader(false);
    }
  };

  var onCloseRoom = function (roomId, data, isCurrent) {
    if (isCurrent === true) {
      $('#talkContentContainer').addClass('disabled');
      TMTalk.disableFileUploader(true);
    }
  };

  var onRecvInvite = function (roomjid, inviterjid, reason) {
    if (TMTalk.properties.focused === false) {
      ASC.TMTalk.notifications.show(
        roomjid,
        ASC.TMTalk.TalkResource.TitleRecvInvite + ' ' + ASC.TMTalk.mucManager.getConferenceName(roomjid),
        ASC.TMTalk.mucManager.getContactName(inviterjid) + ' ' + ASC.TMTalk.TalkResource.LabelRecvInvite
      );
    }
  };

  var onCloseInvite = function (roomjid, name, inviterjid) {
    ASC.TMTalk.notifications.hide(roomjid);
  };

  var onRecvMessageFromChat = function (jid, displayname, displaydate, date, body) {
    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (TMTalk.properties.focused === false || currentRoomData !== null && currentRoomData.type === 'chat' && currentRoomData.id !== jid) {
      ASC.TMTalk.notifications.show(
        jid,
        ASC.TMTalk.contactsManager.getContactName(jid),
        body.length < maxlengthMessage ? body : body.substring(0, maxlengthMessage) + '...'
      );
    }
  };

  var showDialog = function (name, titleval, data, invited) {
    if (arguments.length === 0 && dialogsQueue.length > 0) {
      var dialog = dialogsQueue.pop();
      if (dialog) {
        name      = dialog.name;
        titleval  = dialog.titleval;
        data      = dialog.data;
      }
    }

    if (typeof name !== 'string') {
      return undefined;
    }

    name = name.toLowerCase();
    switch (name) {
      case 'create-room' :
      case 'remove-room' :
      case 'recv-invite' :
      case 'kick-occupant' :
      case 'create-mailing' :
      case 'browser-notifications':
      case 'delete-files':
        break;
      default :
        return undefined;
    }
    //hideAllDialogs();

    var dialogsContainer = document.getElementById('talkDialogsContainer');

    if (!!dialogsContainer.className) {
      if (name === 'recv-invite' && dialogsContainer.className === name) {
        var roomjid = $('#hdnInvitationRoom').val(), inviterjid = $('#hdnInvitationContact').val();
        if (data.roomjid === roomjid && data.inviterjid === inviterjid) {
          return undefined;
        }
      }
      if (name === 'recv-invite' && dialogsQueue.length > 0) {
        var roomjid = data.roomjid, inviterjid = data.inviterjid, dialogsInd = dialogsQueue.length;
        while (dialogsInd--) {
          if (dialogsQueue[dialogsInd].data.roomjid === roomjid && dialogsQueue[dialogsInd].data.inviterjid === inviterjid) {
            break;
          }
        }
        if (dialogsInd >= 0) {
          return undefined;
        }
      }

      dialogsQueue.push({name : name, titleval : titleval, data : data});
      return undefined;
    }

    if (typeof titleval === 'string') {
      $(dialogsContainer)
        .find('div.dialog.' + name + ':first')
        .find('div.head:first div.title:first span.value:first').empty().html(titleval);

      $(dialogsContainer)
      .find('div.dialog.' + name + ':first')
      .find('div.title:first span.value:first').empty().html(titleval);
    }

    $('#txtRoomName').removeClass('invalid-input');
    $('#txtMailingName').parents('div.textfield:first').removeClass('invalid-field');

    if (data && typeof data === 'object') {
      switch (name) {
        case 'create-room' :
          if (data.hasOwnProperty('roomname')) {
            $('#txtRoomName').val(data.roomname);
          }
          if (data.hasOwnProperty('temproomchecked')) {
            $('#cbxTemporaryRoom').attr('checked', data.temproomchecked);
          }
          break;
        case 'remove-room' :
          if (data.hasOwnProperty('roomjid')) {
            $('#hdnRemoveJid').val(data.roomjid);
          }
          break;
        case 'recv-invite' :
          if (data.hasOwnProperty('roomjid')) {
            $('#hdnInvitationRoom').val(data.roomjid);
          }
          if (data.hasOwnProperty('inviterjid')) {
            $('#hdnInvitationContact').val(data.inviterjid);
          }
          if (data.hasOwnProperty('contactname')) {
            $('#lblInviterName').empty().html(data.contactname);
          }
          break;
        case 'kick-occupant' :
          if (data.hasOwnProperty('contactjid')) {
            $('#hdnKickJId').val(data.contactjid); 
            $('#hdnKickInvited').val(invited.invited);
            $('#hdnKickRoomCid').val(invited.roomCid);
          }
          break;
        case 'create-mailing' :
          if (data.hasOwnProperty('mailingname')) {
            $('#txtMailingName').val(data.mailingname);
          }
          break;
      }
    }

    $(dialogsContainer)
      .attr('class', name)
      .find('div.dialog.' + name + ':first')
        .css({opacity : '0', display : 'block'})
        .animate({opacity : 1}, $.browser.msie && $.browser.version < 9 ? 0 : 'middle', function () {
          // TODO:
          var $block = $(this);
          $block.find('div.textfield:first input:first').focus();
          if ($.browser.msie && $.browser.version < 9 && $block.length !== 0) {
            var
              prefix = ' ',
	            block = $block.get(0),
	            cssText = prefix + block.style.cssText,
	            startPos = cssText.toLowerCase().indexOf(prefix + 'filter:'),
	            endPos = cssText.indexOf(';', startPos);
	          if (startPos !== -1) {
	            if (endPos !== -1) {
	              block.style.cssText = [cssText.substring(prefix.length, startPos), cssText.substring(endPos + 1)].join('');
	            } else {
	              blockUI.style.cssText = cssText.substring(prefix.length, startPos);
	            }
	          }
	        }
        });
  };

  var hideDialog = function () {
    $('#talkDialogsContainer').find('div.dialog:visible').animate({opacity : 0}, $.browser.msie && $.browser.version < 9 ? 0 : 'middle', function () {
      jQuery(this).hide();

      var container = document.getElementById('talkDialogsContainer');
      if (container) {
        container.className = '';
      }

      TMTalk.showDialog();
    });
  };

  var hideAllDialogs = function () {
    $('#talkDialogsContainer').find('div.dialog').hide();
    var container = document.getElementById('talkDialogsContainer');
    if (container) {
      container.className = '';
    }
  };

  function createFileuploadInput(browseButtonId) {
      var buttonObj = jq("#" + browseButtonId);

      var inputObj = jq("<input/>")
          .attr("id", "fileupload")
          .attr("type", "file")
          .css("width", "0")
          .css("height", "0");

      inputObj.appendTo(buttonObj.parent());

      buttonObj.on("click", function (e) {
          e.preventDefault();
          jq("#fileupload").click();
      });

      return inputObj;
  }

  function correctFile(file) {
      if (file.size > ASC.TMTalk.properties.item("maxUploadSize")) {
          var message = ASC.TMTalk.properties.item("maxUploadSizeError");
          ASC.TMTalk.meseditorContainer.onSendFileError(message);
          return false;
      }

      return true;
  }

    var createFileUploader = function () {
        var uploader = createFileuploadInput("talkFileUploader");

        uploader.fileupload({
            url: "UploadProgress.ashx?submit=ASC.Web.Talk.HttpHandlers.UploadFileHandler,ASC.Web.Talk",
            autoUpload: false,
            singleFileUploads: true,
            sequentialUploads: true,
            progressInterval: 1000,
            dropZone: "talkRoomsContainer"
        });

        uploader
            .bind("fileuploadadd", function (e, data) {
                if (correctFile(data.files[0])) {
                    ASC.TMTalk.meseditorContainer.onSendFileStart();
                    TMTalk.disableFileUploader(true);
                    data.submit();
                }
            })
            .bind("fileuploaddone", function (e, data) {
                var res = jq.parseJSON(data.result);
                ASC.TMTalk.meseditorContainer.onSendFileComplete(res);
                TMTalk.disableFileUploader(false);
                jq("#pop").addClass("has-files");
            })
            .bind("fileuploadfail", function (e, data) {
                var msg = data.errorThrown || data.textStatus;
                if (data.jqXHR && data.jqXHR.responseText)
                    msg = jq.parseJSON(data.jqXHR.responseText).Message;

                ASC.TMTalk.meseditorContainer.onSendFileError(msg);
                TMTalk.disableFileUploader(false);
            });

    };

    var disableFileUploader = function (disable) {
        if (!jq("#talkMeseditorContainer").is(".connected")
            || jq("#talkMeseditorContainer").is(".disabled")
            || jq("#talkMeseditorContainer").is(".unavailable")) {
            disable = true;
        }

        if (disable === false) {
            jq("#talkFileUploaderFake").remove();
            jq("#talkFileUploader").removeClass("display-none");
        }
        jq("#fileupload").prop("disabled", disable);
    };

  return {
    events      : customEvents,
    properties  : properties,

    init    : init,
    bind    : bind,
    unbind  : unbind,

    keyup         : keyup,
    focus         : focus,
    blur          : blur,
    click         : click,
    blurcallback  : blurcallback,
    clickcallback : clickcallback,

    showDialog      : showDialog,
    hideDialog      : hideDialog,
    hideAllDialogs  : hideAllDialogs,

    createFileUploader: createFileUploader,
    disableFileUploader: disableFileUploader,
  };
})(jQuery);

(function ($) {
  var
    constants = {
      propertySidebarWidth : 'sbw',
      propertyMeseditorHeight : 'meh'
    },
    minPageHeight = 300,
    offsetSidebarContainer = 0,
    offsetMeseditorContainer = 0,
    minMeseditorContainer = 50,
    minSidebarContainerWidth = 252,
    mcHeightOffset = 0,
    ccWidthOffset = 0,
    ccHeightOffset = 0,
    rcHeightOffset = 0,
    vsBottomOffset = 0,
    ssHeightOffset = 0,
    $window = null,
    horSlider = null, $horSlider = null,
    vertSlider = null, $vertSlider = null,
    startSplash = null, $startSplash = null,
    mainContainer = null, $mainContainer = null,
    contentContainer = null, $contentContainer = null,
    roomsContainer = null, $roomsContainer = null,
    meseditorContainer = null, $meseditorContainer = null,
    sidebarContainer = null, $sidebarContainer = null,
    contactsContainer = null, $contactsContainer = null,
    contactToolbarContainer = null, $contactToolbarContainer = null,
    meseditorToolbarContainer = null, $meseditorToolbarContainer = null;

  var platform = (function () {
    var
      ua = navigator.userAgent,
      version = (ua.match(/.+(?:rv|it|ra|ie|ox|me|on|id|os)[\/:\s]([\d._]+)/i)||[0,'0'])[1].replace('_', '');

    return {
      version : isFinite(parseFloat(version)) ? parseFloat(version) : version,
      android : /android/i.test(ua),
      ios     : /iphone|ipad/i.test(ua)
    }
  })();

  $.extend($, {platform : platform});

  $.extend(
    $.support,
    {
      webapp            : window.innerHeight === window.screen.availHeight,
      platform          : platform,
      orientation       : 'orientation' in window,
      touch             : 'ontouchend' in document,
      csstransitions    : 'WebKitTransitionEvent' in window,
      pushState         : !!history.pushState,
      cssPositionFixed  : !('ontouchend' in document),
      iscroll           : $.platform.ios || $.platform.android,
      svg               : !($.browser.mozilla === true),
      dataimage         : !($.browser.msie && $.browser.version < 9)
    }
  );

//-------------------------------------------------------------------------------------------
  function onDragStart () {
    return false;
  }

  function onSelectStart () {
    return false;
  }
//-------------------------------------------------------------------------------------------
  function onMouseMoveVertSlider(evt) {
    var
      contentContainerHeight = $contentContainer.height(),
      newMeseditorHeight = document.body.offsetHeight - evt.pageY - offsetMeseditorContainer;

    if (newMeseditorHeight * 3 > contentContainerHeight) { // if more 33%
      newMeseditorHeight = Math.floor(contentContainerHeight / 3);
    }
    if (newMeseditorHeight < minMeseditorContainer) {
      newMeseditorHeight = minMeseditorContainer;
    }
    ASC.TMTalk.properties.meseditorHeight = newMeseditorHeight;
    meseditorContainer.style.height = newMeseditorHeight + 'px';
    //$meseditorContainer.height(newMeseditorHeight);
    vertSlider.style.bottom = (newMeseditorHeight - 5) + 'px';
    //$vertSlider.css('bottom', newMeseditorHeight + vsBottomOffset + 'px');
    roomsContainer.style.height = contentContainerHeight - meseditorContainer.offsetHeight - roomsContainer.offsetTop - rcHeightOffset - 22 + (ASC.TMTalk.dom.hasClass(roomsContainer, 'multichat') ? 32:0) + 'px';
    //$roomsContainer.height(contentContainerHeight - $meseditorContainer.height() - parseInt($roomsContainer.css('top')) - rcHeightOffset);

    var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
    if (currentRoomData !== null && currentRoomData.type === 'conference' && currentRoomData.minimized === false) {
      var nodes = ASC.TMTalk.dom.getElementsByClassName(roomsContainer, 'room conference current', 'li');
      if (nodes.length > 0) {
        var roomHeight = nodes[0].offsetHeight;
        nodes = ASC.TMTalk.dom.getElementsByClassName(nodes[0], 'sub-panel', 'div');
        if (nodes.length > 0) {
          nodes[0].style.height = Math.ceil(roomHeight / 2) - 90 + 'px';
        }
      }
    }
    if (currentRoomData !== null && currentRoomData.type === 'mailing' && currentRoomData.minimized === false) {
        var nodes = ASC.TMTalk.dom.getElementsByClassName(roomsContainer, 'room mailing current', 'li');
        if (nodes.length > 0) {
            var roomHeight = nodes[0].offsetHeight;
            nodes = ASC.TMTalk.dom.getElementsByClassName(nodes[0], 'sub-panel', 'div');
            if (nodes.length > 0) {
                nodes[0].style.height = Math.ceil(roomHeight / 2) - 90 + 'px';
            }
        }
    }
    return false;
  }

  function onMouseUpVertSlider (evt) {
    ASC.TMTalk.properties.item(constants.propertyMeseditorHeight, meseditorContainer.offsetHeight, true);
    //ASC.TMTalk.properties.item(constants.propertyMeseditorHeight, $meseditorContainer.height(), true);
    $meseditorContainer.removeClass('blocked');
    $window.focus();

    $(document).unbind('dragstart', onDragStart);
    $(document).unbind('mouseup', onMouseUpVertSlider);
    $(document).unbind('mousemove', onMouseMoveVertSlider);
    $(document.body).unbind('selectstart', onSelectStart);
    return false;
  }

  function dragVertSlider (evt) {
    offsetMeseditorContainer = document.body.offsetHeight - evt.pageY - meseditorContainer.offsetHeight;
    //offsetMeseditorContainer = document.body.offsetHeight - evt.pageY - $meseditorContainer.height();
    $meseditorContainer.addClass('blocked');

    $(document).bind('dragstart', onDragStart);
    $(document).bind('mouseup', onMouseUpVertSlider);
    $(document).bind('mousemove', onMouseMoveVertSlider);
    $(document.body).bind('selectstart', onSelectStart);
    return false;
  }
//-------------------------------------------------------------------------------------------
  function onMouseMoveHorSlider(evt) {
    var
      mainContainerWidth = $mainContainer.width(),
      newSidebarWidth = evt.pageX ;

    if (newSidebarWidth * 2 > mainContainerWidth) { // if more 50%
      newSidebarWidth = Math.floor(mainContainerWidth / 2);
    }
    if (newSidebarWidth < minSidebarContainerWidth) {
      newSidebarWidth = minSidebarContainerWidth;
    }
    $sidebarContainer.width(newSidebarWidth);
    $horSlider.css('left', newSidebarWidth + 'px');
    $contentContainer.width(mainContainerWidth - newSidebarWidth - ccWidthOffset);
    return false;
  }

  function onMouseUpHorSlider (evt) {
    ASC.TMTalk.properties.item(constants.propertySidebarWidth, sidebarContainer.offsetWidth, true);
    //ASC.TMTalk.properties.item(constants.propertySidebarWidth, $sidebarContainer.width(), true);
    $meseditorContainer.removeClass('blocked');
    $window.focus();

    $(document).unbind('dragstart', onDragStart);
    $(document).unbind('mouseup', onMouseUpHorSlider);
    $(document).unbind('mousemove', onMouseMoveHorSlider);
    $(document.body).unbind('selectstart', onSelectStart);
    return false;
  }

  function dragHorSlider (evt) {
    offsetSidebarContainer = document.body.offsetWidth - evt.pageX - sidebarContainer.offsetWidth;
    //offsetSidebarContainer = document.body.offsetWidth - evt.pageX - $sidebarContainer.width();
    $meseditorContainer.addClass('blocked');

    $(document).bind('dragstart', onDragStart);
    $(document).bind('mouseup', onMouseUpHorSlider);
    $(document).bind('mousemove', onMouseMoveHorSlider);
    $(document.body).bind('selectstart', onSelectStart);
    return false;
  }
//-------------------------------------------------------------------------------------------
  $(window).keyup(TMTalk.keyup).blur(TMTalk.blur).focus(TMTalk.focus);
  $(document).click(TMTalk.click);

  $(function () {
    //$(document.body).addClass('focused');

    if (ASC.TMTalk.flashPlayer.isCorrect) {
        var o = document.createElement('div'),
            soundsContainerId = 'talkSoundsContainer-' + Math.floor(Math.random() * 1000000);

        o.setAttribute('id', soundsContainerId);
        document.body.appendChild(o);
        swfobject.embedSWF(
            ASC.TMTalk.properties.item('sounds') ? ASC.TMTalk.properties.item('sounds') : ASC.TMTalk.Config.sounds,
            soundsContainerId,
            1,
            1,
            '9.0.0',
            ASC.TMTalk.properties.item('expressInstall'),
            { apiInit: function(id) { ASC.TMTalk.sounds.init(id); }, apiId: soundsContainerId },
            { allowScriptAccess: 'always', wmode: 'transparent' },
            { styleclass: 'soundsContainer', wmode: 'transparent' }
        );
        ASC.TMTalk.sounds.init(soundsContainerId);
    } else {
        ASC.TMTalk.sounds.initHtml();
    }

    $('#talkWrapper').show();
    $window = $(window);
    horSlider = document.getElementById('talkHorSlider'); $horSlider = $(horSlider);
    vertSlider = document.getElementById('talkVertSlider'); $vertSlider = $(vertSlider);
    startSplash = document.getElementById('talkStartSplash'); $startSplash = $(startSplash);
    mainContainer = document.getElementById('talkMainContainer'); $mainContainer = $(mainContainer);
    sidebarContainer = document.getElementById('talkSidebarContainer'); $sidebarContainer = $(sidebarContainer);
    contentContainer = document.getElementById('talkContentContainer'); $contentContainer = $(contentContainer);
    meseditorContainer = document.getElementById('talkMeseditorContainer'); $meseditorContainer = $(meseditorContainer);
    roomsContainer = document.getElementById('talkRoomsContainer'); $roomsContainer = $(roomsContainer);
    contactsContainer = document.getElementById('talkContactsContainer'); $contactsContainer = $(contactsContainer);
    contactToolbarContainer = document.getElementById('talkContactToolbarContainer'); $contactToolbarContainer = $(contactToolbarContainer);
    meseditorToolbarContainer = document.getElementById('talkMeseditorToolbarContainer'); $meseditorToolbarContainer = $(meseditorToolbarContainer);

    mcHeightOffset = $('#talkTabContainer').height() + 10 * 2 + 10 * 2 + 1;
    ccWidthOffset = $horSlider.width();
    ccHeightOffset = $('#talkStatusContainer').outerHeight(true) + 1 * 2;
    rcHeightOffset = parseInt($meseditorContainer.css('bottom')) + $vertSlider.height() + 1 * 2 + 1;
    vsBottomOffset = $meseditorToolbarContainer.outerHeight(true) + 1;
    ssHeightOffset = $meseditorToolbarContainer.outerHeight(true) + 10 + 1;

    var windowHeight = $window.height();
    if (windowHeight < minPageHeight) {
      windowHeight = minPageHeight;
    }

    if ($.browser.msie && $.browser.version < 9) {
      $(document.body).add('#studioPageContent').css('backgroundColor', '#0A4462');
      $startSplash.find('div.background').css('backgroundColor', '#4A8CAC');
    }

    var mainContainerHeight = windowHeight - mcHeightOffset;
    mainContainer.style.height = mainContainerHeight + 'px';
    //$mainContainer.height(windowHeight - mcHeightOffset);
    contactsContainer.style.height = mainContainerHeight;
    //$contactsContainer.height($mainContainer.height() - $contactToolbarContainer.height() - ccHeightOffset);

    var
      contentContainerHeight = contentContainer.offsetHeight,
      //contentContainerHeight = $contentContainer.height(),
      meseditorHeight = ASC.TMTalk.properties.item(constants.propertyMeseditorHeight);
    meseditorHeight = isFinite(+meseditorHeight) ? +meseditorHeight : minMeseditorContainer;
    if (meseditorHeight * 3 > contentContainerHeight) { // if more 33%
      meseditorHeight = Math.floor(contentContainerHeight / 3);
    }
    if (meseditorHeight < minMeseditorContainer) {
      meseditorHeight = minMeseditorContainer;
    }
    meseditorContainer.style.height = meseditorHeight + 'px';
      //$meseditorContainer.height(meseditorHeight);
    vertSlider.style.bottom = (meseditorHeight - 5) + 'px';
    //$vertSlider.css('bottom', meseditorHeight + vsBottomOffset + 'px');

    var roomsContainerHeight = contentContainerHeight - roomsContainer.offsetTop - ($roomsContainer.hasClass('history') ? 2 : meseditorContainer.offsetHeight + rcHeightOffset);
    if (roomsContainerHeight < 0) {
      roomsContainerHeight = -roomsContainerHeight;
    }
    roomsContainer.style.height = roomsContainerHeight-2 + 'px';
    //$roomsContainer.height(contentContainerHeight - parseInt($roomsContainer.css('top')) - ($roomsContainer.hasClass('history') ? 2 : $meseditorContainer.height() + rcHeightOffset));

    var
      mainContainerWidth = $mainContainer.width(),
      sidebarWidth = ASC.TMTalk.properties.item(constants.propertySidebarWidth);
    sidebarWidth = isFinite(+sidebarWidth) ? +sidebarWidth : minSidebarContainerWidth;
    if (sidebarWidth * 2 > mainContainerWidth) { // if more 50%
      sidebarWidth = Math.floor(mainContainerWidth / 2);
    }
    if (sidebarWidth < minSidebarContainerWidth) {
      sidebarWidth = minSidebarContainerWidth;
    }
    sidebarContainer.style.width = sidebarWidth + 'px';
    //$sidebarContainer.width(sidebarWidth);
    horSlider.style.left = sidebarWidth + 'px';
    //$horSlider.css('right', sidebarWidth + 'px');
    contentContainer.style.width = mainContainerWidth - sidebarWidth - ccWidthOffset + 'px';
    //$contentContainer.width(mainContainerWidth - sidebarWidth - ccWidthOffset);

    startSplash.style.height = contentContainer.offsetHeight - ssHeightOffset + 'px';
    //$startSplash.height($contentContainer.height() - ssHeightOffset);

    if (ASC.TMTalk.properties.item('hidscd') !== '1') {
      try {
        google.gears.factory.create('beta.desktop').createShortcut(
          ASC.TMTalk.TalkResource.ProductName,
          location.href,
            {
                '16x16': ASC.TMTalk.Icons.addonIcon16,
                '32x32': ASC.TMTalk.Icons.addonIcon32,
                '48x48': ASC.TMTalk.Icons.addonIcon48,
                '128x128': ASC.TMTalk.Icons.addonIcon128
            },
          ASC.TMTalk.TalkResource.HintCreateShortcutDialog
        );
      } catch (err) {}
    }
    ASC.TMTalk.properties.item('hidscd', '1', true);

    if ($.browser.safari) {
      $('#talkStartSplash').mousedown(function () {
        if (window.getSelection) {
          window.getSelection().removeAllRanges();
        }
        return false;
      });
    }

    //if (ASC.TMTalk.properties.item('hidnd') !== '1') {
    //  if (ASC.TMTalk.notifications.supported.current === true) {
    //    if (ASC.TMTalk.notifications.enabled() === true) {
    //      $('#cbxToggleNotifications').removeClass('disabled');
    //    } else {
    //      $('#cbxToggleNotifications').addClass('disabled');
    //    }
    //    TMTalk.showDialog('browser-notifications');
    //  }
    //}

    //switch (ASC.TMTalk.properties.item('hidnd')) {
    //  case '0' :
    //    $('#cbxToggleNotificationsDialog').attr('checked', false);
    //    break;
    //  case '1' :
    //    $('#cbxToggleNotificationsDialog').attr('checked', true);
    //    break;
    //  default :
    //    $('#cbxToggleNotificationsDialog').attr('checked', true);
    //    ASC.TMTalk.properties.item('hidnd', '1', true);
    //    break;
    //}

    $(document).keydown($.support.touch ? null : function (evt) {
      // shift + tab
      if (evt.shiftKey === true && evt.keyCode === 9) {
        // TODO :
        ASC.TMTalk.tabsContainer.nextTab();
        return false;
      }
      // esc
      if (evt.keyCode === 27) {
        // TODO :
        TMTalk.hideAllDialogs();
        return false;
      }
      // shift + F
      if (evt.shiftKey === true && evt.keyCode === 70) {
         // TODO :
        if (ASC.TMTalk.properties.item('enblfltr') === '0') {
          ASC.TMTalk.properties.item('enblfltr', '1');
        }
        return false;
      }
    });

    $(window)
      .keypress(function (evt) {
        if (evt.ctrlKey && evt.charCode === 119 && ASC.TMTalk.connectionManager.connected()) {
          ASC.TMTalk.connectionManager.terminate();
        }
      })
      .on("beforeunload", ASC.TMTalk.connectionManager.terminate)
      .resize(function () {
        var windowHeight = $window.height();
        if (windowHeight < minPageHeight) {
          windowHeight = minPageHeight;
        }

        var
          containerHeight = windowHeight - mcHeightOffset,
          contactsContainerHeight = containerHeight,
          roomsContainerHeight = containerHeight - roomsContainer.offsetTop - ($roomsContainer.hasClass('history') ? 2 : meseditorContainer.offsetHeight + rcHeightOffset) + 
                                ($roomsContainer.hasClass('multichat') ? 32 : 0);

        if (containerHeight < 0) {
          containerHeight = -containerHeight;
        }
        if (contactsContainerHeight < 0) {
          contactsContainerHeight = -contactsContainerHeight;
        }
        if (roomsContainerHeight < 0) {
          roomsContainerHeight = -roomsContainerHeight;
        }
        containerHeight = containerHeight +40;
        mainContainer.style.height = containerHeight + 'px';
        //$mainContainer.height(containerHeight);
        contactsContainer.style.height = contactsContainerHeight + 'px';
          //$contactsContainer.height(containerHeight - $contactToolbarContainer.height() - ccHeightOffset);
        roomsContainer.style.height = roomsContainerHeight + 18  + 'px';
        if ($roomsContainer.hasClass('history')) {
            //jq("#cha").tlCombobox();
            roomsContainer.style.height = roomsContainerHeight -71 + 'px';
        }
          
        //$roomsContainer.height(containerHeight - parseInt($roomsContainer.css('top')) - ($roomsContainer.hasClass('history') ? 2 : $meseditorContainer.height() + rcHeightOffset));

        var
          sidebarWidth = sidebarContainer.offsetWidth,
          mainContainerWidth = mainContainer.offsetWidth;
          //sidebarWidth = $sidebarContainer.width(),
          //mainContainerWidth = $mainContainer.width();

        sidebarWidth = isFinite(+sidebarWidth) ? +sidebarWidth : minSidebarContainerWidth;
        if (sidebarWidth * 2 > mainContainerWidth) { // if more 50%
          sidebarWidth = Math.floor(mainContainerWidth / 2);
        }
        if (sidebarWidth < minSidebarContainerWidth) {
          sidebarWidth = minSidebarContainerWidth;
        }
        sidebarContainer.style.width = sidebarWidth + 'px';
        //$sidebarContainer.width(sidebarWidth);
        horSlider.style.left = sidebarWidth + 'px';
        //$horSlider.css('right', sidebarWidth + 'px');
        contentContainer.style.width = mainContainerWidth - sidebarWidth - ccWidthOffset + 'px';
        //$contentContainer.width(mainContainerWidth - sidebarWidth - ccWidthOffset);

        startSplash.style.height = contentContainer.offsetHeight - ssHeightOffset + 'px';
        //$startSplash.height($contentContainer.height() - ssHeightOffset);

        var currentRoomData = ASC.TMTalk.roomsManager.getRoomData();
        if (currentRoomData !== null && currentRoomData.type === 'conference' && currentRoomData.minimized === false) {
          var nodes = ASC.TMTalk.dom.getElementsByClassName(roomsContainer, 'room conference current', 'li');
          if (nodes.length > 0) {
            var roomHeight = nodes[0].offsetHeight;
            nodes = ASC.TMTalk.dom.getElementsByClassName(nodes[0], 'sub-panel', 'div');
            if (nodes.length > 0) {
              nodes[0].style.height = Math.ceil(roomHeight / 2) - 90 + 'px';
            }
          }
        }
        if (currentRoomData !== null && currentRoomData.type === 'mailing' && currentRoomData.minimized === false) {
            var nodes = ASC.TMTalk.dom.getElementsByClassName(roomsContainer, 'room mailing current', 'li');
            if (nodes.length > 0) {
                var roomHeight = nodes[0].offsetHeight;
                nodes = ASC.TMTalk.dom.getElementsByClassName(nodes[0], 'sub-panel', 'div');
                if (nodes.length > 0) {
                    nodes[0].style.height = Math.ceil(roomHeight / 2) - 90 + 'px';
                }
            }
        }
        if ((($('#talkContentContainer').width() + $('#talkSidebarContainer').width()) > $('#talkMainContainer').width())) {
            $(window).resize();
        }
      });

    $('#talkHorSlider').mousedown(function (evt) {
      return dragHorSlider(evt);
    });

    $('#talkVertSlider').mousedown(function (evt) {
      return dragVertSlider(evt);
    });

    $('#talkDialogsContainer')
      .keydown(function (evt) {
        evt.originalEvent.stopPropagation ? evt.originalEvent.stopPropagation() : evt.originalEvent.cancelBubble = true;
      })
      .keypress(function (evt) {
        switch (evt.keyCode) {
          case 13 :
              $('#talkDialogsContainer').find('div.dialog:visible:first div.toolbar:first div.button-talk:first').click();
            return false;
          case 27 :
            TMTalk.hideDialog();
            break;
          default :
            if (evt.target.tagName.toLowerCase() === 'input') {
              $(evt.target).parents('div.textfield:first').removeClass('invalid-field');
            }
        }
      })
      .click(function (evt) {
        var $target = $(evt.target);
        if ($target.hasClass('button-talk') && $target.hasClass('close-dialog')) {
          TMTalk.hideDialog();
        }
      });

    //$('#cbxToggleNotifications').click(function (evt) {
    //  var $target = $(evt.target);
      //  if ($target.hasClass('button-talk')) {
    //    var $this = $(this);
    //    if ($this.toggleClass('disabled').hasClass('disabled')) {
    //      $this.addClass('disabled');
    //      ASC.TMTalk.notifications.disable();
    //    } else {
    //      $this.addClass('disabled');
    //      ASC.TMTalk.notifications.enable(function (val) {
    //        if (val === true) {
    //          $('#cbxToggleNotifications').removeClass('disabled');
    //        } else {
    //          $('#cbxToggleNotifications').addClass('disabled');
    //        }
    //      });
    //    }
    //  }
    //});

    //$('#cbxToggleNotificationsDialog').click(function (evt) {
    //  ASC.TMTalk.properties.item('hidnd', $(this).is(':checked') ? '1' : '0', true);
      //});
    //hack for resizing
    jq(window).resize();
  });
})(jQuery);


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Dao/DaoFactory.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Projects.Core.DataInterfaces;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Projects.Data
{
    public class DaoFactory : IDaoFactory
    {
        public ILifetimeScope Container { get; set; }
        private TypedParameter Tenant { get; set; }

        public DaoFactory(int tenantId)
        {
            Tenant = DIHelper.GetParameter(tenantId);
        }

        private IProjectDao projectDao;
        public IProjectDao ProjectDao { get { return projectDao ?? (projectDao = Container.Resolve<IProjectDao>(Tenant)); } }

        private IParticipantDao participantDao;
        public IParticipantDao ParticipantDao
        {
            get
            {
                return participantDao ?? (participantDao = Container.Resolve<IParticipantDao>(Tenant));
            }
        }

        private IMilestoneDao milestoneDao;
        public IMilestoneDao MilestoneDao { get { return milestoneDao ?? (milestoneDao = Container.Resolve<IMilestoneDao>(Tenant)); } }

        private ITaskDao taskDao;
        public ITaskDao TaskDao { get { return taskDao ?? (taskDao = Container.Resolve<ITaskDao>(Tenant)); } }

        private ISubtaskDao subtaskDao;
        public ISubtaskDao SubtaskDao { get { return subtaskDao ?? (subtaskDao = Container.Resolve<ISubtaskDao>(Tenant)); } }

        private IMessageDao messageDao;
        public IMessageDao MessageDao { get { return messageDao ?? (messageDao = Container.Resolve<IMessageDao>(Tenant)); } }

        private ICommentDao commentDao;
        public ICommentDao CommentDao { get { return commentDao ?? (commentDao = Container.Resolve<ICommentDao>(Tenant)); } }

        private ITemplateDao templateDao;
        public ITemplateDao TemplateDao { get { return templateDao ?? (templateDao = Container.Resolve<ITemplateDao>(Tenant)); } }

        private ITimeSpendDao timeSpendDao;
        public ITimeSpendDao TimeSpendDao { get { return timeSpendDao ?? (timeSpendDao = Container.Resolve<ITimeSpendDao>(Tenant)); } }

        private IReportDao reportDao;
        public IReportDao ReportDao { get { return reportDao ?? (reportDao = Container.Resolve<IReportDao>(Tenant)); } }

        private ISearchDao searchDao;
        public ISearchDao SearchDao { get { return searchDao ?? (searchDao = Container.Resolve<ISearchDao>(Tenant)); } }

        private ITagDao tagDao;
        public ITagDao TagDao { get { return tagDao ?? (tagDao = Container.Resolve<ITagDao>(Tenant)); } }

        private IStatusDao statusDao;
        public IStatusDao StatusDao { get { return statusDao ?? (statusDao = Container.Resolve<IStatusDao>(Tenant)); } }

    }
}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/ViewSwitcher/ViewSwitcherBaseItem.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Text;
using System.Web.UI;

namespace ASC.Web.Studio.UserControls.Common.ViewSwitcher
{
    public abstract class ViewSwitcherBaseItem : Control
    {
        public string SortUrl { get; set; }

        public string SortLabel { get; set; }

        public bool IsSelected { get; set; }

        internal bool IsLast { get; set; }

        public string DivID { get; set; }

        public string AdditionalHtml { get; set; }

        public string HintText { get; set; }

        public string GetSortLink
        {
            get
            {
                var idString = string.Empty;
                if (!string.IsNullOrEmpty(DivID))
                {
                    idString = string.Format(" id='{0}' ", DivID);
                }
                var cssClass = "viewSwitcherItem";
                if (IsSelected)
                {
                    cssClass = "viewSwithcerSelectedItem";
                }
                var sb = new StringBuilder();
                sb.AppendFormat("<div {0} class='{1}'>{2}{3}</div>", idString, cssClass, GetLink(), AdditionalHtml ?? string.Empty);
                return sb.ToString();
            }
        }

        public abstract string GetLink();
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/Common/BlogsSearchHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Blogs.Core;
using ASC.Core;
using ASC.Web.Community.Modules.Blogs.Core.Resources;
using ASC.Web.Community.Product;
using ASC.Web.Core.ModuleManagement.Common;
using ASC.Web.Core.Users;
using ASC.Web.Core.Utility;
using ASC.Web.Core.Utility.Skins;
using ASC.Web.Studio.Controls.Common;

namespace ASC.Web.Community.Blogs
{
    public class BlogsSearchHandler : BaseSearchHandlerEx
    {
        public override SearchResultItem[] Search(string text)
        {
            var posts = BasePage.GetEngine().SearchPosts(text, new PagingQuery());
            var result = new List<SearchResultItem>(posts.Count);
            result.AddRange(posts.Select(post => new SearchResultItem
            {
                Description = BlogsResource.Blogs + ", " + DisplayUserSettings.GetFullUserName(CoreContext.UserManager.GetUsers(post.UserID), false) + ", " + post.Datetime.ToLongDateString(),
                Name = post.Title,
                URL = VirtualPathUtility.ToAbsolute(Constants.BaseVirtualPath) + "ViewBlog.aspx?blogid=" + post.ID.ToString(),
                Date = post.Datetime
            }));

            return result.ToArray();
        }

        public override ImageOptions Logo
        {
            get { return new ImageOptions { ImageFileName = "blog_add.png", PartID = Constants.ModuleID }; }
        }

        public override string SearchName
        {
            get { return BlogsResource.SearchDefaultString; }
        }

        public override Guid ProductID
        {
            get { return CommunityProduct.ID; }
        }

        public override Guid ModuleID
        {
            get { return Constants.ModuleID; }
        }

        public override IItemControl Control
        {
            get { return new ResultsView(); }
        }
    }
}

<|start_filename|>common/TMResourceManager/ASC.Resource.Data/Model/Author.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

namespace TMResourceData.Model
{
    public class Author
    {
        public string Login { get; set; }
        public string Password { get; set; }
        public bool IsAdmin { get; set; }
        public List<ResCulture> Langs { get; set; }
        public List<ResProject> Projects { get; set; }

        public Author()
        { }

        public Author(string login)
        {
            Login = login;
            IsAdmin = false;
            Langs = new List<ResCulture>();
            Projects = new List<ResProject>();
        }
    }
}


<|start_filename|>common/Tests/ASC.Api.Calendar.Test/RecurrenceRuleTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Web.Core.Calendars;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace ASC.Api.Calendar.Test
{
    [TestClass]
    public class RecurrenceRuleTest
    {
        private DateTime _toDate = new DateTime(2013, 6, 10, 9, 0, 0);
        private DateTime _fromDate = new DateTime(1990, 6, 10, 9, 0, 0);

        [TestMethod]
        public void YearlyRules()
        {           

            //test 1
            var r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Count = 10,
                ByMonth = new int[] { 6, 7 }
            };

            var dates = r1.GetDates(new DateTime(1997, 6, 10, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){new DateTime(1997, 6, 10, 9, 0, 0), new DateTime(1997, 7, 10, 9, 0, 0),
            new DateTime(1998, 6, 10, 9, 0, 0),new DateTime(1998, 7, 10, 9, 0, 0),
            new DateTime(1999, 6, 10, 9, 0, 0),new DateTime(1999, 7, 10, 9, 0, 0),
            new DateTime(2000, 6, 10, 9, 0, 0),new DateTime(2000, 7, 10, 9, 0, 0),
            new DateTime(2001, 6, 10, 9, 0, 0),new DateTime(2001, 7, 10, 9, 0, 0)}, dates);


            //test 2
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Interval = 2,
                Count = 10,
                ByMonth = new int[] { 1, 2,3 }
            };
            dates = r1.GetDates(new DateTime(1997, 3, 10, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){new DateTime(1997, 3, 10, 9, 0, 0),
                new DateTime(1999, 1, 10, 9, 0, 0),new DateTime(1999, 2, 10, 9, 0, 0), new DateTime(1999, 3, 10, 9, 0, 0),
                new DateTime(2001, 1, 10, 9, 0, 0),new DateTime(2001, 2, 10, 9, 0, 0), new DateTime(2001, 3, 10, 9, 0, 0),
                new DateTime(2003, 1, 10, 9, 0, 0),new DateTime(2003, 2, 10, 9, 0, 0), new DateTime(2003, 3, 10, 9, 0, 0),
            }, dates);


            //test 3
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Interval = 3,
                Count = 10,
                ByYearDay = new int[] { 1, 100, 200 }
            };
            dates = r1.GetDates(new DateTime(1997, 1, 1, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
                new DateTime(1997, 1, 1, 9, 0, 0),new DateTime(1997, 4, 10, 9, 0, 0),new DateTime(1997, 7, 19, 9, 0, 0), 
                new DateTime(2000, 1, 1, 9, 0, 0),new DateTime(2000, 4, 9, 9, 0, 0),new DateTime(2000, 7, 18, 9, 0, 0), 
                new DateTime(2003, 1, 1, 9, 0, 0),new DateTime(2003, 4, 10, 9, 0, 0),new DateTime(2003, 7, 19, 9, 0, 0), 
                new DateTime(2006, 1, 1, 9, 0, 0)
            }, dates);


            //test 4
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Count = 3,
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("20MO") }
            };
            dates = r1.GetDates(new DateTime(1997, 5, 19, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
                new DateTime(1997, 5, 19, 9, 0, 0),new DateTime(1998, 5, 18, 9, 0, 0),new DateTime(1999, 5, 17, 9, 0, 0)
            }, dates);


            //test 5
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Count = 3,
                ByWeekNo = new int[]{20},
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("MO") }
            };
            dates = r1.GetDates(new DateTime(1997, 5, 12, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
                new DateTime(1997, 5, 12, 9, 0, 0),new DateTime(1998, 5, 11, 9, 0, 0),new DateTime(1999, 5, 17, 9, 0, 0)
            }, dates);

            //test 6
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Count = 11,
                ByMonth = new int[] { 3 },
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("TH") }
            };
            dates = r1.GetDates(new DateTime(1997, 3, 13, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
               new DateTime(1997, 3, 13, 9, 0, 0), new DateTime(1997, 3, 20, 9, 0, 0),new DateTime(1997, 3, 27, 9, 0, 0),
               new DateTime(1998, 3, 5, 9, 0, 0), new DateTime(1998, 3, 12, 9, 0, 0),new DateTime(1998, 3, 19, 9, 0, 0),new DateTime(1998, 3, 26, 9, 0, 0),
               new DateTime(1999, 3, 4, 9, 0, 0),new DateTime(1999, 3, 11, 9, 0, 0),new DateTime(1999, 3, 18, 9, 0, 0),new DateTime(1999, 3, 25, 9, 0, 0)
            }, dates);


            //test 7
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Count = 13,
                ByMonth = new int[] { 6,7,8 },
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("TH") }
            };
            dates = r1.GetDates(new DateTime(1997, 6, 5, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
               new DateTime(1997, 6, 5, 9, 0, 0), new DateTime(1997, 6, 12, 9, 0, 0),new DateTime(1997, 6, 19, 9, 0, 0),new DateTime(1997, 6, 26, 9, 0, 0),
               new DateTime(1997, 7, 3, 9, 0, 0), new DateTime(1997, 7, 10, 9, 0, 0),new DateTime(1997, 7, 17, 9, 0, 0),new DateTime(1997, 7, 24, 9, 0, 0),new DateTime(1997, 7, 31, 9, 0, 0),
               new DateTime(1997, 8, 7, 9, 0, 0), new DateTime(1997, 8, 14, 9, 0, 0),new DateTime(1997, 8, 21, 9, 0, 0),new DateTime(1997, 8, 28, 9, 0, 0)
               
            }, dates);

            //test 8
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Interval = 4,
                Count = 3,
                ByMonth = new int[] { 11 },
                ByMonthDay = new int[] { 2,3,4,5,6,7,8 },
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("TU") }
            };
            dates = r1.GetDates(new DateTime(1996, 11, 5, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
               new DateTime(1996, 11, 5, 9, 0, 0), 
               new DateTime(2000, 11, 7, 9, 0, 0),
               new DateTime(2004, 11, 2, 9, 0, 0)
            }, dates);


            //friday 13
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Yearly,
                Until = new DateTime(2013,1,1),
                ByMonthDay = new int[] { 13 },
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("fr") }
            };
            dates = r1.GetDates(new DateTime(2012, 1, 1, 0, 0, 0), _fromDate, new DateTime(2014, 1, 1, 0, 0, 0));
           


        }

        [TestMethod]
        public void MonthlyRules()
        {
            //test 1
            var r1 = new RecurrenceRule()
            {
                Freq = Frequency.Monthly,
                Count = 10,
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("1FR") }
            };

            var dates = r1.GetDates(new DateTime(1997, 9, 5, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 5, 9, 0, 0), new DateTime(1997, 10, 3, 9, 0, 0),
            new DateTime(1997, 11, 7, 9, 0, 0),new DateTime(1997, 12, 5, 9, 0, 0),
            new DateTime(1998, 1, 2, 9, 0, 0),new DateTime(1998, 2, 6, 9, 0, 0),
            new DateTime(1998, 3, 6, 9, 0, 0),new DateTime(1998, 4, 3, 9, 0, 0),
            new DateTime(1998, 5, 1, 9, 0, 0), new DateTime(1998, 6, 5, 9, 0, 0)}, dates);

            //test 2
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Monthly,
                Until = new DateTime(1997, 12, 24),
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("1FR") }
            };

            dates = r1.GetDates(new DateTime(1997, 9, 5, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 5, 9, 0, 0), new DateTime(1997, 10, 3, 9, 0, 0),
            new DateTime(1997, 11, 7, 9, 0, 0),new DateTime(1997, 12, 5, 9, 0, 0)}, dates);


            //test 3
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Monthly,
                Count = 10,
                Interval = 2,
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("1SU"), RecurrenceRule.WeekDay.Parse("-1SU") }
            };

            dates = r1.GetDates(new DateTime(1997, 9, 7, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 7, 9, 0, 0), new DateTime(1997, 9, 28, 9, 0, 0),
            new DateTime(1997, 11, 2, 9, 0, 0),new DateTime(1997, 11, 30, 9, 0, 0),
            new DateTime(1998, 1, 4, 9, 0, 0),new DateTime(1998, 1, 25, 9, 0, 0),
            new DateTime(1998, 3, 1, 9, 0, 0),new DateTime(1998, 3, 29, 9, 0, 0),
            new DateTime(1998, 5, 3, 9, 0, 0),new DateTime(1998, 5, 31, 9, 0, 0)
            }, dates);


            //test 4
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Monthly,
                Count = 6,                
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("-2MO")}
            };

            dates = r1.GetDates(new DateTime(1997, 9, 22, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 22, 9, 0, 0), new DateTime(1997, 10, 20, 9, 0, 0),
            new DateTime(1997, 11, 17, 9, 0, 0),new DateTime(1997, 12, 22, 9, 0, 0),
            new DateTime(1998, 1, 19, 9, 0, 0),new DateTime(1998, 2, 16, 9, 0, 0)
            
            }, dates);

            //test 5
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Monthly,
                Interval = 18,
                Count = 10,
                ByMonthDay = new int[] {10,11,12,13,14,15 }
            };

            dates = r1.GetDates(new DateTime(1997, 9, 10, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 10, 9, 0, 0), new DateTime(1997, 9, 11, 9, 0, 0),
            new DateTime(1997, 9, 12, 9, 0, 0),new DateTime(1997, 9, 13, 9, 0, 0),
            new DateTime(1997, 9, 14, 9, 0, 0),new DateTime(1997, 9, 15, 9, 0, 0),
            new DateTime(1999, 3, 10, 9, 0, 0),new DateTime(1999, 3, 11, 9, 0, 0),
            new DateTime(1999, 3, 12, 9, 0, 0),new DateTime(1999, 3, 13, 9, 0, 0)
            
            }, dates);

        }

        [TestMethod]
        public void WeeklyRules()
        {
            //test 1
            var r1 = new RecurrenceRule()
            {
                Freq = Frequency.Weekly,
                Count = 10                
            };

            var dates = r1.GetDates(new DateTime(1997, 9, 2, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 2, 9, 0, 0), new DateTime(1997, 9, 9, 9, 0, 0),
            new DateTime(1997, 9, 16, 9, 0, 0),new DateTime(1997, 9, 23, 9, 0, 0),
            new DateTime(1997, 9, 30, 9, 0, 0),new DateTime(1997, 10, 7, 9, 0, 0),
            new DateTime(1997, 10, 14, 9, 0, 0),new DateTime(1997, 10, 21, 9, 0, 0),
            new DateTime(1997, 10, 28, 9, 0, 0), new DateTime(1997, 11, 4, 9, 0, 0)}, dates);


            //test 2
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Weekly,
                Interval = 2,
                WKST = RecurrenceRule.WeekDay.Parse("su"),
                Count = 10
            };

            dates = r1.GetDates(new DateTime(1997, 9, 2, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 2, 9, 0, 0), new DateTime(1997, 9, 16, 9, 0, 0),
            new DateTime(1997, 9, 30, 9, 0, 0),new DateTime(1997, 10, 14, 9, 0, 0),
            new DateTime(1997, 10, 28, 9, 0, 0),new DateTime(1997, 11, 11, 9, 0, 0),
            new DateTime(1997, 11, 25, 9, 0, 0),new DateTime(1997, 12, 9, 9, 0, 0),
            new DateTime(1997, 12, 23, 9, 0, 0), new DateTime(1998, 1, 6, 9, 0, 0)}, dates);

            //test 3
            r1 = new RecurrenceRule()
            {
                Freq = Frequency.Weekly,
                Interval = 2,
                WKST = RecurrenceRule.WeekDay.Parse("su"),
                Count = 8,
                ByDay = new RecurrenceRule.WeekDay[] { RecurrenceRule.WeekDay.Parse("tu"), RecurrenceRule.WeekDay.Parse("th") }
            };

            dates = r1.GetDates(new DateTime(1997, 9, 2, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 2, 9, 0, 0), new DateTime(1997, 9, 4, 9, 0, 0),
            new DateTime(1997, 9, 16, 9, 0, 0),new DateTime(1997, 9, 18, 9, 0, 0),
            new DateTime(1997, 9, 30, 9, 0, 0),new DateTime(1997, 10, 2, 9, 0, 0),
            new DateTime(1997, 10, 14, 9, 0, 0),new DateTime(1997, 10, 16, 9, 0, 0)}, dates);


            r1 = RecurrenceRule.Parse("freq=weekly;count=3;interval=2;byday=mo");
            dates = r1.GetDates(new DateTime(2012, 1, 2, 0, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(2012, 1, 2, 0, 0, 0), new DateTime(2012, 1, 16, 0, 0, 0),
            new DateTime(2012, 1, 30, 0, 0, 0)}, dates);



        }


        [TestMethod]
        public void DailyRules()
        {
            //test 1
            var r1 = new RecurrenceRule()
            {
                Freq = Frequency.Daily,
                Count = 5,
                Interval = 10
            };

            var dates = r1.GetDates(new DateTime(1997, 9, 2, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 2, 9, 0, 0), new DateTime(1997, 9, 12, 9, 0, 0),
            new DateTime(1997, 9, 22, 9, 0, 0),new DateTime(1997, 10, 2, 9, 0, 0),
            new DateTime(1997, 10, 12, 9, 0, 0)}, dates);

        }

        [TestMethod]
        public void HorlyRules()
        {
            //test 1
            var r1 = new RecurrenceRule()
            {
                Freq = Frequency.Hourly,
                Until = new DateTime(1997,9,2,17,0,0),
                Interval = 3
            };

            var dates = r1.GetDates(new DateTime(1997, 9, 2, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 2, 9, 0, 0), new DateTime(1997, 9, 2, 12, 0, 0),            
            new DateTime(1997, 9, 2, 15, 0, 0)}, dates);
        }

        [TestMethod]
        public void MinutelyRules()
        {
            //test 1
            var r1 = new RecurrenceRule()
            {
                Freq = Frequency.Minutely,
                ByHour = new int[]{9,10,11,12,13,14,15,16},
                Count = 5,
                Interval = 20
            };

            var dates = r1.GetDates(new DateTime(1997, 9, 2, 9, 0, 0), _fromDate, _toDate);

            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 2, 9, 0, 0), new DateTime(1997, 9, 2, 9, 20, 0),            
            new DateTime(1997, 9, 2, 9, 40, 0),new DateTime(1997, 9, 2, 10, 0, 0),new DateTime(1997, 9, 2, 10, 20, 0)}, dates);
        }

        [TestMethod]
        public void BySetPosRules()
        {
            //test 1
            var r1 = RecurrenceRule.Parse("FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2;count=7");
            var dates = r1.GetDates(new DateTime(1997, 9, 29, 9, 0, 0), _fromDate, _toDate);
            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 29, 9, 0, 0), new DateTime(1997, 10, 30, 9, 0, 0),            
            new DateTime(1997, 11, 27, 9, 0, 0),new DateTime(1997, 12, 30, 9, 0, 0),new DateTime(1998, 1, 29, 9, 0, 0),
            new DateTime(1998, 2, 26, 9, 0, 0),new DateTime(1998, 3, 30, 9, 0, 0)}, dates);


            //test 2
            r1 = RecurrenceRule.Parse("FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3");
            dates = r1.GetDates(new DateTime(1997, 9, 4, 9, 0, 0), _fromDate, _toDate);
            CollectionAssert.AreEqual(new List<DateTime>(){
            new DateTime(1997, 9, 4, 9, 0, 0), new DateTime(1997, 10, 7, 9, 0, 0),            
            new DateTime(1997, 11, 6, 9, 0, 0)}, dates);
        }

        [TestMethod]
        public void ParseFromStringTest()
        {
            //tets
            var r1 = RecurrenceRule.Parse("FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU");
            Assert.AreEqual( new DateTime(1997, 12, 24, 0, 0, 0),r1.Until);
        }


    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Utility/HtmlUtility/CodeFormat/CodeFormat.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Copyright � 2001-2003 <NAME> [<EMAIL>]
/*
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the author(s) be held liable for any damages arising from
 * the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 
 *   1. The origin of this software must not be misrepresented; you must not
 *      claim that you wrote the original software. If you use this software
 *      in a product, an acknowledgment in the product documentation would be
 *      appreciated but is not required.
 * 
 *   2. Altered source versions must be plainly marked as such, and must not
 *      be misrepresented as being the original software.
 * 
 *   3. This notice may not be removed or altered from any source distribution.
 */
#endregion

using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace ASC.Web.Studio.Utility.HtmlUtility.CodeFormat
{
    /// <summary>
    /// Provides a base class for formatting most programming languages.
    /// </summary>
    internal abstract class CodeFormat : SourceFormat
    {
        /// <summary>
        /// Must be overridden to provide a list of keywords defined in 
        /// each language.
        /// </summary>
        /// <remarks>
        /// Keywords must be separated with spaces.
        /// </remarks>
        protected abstract string Keywords { get; }

        /// <summary>
        /// Can be overridden to provide a list of preprocessors defined in 
        /// each language.
        /// </summary>
        /// <remarks>
        /// Preprocessors must be separated with spaces.
        /// </remarks>
        protected virtual string Preprocessors
        {
            get { return ""; }
        }

        /// <summary>
        /// Must be overridden to provide a regular expression string
        /// to match strings literals. 
        /// </summary>
        protected abstract string StringRegEx { get; }

        /// <summary>
        /// Must be overridden to provide a regular expression string
        /// to match comments. 
        /// </summary>
        protected abstract string CommentRegEx { get; }

        /// <summary>
        /// Determines if the language is case sensitive.
        /// </summary>
        /// <value><b>true</b> if the language is case sensitive, <b>false</b> 
        /// otherwise. The default is true.</value>
        /// <remarks>
        /// A case-insensitive language formatter must override this 
        /// property to return false.
        /// </remarks>
        public virtual bool CaseSensitive
        {
            get { return true; }
        }

        /// <summary/>
        protected CodeFormat()
        {
            //generate the keyword and preprocessor regexes from the keyword lists
            var r = new Regex(@"\w+|-\w+|#\w+|@@\w+|#(?:\\(?:s|w)(?:\*|\+)?\w+)+|@\\w\*+");
            var regKeyword = r.Replace(Keywords, @"(?<=^|\W)$0(?=\W)");
            var regPreproc = r.Replace(Preprocessors, @"(?<=^|\s)$0(?=\s|$)");
            r = new Regex(@" +");
            regKeyword = r.Replace(regKeyword, @"|");
            regPreproc = r.Replace(regPreproc, @"|");

            if (regPreproc.Length == 0)
            {
                regPreproc = "(?!.*)_{37}(?<!.*)"; //use something quite impossible...
            }

            //build a master regex with capturing groups
            var regAll = new StringBuilder();
            regAll.Append("(");
            regAll.Append(CommentRegEx);
            regAll.Append(")|(");
            regAll.Append(StringRegEx);
            if (regPreproc.Length > 0)
            {
                regAll.Append(")|(");
                regAll.Append(regPreproc);
            }
            regAll.Append(")|(");
            regAll.Append(regKeyword);
            regAll.Append(")");

            var caseInsensitive = CaseSensitive ? 0 : RegexOptions.IgnoreCase;
            CodeRegex = new Regex(regAll.ToString(), RegexOptions.Singleline | caseInsensitive);
        }

        /// <summary>
        /// Called to evaluate the HTML fragment corresponding to each 
        /// matching token in the code.
        /// </summary>
        /// <param name="match">The <see cref="Match"/> resulting from a 
        /// single regular expression match.</param>
        /// <returns>A string containing the HTML code fragment.</returns>
        protected override string MatchEval(Match match)
        {
            if (match.Groups[1].Success) //comment
            {
                var reader = new StringReader(match.ToString());
                string line;
                var sb = new StringBuilder();
                while ((line = reader.ReadLine()) != null)
                {
                    if (sb.Length > 0)
                    {
                        sb.Append("\n");
                    }
                    sb.Append("<span class=\"rem\">");
                    sb.Append(line);
                    sb.Append("</span>");
                }
                return sb.ToString();
            }
            if (match.Groups[2].Success) //string literal
            {
                return "<span class=\"str\">" + match + "</span>";
            }
            if (match.Groups[3].Success) //preprocessor keyword
            {
                return "<span class=\"preproc\">" + match + "</span>";
            }
            if (match.Groups[4].Success) //keyword
            {
                return "<span class=\"kwrd\">" + match + "</span>";
            }
            return ""; //none of the above
        }
    }
}

<|start_filename|>common/ASC.Data.Backup/Extensions/DataExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Data;
using System.Data.Common;

namespace ASC.Data.Backup.Extensions
{
    public static class DataExtensions
    {
        public static DbCommand WithTimeout(this DbCommand command, int timeout)
        {
            if (command != null)
            {
                command.CommandTimeout = timeout;
            }
            return command;
        }

        public static DbConnection Fix(this DbConnection connection)
        {
            if (connection != null && connection.State != ConnectionState.Open)
            {
                connection.Close();
                connection.Open();
            }
            return connection;
        }
    }
}


<|start_filename|>module/ASC.Mail.Server/ASC.Mail.Server/Core/Dao/BaseDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.IO;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Server.Core.DbSchema.Interfaces;
using ASC.Mail.Server.Extensions;

namespace ASC.Mail.Server.Core.Dao
{
    public abstract class BaseDao
    {
        public IDbManager Db { get; private set; }

        public ITable Table { get; private set; }

        protected BaseDao(ITable table, IDbManager dbManager)
        {
            Db = dbManager;
            Table = table;
        }

        protected SqlQuery Query(string alias = null)
        {
            if (!Table.OrderedColumnCollection.Any())
                throw new InvalidDataException("Table.OrderedColumnCollection is null or empty");

            if (string.IsNullOrEmpty(alias))
            {
                return new SqlQuery(Table.Name).Select(Table.OrderedColumnCollection.ToArray());
            }

            return
                new SqlQuery(Table.Name.Alias(alias)).Select(
                    Table.OrderedColumnCollection.Select(c => c.Prefix(alias)).ToArray());
        }
    }
}


<|start_filename|>module/ASC.Thrdparty/ASC.FederatedLogin/LoginProviders/BitlyLoginProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Xml.Linq;
using System.Xml.XPath;

using ASC.Core.Common.Configuration;

namespace ASC.FederatedLogin.LoginProviders
{
    public class BitlyLoginProvider : Consumer, IValidateKeysProvider
    {
        private static string BitlyClientId
        {
            get { return Instance["bitlyClientId"]; }
        }

        private static string BitlyClientSecret
        {
            get { return Instance["bitlyClientSecret"]; }
        }

        private static string BitlyUrl
        {
            get { return Instance["bitlyUrl"]; }
        }

        private static BitlyLoginProvider Instance
        {
            get { return ConsumerFactory.Get<BitlyLoginProvider>(); }
        }

        public BitlyLoginProvider() { }

        public BitlyLoginProvider(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
            : base(name, order, props, additional)
        {
        }

        public bool ValidateKeys()
        {
            try
            {
                return !string.IsNullOrEmpty(GetShortenLink("https://www.onlyoffice.com"));
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static bool Enabled
        {
            get
            {
                return !String.IsNullOrEmpty(BitlyClientId) &&
                       !String.IsNullOrEmpty(BitlyClientSecret) &&
                       !String.IsNullOrEmpty(BitlyUrl);
            }
        }

        public static String GetShortenLink(String shareLink)
        {
            var uri = new Uri(shareLink);

            var bitly = string.Format(BitlyUrl, BitlyClientId, BitlyClientSecret, Uri.EscapeDataString(uri.ToString()));
            XDocument response;
            try
            {
                response = XDocument.Load(bitly);
            }
            catch (Exception e)
            {
                throw new InvalidOperationException(e.Message, e);
            }

            var status = response.XPathSelectElement("/response/status_code").Value;
            if (status != ((int)HttpStatusCode.OK).ToString(CultureInfo.InvariantCulture))
            {
                throw new InvalidOperationException(status);
            }

            var data = response.XPathSelectElement("/response/data/url");

            return data.Value;
        }
    }
}


<|start_filename|>web/core/ASC.Web.Core/WhiteLabel/CompanyWhiteLabelSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Core;
using ASC.Core.Common.Settings;

using Newtonsoft.Json;

namespace ASC.Web.Core.WhiteLabel
{
    [Serializable]
    [DataContract]
    public class CompanyWhiteLabelSettings : BaseSettings<CompanyWhiteLabelSettings>
    {
        [DataMember(Name = "CompanyName")]
        public string CompanyName { get; set; }

        [DataMember(Name = "Site")]
        public string Site { get; set; }

        [DataMember(Name = "Email")]
        public string Email { get; set; }

        [DataMember(Name = "Address")]
        public string Address { get; set; }

        [DataMember(Name = "Phone")]
        public string Phone { get; set; }

        [DataMember(Name = "IsLicensor")]
        public bool IsLicensorSetting { get; set; }

        public bool IsLicensor
        {
            get
            {
                return IsLicensorSetting
                    && (IsDefault || CoreContext.TenantManager.GetTenantQuota(CoreContext.TenantManager.GetCurrentTenant().TenantId).Branding);
            }
            set { IsLicensorSetting = value; }
        }

        public bool IsDefault
        {
            get
            {
                var defaultSettings = GetDefault() as CompanyWhiteLabelSettings;

                if (defaultSettings == null) return false;

                return CompanyName == defaultSettings.CompanyName &&
                       Site == defaultSettings.Site &&
                       Email == defaultSettings.Email &&
                       Address == defaultSettings.Address &&
                       Phone == defaultSettings.Phone &&
                       IsLicensorSetting == defaultSettings.IsLicensorSetting;
            }
        }

        #region ISettings Members

        public override Guid ID
        {
            get { return new Guid("{C3C5A846-01A3-476D-A962-1CFD78C04ADB}"); }
        }

        private static CompanyWhiteLabelSettings _default;

        public override ISettings GetDefault()
        {
            if (_default != null) return _default;

            var settings = CoreContext.Configuration.GetSetting("CompanyWhiteLabelSettings");

            _default = string.IsNullOrEmpty(settings) ? new CompanyWhiteLabelSettings() : JsonConvert.DeserializeObject<CompanyWhiteLabelSettings>(settings);

            return _default;
        }

        #endregion

        public static CompanyWhiteLabelSettings Instance
        {
            get
            {
                return LoadForDefaultTenant();
            }
        }
    }
}


<|start_filename|>module/ASC.VoipService/IVoipProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.VoipService.Twilio;

namespace ASC.VoipService
{
    public interface IVoipProvider
    {
        IEnumerable<VoipPhone> GetExistingPhoneNumbers();

        IEnumerable<VoipPhone> GetAvailablePhoneNumbers(PhoneNumberType phoneNumberType, string isoCountryCode);

        VoipPhone BuyNumber(string phoneNumber);

        VoipPhone DeleteNumber(VoipPhone phone);

        VoipPhone GetPhone(object[] r);

        VoipPhone GetPhone(string id);

        VoipCall GetCall(string callId);

        string GetToken(Agent agent, int seconds = 60 * 60 * 24);

        void UpdateSettings(VoipPhone phone);

        VoipRecord GetRecord(string callId, string recordId);

        void CreateQueue(VoipPhone newPhone);

        void DisablePhone(VoipPhone phone);
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Search/ProjectsWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.ElasticSearch;
using ASC.Projects.Core.Domain;
using ASC.Web.Projects.Configuration;

namespace ASC.Web.Projects.Core.Search
{
    public sealed class ProjectsWrapper : Wrapper
    {
        [Column("title", 1)]
        public string Title { get; set; }

        [Column("description", 2)]
        public string Description { get; set; }

        //[Join(JoinTypeEnum.Sub, "id:project_id")]
        //public List<TagsWrapper> TagsWrapper { get; set; }

        protected override string Table { get { return "projects_projects"; } }

        public static implicit operator ProjectsWrapper(Project project)
        {
            return ProductEntryPoint.Mapper.Map<ProjectsWrapper>(project);
            //var result = Mapper.Map<ProjectsWrapper>(project);

            //result.TagsWrapper = new List<TagsWrapper>();

            //return result;
        }
    }

    //public sealed class TagsWrapper : Wrapper
    //{
    //    [ColumnId("")]
    //    public override int Id { get; set; }

    //    [ColumnTenantId("")]
    //    public override int TenantId { get; set; }

    //    [ColumnLastModified("")]
    //    public override DateTime LastModifiedOn { get; set; }

    //    [ColumnMeta("tag_id", 1)]
    //    public int TagId { get; set; }

    //    protected override string Table { get { return "projects_project_tag"; } }
    //}
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/talk/UserControls/RoomsContainer.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text;
using System.Web;
using System.Web.UI;

namespace ASC.Web.Talk.UserControls
{
    public partial class RoomsContainer : UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterBodyScripts("~/addons/talk/js/talk.roomscontainer.js");

            var script = new StringBuilder();

            script.AppendLine("ASC.TMTalk.roomsContainer.init([");

            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile01.gif") + @"', title: ':-)', aliases: [':-)', ':)', '=)'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile02.gif") + @"', title: ';-)', aliases: [';-)'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile03.gif") + @"', title: ':-\\', aliases: [':-\\'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile04.gif") + @"', title: ':-D', aliases: [':-D', ':D'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile05.gif") + @"', title: ':-(', aliases: [':-(', ':('] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile06.gif") + @"', title: '8-)', aliases: ['8-)'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile07.gif") + @"', title: '*DANCE*', aliases: ['*DANCE*'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile08.gif") + @"', title: '[:-}', aliases: ['[:-}'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile09.gif") + @"', title: '%-)', aliases: ['%-)', '%)'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile10.gif") + @"', title: '=-O', aliases: ['=-O'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile11.gif") + @"', title: ':-P', aliases: [':-P'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile12.gif") + @"', title: ':\'(', aliases: [':\'('] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile13.gif") + @"', title: ':-!', aliases: [':-!'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile14.gif") + @"', title: '*THUMBS UP*', aliases: ['*THUMBS UP*'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile15.gif") + @"', title: '*SORRY*', aliases: ['*SORRY*'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile16.gif") + @"', title: '*YAHOO*', aliases: ['*YAHOO*'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile17.gif") + @"', title: '*OK*', aliases: ['*OK*'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile18.gif") + @"', title: ']:->', aliases: [']:-&gt;', ']:-&amp;gt;'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile19.gif") + @"', title: '*HELP*', aliases: ['*HELP*'] },");
            script.AppendLine("{ src: '" + VirtualPathUtility.ToAbsolute("~/addons/talk/css/default/imagescss/smiles/smile20.gif") + @"', title: '*DRINK*', aliases: ['*DRINK*'] }");

            script.AppendLine("],");

            script.AppendLine("'" + GetOverdueInterval() + "');");

            Page.RegisterInlineScript(script.ToString());
        }

        public String GetOverdueInterval()
        {
            return new TalkConfiguration().OverdueInterval;
        }
    }
}


<|start_filename|>common/Tests/ASC.Core.Common.Tests/DbBaseTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#if DEBUG
namespace ASC.Core.Common.Tests
{
    using System;
    using System.Configuration;


    public class DbBaseTest<TDbService>
    {
        protected TDbService Service
        {
            get;
            private set;
        }

        protected int Tenant
        {
            get;
            private set;
        }


        protected DbBaseTest()
        {
            Service = (TDbService)Activator.CreateInstance(typeof(TDbService), ConfigurationManager.ConnectionStrings["core"]);
            Tenant = 1024;

            //var pattern = "%message (%property{duration} ms)     %property{sql}    %property{sqlParams}%newline";
            //BasicConfigurator.Configure(new DebugAppender { Layout = new PatternLayout(pattern) });
        }
    }
}
#endif


<|start_filename|>module/ASC.VoipService/Dao/VoipDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core.Common.Configuration;
using ASC.Core.Tenants;
using ASC.VoipService.Twilio;

namespace ASC.VoipService.Dao
{
    public class VoipDao : AbstractDao
    {
        public VoipDao(int tenantID)
            : base(tenantID)
        {
        }

        public virtual VoipPhone SaveOrUpdateNumber(VoipPhone phone)
        {
            if (!string.IsNullOrEmpty(phone.Number))
            {
                phone.Number = phone.Number.TrimStart('+');
            }

            using (var db = GetDb())
            {
                var insert = Insert("crm_voip_number")
                    .InColumnValue("id", phone.Id)
                    .InColumnValue("number", phone.Number)
                    .InColumnValue("alias", phone.Alias);

                if (phone.Settings != null)
                {
                    insert.InColumnValue("settings", phone.Settings.ToString());
                }

                db.ExecuteNonQuery(insert);
            }
            return phone;
        }

        public virtual void DeleteNumber(string phoneId = "")
        {
            using (var db = GetDb())
            {
                var query = Delete("crm_voip_number");
                if (!string.IsNullOrEmpty(phoneId))
                {
                    query.Where("id", phoneId);
                }
                db.ExecuteNonQuery(query);
            }
        }

        public virtual IEnumerable<VoipPhone> GetNumbers(params object[] ids)
        {
            using (var db = GetDb())
            {
                var query = Query("crm_voip_number")
                    .Select("id", "number", "alias", "settings");

                if (ids.Any())
                {
                    query.Where(Exp.In("number", ids) | Exp.In("id", ids));
                }

                return db.ExecuteList(query).ConvertAll(ToPhone);
            }
        }

        public VoipPhone GetNumber(string id)
        {
            return GetNumbers(id.TrimStart('+')).FirstOrDefault();
        }

        public virtual VoipPhone GetCurrentNumber()
        {
            return GetNumbers().FirstOrDefault(r => r.Caller != null);
        }


        public VoipCall SaveOrUpdateCall(VoipCall call)
        {
            using (var db = GetDb())
            {
                var query = Insert("crm_voip_calls")
                    .InColumnValue("id", call.Id)
                    .InColumnValue("number_from", call.From)
                    .InColumnValue("number_to", call.To)
                    .InColumnValue("contact_id", call.ContactId);

                if (!string.IsNullOrEmpty(call.ParentID))
                {
                    query.InColumnValue("parent_call_id", call.ParentID);
                }

                if (call.Status.HasValue)
                {
                    query.InColumnValue("status", call.Status.Value);
                }

                if (!call.AnsweredBy.Equals(Guid.Empty))
                {
                    query.InColumnValue("answered_by", call.AnsweredBy);
                }

                if (call.DialDate == DateTime.MinValue)
                {
                    call.DialDate = DateTime.UtcNow;
                }

                query.InColumnValue("dial_date", TenantUtil.DateTimeToUtc(call.DialDate));

                if (call.DialDuration > 0)
                {
                    query.InColumnValue("dial_duration", call.DialDuration);
                }
                if (call.Price > Decimal.Zero)
                {
                    query.InColumnValue("price", call.Price);
                }

                if (call.VoipRecord != null)
                {
                    if (!string.IsNullOrEmpty(call.VoipRecord.Id))
                    {
                        query.InColumnValue("record_sid", call.VoipRecord.Id);
                    }
                    if (!string.IsNullOrEmpty(call.VoipRecord.Uri))
                    {
                        query.InColumnValue("record_url", call.VoipRecord.Uri);
                    }

                    if (call.VoipRecord.Duration != 0)
                    {
                        query.InColumnValue("record_duration", call.VoipRecord.Duration);
                    }

                    if (call.VoipRecord.Price != default(decimal))
                    {
                        query.InColumnValue("record_price", call.VoipRecord.Price);
                    }
                }

                db.ExecuteNonQuery(query);
            }

            return call;
        }

        public IEnumerable<VoipCall> GetCalls(VoipCallFilter filter)
        {
            using (var db = GetDb())
            {
                var query = GetCallsQuery(filter);

                if (filter.SortByColumn != null)
                {
                    query.OrderBy(filter.SortByColumn, filter.SortOrder);
                }

                query.SetFirstResult((int)filter.Offset);
                query.SetMaxResults((int)filter.Max * 3);

                var calls = db.ExecuteList(query).ConvertAll(ToCall);

                calls = calls.GroupJoin(calls, call => call.Id, h => h.ParentID, (call, h) =>
                {
                    call.ChildCalls.AddRange(h);
                    return call;
                }).Where(r => string.IsNullOrEmpty(r.ParentID)).ToList();

                return calls;
            }
        }

        public VoipCall GetCall(string id)
        {
            return GetCalls(new VoipCallFilter { Id = id }).FirstOrDefault();
        }

        public int GetCallsCount(VoipCallFilter filter)
        {
            using (var db = GetDb())
            {
                var query = GetCallsQuery(filter).Where("ca.parent_call_id", "");
                var queryCount = new SqlQuery().SelectCount().From(query, "t1");

                return db.ExecuteScalar<int>(queryCount);
            }
        }

        public IEnumerable<VoipCall> GetMissedCalls(Guid agent, long count = 0, DateTime? from = null)
        {
            using (var db = GetDb())
            {
                var query = GetCallsQuery(new VoipCallFilter { Agent = agent, SortBy = "date", SortOrder = true, Type = "missed" });

                var subQuery = new SqlQuery("crm_voip_calls tmp")
                    .SelectMax("tmp.dial_date")
                    .Where(Exp.EqColumns("ca.tenant_id", "tmp.tenant_id"))
                    .Where(Exp.EqColumns("ca.number_from", "tmp.number_from") | Exp.EqColumns("ca.number_from", "tmp.number_to"))
                    .Where(Exp.Lt("tmp.status", VoipCallStatus.Missed));

                if (from.HasValue)
                {
                    query.Where(Exp.Ge("ca.dial_date", TenantUtil.DateTimeFromUtc(from.Value)));
                }

                if (count != 0)
                {
                    query.SetMaxResults((int)count);
                }

                query.Select(subQuery, "tmp_date");

                query.Having(Exp.Sql("ca.dial_date >= tmp_date") | Exp.Eq("tmp_date", null));

                return db.ExecuteList(query).ConvertAll(ToCall);
            }
        }

        private SqlQuery GetCallsQuery(VoipCallFilter filter)
        {
            var query = Query("crm_voip_calls ca")
                .Select("ca.id", "ca.parent_call_id", "ca.number_from", "ca.number_to", "ca.answered_by", "ca.dial_date", "ca.dial_duration", "ca.price", "ca.status")
                .Select("ca.record_sid", "ca.record_url", "ca.record_duration", "ca.record_price")
                .Select("ca.contact_id", "co.is_company", "co.company_name", "co.first_name", "co.last_name")
                .LeftOuterJoin("crm_contact co", Exp.EqColumns("ca.contact_id", "co.id"))
                .GroupBy("ca.id");

            if (!string.IsNullOrEmpty(filter.Id))
            {
                query.Where(Exp.Eq("ca.id", filter.Id) | Exp.Eq("ca.parent_call_id", filter.Id));
            }

            if (filter.ContactID.HasValue)
            {
                query.Where(Exp.Eq("ca.contact_id", filter.ContactID.Value));
            }

            if (!string.IsNullOrWhiteSpace(filter.SearchText))
            {
                query.Where(Exp.Like("ca.id", filter.SearchText, SqlLike.StartWith));
            }

            if (filter.TypeStatus.HasValue)
            {
                query.Where("ca.status", filter.TypeStatus.Value);
            }

            if (filter.FromDate.HasValue)
            {
                query.Where(Exp.Ge("ca.dial_date", filter.FromDate.Value));
            }

            if (filter.ToDate.HasValue)
            {
                query.Where(Exp.Le("ca.dial_date", filter.ToDate.Value));
            }

            if (filter.Agent.HasValue)
            {
                query.Where("ca.answered_by", filter.Agent.Value);
            }

            return query;
        }

        #region Converters

        private static VoipPhone ToPhone(object[] r)
        {
            return GetProvider().GetPhone(r);
        }

        private static VoipCall ToCall(object[] r)
        {
            var call = new VoipCall
            {
                Id = (string)r[0],
                ParentID = (string)r[1],
                From = (string)r[2],
                To = (string)r[3],
                AnsweredBy = new Guid((string)r[4]),
                DialDate = TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[5])),
                DialDuration = Convert.ToInt32(r[6] ?? "0"),
                Price = Convert.ToDecimal(r[7]),
                Status = (VoipCallStatus)Convert.ToInt32(r[8]),
                VoipRecord = new VoipRecord
                {
                    Id = (string)r[9],
                    Uri = (string)r[10],
                    Duration = Convert.ToInt32(r[11] ?? "0"),
                    Price = Convert.ToDecimal(r[12])
                },
                ContactId = Convert.ToInt32(r[13]),
                ContactIsCompany = Convert.ToBoolean(r[14])
            };

            if (call.ContactId != 0)
            {
                call.ContactTitle = call.ContactIsCompany
                                        ? r[15] == null ? null : Convert.ToString(r[15])
                                        : r[16] == null || r[17] == null ? null :
                                              string.Format("{0} {1}", Convert.ToString(r[16]), Convert.ToString(r[17]));
            }

            return call;
        }

        public static Consumer Consumer
        {
            get { return ConsumerFactory.GetByName("twilio"); }
        }

        public static TwilioProvider GetProvider()
        {
            return new TwilioProvider(Consumer["twilioAccountSid"], Consumer["twilioAuthToken"]);
        }

        public static bool ConfigSettingsExist
        {
            get
            {
                return !string.IsNullOrEmpty(Consumer["twilioAccountSid"]) &&
                       !string.IsNullOrEmpty(Consumer["twilioAuthToken"]);
            }
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Documents/DocumentsApi.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mime;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

using ASC.Api.Attributes;
using ASC.Api.Collections;
using ASC.Api.Exceptions;
using ASC.Api.Impl;
using ASC.Api.Utils;
using ASC.Core;
using ASC.Core.Users;
using ASC.FederatedLogin.Helpers;
using ASC.FederatedLogin.LoginProviders;
using ASC.Files.Core;
using ASC.MessagingSystem;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Core.Compress;
using ASC.Web.Files.Core.Entries;
using ASC.Web.Files.Helpers;
using ASC.Web.Files.HttpHandlers;
using ASC.Web.Files.Services.DocumentService;
using ASC.Web.Files.Services.WCFService;
using ASC.Web.Files.Services.WCFService.FileOperations;
using ASC.Web.Files.Utils;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

using Newtonsoft.Json.Linq;

using FileShare = ASC.Files.Core.Security.FileShare;
using FilesNS = ASC.Web.Files.Services.WCFService;
using MimeMapping = ASC.Common.Web.MimeMapping;
using SortedByType = ASC.Files.Core.SortedByType;

namespace ASC.Api.Documents
{
    /// <summary>
    /// Provides access to documents
    /// </summary>
    public class DocumentsApi : Interfaces.IApiEntryPoint
    {
        private readonly ApiContext _context;
        private readonly IFileStorageService _fileStorageService;

        /// <summary>
        /// </summary>
        public string Name
        {
            get { return "files"; }
        }

        /// <summary>
        /// </summary>
        /// <param name="context"></param>
        /// <param name="fileStorageService"></param>
        public DocumentsApi(ApiContext context, IFileStorageService fileStorageService)
        {
            _context = context;
            _fileStorageService = fileStorageService;
        }


        /// <summary>
        ///
        /// </summary>
        /// <short>List of Sections</short>
        /// <param name="userIdOrGroupId" optional="true">User or group ID</param>
        /// <param name="filterType" optional="true">Filter type</param>
        /// <param name="withsubfolders"></param>
        /// <param name="withoutTrash"></param>
        /// <param name="withoutAdditionalFolder"></param>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <category>Folders</category>
        /// <returns></returns>
        [Read("@root")]
        public IEnumerable<FolderContentWrapper> GetRootFolders(Guid userIdOrGroupId, FilterType filterType, bool withsubfolders, bool withoutTrash, bool withoutAdditionalFolder)
        {
            var IsVisitor = CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor();
            var result = new SortedSet<object>();

            if (!IsVisitor)
            {
                result.Add(Global.FolderMy);
            }

            if (!CoreContext.Configuration.Personal && !CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsOutsider())
            {
                result.Add(Global.FolderShare);
            }

            if (!IsVisitor && !withoutAdditionalFolder)
            {
                if (FilesSettings.FavoritesSection)
                {
                    result.Add(Global.FolderFavorites);
                }

                if (FilesSettings.RecentSection)
                {
                    result.Add(Global.FolderRecent);
                }

                if (PrivacyRoomSettings.Available)
                {
                    result.Add(Global.FolderPrivacy);
                }
            }

            if (!CoreContext.Configuration.Personal)
            {
                result.Add(Global.FolderCommon);
            }

            if (!IsVisitor
               && !withoutAdditionalFolder
               && FileUtility.ExtsWebTemplate.Any()
               && FilesSettings.TemplatesSection)
            {
                result.Add(Global.FolderTemplates);
            }

            if (!IsVisitor
               && !withoutTrash)
            {
                result.Add((int)Global.FolderTrash);
            }

            return result.Select(r => ToFolderContentWrapper(r, userIdOrGroupId, filterType));
        }

        /// <summary>
        /// Returns the detailed list of files and folders located in the current user My section
        /// </summary>
        /// <short>Section My</short>
        /// <category>Folders</category>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>My folder contents</returns>
        [Read("@my")]
        public FolderContentWrapper GetMyFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderMy, userIdOrGroupId, filterType);
        }

        /// <summary>
        /// Returns the detailed list of files and folders located in the current user Projects section
        /// </summary>
        /// <short>Section Projects</short>
        /// <category>Folders</category>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Projects folder contents</returns>
        [Read("@projects")]
        public FolderContentWrapper GetProjectsFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderProjects, userIdOrGroupId, filterType);
        }


        /// <summary>
        /// Returns the detailed list of files and folders located in the Common section
        /// </summary>
        /// <short>Section Common</short>
        /// <category>Folders</category>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Common folder contents</returns>
        [Read("@common")]
        public FolderContentWrapper GetCommonFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderCommon, userIdOrGroupId, filterType);
        }

        /// <summary>
        /// Returns the detailed list of files and folders located in the Shared with Me section
        /// </summary>
        /// <short>Section Shared</short>
        /// <category>Folders</category>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Shared folder contents</returns>
        [Read("@share")]
        public FolderContentWrapper GetShareFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderShare, userIdOrGroupId, filterType);
        }

        /// <summary>
        /// Returns the detailed list of recent files
        /// </summary>
        /// <short>Section Recent</short>
        /// <category>Folders</category>
        /// <param name="userIdOrGroupId" optional="true">User or group ID</param>
        /// <param name="filterType" optional="true">Filter type</param>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Recent contents</returns>
        [Read("@recent")]
        public FolderContentWrapper GetRecentFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderRecent, userIdOrGroupId, filterType);
        }

        /// <summary>
        /// Returns the detailed list of favorites files
        /// </summary>
        /// <short>Section Favorite</short>
        /// <category>Folders</category>
        /// <param name="userIdOrGroupId" optional="true">User or group ID</param>
        /// <param name="filterType" optional="true">Filter type</param>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Favorites contents</returns>
        [Read("@favorites")]
        public FolderContentWrapper GetFavoritesFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderFavorites, userIdOrGroupId, filterType);
        }

        /// <summary>
        /// Returns the detailed list of templates files
        /// </summary>
        /// <short>Section Template</short>
        /// <category>Folders</category>
        /// <param name="userIdOrGroupId" optional="true">User or group ID</param>
        /// <param name="filterType" optional="true">Filter type</param>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Templates contents</returns>
        [Read("@templates")]
        public FolderContentWrapper GetTemplatesFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderTemplates, userIdOrGroupId, filterType);
        }

        /// <summary>
        /// Returns the detailed list of files and folders located in the Recycle Bin
        /// </summary>
        /// <short>Section Trash</short>
        /// <category>Folders</category>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Trash folder contents</returns>
        [Read("@trash")]
        public FolderContentWrapper GetTrashFolder(Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(Global.FolderTrash, userIdOrGroupId, filterType);
        }

        /// <summary>
        /// Returns the detailed list of files and folders located in the folder with the ID specified in the request
        /// </summary>
        /// <short>
        /// Folder by ID
        /// </short>
        /// <category>Folders</category>
        /// <param name="folderId">Folder ID</param>
        /// <param name="userIdOrGroupId" optional="true">User or group ID</param>
        /// <param name="filterType" optional="true">Filter type</param>
        /// <param name="sortBy" optional="true" remark="Allowed values: DateAndTime, AZ, Size, Author, Type, New, DateAndTimeCreation">Sort by field name.</param>
        /// <param name="sortOrder" optional="true" remark="Allowed values: descending or ascending">Sorting direction</param>
        /// <param name="startIndex" optional="true">The number of elements to be skipped in the beginning. Used for response data pagination.</param>
        /// <param name="count" optional="true">Number of the elements returned.</param>
        /// <param name="filterValue">Filter value.</param>
        /// <returns>Folder contents</returns>
        [Read("{folderId}")]
        public FolderContentWrapper GetFolder(String folderId, Guid userIdOrGroupId, FilterType filterType)
        {
            return ToFolderContentWrapper(folderId, userIdOrGroupId, filterType).NotFoundIfNull();

        }

        /// <summary>
        /// Uploads the file specified with single file upload or standart multipart/form-data method to My section
        /// </summary>
        /// <short>Upload to My</short>
        /// <category>Uploads</category>
        /// <remarks>
        /// <![CDATA[
        ///  Upload can be done in 2 different ways:
        ///  <ol>
        /// <li>Single file upload. You should set Content-Type &amp; Content-Disposition header to specify filename and content type, and send file in request body</li>
        /// <li>Using standart multipart/form-data method</li>
        /// </ol>]]>
        /// </remarks>
        /// <param name="file" visible="false">Request Input stream</param>
        /// <param name="contentType" visible="false">Content-Type Header</param>
        /// <param name="contentDisposition" visible="false">Content-Disposition Header</param>
        /// <param name="files" visible="false">List of files when posted as multipart/form-data</param>
        /// <returns>Uploaded file</returns>
        [Create("@my/upload")]
        public object UploadFileToMy(Stream file, ContentType contentType, ContentDisposition contentDisposition, IEnumerable<HttpPostedFileBase> files)
        {
            return UploadFile(Global.FolderMy.ToString(), file, contentType, contentDisposition, files, false, null);
        }

        /// <summary>
        /// Uploads the file specified with single file upload or standart multipart/form-data method to Common section
        /// </summary>
        /// <short>Upload to Common</short>
        /// <category>Uploads</category>
        /// <remarks>
        /// <![CDATA[
        ///  Upload can be done in 2 different ways:
        ///  <ol>
        /// <li>Single file upload. You should set Content-Type &amp; Content-Disposition header to specify filename and content type, and send file in request body</li>
        /// <li>Using standart multipart/form-data method</li>
        /// </ol>]]>
        /// </remarks>
        /// <param name="file" visible="false">Request Input stream</param>
        /// <param name="contentType" visible="false">Content-Type Header</param>
        /// <param name="contentDisposition" visible="false">Content-Disposition Header</param>
        /// <param name="files" visible="false">List of files when posted as multipart/form-data</param>
        /// <returns>Uploaded file</returns>
        [Create("@common/upload")]
        public object UploadFileToCommon(Stream file, ContentType contentType, ContentDisposition contentDisposition, IEnumerable<HttpPostedFileBase> files)
        {
            return UploadFile(Global.FolderCommon.ToString(), file, contentType, contentDisposition, files, false, null);
        }


        /// <summary>
        /// Uploads the file specified with single file upload or standart multipart/form-data method to the selected folder
        /// </summary>
        /// <short>Upload file</short>
        /// <category>Uploads</category>
        /// <remarks>
        /// <![CDATA[
        ///  Upload can be done in 2 different ways:
        ///  <ol>
        /// <li>Single file upload. You should set Content-Type &amp; Content-Disposition header to specify filename and content type, and send file in request body</li>
        /// <li>Using standart multipart/form-data method</li>
        /// </ol>]]>
        /// </remarks>
        /// <param name="folderId">Folder ID to upload to</param>
        /// <param name="file" visible="false">Request Input stream</param>
        /// <param name="contentType" visible="false">Content-Type Header</param>
        /// <param name="contentDisposition" visible="false">Content-Disposition Header</param>
        /// <param name="files" visible="false">List of files when posted as multipart/form-data</param>
        /// <param name="createNewIfExist" visible="false">Create New If Exist</param>
        /// <param name="storeOriginalFileFlag" visible="false">If True, upload documents in original formats as well</param>
        /// <param name="keepConvertStatus" visible="false">Keep status conversation after finishing</param>
        /// <returns>Uploaded file</returns>
        [Create("{folderId}/upload")]
        public object UploadFile(string folderId, Stream file, ContentType contentType, ContentDisposition contentDisposition, IEnumerable<HttpPostedFileBase> files, bool? createNewIfExist, bool? storeOriginalFileFlag, bool keepConvertStatus = false)
        {
            if (storeOriginalFileFlag.HasValue)
            {
                FilesSettings.StoreOriginalFiles = storeOriginalFileFlag.Value;
            }

            if (files != null && files.Any())
            {
                if (files.Count() == 1)
                {
                    //Only one file. return it
                    var postedFile = files.First();
                    return InsertFile(folderId, postedFile.InputStream, postedFile.FileName, createNewIfExist, keepConvertStatus);
                }
                //For case with multiple files
                return files.Select(postedFile => InsertFile(folderId, postedFile.InputStream, postedFile.FileName, createNewIfExist, keepConvertStatus)).ToList();
            }
            if (file != null)
            {
                var fileName = "file" + MimeMapping.GetExtention(contentType.MediaType);
                if (contentDisposition != null)
                {
                    fileName = contentDisposition.FileName;
                }

                return InsertFile(folderId, file, fileName, createNewIfExist, keepConvertStatus);
            }
            throw new InvalidOperationException("No input files");
        }

        /// <summary>
        /// Uploads the file specified with single file upload to Common section
        /// </summary>
        /// <short>Insert to My</short>
        /// <param name="file" visible="false">Request Input stream</param>
        /// <param name="title">Name of file which has to be uploaded</param>
        /// <param name="createNewIfExist" visible="false">Create New If Exist</param>
        /// <param name="keepConvertStatus" visible="false">Keep status conversation after finishing</param>
        /// <category>Uploads</category>
        /// <returns></returns>
        [Create("@my/insert")]
        public FileWrapper InsertFileToMy(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false)
        {
            return InsertFile(Global.FolderMy.ToString(), file, title, createNewIfExist, keepConvertStatus);
        }

        /// <summary>
        /// Uploads the file specified with single file upload to Common section
        /// </summary>
        /// <short>Insert to Common</short>
        /// <param name="file" visible="false">Request Input stream</param>
        /// <param name="title">Name of file which has to be uploaded</param>
        /// <param name="createNewIfExist" visible="false">Create New If Exist</param>
        /// <param name="keepConvertStatus" visible="false">Keep status conversation after finishing</param>
        /// <category>Uploads</category>
        /// <returns></returns>
        [Create("@common/insert")]
        public FileWrapper InsertFileToCommon(Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false)
        {
            return InsertFile(Global.FolderCommon.ToString(), file, title, createNewIfExist, keepConvertStatus);
        }

        /// <summary>
        /// Uploads the file specified with single file upload
        /// </summary>
        /// <param name="folderId">Folder ID to upload to</param>
        /// <param name="file" visible="false">Request Input stream</param>
        /// <param name="title">Name of file which has to be uploaded</param>
        /// <param name="createNewIfExist" visible="false">Create New If Exist</param>
        /// <param name="keepConvertStatus" visible="false">Keep status conversation after finishing</param>
        /// <category>Uploads</category>
        /// <returns></returns>
        [Create("{folderId}/insert")]
        public FileWrapper InsertFile(string folderId, Stream file, string title, bool? createNewIfExist, bool keepConvertStatus = false)
        {
            try
            {
                var resultFile = FileUploader.Exec(folderId, title, file.Length, file, createNewIfExist.HasValue ? createNewIfExist.Value : !FilesSettings.UpdateIfExist, !keepConvertStatus);
                return new FileWrapper(resultFile);
            }
            catch (FileNotFoundException e)
            {
                throw new ItemNotFoundException("File not found", e);
            }
            catch (DirectoryNotFoundException e)
            {
                throw new ItemNotFoundException("Folder not found", e);
            }
        }

        /// <summary>
        /// Update file content
        /// </summary>
        /// <category>Files</category>
        /// <param name="file">Stream of file</param>
        /// <param name="fileId">File ID</param>
        /// <param name="encrypted" visible="false"></param>
        /// <param name="forcesave" visible="false"></param>
        [Update("{fileId}/update")]
        public FileWrapper UpdateFileStream(Stream file, string fileId, bool encrypted = false, bool forcesave = false)
        {
            try
            {
                var resultFile = _fileStorageService.UpdateFileStream(fileId, file, encrypted, forcesave);
                return new FileWrapper(resultFile);
            }
            catch (FileNotFoundException e)
            {
                throw new ItemNotFoundException("File not found", e);
            }
        }


        /// <summary>
        /// Save file 
        /// </summary>
        /// <short>Editing save</short>
        /// <param name="fileId">File ID</param>
        /// <param name="fileExtension"></param>
        /// <param name="downloadUri"></param>
        /// <param name="stream"></param>
        /// <param name="doc"></param>
        /// <param name="forcesave"></param>
        /// <category>Files</category>
        /// <returns></returns>
        [Update("file/{fileId}/saveediting")]
        public FileWrapper SaveEditing(String fileId, string fileExtension, string downloadUri, Stream stream, String doc, bool forcesave)
        {
            return new FileWrapper(_fileStorageService.SaveEditing(fileId, fileExtension, downloadUri, stream, doc, forcesave));
        }

        /// <summary>
        /// Lock file when editing
        /// </summary>
        /// <short>Editing start</short>
        /// <param name="fileId">File ID</param>
        /// <param name="editingAlone" visible="false"></param>
        /// <param name="doc" visible="false"></param>
        /// <category>Files</category>
        /// <returns>File key for Document Service</returns>
        [Create("file/{fileId}/startedit")]
        public string StartEdit(String fileId, bool editingAlone, String doc)
        {
            return _fileStorageService.StartEdit(fileId, editingAlone, doc);
        }

        /// <summary>
        /// Continue to lock file when editing
        /// </summary>
        /// <short>Editing track</short>
        /// <param name="fileId">File ID</param>
        /// <param name="tabId" visible="false"></param>
        /// <param name="docKeyForTrack" visible="false"></param>
        /// <param name="doc" visible="false"></param>
        /// <param name="isFinish">for unlock</param>
        /// <category>Files</category>
        /// <returns></returns>
        [Read("file/{fileId}/trackeditfile")]
        public KeyValuePair<bool, String> TrackEditFile(String fileId, Guid tabId, String docKeyForTrack, String doc, bool isFinish)
        {
            return _fileStorageService.TrackEditFile(fileId, tabId, docKeyForTrack, doc, isFinish);
        }

        /// <summary>
        /// Get initialization configuration for open editor
        /// </summary>
        /// <short>Editing open</short>
        /// <param name="fileId">File ID</param>
        /// <param name="version">File version</param>
        /// <param name="doc" visible="false"></param>
        /// <category>Files</category>
        /// <returns>Configuration</returns>
        [Read("file/{fileId}/openedit", false)] //NOTE: this method doesn't requires auth!!!
        public Configuration OpenEdit(String fileId, int version, String doc)
        {
            Configuration configuration;
            DocumentServiceHelper.GetParams(fileId, version, doc, true, true, true, out configuration);
            configuration.Type = Configuration.EditorType.External;

            configuration.EditorConfig.CallbackUrl = DocumentServiceTracker.GetCallbackUrl(configuration.Document.Info.File.ID.ToString());

            if (configuration.Document.Info.File.RootFolderType == FolderType.Privacy
                && PrivacyRoomSettings.Enabled)
            {
                var keyPair = EncryptionKeyPair.GetKeyPair();
                if (keyPair != null)
                {
                    configuration.EditorConfig.EncryptionKeys = new Configuration.EditorConfiguration.EncryptionKeysConfig
                    {
                        PrivateKeyEnc = keyPair.PrivateKeyEnc,
                        PublicKey = keyPair.PublicKey,
                    };
                }
            }

            if (!configuration.Document.Info.File.Encrypted && !configuration.Document.Info.File.ProviderEntry) EntryManager.MarkAsRecent(configuration.Document.Info.File);

            configuration.Token = DocumentServiceHelper.GetSignature(configuration);
            return configuration;
        }


        /// <summary>
        /// Creates session to upload large files in multiple chunks.
        /// </summary>
        /// <short>Chunked upload</short>
        /// <category>Uploads</category>
        /// <param name="folderId">Id of the folder in which file will be uploaded</param>
        /// <param name="fileName">Name of file which has to be uploaded</param>
        /// <param name="fileSize">Length in bytes of file which has to be uploaded</param>
        /// <param name="relativePath">Relative folder from folderId</param>
        /// <param name="encrypted" visible="false"></param>
        /// <remarks>
        /// <![CDATA[
        /// Each chunk can have different length but its important what length is multiple of <b>512</b> and greater or equal than <b>10 mb</b>. Last chunk can have any size.
        /// After initial request respond with status 200 OK you must obtain value of 'location' field from the response. Send all your chunks to that location.
        /// Each chunk must be sent in strict order in which chunks appears in file.
        /// After receiving each chunk if no errors occured server will respond with current information about upload session.
        /// When number of uploaded bytes equal to the number of bytes you send in initial request server will respond with 201 Created and will send you info about uploaded file.
        /// ]]>
        /// </remarks>
        /// <returns>
        /// <![CDATA[
        /// Information about created session. Which includes:
        /// <ul>
        /// <li><b>id:</b> unique id of this upload session</li>
        /// <li><b>created:</b> UTC time when session was created</li>
        /// <li><b>expired:</b> UTC time when session will be expired if no chunks will be sent until that time</li>
        /// <li><b>location:</b> URL to which you must send your next chunk</li>
        /// <li><b>bytes_uploaded:</b> If exists contains number of bytes uploaded for specific upload id</li>
        /// <li><b>bytes_total:</b> Number of bytes which has to be uploaded</li>
        /// </ul>
        /// ]]>
        /// </returns>
        [Create("{folderId}/upload/create_session")]
        public object CreateUploadSession(string folderId, string fileName, long fileSize, string relativePath, bool encrypted)
        {
            var file = FileUploader.VerifyChunkedUpload(folderId, fileName, fileSize, FilesSettings.UpdateIfExist, relativePath);

            if (FilesLinkUtility.IsLocalFileUploader)
            {
                var session = FileUploader.InitiateUpload(file.FolderID.ToString(), (file.ID ?? "").ToString(), file.Title, file.ContentLength, encrypted);

                var response = ChunkedUploaderHandler.ToResponseObject(session, true);
                return new
                {
                    success = true,
                    data = response
                };
            }

            var createSessionUrl = FilesLinkUtility.GetInitiateUploadSessionUrl(file.FolderID, file.ID, file.Title, file.ContentLength, encrypted);
            var request = (HttpWebRequest)WebRequest.Create(createSessionUrl);
            request.Method = "POST";
            request.ContentLength = 0;

            // hack for uploader.onlyoffice.com in api requests
            var rewriterHeader = _context.RequestContext.HttpContext.Request.Headers[HttpRequestExtensions.UrlRewriterHeader];
            if (!string.IsNullOrEmpty(rewriterHeader))
            {
                request.Headers[HttpRequestExtensions.UrlRewriterHeader] = rewriterHeader;
            }

            // hack. http://ubuntuforums.org/showthread.php?t=1841740
            if (WorkContext.IsMono)
            {
                ServicePointManager.ServerCertificateValidationCallback += (s, ce, ca, p) => true;
            }

            using (var response = request.GetResponse())
            using (var responseStream = response.GetResponseStream())
            {
                return JObject.Parse(new StreamReader(responseStream).ReadToEnd()); //result is json string
            }
        }

        /// <summary>
        /// Creates a text (.txt) file in My section with the title and contents sent in the request
        /// </summary>
        /// <short>Create txt in My</short>
        /// <category>Files</category>
        /// <param name="title">File title</param>
        /// <param name="content">File contents</param>
        /// <returns>Folder contents</returns>
        /// <visible>false</visible>
        [Create("@my/text")]
        public FileWrapper CreateTextFileInMy(string title, string content)
        {
            return CreateTextFile(Global.FolderMy.ToString(), title, content);
        }

        /// <summary>
        /// Creates a text (.txt) file in Common Documents section with the title and contents sent in the request
        /// </summary>
        /// <short>Create txt in Common</short>
        /// <category>Files</category>
        /// <param name="title">File title</param>
        /// <param name="content">File contents</param>
        /// <returns>Folder contents</returns>
        /// <visible>false</visible>
        [Create("@common/text")]
        public FileWrapper CreateTextFileInCommon(string title, string content)
        {
            return CreateTextFile(Global.FolderCommon.ToString(), title, content);
        }

        /// <summary>
        /// Creates a text (.txt) file in the selected folder with the title and contents sent in the request
        /// </summary>
        /// <short>Create txt</short>
        /// <category>Files</category>
        /// <param name="folderId">Folder ID</param>
        /// <param name="title">File title</param>
        /// <param name="content">File contents</param>
        /// <returns>Folder contents</returns>
        /// <visible>false</visible>
        [Create("{folderId}/text")]
        public FileWrapper CreateTextFile(string folderId, string title, string content)
        {
            if (title == null) throw new ArgumentNullException("title");
            //Try detect content
            var extension = ".txt";
            if (!string.IsNullOrEmpty(content))
            {
                if (Regex.IsMatch(content, @"<([^\s>]*)(\s[^<]*)>"))
                {
                    extension = ".html";
                }
            }
            return CreateFile(folderId, title, content, extension);
        }

        private static FileWrapper CreateFile(string folderId, string title, string content, string extension)
        {
            using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(content)))
            {
                var file = FileUploader.Exec(folderId,
                                  title.EndsWith(extension, StringComparison.OrdinalIgnoreCase) ? title : (title + extension),
                                  memStream.Length, memStream);
                return new FileWrapper(file);
            }
        }

        /// <summary>
        /// Creates an html (.html) file in the selected folder with the title and contents sent in the request
        /// </summary>
        /// <short>Create html</short>
        /// <category>Files</category>
        /// <param name="folderId">Folder ID</param>
        /// <param name="title">File title</param>
        /// <param name="content">File contents</param>
        /// <returns>Folder contents</returns>
        /// <visible>false</visible>
        [Create("{folderId}/html")]
        public FileWrapper CreateHtmlFile(string folderId, string title, string content)
        {
            if (title == null) throw new ArgumentNullException("title");
            return CreateFile(folderId, title, content, ".html");
        }

        /// <summary>
        /// Creates an html (.html) file in My section with the title and contents sent in the request
        /// </summary>
        /// <short>Create html in My</short>
        /// <category>Files</category>
        /// <param name="title">File title</param>
        /// <param name="content">File contents</param>
        /// <returns>Folder contents</returns>
        /// <visible>false</visible>
        [Create("@my/html")]
        public FileWrapper CreateHtmlFileInMy(string title, string content)
        {
            return CreateHtmlFile(Global.FolderMy.ToString(), title, content);
        }


        /// <summary>
        /// Creates an html (.html) file in Common section with the title and contents sent in the request
        /// </summary>
        /// <short>Create html in Common</short>
        /// <category>Files</category>
        /// <param name="title">File title</param>
        /// <param name="content">File contents</param>
        /// <returns>Folder contents</returns>
        /// <visible>false</visible>
        [Create("@common/html")]
        public FileWrapper CreateHtmlFileInCommon(string title, string content)
        {
            return CreateHtmlFile(Global.FolderCommon.ToString(), title, content);
        }


        /// <summary>
        /// Creates a new folder with the title sent in the request. The ID of a parent folder can be also specified.
        /// </summary>
        /// <short>
        /// Create folder
        /// </short>
        /// <category>Folders</category>
        /// <param name="folderId">Parent folder ID</param>
        /// <param name="title">Title of new folder</param>
        /// <returns>New folder contents</returns>
        [Create("folder/{folderId}")]
        public FolderWrapper CreateFolder(string folderId, string title)
        {
            var folder = _fileStorageService.CreateNewFolder(folderId, title);
            return new FolderWrapper(folder);
        }

        /// <summary>
        /// Creates a new file in the My section with the title sent in the request
        /// </summary>
        /// <short>Create file in My</short>
        /// <category>Files</category>
        /// <param name="title" remark="Allowed values: the file must have one of the following extensions: DOCX, XLSX, PPTX">File title</param>
        /// <remarks>In case the extension for the file title differs from DOCX/XLSX/PPTX and belongs to one of the known text, spreadsheet or presentation formats, it will be changed to DOCX/XLSX/PPTX accordingly. If the file extension is not set or is unknown, the DOCX extension will be added to the file title.</remarks>
        /// <returns>New file info</returns>
        [Create("@my/file")]
        public FileWrapper CreateFile(string title)
        {
            return CreateFile(Global.FolderMy.ToString(), title, null);
        }

        /// <summary>
        /// Creates a new file in the specified folder with the title sent in the request
        /// </summary>
        /// <short>Create file</short>
        /// <category>Files</category>
        /// <param name="folderId">Folder ID</param>
        /// <param name="title" remark="Allowed values: the file must have one of the following extensions: DOCX, XLSX, PPTX">File title</param>
        /// <param name="templateId">File ID for using as template</param>
        /// <remarks>In case the extension for the file title differs from DOCX/XLSX/PPTX and belongs to one of the known text, spreadsheet or presentation formats, it will be changed to DOCX/XLSX/PPTX accordingly. If the file extension is not set or is unknown, the DOCX extension will be added to the file title.</remarks>
        /// <returns>New file info</returns>
        [Create("{folderId}/file")]
        public FileWrapper CreateFile(string folderId, string title, string templateId)
        {
            var file = _fileStorageService.CreateNewFile(folderId, title, templateId);
            return new FileWrapper(file);
        }

        /// <summary>
        /// Renames the selected folder to the new title specified in the request
        /// </summary>
        /// <short>
        /// Rename folder
        /// </short>
        /// <category>Folders</category>
        /// <param name="folderId">Folder ID</param>
        /// <param name="title">New title</param>
        /// <returns>Folder contents</returns>
        [Update("folder/{folderId}")]
        public FolderWrapper RenameFolder(string folderId, string title)
        {
            var folder = _fileStorageService.FolderRename(folderId, title);
            return new FolderWrapper(folder);
        }

        /// <summary>
        /// Returns a detailed information about the folder with the ID specified in the request
        /// </summary>
        /// <short>Folder information</short>
        /// <category>Folders</category>
        /// <returns>Folder info</returns>
        [Read("folder/{folderId}")]
        public FolderWrapper GetFolderInfo(string folderId)
        {
            var folder = _fileStorageService.GetFolder(folderId).NotFoundIfNull("Folder not found");

            return new FolderWrapper(folder);
        }

        /// <summary>
        /// Returns parent folders
        /// </summary>
        /// <short>Folder path</short>
        /// <param name="folderId"></param>
        /// <category>Folders</category>
        /// <returns>Parent folders</returns>
        [Read("folder/{folderId}/path")]
        public IEnumerable<FolderWrapper> GetFolderPath(string folderId)
        {
            return EntryManager.GetBreadCrumbs(folderId).Select(f => new FolderWrapper(f)).ToSmartList();
        }

        /// <summary>
        /// Returns a detailed information about the file with the ID specified in the request
        /// </summary>
        /// <short>File information</short>
        /// <category>Files</category>
        /// <returns>File info</returns>
        [Read("file/{fileId}")]
        public FileWrapper GetFileInfo(string fileId, int version = -1)
        {
            var file = _fileStorageService.GetFile(fileId, version).NotFoundIfNull("File not found");
            return new FileWrapper(file);
        }

        /// <summary>
        ///     Updates the information of the selected file with the parameters specified in the request
        /// </summary>
        /// <short>Update file info</short>
        /// <category>Files</category>
        /// <param name="fileId">File ID</param>
        /// <param name="title">New title</param>
        /// <param name="lastVersion">File last version number</param>
        /// <returns>File info</returns>
        [Update("file/{fileId}")]
        public FileWrapper UpdateFile(String fileId, String title, int lastVersion)
        {
            if (!String.IsNullOrEmpty(title))
                _fileStorageService.FileRename(fileId.ToString(CultureInfo.InvariantCulture), title);

            if (lastVersion > 0)
                _fileStorageService.UpdateToVersion(fileId.ToString(CultureInfo.InvariantCulture), lastVersion);

            return GetFileInfo(fileId);
        }

        /// <summary>
        /// Deletes the file with the ID specified in the request
        /// </summary>
        /// <short>Delete file</short>
        /// <category>Operations</category>
        /// <param name="fileId">File ID</param>
        /// <param name="deleteAfter">Delete after finished</param>
        /// <param name="immediately">Don't move to the Recycle Bin</param>
        /// <returns>Operation result</returns>
        [Delete("file/{fileId}")]
        public IEnumerable<FileOperationWraper> DeleteFile(String fileId, bool deleteAfter, bool immediately)
        {
            return DeleteBatchItems(null, new[] { fileId }, deleteAfter, immediately);
        }

        /// <summary>
        ///  Start conversion operation
        /// </summary>
        /// <short>Convert start</short>
        /// <category>Operations</category>
        /// <param name="fileId"></param>
        /// <returns>Operation result</returns>
        [Update("file/{fileId}/checkconversion")]
        public IEnumerable<ConversationResult> StartConversion(String fileId)
        {
            return CheckConversion(fileId, true);
        }

        /// <summary>
        ///  Check conversion status
        /// </summary>
        /// <short>Convert status</short>
        /// <category>Operations</category>
        /// <param name="fileId"></param>
        /// <param name="start"></param>
        /// <returns>Operation result</returns>
        [Read("file/{fileId}/checkconversion")]
        public IEnumerable<ConversationResult> CheckConversion(String fileId, bool start)
        {
            return _fileStorageService.CheckConversion(new FilesNS.ItemList<FilesNS.ItemList<string>>
            {
                new FilesNS.ItemList<string> { fileId, "0", start.ToString() }
            })
            .Select(r =>
            {
                var o = new ConversationResult
                {
                    Id = r.Id,
                    Error = r.Error,
                    OperationType = r.OperationType,
                    Processed = r.Processed,
                    Progress = r.Progress,
                    Source = r.Source,
                };
                if (!string.IsNullOrEmpty(r.Result))
                {
                    var jResult = JObject.Parse(r.Result);
                    o.File = GetFileInfo(jResult.Value<string>("id"), jResult.Value<int>("version"));
                }
                return o;
            });
        }

        /// <summary>
        /// Deletes the folder with the ID specified in the request
        /// </summary>
        /// <short>Delete folder</short>
        /// <category>Operations</category>
        /// <param name="folderId">Folder ID</param>
        /// <param name="deleteAfter">Delete after finished</param>
        /// <param name="immediately">Don't move to the Recycle Bin</param>
        /// <returns>Operation result</returns>
        [Delete("folder/{folderId}")]
        public IEnumerable<FileOperationWraper> DeleteFolder(String folderId, bool deleteAfter, bool immediately)
        {
            return DeleteBatchItems(new[] { folderId }, null, deleteAfter, immediately);
        }

        /// <summary>
        /// Checking for conflicts
        /// </summary>
        /// <category>Operations</category>
        /// <param name="destFolderId">Destination folder ID</param>
        /// <param name="folderIds">Folder ID list</param>
        /// <param name="fileIds">File ID list</param>
        /// <returns>Conflicts file ids</returns>
        [Read("fileops/move")]
        public IEnumerable<FileWrapper> MoveOrCopyBatchCheck(String destFolderId, IEnumerable<String> folderIds, IEnumerable<String> fileIds)
        {
            var itemList = new Web.Files.Services.WCFService.ItemList<String>();

            itemList.AddRange((folderIds ?? new List<String>()).Select(x => "folder_" + x));
            itemList.AddRange((fileIds ?? new List<String>()).Select(x => "file_" + x));

            var ids = _fileStorageService.MoveOrCopyFilesCheck(itemList, destFolderId).Keys.Select(id => "file_" + id);

            var entries = _fileStorageService.GetItems(new Web.Files.Services.WCFService.ItemList<string>(ids), FilterType.FilesOnly, false, "", "");
            return entries.Select(x => new FileWrapper((Files.Core.File)x)).ToSmartList();
        }

        /// <summary>
        ///   Moves all the selected files and folders to the folder with the ID specified in the request
        /// </summary>
        /// <short>Move to folder</short>
        /// <category>Operations</category>
        /// <param name="destFolderId">Destination folder ID</param>
        /// <param name="folderIds">Folder ID list</param>
        /// <param name="fileIds">File ID list</param>
        /// <param name="conflictResolveType">Overwriting behavior: skip(0), overwrite(1) or duplicate(2)</param>
        /// <param name="deleteAfter">Delete after finished</param>
        /// <returns>Operation result</returns>
        [Update("fileops/move")]
        public IEnumerable<FileOperationWraper> MoveBatchItems(String destFolderId, IEnumerable<String> folderIds, IEnumerable<String> fileIds, FileConflictResolveType conflictResolveType, bool deleteAfter)
        {
            var itemList = new Web.Files.Services.WCFService.ItemList<String>();

            itemList.AddRange((folderIds ?? new List<String>()).Select(x => "folder_" + x));
            itemList.AddRange((fileIds ?? new List<String>()).Select(x => "file_" + x));

            return _fileStorageService.MoveOrCopyItems(itemList, destFolderId, conflictResolveType, false, deleteAfter).Select(o => new FileOperationWraper(o));
        }

        /// <summary>
        ///   Copies all the selected files and folders to the folder with the ID specified in the request
        /// </summary>
        /// <short>Copy to folder</short>
        /// <category>Operations</category>
        /// <param name="destFolderId">Destination folder ID</param>
        /// <param name="folderIds">Folder ID list</param>
        /// <param name="fileIds">File ID list</param>
        /// <param name="conflictResolveType">Overwriting behavior: skip(0), overwrite(1) or duplicate(2)</param>
        /// <param name="deleteAfter">Delete after finished</param>
        /// <returns>Operation result</returns>
        [Update("fileops/copy")]
        public IEnumerable<FileOperationWraper> CopyBatchItems(String destFolderId, IEnumerable<String> folderIds, IEnumerable<String> fileIds, FileConflictResolveType conflictResolveType, bool deleteAfter)
        {
            var itemList = new Web.Files.Services.WCFService.ItemList<String>();

            itemList.AddRange((folderIds ?? new List<String>()).Select(x => "folder_" + x));
            itemList.AddRange((fileIds ?? new List<String>()).Select(x => "file_" + x));

            return _fileStorageService.MoveOrCopyItems(itemList, destFolderId, conflictResolveType, true, deleteAfter).Select(o => new FileOperationWraper(o));
        }

        /// <summary>
        ///   Marks all files and folders as read
        /// </summary>
        /// <short>Mark as read</short>
        /// <category>Operations</category>
        /// <returns>Operation result</returns>
        [Update("fileops/markasread")]
        public IEnumerable<FileOperationWraper> MarkAsRead(IEnumerable<String> folderIds, IEnumerable<String> fileIds)
        {
            var itemList = new Web.Files.Services.WCFService.ItemList<String>();

            itemList.AddRange((folderIds ?? new List<String>()).Select(x => "folder_" + x));
            itemList.AddRange((fileIds ?? new List<String>()).Select(x => "file_" + x));

            return _fileStorageService.MarkAsRead(itemList).Select(o => new FileOperationWraper(o));
        }

        /// <summary>
        ///  Finishes all the active Operations
        /// </summary>
        /// <short>Finish all</short>
        /// <category>Operations</category>
        /// <returns>Operation result</returns>
        [Update("fileops/terminate")]
        public IEnumerable<FileOperationWraper> TerminateTasks()
        {
            return _fileStorageService.TerminateTasks().Select(o => new FileOperationWraper(o));
        }


        /// <summary>
        ///  Returns the list of all active Operations
        /// </summary>
        /// <short>Operations list</short>
        /// <category>Operations</category>
        /// <returns>Operation result</returns>
        [Read("fileops")]
        public IEnumerable<FileOperationWraper> GetOperationStatuses()
        {
            return _fileStorageService.GetTasksStatuses().Select(o => new FileOperationWraper(o));
        }

        /// <summary>
        /// Start downlaod process of files and folders with ID
        /// </summary>
        /// <short>Finish Operations</short>
        /// <param name="fileConvertIds" visible="false">File ID list for download with convert to format</param>
        /// <param name="fileIds">File ID list</param>
        /// <param name="folderIds">Folder ID list</param>
        /// <category>Operations</category>
        /// <returns>Operation result</returns>
        [Update("fileops/bulkdownload")]
        public IEnumerable<FileOperationWraper> BulkDownload(
            IEnumerable<ItemKeyValuePair<String, String>> fileConvertIds,
            IEnumerable<String> fileIds,
            IEnumerable<String> folderIds)
        {
            var itemList = new Dictionary<String, String>();

            foreach (var fileId in fileConvertIds.Where(fileId => !itemList.ContainsKey(fileId.Key)))
            {
                itemList.Add("file_" + fileId.Key, fileId.Value);
            }

            foreach (var fileId in fileIds.Where(fileId => !itemList.ContainsKey(fileId)))
            {
                itemList.Add("file_" + fileId, string.Empty);
            }

            foreach (var folderId in folderIds.Where(folderId => !itemList.ContainsKey(folderId)))
            {
                itemList.Add("folder_" + folderId, String.Empty);
            }

            return _fileStorageService.BulkDownload(itemList).Select(o => new FileOperationWraper(o));
        }

        /// <summary>
        ///   Deletes the files and folders with the IDs specified in the request
        /// </summary>
        /// <param name="folderIds">Folder ID list</param>
        /// <param name="fileIds">File ID list</param>
        /// <param name="deleteAfter">Delete after finished</param>
        /// <param name="immediately">Don't move to the Recycle Bin</param>
        /// <short>Delete files and folders</short>
        /// <category>Operations</category>
        /// <returns>Operation result</returns>
        [Update("fileops/delete")]
        public IEnumerable<FileOperationWraper> DeleteBatchItems(IEnumerable<String> folderIds, IEnumerable<String> fileIds, bool deleteAfter, bool immediately)
        {
            var itemList = new Web.Files.Services.WCFService.ItemList<String>();

            itemList.AddRange((folderIds ?? new List<String>()).Select(x => "folder_" + x));
            itemList.AddRange((fileIds ?? new List<String>()).Select(x => "file_" + x));

            return _fileStorageService.DeleteItems("delete", itemList, false, deleteAfter, immediately).Select(o => new FileOperationWraper(o));
        }

        /// <summary>
        ///   Deletes all files and folders from the recycle bin
        /// </summary>
        /// <short>Clear recycle bin</short>
        /// <category>Operations</category>
        /// <returns>Operation result</returns>
        [Update("fileops/emptytrash")]
        public IEnumerable<FileOperationWraper> EmptyTrash()
        {
            return _fileStorageService.EmptyTrash().Select(o => new FileOperationWraper(o));
        }

        /// <summary>
        /// Returns the detailed information about all the available file versions with the ID specified in the request
        /// </summary>
        /// <short>File versions</short>
        /// <category>Files</category>
        /// <param name="fileId">File ID</param>
        /// <returns>File information</returns>
        [Read("file/{fileId}/history")]
        public IEnumerable<FileWrapper> GetFileVersionInfo(string fileId)
        {
            var files = _fileStorageService.GetFileHistory(fileId);
            return files.Select(x => new FileWrapper(x)).ToSmartList();
        }

        /// <summary>
        /// Change version history
        /// </summary>
        /// <param name="fileId">File ID</param>
        /// <param name="version">Version of history</param>
        /// <param name="continueVersion">Mark as version or revision</param>
        /// <category>Files</category>
        /// <returns></returns>
        [Update("file/{fileId}/history")]
        public IEnumerable<FileWrapper> ChangeHistory(string fileId, int version, bool continueVersion)
        {
            var history = _fileStorageService.CompleteVersion(fileId, version, continueVersion).Value;
            return history.Select(x => new FileWrapper(x)).ToSmartList();
        }

        /// <summary>
        /// Returns the detailed information about shared file with the ID specified in the request
        /// </summary>
        /// <short>File sharing</short>
        /// <category>Sharing</category>
        /// <param name="fileId">File ID</param>
        /// <returns>Shared file information</returns>
        [Read("file/{fileId}/share")]
        public IEnumerable<FileShareWrapper> GetFileSecurityInfo(string fileId)
        {
            var fileShares = _fileStorageService.GetSharedInfo(new Web.Files.Services.WCFService.ItemList<string> { String.Format("file_{0}", fileId) });
            return fileShares.Select(x => new FileShareWrapper(x)).ToSmartList();
        }

        /// <summary>
        /// Returns the detailed information about shared folder with the ID specified in the request
        /// </summary>
        /// <short>Folder sharing</short>
        /// <param name="folderId">Folder ID</param>
        /// <category>Sharing</category>
        /// <returns>Shared folder information</returns>
        [Read("folder/{folderId}/share")]
        public IEnumerable<FileShareWrapper> GetFolderSecurityInfo(string folderId)
        {
            var fileShares = _fileStorageService.GetSharedInfo(new Web.Files.Services.WCFService.ItemList<string> { String.Format("folder_{0}", folderId) });
            return fileShares.Select(x => new FileShareWrapper(x)).ToSmartList();
        }

        /// <summary>
        /// Sets sharing settings for the file with the ID specified in the request
        /// </summary>
        /// <param name="fileId">File ID</param>
        /// <param name="share">Collection of sharing rights</param>
        /// <param name="notify">Should notify people</param>
        /// <param name="sharingMessage">Sharing message to send when notifying</param>
        /// <short>Share file</short>
        /// <category>Sharing</category>
        /// <remarks>
        /// Each of the FileShareParams must contain two parameters: 'ShareTo' - ID of the user with whom we want to share and 'Access' - access type which we want to grant to the user (Read, ReadWrite, etc) 
        /// </remarks>
        /// <returns>Shared file information</returns>
        [Update("file/{fileId}/share")]
        public IEnumerable<FileShareWrapper> SetFileSecurityInfo(string fileId, IEnumerable<FileShareParams> share, bool notify, string sharingMessage)
        {
            if (share != null && share.Any())
            {
                var list = new Web.Files.Services.WCFService.ItemList<AceWrapper>(share.Select(x => x.ToAceObject()));
                var aceCollection = new AceCollection
                {
                    Entries = new Web.Files.Services.WCFService.ItemList<string> { "file_" + fileId },
                    Aces = list,
                    Message = sharingMessage
                };
                _fileStorageService.SetAceObject(aceCollection, notify);
            }
            return GetFileSecurityInfo(fileId);
        }

        /// <summary>
        /// Sets sharing settings for the folder with the ID specified in the request
        /// </summary>
        /// <short>Share folder</short>
        /// <param name="folderId">Folder ID</param>
        /// <param name="share">Collection of sharing rights</param>
        /// <param name="notify">Should notify people</param>
        /// <param name="sharingMessage">Sharing message to send when notifying</param>
        /// <remarks>
        /// Each of the FileShareParams must contain two parameters: 'ShareTo' - ID of the user with whom we want to share and 'Access' - access type which we want to grant to the user (Read, ReadWrite, etc) 
        /// </remarks>
        /// <category>Sharing</category>
        /// <returns>Shared folder information</returns>
        [Update("folder/{folderId}/share")]
        public IEnumerable<FileShareWrapper> SetFolderSecurityInfo(string folderId, IEnumerable<FileShareParams> share, bool notify, string sharingMessage)
        {
            if (share != null && share.Any())
            {
                var list = new Web.Files.Services.WCFService.ItemList<AceWrapper>(share.Select(x => x.ToAceObject()));
                var aceCollection = new AceCollection
                {
                    Entries = new Web.Files.Services.WCFService.ItemList<string> { "folder_" + folderId },
                    Aces = list,
                    Message = sharingMessage
                };
                _fileStorageService.SetAceObject(aceCollection, notify);
            }

            return GetFolderSecurityInfo(folderId);
        }

        /// <summary>
        ///   Removes sharing rights for the group with the ID specified in the request
        /// </summary>
        /// <param name="folderIds">Folders ID</param>
        /// <param name="fileIds">Files ID</param>
        /// <short>Remove group sharing rights</short>
        /// <category>Sharing</category>
        /// <returns>Shared file information</returns>
        [Delete("share")]
        public bool RemoveSecurityInfo(IEnumerable<String> folderIds, IEnumerable<String> fileIds)
        {
            var itemList = new Web.Files.Services.WCFService.ItemList<String>();

            itemList.AddRange((folderIds ?? new List<String>()).Select(x => "folder_" + x));
            itemList.AddRange((fileIds ?? new List<String>()).Select(x => "file_" + x));

            _fileStorageService.RemoveAce(itemList);

            return true;
        }

        /// <summary>
        ///   Returns the external link to the shared file with the ID specified in the request
        /// </summary>
        /// <short>Shared link</short>
        /// <param name="fileId">File ID</param>
        /// <param name="share">Access right</param>
        /// <category>Sharing</category>
        /// <returns>Shared file link</returns>
        [Update("{fileId}/sharedlink")]
        public string GenerateSharedLink(string fileId, FileShare share)
        {
            var file = GetFileInfo(fileId);

            var objectId = "file_" + file.Id;
            var sharedInfo = _fileStorageService.GetSharedInfo(new Web.Files.Services.WCFService.ItemList<string> { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId);
            if (sharedInfo == null || sharedInfo.Share != share)
            {
                var list = new Web.Files.Services.WCFService.ItemList<AceWrapper>
                    {
                        new AceWrapper
                            {
                                SubjectId = FileConstant.ShareLinkId,
                                SubjectGroup = true,
                                Share = share
                            }
                    };
                var aceCollection = new AceCollection
                {
                    Entries = new Web.Files.Services.WCFService.ItemList<string> { objectId },
                    Aces = list
                };
                _fileStorageService.SetAceObject(aceCollection, false);
                sharedInfo = _fileStorageService.GetSharedInfo(new Web.Files.Services.WCFService.ItemList<string> { objectId }).Find(r => r.SubjectId == FileConstant.ShareLinkId);
            }

            return sharedInfo.Link;
        }

        /// <summary>
        ///   Get a list of available providers
        /// </summary>
        /// <category>Third-Party Integration</category>
        /// <returns>List of provider key</returns>
        /// <remarks>List of provider key: DropboxV2, Box, WebDav, Yandex, OneDrive, SharePoint, GoogleDrive</remarks>
        /// <returns></returns>
        [Read("thirdparty/capabilities")]
        public List<List<string>> Capabilities()
        {
            var result = new List<List<string>>();

            if (CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor()
                || (!FilesSettings.EnableThirdParty
                    && !CoreContext.Configuration.Personal))
            {
                return result;
            }

            if (ThirdpartyConfiguration.SupportBoxInclusion)
            {
                result.Add(new List<string> { "Box", BoxLoginProvider.Instance.ClientID, BoxLoginProvider.Instance.RedirectUri });
            }
            if (ThirdpartyConfiguration.SupportDropboxInclusion)
            {
                result.Add(new List<string> { "DropboxV2", DropboxLoginProvider.Instance.ClientID, DropboxLoginProvider.Instance.RedirectUri });
            }
            if (ThirdpartyConfiguration.SupportGoogleDriveInclusion)
            {
                result.Add(new List<string> { "GoogleDrive", GoogleLoginProvider.Instance.ClientID, GoogleLoginProvider.Instance.RedirectUri });
            }
            if (ThirdpartyConfiguration.SupportOneDriveInclusion)
            {
                result.Add(new List<string> { "OneDrive", OneDriveLoginProvider.Instance.ClientID, OneDriveLoginProvider.Instance.RedirectUri });
            }
            if (ThirdpartyConfiguration.SupportSharePointInclusion)
            {
                result.Add(new List<string> { "SharePoint" });
            }
            if (ThirdpartyConfiguration.SupportkDriveInclusion)
            {
                result.Add(new List<string> { "kDrive" });
            }
            if (ThirdpartyConfiguration.SupportYandexInclusion)
            {
                result.Add(new List<string> { "Yandex" });
            }
            if (ThirdpartyConfiguration.SupportWebDavInclusion)
            {
                result.Add(new List<string> { "WebDav" });
            }

            //Obsolete BoxNet, DropBox, Google, SkyDrive,

            return result;
        }

        /// <summary>
        ///   Saves the third party file storage service account
        /// </summary>
        /// <short>Save third party account</short>
        /// <param name="url">Connection url for SharePoint</param>
        /// <param name="login">Login</param>
        /// <param name="password">Password</param>
        /// <param name="token">Authentication token</param>
        /// <param name="isCorporate"></param>
        /// <param name="customerTitle">Title</param>
        /// <param name="providerKey">Provider Key</param>
        /// <param name="providerId">Provider ID</param>
        /// <category>Third-Party Integration</category>
        /// <returns>Folder contents</returns>
        /// <remarks>List of provider key: <KEY>, Box, WebDav, Yandex, OneDrive, SharePoint, GoogleDrive</remarks>
        /// <exception cref="ArgumentException"></exception>
        [Create("thirdparty")]
        public FolderWrapper SaveThirdParty(
            String url,
            String login,
            String password,
            String token,
            bool isCorporate,
            String customerTitle,
            String providerKey,
            String providerId)
        {
            var thirdPartyParams = new ThirdPartyParams
            {
                AuthData = new AuthData(url, login, password, token),
                Corporate = isCorporate,
                CustomerTitle = customerTitle,
                ProviderId = providerId,
                ProviderKey = providerKey,
            };

            var folder = _fileStorageService.SaveThirdParty(thirdPartyParams);

            return new FolderWrapper(folder);
        }

        /// <summary>
        ///    Returns the list of all connected third party services
        /// </summary>
        /// <category>Third-Party Integration</category>
        /// <short>Third party list</short>
        /// <returns>Connected providers</returns>
        [Read("thirdparty")]
        public IEnumerable<ThirdPartyParams> GetThirdPartyAccounts()
        {
            return _fileStorageService.GetThirdParty();
        }

        /// <summary>
        ///    Returns the list of third party services connected in the Common section
        /// </summary>
        /// <category>Third-Party Integration</category>
        /// <short>Third party folder</short>
        /// <returns>Connected providers folder</returns>
        [Read("thirdparty/common")]
        public IEnumerable<Folder> GetCommonThirdPartyFolders()
        {
            var parent = _fileStorageService.GetFolder(Global.FolderCommon.ToString());
            return EntryManager.GetThirpartyFolders(parent);
        }

        /// <summary>
        ///   Removes the third party file storage service account with the ID specified in the request
        /// </summary>
        /// <param name="providerId">Provider ID. Provider id is part of folder id.
        /// Example, folder id is "sbox-123", then provider id is "123"
        /// </param>
        /// <short>Remove third party account</short>
        /// <category>Third-Party Integration</category>
        /// <returns>Folder id</returns>
        ///<exception cref="ArgumentException"></exception>
        [Delete("thirdparty/{providerId:[0-9]+}")]
        public object DeleteThirdParty(int providerId)
        {
            return _fileStorageService.DeleteThirdParty(providerId.ToString(CultureInfo.InvariantCulture));

        }

        /// <summary>
        /// Search files
        /// </summary>
        /// <param name="query">Queary string</param>
        /// <returns>Files and folders</returns>
        [Read(@"@search/{query}")]
        public IEnumerable<FileEntryWrapper> Search(string query)
        {
            var searcher = new Web.Files.Configuration.SearchHandler();
            var files = searcher.SearchFiles(query).Select(r => (FileEntryWrapper)new FileWrapper(r));
            var folders = searcher.SearchFolders(query).Select(f => (FileEntryWrapper)new FolderWrapper(f));

            return files.Concat(folders);
        }

        /// <summary>
        /// Adding files to favorite list
        /// </summary>
        /// <short>Favorite add</short>
        /// <category>Files</category>
        /// <param name="folderIds" visible="false"></param>
        /// <param name="fileIds">File IDs</param>
        /// <returns></returns>
        [Create("favorites")]
        public bool AddFavorites(IEnumerable<String> folderIds, IEnumerable<String> fileIds)
        {
            var list = _fileStorageService.AddToFavorites(new FilesNS.ItemList<string>(folderIds), new FilesNS.ItemList<string>(fileIds));
            return true;
        }

        /// <summary>
        /// Removing files from favorite list
        /// </summary>
        /// <short>Favorite delete</short>
        /// <category>Files</category>
        /// <param name="folderIds" visible="false"></param>
        /// <param name="fileIds">File IDs</param>
        /// <returns></returns>
        [Delete("favorites")]
        public bool DeleteFavorites(IEnumerable<String> folderIds, IEnumerable<String> fileIds)
        {
            var list = _fileStorageService.DeleteFavorites(new FilesNS.ItemList<string>(folderIds), new FilesNS.ItemList<string>(fileIds));
            return true;
        }

        /// <summary>
        /// Adding files to template list
        /// </summary>
        /// <short>Template add</short>
        /// <category>Files</category>
        /// <param name="fileIds">File IDs</param>
        /// <returns></returns>
        [Create("templates")]
        public bool AddTemplates(IEnumerable<String> fileIds)
        {
            var list = _fileStorageService.AddToTemplates(new FilesNS.ItemList<string>(fileIds));
            return true;
        }

        /// <summary>
        /// Removing files from template list
        /// </summary>
        /// <short>Template delete</short>
        /// <category>Files</category>
        /// <param name="fileIds">File IDs</param>
        /// <returns></returns>
        [Delete("templates")]
        public bool DeleteTemplates(IEnumerable<String> fileIds)
        {
            var list = _fileStorageService.DeleteTemplates(new FilesNS.ItemList<string>(fileIds));
            return true;
        }


        /// <summary>
        /// Store file in original formats when upload and convert
        /// </summary>
        /// <param name="set"></param>
        /// <category>Settings</category>
        /// <returns></returns>
        [Update(@"storeoriginal")]
        public bool StoreOriginal(bool set)
        {
            return _fileStorageService.StoreOriginal(set);
        }

        /// <summary>
        /// Do not show the confirmation dialog
        /// </summary>
        /// <param name="save"></param>
        /// <category>Settings</category>
        /// <visible>false</visible>
        /// <returns></returns>
        [Update(@"hideconfirmconvert")]
        public bool HideConfirmConvert(bool save)
        {
            return _fileStorageService.HideConfirmConvert(save);
        }

        /// <summary>
        /// Update the file version if the same name is exist
        /// </summary>
        /// <param name="set"></param>
        /// <category>Settings</category>
        /// <returns></returns>
        [Update(@"updateifexist")]
        public bool UpdateIfExist(bool set)
        {
            return _fileStorageService.UpdateIfExist(set);
        }

        /// <summary>
        /// Display recent folder
        /// </summary>
        /// <param name="set"></param>
        /// <category>Settings</category>
        /// <returns></returns>
        [Update(@"displayRecent")]
        public bool DisplayRecent(bool set)
        {
            return _fileStorageService.DisplayRecent(set);
        }

        /// <summary>
        /// Display favorite folder
        /// </summary>
        /// <param name="set"></param>
        /// <category>Settings</category>
        /// <returns></returns>
        [Update(@"settings/favorites")]
        public bool DisplayFavorite(bool set)
        {
            return _fileStorageService.DisplayFavorite(set);
        }

        /// <summary>
        /// Display template folder
        /// </summary>
        /// <param name="set"></param>
        /// <category>Settings</category>
        /// <returns></returns>
        [Update(@"settings/templates")]
        public bool DisplayTemplates(bool set)
        {
            return _fileStorageService.DisplayTemplates(set);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="set"></param>
        /// <category>Settings</category>
        /// <returns></returns>
        [Update(@"settings/downloadtargz")]
        public ICompress ChangeDownloadZip(bool set)
        {
            return _fileStorageService.ChangeDownloadTarGz(set);
        }

        /// <summary>
        ///  Checking document service location
        /// </summary>
        /// <param name="docServiceUrl">Document editing service Domain</param>
        /// <param name="docServiceUrlInternal">Document command service Domain</param>
        /// <param name="docServiceUrlPortal">Community Server Address</param>
        /// <category>Settings</category>
        /// <returns></returns>
        [Update("docservice")]
        public IEnumerable<string> CheckDocServiceUrl(string docServiceUrl, string docServiceUrlInternal, string docServiceUrlPortal)
        {
            FilesLinkUtility.DocServiceUrl = docServiceUrl;
            FilesLinkUtility.DocServiceUrlInternal = docServiceUrlInternal;
            FilesLinkUtility.DocServicePortalUrl = docServiceUrlPortal;

            MessageService.Send(HttpContext.Current.Request, MessageAction.DocumentServiceLocationSetting);

            var https = new Regex(@"^https://", RegexOptions.IgnoreCase);
            var http = new Regex(@"^http://", RegexOptions.IgnoreCase);
            if (https.IsMatch(CommonLinkUtility.GetFullAbsolutePath("")) && http.IsMatch(FilesLinkUtility.DocServiceUrl))
            {
                throw new Exception("Mixed Active Content is not allowed. HTTPS address for Document Server is required.");
            }

            DocumentServiceConnector.CheckDocServiceUrl();

            return new[]
                {
                    FilesLinkUtility.DocServiceUrl,
                    FilesLinkUtility.DocServiceUrlInternal,
                    FilesLinkUtility.DocServicePortalUrl
                };
        }


        /// <summary>
        /// Get the address of connected editors
        /// </summary>
        /// <category>Settings</category>
        /// <param name="version" visible="false"></param>
        /// <returns>Address</returns>
        [Read("docservice")]
        public object GetDocServiceUrl(bool version)
        {
            var url = CommonLinkUtility.GetFullAbsolutePath(FilesLinkUtility.DocServiceApiUrl);
            if (!version)
            {
                return url;
            }

            var dsVersion = DocumentServiceConnector.GetVersion();

            return new
            {
                version = dsVersion,
                docServiceUrlApi = url,
            };
        }

        /// <summary>
        /// Create thumbnails for files with the IDs specified in the request
        /// </summary>
        /// <short>Create thumbnails</short>
        /// <category>Files</category>
        /// <param name="fileIds">File IDs</param>
        /// <visible>false</visible>
        /// <returns></returns>
        [Create("thumbnails")]
        public IEnumerable<String> CreateThumbnails(IEnumerable<String> fileIds)
        {
            try
            {
                using (var thumbnailBuilderServiceClient = new ThumbnailBuilderServiceClient())
                {
                    thumbnailBuilderServiceClient.BuildThumbnails(CoreContext.TenantManager.GetCurrentTenant().TenantId, fileIds);
                }
            }
            catch (Exception e)
            {
                Common.Logging.LogManager.GetLogger("ASC.Api.Documents").Error("CreateThumbnails", e);
            }
            return fileIds;
        }


        private FolderContentWrapper ToFolderContentWrapper(object folderId, Guid userIdOrGroupId, FilterType filterType)
        {
            OrderBy orderBy = null;
            SortedByType sortBy;
            if (Enum.TryParse(_context.SortBy, true, out sortBy))
            {
                orderBy = new OrderBy(sortBy, !_context.SortDescending);
            }
            var startIndex = Convert.ToInt32(_context.StartIndex);
            return new FolderContentWrapper(_fileStorageService.GetFolderItems(folderId.ToString(),
                                                                               startIndex,
                                                                               Convert.ToInt32(_context.Count) - 1, //NOTE: in ApiContext +1
                                                                               filterType,
                                                                               filterType == FilterType.ByUser,
                                                                               userIdOrGroupId.ToString(),
                                                                               _context.FilterValue,
                                                                               false,
                                                                               false,
                                                                               orderBy),
                                            startIndex);
        }

        #region wordpress

        /// <visible>false</visible>
        [Read("wordpress-info")]
        public object GetWordpressInfo()
        {
            var token = WordpressToken.GetToken();
            if (token != null)
            {
                var meInfo = WordpressHelper.GetWordpressMeInfo(token.AccessToken);
                var blogId = JObject.Parse(meInfo).Value<string>("token_site_id");
                var wordpressUserName = JObject.Parse(meInfo).Value<string>("username");

                var blogInfo = RequestHelper.PerformRequest(WordpressLoginProvider.WordpressSites + blogId, "", "GET", "");
                var jsonBlogInfo = JObject.Parse(blogInfo);
                jsonBlogInfo.Add("username", wordpressUserName);

                blogInfo = jsonBlogInfo.ToString();
                return new
                {
                    success = true,
                    data = blogInfo
                };
            }
            return new
            {
                success = false
            };
        }

        /// <visible>false</visible>
        [Read("wordpress-delete")]
        public object DeleteWordpressInfo()
        {
            var token = WordpressToken.GetToken();
            if (token != null)
            {
                WordpressToken.DeleteToken(token);
                return new
                {
                    success = true
                };
            }
            return new
            {
                success = false
            };
        }

        /// <visible>false</visible>
        [Create("wordpress-save")]
        public object WordpressSave(string code)
        {
            if (code == "")
            {
                return new
                {
                    success = false
                };
            }
            try
            {
                var token = OAuth20TokenHelper.GetAccessToken<WordpressLoginProvider>(code);
                WordpressToken.SaveToken(token);
                var meInfo = WordpressHelper.GetWordpressMeInfo(token.AccessToken);
                var blogId = JObject.Parse(meInfo).Value<string>("token_site_id");

                var wordpressUserName = JObject.Parse(meInfo).Value<string>("username");

                var blogInfo = RequestHelper.PerformRequest(WordpressLoginProvider.WordpressSites + blogId, "", "GET", "");
                var jsonBlogInfo = JObject.Parse(blogInfo);
                jsonBlogInfo.Add("username", wordpressUserName);

                blogInfo = jsonBlogInfo.ToString();
                return new
                {
                    success = true,
                    data = blogInfo
                };
            }
            catch (Exception)
            {
                return new
                {
                    success = false
                };
            }
        }

        /// <visible>false</visible>
        [Create("wordpress")]
        public bool CreateWordpressPost(string code, string title, string content, int status)
        {
            try
            {
                var token = WordpressToken.GetToken();
                var meInfo = WordpressHelper.GetWordpressMeInfo(token.AccessToken);
                var parser = JObject.Parse(meInfo);
                if (parser == null) return false;
                var blogId = parser.Value<string>("token_site_id");

                if (blogId != null)
                {
                    var createPost = WordpressHelper.CreateWordpressPost(title, content, status, blogId, token);
                    return createPost;
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        #endregion

        #region easybib

        /// <visible>false</visible>
        [Read("easybib-citation-list")]
        public object GetEasybibCitationList(int source, string data)
        {
            try
            {
                var citationList = EasyBibHelper.GetEasyBibCitationsList(source, data);
                return new
                {
                    success = true,
                    citations = citationList
                };
            }
            catch (Exception)
            {
                return new
                {
                    success = false
                };
            }

        }

        /// <visible>false</visible>
        [Read("easybib-styles")]
        public object GetEasybibStyles()
        {
            try
            {
                var data = EasyBibHelper.GetEasyBibStyles();
                return new
                {
                    success = true,
                    styles = data
                };
            }
            catch (Exception)
            {
                return new
                {
                    success = false
                };
            }
        }

        /// <visible>false</visible>
        [Create("easybib-citation")]
        public object EasyBibCitationBook(string citationData)
        {
            try
            {
                var citat = EasyBibHelper.GetEasyBibCitation(citationData);
                if (citat != null)
                {
                    return new
                    {
                        success = true,
                        citation = citat
                    };
                }
                else
                {
                    return new
                    {
                        success = false
                    };
                }

            }
            catch (Exception)
            {
                return new
                {
                    success = false
                };
            }
        }

        #endregion

        /// <summary>
        /// Result of file conversation operation.
        /// </summary>
        [DataContract(Name = "operation_result", Namespace = "")]
        public class ConversationResult
        {
            /// <summary>
            /// Operation Id.
            /// </summary>
            [DataMember(Name = "id")]
            public string Id { get; set; }

            /// <summary>
            /// Operation type.
            /// </summary>
            [DataMember(Name = "operation")]
            public FileOperationType OperationType { get; set; }

            /// <summary>
            /// Operation progress.
            /// </summary>
            [DataMember(Name = "progress")]
            public int Progress { get; set; }

            /// <summary>
            /// Source files for operation.
            /// </summary>
            [DataMember(Name = "source")]
            public string Source { get; set; }

            /// <summary>
            /// Result file of operation.
            /// </summary>
            [DataMember(Name = "result")]
            public FileWrapper File { get; set; }

            /// <summary>
            /// Error during conversation.
            /// </summary>
            [DataMember(Name = "error")]
            public string Error { get; set; }

            /// <summary>
            /// Is operation processed.
            /// </summary>
            [DataMember(Name = "processed")]
            public string Processed { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/ThirdPartyApp/Token.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Diagnostics;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Core;
using ASC.FederatedLogin;
using ASC.FederatedLogin.Helpers;
using ASC.Files.Core;
using ASC.Security.Cryptography;
using ASC.Web.Files.Classes;

namespace ASC.Web.Files.ThirdPartyApp
{
    [DebuggerDisplay("{App} - {AccessToken}")]
    public class Token : OAuth20Token
    {
        public String App { get; private set; }

        public Token(OAuth20Token oAuth20Token, string app)
            : base(oAuth20Token)
        {
            App = app;
        }

        public override string ToString()
        {
            return GetRefreshedToken();
        }

        public String GetRefreshedToken()
        {
            if (IsExpired)
            {
                var app = ThirdPartySelector.GetApp(App);
                try
                {
                    Global.Logger.Debug("Refresh token for app: " + App);

                    var refreshUrl = app.GetRefreshUrl();

                    var refreshed = OAuth20TokenHelper.RefreshToken(refreshUrl, this);

                    if (refreshed != null)
                    {
                        AccessToken = refreshed.AccessToken;
                        RefreshToken = refreshed.RefreshToken;
                        ExpiresIn = refreshed.ExpiresIn;
                        Timestamp = DateTime.UtcNow;

                        SaveToken(this);
                    }
                }
                catch (Exception ex)
                {
                    Global.Logger.Error("Refresh token for app: " + app, ex);
                }
            }
            return AccessToken;
        }

        private const string TableTitle = "files_thirdparty_app";

        public static void SaveToken(Token token)
        {
            using (var db = new DbManager(FileConstant.DatabaseId))
            {
                var queryInsert = new SqlInsert(TableTitle, true)
                    .InColumnValue("tenant_id", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                    .InColumnValue("user_id", SecurityContext.CurrentAccount.ID.ToString())
                    .InColumnValue("app", token.App)
                    .InColumnValue("token", EncryptToken(token));

                db.ExecuteNonQuery(queryInsert);
            }
        }

        public static Token GetToken(string app)
        {
            return GetToken(app, SecurityContext.CurrentAccount.ID.ToString());
        }

        public static Token GetToken(string app, string userId)
        {
            using (var db = new DbManager(FileConstant.DatabaseId))
            {
                var querySelect = new SqlQuery(TableTitle)
                    .Select("token")
                    .Where("tenant_id", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                    .Where("user_id", userId)
                    .Where("app", app);

                var oAuth20Token = db.ExecuteList(querySelect).ConvertAll(r => DecryptToken(r[0] as string)).FirstOrDefault();
                if (oAuth20Token == null) return null;

                return new Token(oAuth20Token, app);
            }
        }

        public static void DeleteToken(string app, Guid? userId = null)
        {
            using (var db = new DbManager(FileConstant.DatabaseId))
            {
                db.ExecuteNonQuery(new SqlDelete(TableTitle)
                                       .Where("tenant_id", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                                       .Where("user_id", (userId ?? SecurityContext.CurrentAccount.ID).ToString())
                                       .Where("app", app));
            }
        }

        private static string EncryptToken(OAuth20Token token)
        {
            var t = token.ToJson();
            return string.IsNullOrEmpty(t) ? string.Empty : InstanceCrypto.Encrypt(t);
        }

        private static OAuth20Token DecryptToken(string token)
        {
            return string.IsNullOrEmpty(token) ? null : FromJson(InstanceCrypto.Decrypt(token));
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/TariffNotify.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Users;
using ASC.Web.Core;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    [AjaxNamespace("TariffNotifyController")]
    public partial class TariffNotify : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/TariffSettings/TariffNotify.ascx"; }
        }

        protected Tuple<string, string> Notify = null;
        protected bool CanClose = false;

        protected void Page_Load(object sender, EventArgs e)
        {
            if (CoreContext.Configuration.Personal && SetupInfo.IsVisibleSettings("PersonalMaxSpace"))
            {
                Notify = GetPersonalTariffNotify();
                return;
            }

            if (SecurityContext.IsAuthenticated
                && TenantExtra.EnableTariffSettings
                && !TariffSettings.HideNotify
                && !CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsVisitor())
            {
                Page.RegisterStyle("~/UserControls/Management/TariffSettings/css/tariffnotify.less");

                Notify = GetTariffNotify();

                if (CanClose)
                {
                    Page.RegisterBodyScripts("~/UserControls/Management/TariffSettings/js/tariffnotify.js");
                    AjaxPro.Utility.RegisterTypeForAjax(GetType());
                }
            }
        }

        private Tuple<string, string> GetPersonalTariffNotify()
        {
            var maxTotalSize = CoreContext.Configuration.PersonalMaxSpace;

            var webItem = WebItemManager.Instance[WebItemManager.DocumentsProductID];
            var spaceUsageManager = webItem.Context.SpaceUsageStatManager as IUserSpaceUsage;

            if (spaceUsageManager == null) return null;

            var usedSize = spaceUsageManager.GetUserSpaceUsage(SecurityContext.CurrentAccount.ID);

            long notifySize;
            long.TryParse(ConfigurationManagerExtension.AppSettings["web.tariff-notify.storage"] ?? "104857600", out notifySize); //100 MB

            if (notifySize > 0 && maxTotalSize - usedSize < notifySize)
            {
                var head = string.Format(Resource.PersonalTariffExceedLimit, FileSizeComment.FilesSizeToString(maxTotalSize));

                string text;

                if (CoreContext.Configuration.CustomMode)
                {
                    text = string.Format(Resource.PersonalTariffExceedLimitInfoText, string.Empty, string.Empty, "</br>");
                }
                else
                {
                    var settings = MailWhiteLabelSettings.Instance;
                    var supportLink = string.Format("<a target=\"_blank\" href=\"{0}\">", settings.SupportUrl);
                    text = string.Format(Resource.PersonalTariffExceedLimitInfoText, supportLink, "</a>", "</br>");
                }

                return new Tuple<string, string>(head, text);
            }

            return null;
        }

        private Tuple<string, string> GetTariffNotify()
        {
            var hidePricingPage = !CoreContext.UserManager.GetUsers(SecurityContext.CurrentAccount.ID).IsAdmin() && TariffSettings.HidePricingPage;

            var tariff = TenantExtra.GetCurrentTariff();

            var count = tariff.DueDate.Date.Subtract(DateTime.Today).Days;
            if (tariff.State == TariffState.Trial)
            {
                if (!hidePricingPage && count <= 5)
                {
                    var text = String.Format(CoreContext.Configuration.Standalone ? Resource.TariffLinkStandalone : Resource.TrialPeriodInfoText,
                                             "<a href=\"" + TenantExtra.GetTariffPageLink() + "\">", "</a>");

                    if (count <= 0)
                        return new Tuple<string, string>(Resource.TrialPeriodExpired, text);

                    var end = GetNumeralResourceByCount(count, Resource.Day, Resource.DaysOne, Resource.DaysTwo);
                    return new Tuple<string, string>(string.Format(Resource.TrialPeriod, count, end), text);
                }

                if (CoreContext.Configuration.Standalone)
                {
                    return new Tuple<string, string>(Resource.TrialPeriodInfoTextLicense, string.Empty);
                }
            }

            if (!hidePricingPage && tariff.State == TariffState.Paid)
            {
                if (CoreContext.Configuration.Standalone)
                {
                    CanClose = true;
                    var text = String.Format(Resource.TariffLinkStandaloneLife,
                                             "<a href=\"" + TenantExtra.GetTariffPageLink() + "\">", "</a>");
                    if (count <= 0)
                        return new Tuple<string, string>(Resource.PaidPeriodExpiredStandaloneLife, text);

                    if (count < 10)
                    {
                        var end = GetNumeralResourceByCount(count, Resource.Day, Resource.DaysOne, Resource.DaysTwo);
                        return new Tuple<string, string>(string.Format(Resource.PaidPeriodStandaloneLife, count, end), text);
                    }
                }
                else
                {
                    var quota = TenantExtra.GetTenantQuota();
                    long notifySize;
                    long.TryParse(ConfigurationManagerExtension.AppSettings["web.tariff-notify.storage"] ?? "314572800", out notifySize); //300 MB
                    if (notifySize > 0 && quota.MaxTotalSize - TenantStatisticsProvider.GetUsedSize() < notifySize)
                    {
                        var head = string.Format(Resource.TariffExceedLimit, FileSizeComment.FilesSizeToString(quota.MaxTotalSize));
                        var text = String.Format(Resource.TariffExceedLimitInfoText, "<a href=\"" + TenantExtra.GetTariffPageLink() + "\">", "</a>");
                        return new Tuple<string, string>(head, text);
                    }
                }
            }

            if (!hidePricingPage && tariff.State == TariffState.Delay)
            {
                var text = String.Format(Resource.TariffPaymentDelayText,
                                         "<a href=\"" + TenantExtra.GetTariffPageLink() + "\">", "</a>",
                                         tariff.DelayDueDate.Date.ToLongDateString());
                return new Tuple<string, string>(Resource.TariffPaymentDelay, text);
            }

            return null;
        }

        public static string GetNumeralResourceByCount(int count, string resource, string resourceOne, string resourceTwo)
        {
            var num = count % 100;
            if (num >= 11 && num <= 19)
            {
                return resourceTwo;
            }

            var i = count % 10;
            switch (i)
            {
                case (1):
                    return resource;
                case (2):
                case (3):
                case (4):
                    return resourceOne;
                default:
                    return resourceTwo;
            }
        }

        [AjaxMethod]
        public void HideNotify()
        {
            TariffSettings.HideNotify = true;
        }
    }
}

<|start_filename|>module/ASC.Socket.IO/app/hubs/voipPhone.js<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2020
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


function findAgent(agentId, item) {
    return item.id === agentId;
}
class VoipPhone {
    constructor(numberId) {
        this.agents = [];
        this.calls = [];
        this.numberId = numberId;
    }

    addOrUpdateAgent(agent) {
        const existingAgent = this.agents.find(findAgent.bind(null, agent.Id));
        if (existingAgent) {
            existingAgent.status = agent.status;
        } else {
            this.agents.push(agent);
        }
    }

    removeAgent(agentId) {
        const existingAgent = this.agents.some(findAgent.bind(null, agentId));
        if (!existingAgent) return false;

        this.agents = this.agents.filter((item) => item.id !== agentId);
        return true;
    }

    addCall(callId) {
        if (this.calls.some((item) => item === callId)) return;
        this.calls.push(callId);
    }

    removeCall(callId) {
        if (!callId || !this.calls.some((item) => item === callId)) return;
        this.calls = this.calls.filter((item) => item !== callId);
    }

    anyCalls() {
        return !!this.calls.length;
    }

    dequeueCall() {
        return this.calls.pop();
    }

    enqueue(callId, agent) {
        if (agent && this.removeAgent(agent)) {
            return agent;
        }

        const agents = this.agents.filter((item) =>item.status === 0 );
        if (agents.length) {
            return agents[0].id;
        }

        this.addCall(callId);
        return "";
    }

    onlineAgents() {
        return this.agents.filter((item) => item.status === 0).map((item) => item.id);
    }

    getAgentStatus(agentId) {
        const agent = this.agents.find(findAgent.bind(null, agentId));
        return agent ? agent.status : 2;
    }

    getAgent(contactResponsibles) {
        const isAnyNotOffline = !!this.agents.length;
        let result = this.agents.find((item) => {
            return item.status === 0 && contactResponsibles.includes(item.id);
        });

        if (!result) {
            result = this.agents.find((item) => item.status === 0);
        }

        if (result) {
            result.status = 1;
        }

        return { result, isAnyNotOffline };
    }
}

module.exports = VoipPhone;

<|start_filename|>module/ASC.Files.Thirdparty/ProviderDao/ProviderFolderDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

using ASC.Files.Core;

namespace ASC.Files.Thirdparty.ProviderDao
{
    internal class ProviderFolderDao : ProviderDaoBase, IFolderDao
    {
        public void Dispose()
        {
        }

        public Folder GetFolder(object folderId)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                var result = folderDao.GetFolder(selector.ConvertId(folderId));

                if (result != null && !Default.IsMatch(folderId))
                {
                    SetSharedProperty(new[] { result });
                }

                return result;
            }
        }

        public Folder GetFolder(string title, object parentId)
        {
            var selector = GetSelector(parentId);
            return selector.GetFolderDao(parentId).GetFolder(title, selector.ConvertId(parentId));
        }

        public Folder GetRootFolder(object folderId)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                return folderDao.GetRootFolder(selector.ConvertId(folderId));
            }
        }

        public Folder GetRootFolderByFile(object fileId)
        {
            var selector = GetSelector(fileId);
            using (var folderDao = selector.GetFolderDao(fileId))
            {
                return folderDao.GetRootFolderByFile(selector.ConvertId(fileId));
            }
        }

        public List<Folder> GetFolders(object parentId)
        {
            var selector = GetSelector(parentId);
            using (var folderDao = selector.GetFolderDao(parentId))
            {
                return folderDao
                        .GetFolders(selector.ConvertId(parentId))
                        .Where(r => r != null)
                        .ToList();
            }
        }

        public List<Folder> GetFolders(object parentId, OrderBy orderBy, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool withSubfolders = false)
        {
            var selector = GetSelector(parentId);
            using (var folderDao = selector.GetFolderDao(parentId))
            {
                var result = folderDao.GetFolders(selector.ConvertId(parentId), orderBy, filterType, subjectGroup, subjectID, searchText, withSubfolders)
                        .Where(r => r != null).ToList();

                if (!result.Any()) return new List<Folder>();

                if (!Default.IsMatch(parentId))
                {
                    SetSharedProperty(result);
                }

                return result;
            }
        }

        public List<Folder> GetFolders(object[] folderIds, FilterType filterType = FilterType.None, bool subjectGroup = false, Guid? subjectID = null, string searchText = "", bool searchSubfolders = false, bool checkShare = true)
        {
            var result = Enumerable.Empty<Folder>();

            foreach (var selector in GetSelectors())
            {
                var selectorLocal = selector;
                var matchedIds = folderIds.Where(selectorLocal.IsMatch).ToList();

                if (!matchedIds.Any()) continue;

                result = result.Concat(matchedIds.GroupBy(selectorLocal.GetIdCode)
                                                .SelectMany(matchedId =>
                                                {
                                                    using (var folderDao = selectorLocal.GetFolderDao(matchedId.FirstOrDefault()))
                                                    {
                                                        return folderDao
                                                            .GetFolders(matchedId.Select(selectorLocal.ConvertId).ToArray(),
                                                                filterType, subjectGroup, subjectID, searchText, searchSubfolders, checkShare);
                                                    }
                                                })
                                                .Where(r => r != null));
            }

            return result.Distinct().ToList();
        }

        public List<Folder> GetParentFolders(object folderId)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                return folderDao.GetParentFolders(selector.ConvertId(folderId));
            }
        }

        public object SaveFolder(Folder folder)
        {
            if (folder == null) throw new ArgumentNullException("folder");

            if (folder.ID != null)
            {
                var folderId = folder.ID;
                var selector = GetSelector(folderId);
                folder.ID = selector.ConvertId(folderId);
                using (var folderDao = selector.GetFolderDao(folderId))
                {
                    var newFolderId = folderDao.SaveFolder(folder);
                    folder.ID = folderId;
                    return newFolderId;
                }
            }
            if (folder.ParentFolderID != null)
            {
                var folderId = folder.ParentFolderID;
                var selector = GetSelector(folderId);
                folder.ParentFolderID = selector.ConvertId(folderId);
                using (var folderDao = selector.GetFolderDao(folderId))
                {
                    var newFolderId = folderDao.SaveFolder(folder);
                    folder.ParentFolderID = folderId;
                    return newFolderId;
                }

            }
            throw new ArgumentException("No folder id or parent folder id to determine provider");
        }

        public void DeleteFolder(object folderId)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                folderDao.DeleteFolder(selector.ConvertId(folderId));
            }
        }

        public object MoveFolder(object folderId, object toFolderId, CancellationToken? cancellationToken)
        {
            var selector = GetSelector(folderId);
            if (IsCrossDao(folderId, toFolderId))
            {
                var newFolder = PerformCrossDaoFolderCopy(folderId, toFolderId, true, cancellationToken);
                return newFolder != null ? newFolder.ID : null;
            }
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                return folderDao.MoveFolder(selector.ConvertId(folderId), selector.ConvertId(toFolderId), null);
            }
        }

        public Folder CopyFolder(object folderId, object toFolderId, CancellationToken? cancellationToken)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                return IsCrossDao(folderId, toFolderId)
                    ? PerformCrossDaoFolderCopy(folderId, toFolderId, false, cancellationToken)
                    : folderDao.CopyFolder(selector.ConvertId(folderId), selector.ConvertId(toFolderId), null);
            }
        }

        public IDictionary<object, string> CanMoveOrCopy(object[] folderIds, object to)
        {
            if (!folderIds.Any()) return new Dictionary<object, string>();

            var selector = GetSelector(to);
            var matchedIds = folderIds.Where(selector.IsMatch).ToArray();

            if (!matchedIds.Any()) return new Dictionary<object, string>();

            using (var folderDao = selector.GetFolderDao(matchedIds.FirstOrDefault()))
            {
                return folderDao.CanMoveOrCopy(matchedIds, to);
            }
        }

        public object RenameFolder(Folder folder, string newTitle)
        {
            var folderId = folder.ID;
            var selector = GetSelector(folderId);
            folder.ID = selector.ConvertId(folderId);
            folder.ParentFolderID = selector.ConvertId(folder.ParentFolderID);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                return folderDao.RenameFolder(folder, newTitle);
            }
        }

        public int GetItemsCount(object folderId)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                return folderDao.GetItemsCount(selector.ConvertId(folderId));
            }
        }

        public bool IsEmpty(object folderId)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                return folderDao.IsEmpty(selector.ConvertId(folderId));
            }
        }

        public bool UseTrashForRemove(Folder folder)
        {
            var selector = GetSelector(folder.ID);
            using (var folderDao = selector.GetFolderDao(folder.ID))
            {
                return folderDao.UseTrashForRemove(folder);
            }
        }

        public bool UseRecursiveOperation(object folderId, object toRootFolderId)
        {
            var selector = GetSelector(folderId);
            bool useRecursive;

            using (var folderDao = selector.GetFolderDao(folderId))
            {
                useRecursive = folderDao.UseRecursiveOperation(folderId, null);
            }
            if (toRootFolderId != null)
            {
                var toFolderSelector = GetSelector(toRootFolderId);

                using (var folderDao = toFolderSelector.GetFolderDao(toRootFolderId))
                {
                    useRecursive = useRecursive && folderDao.UseRecursiveOperation(folderId, toFolderSelector.ConvertId(toRootFolderId));
                }
            }
            return useRecursive;
        }

        public bool CanCalculateSubitems(object entryId)
        {
            var selector = GetSelector(entryId);
            using (var folderDao = selector.GetFolderDao(entryId))
            {
                return folderDao.CanCalculateSubitems(entryId);
            }
        }

        public long GetMaxUploadSize(object folderId, bool chunkedUpload)
        {
            var selector = GetSelector(folderId);
            using (var folderDao = selector.GetFolderDao(folderId))
            {
                var storageMaxUploadSize = folderDao.GetMaxUploadSize(selector.ConvertId(folderId), chunkedUpload);

                if (storageMaxUploadSize == -1 || storageMaxUploadSize == long.MaxValue)
                    storageMaxUploadSize = 1024L * 1024L * 1024L;

                return storageMaxUploadSize;
            }
        }

        #region Only for TMFolderDao

        public void ReassignFolders(object[] folderIds, Guid newOwnerId)
        {
            foreach (var selector in GetSelectors())
            {
                var selectorLocal = selector;
                var matchedIds = folderIds.Where(selectorLocal.IsMatch);

                if (!matchedIds.Any()) continue;

                foreach (var matchedId in matchedIds.GroupBy(selectorLocal.GetIdCode))
                {
                    using (var folderDao = selectorLocal.GetFolderDao(matchedId.FirstOrDefault()))
                    {
                        folderDao.ReassignFolders(matchedId.Select(selectorLocal.ConvertId).ToArray(), newOwnerId);
                    }
                }
            }
        }

        public IEnumerable<Folder> Search(string text, bool bunch)
        {
            using (var folderDao = TryGetFolderDao())
            {
                return folderDao.Search(text, bunch);
            }
        }

        public object GetFolderID(string module, string bunch, string data, bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderID(module, bunch, data, createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public IEnumerable<object> GetFolderIDs(string module, string bunch, IEnumerable<string> data, bool createIfNotExists)
        {
            using (var folderDao = TryGetFolderDao())
            {
                return folderDao.GetFolderIDs(module, bunch, data, createIfNotExists);
            }
        }

        public object GetFolderIDCommon(bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDCommon(createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDProjects(bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDProjects(createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDPhotos(bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDProjects(createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public string GetBunchObjectID(object folderID)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetBunchObjectID(folderID);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public Dictionary<string, string> GetBunchObjectIDs(List<object> folderIDs)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetBunchObjectIDs(folderIDs);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDUser(bool createIfNotExists, Guid? userId = null)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDUser(createIfNotExists, userId);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDShare(bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDShare(createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDRecent(bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDRecent(createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDFavorites(bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDFavorites(createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDTemplates(bool createIfNotExists)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDTemplates(createIfNotExists);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDPrivacy(bool createIfNotExists, Guid? userId = null)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDPrivacy(createIfNotExists, userId);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        public object GetFolderIDTrash(bool createIfNotExists, Guid? userId = null)
        {
            foreach (var selector in GetSelectors())
            {
                using (var folderDao = selector.GetFolderDao(null))
                {
                    var folderId = folderDao.GetFolderIDTrash(createIfNotExists, userId);
                    if (folderId != null) return folderId;
                }
            }
            return null;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/Core/PeopleProduct.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Core;
using ASC.Web.Core;
using ASC.Web.Core.Utility;
using ASC.Web.People.Resources;

namespace ASC.Web.People.Core
{
    public class PeopleProduct : Product
    {
        internal const string ProductPath = "~/Products/People/";

        private ProductContext _context;

        public static Guid ID
        {
            get { return new Guid("{F4D98AFD-D336-4332-8778-3C6945C81EA0}"); }
        }

        public override bool Visible { get { return true; } }

        public override ProductContext Context
        {
            get { return _context; }
        }

        public override string Name
        {
            get { return PeopleResource.ProductName; }
        }

        public override string Description
        {
            get
            {
                var id = SecurityContext.CurrentAccount.ID;

                if (CoreContext.UserManager.IsUserInGroup(id, ASC.Core.Users.Constants.GroupAdmin.ID) || CoreContext.UserManager.IsUserInGroup(id, ID))
                    return PeopleResource.ProductDescriptionEx;

                return PeopleResource.ProductDescription;
            }
        }

        public override Guid ProductID
        {
            get { return ID; }
        }

        public override string StartURL
        {
            get { return ProductPath; }
        }

        public override string HelpURL
        {
            get { return string.Concat(ProductPath, "Help.aspx"); }
        }

        public static string GetStartURL()
        {
            return ProductPath;
        }

        public override string ProductClassName
        {
            get { return "people"; }
        }

        public override void Init()
        {
            _context = new ProductContext
            {
                MasterPageFile = "~/Products/People/PeopleBaseTemplate.Master",
                DisabledIconFileName = "product_disabled_logo.png",
                IconFileName = "product_logo.png",
                LargeIconFileName = "product_logolarge.svg",
                DefaultSortOrder = 50,
                AdminOpportunities = () => PeopleResource.ProductAdminOpportunities.Split('|').ToList(),
                UserOpportunities = () => PeopleResource.ProductUserOpportunities.Split('|').ToList()
            };

            SearchHandlerManager.Registry(new SearchHandler());
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Autoreply/Utility/Html/HtmlSanitizer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using HtmlAgilityPack;

namespace ASC.Mail.Autoreply.Utility.Html
{
    public class HtmlSanitizer
    {
        private static readonly List<string> MaliciousTags = new List<string> { "script", "style" };
        private static readonly List<string> LineBreakers = new List<string> { "p", "div", "blockquote", "br" };  
        private static readonly List<string> WhiteList = new List<string> {"b", "strong", "it", "em", "dfn", "sub", "sup", "strike", "s", "del", "code", "kbd", "samp", "ins", "h1", "h2", "h3", "h4", "h5", "h6"};

        public static String Sanitize(String html)
        {
            if (String.IsNullOrEmpty(html))
                return html;

            var doc = new HtmlDocument();
            doc.LoadHtml(html);
            
            var sw = new StringWriter();
            ProcessNode(doc.DocumentNode, sw);
            sw.Flush();
            return sw.ToString();
        }

        private static void ProcessContent(HtmlNode node, TextWriter outText)
        {
            foreach (var child in node.ChildNodes)
            {
                ProcessNode(child, outText);
            }
        }

        private static void ProcessNode(HtmlNode node, TextWriter outText)
        {
            switch (node.NodeType)
            {
                case HtmlNodeType.Comment:
                    break;

                case HtmlNodeType.Document:
                    ProcessContent(node, outText);
                    break;

                case HtmlNodeType.Element:
                    var name = node.Name.ToLowerInvariant();

                    if (MaliciousTags.Contains(name))
                        break;

                    if (WhiteList.Contains(name) && node.HasChildNodes && node.Closed)
                    {
                        outText.Write("<{0}>", name);
                        ProcessContent(node, outText);
                        outText.Write("</{0}>", name);
                        break;
                    }

                    if (name.Equals("img") && node.HasAttributes && node.Attributes["src"] != null)
                    {
                        outText.Write("<img src=\"{0}\"/>", node.Attributes["src"].Value);
                    }
                    else if (LineBreakers.Contains(name))
                    {
                        outText.Write("<br>");
                    }

                    if (node.HasChildNodes)
                        ProcessContent(node, outText);
                    
                    break;

                case HtmlNodeType.Text:
                    var text = ((HtmlTextNode) node).Text;

                    if (HtmlNode.IsOverlappedClosingElement(text))
                        break;

                    if (text.Trim().Length > 0)
                        outText.Write(text);

                    break;
            }
        }
    }
}


<|start_filename|>module/ASC.Feed.Aggregator/Config/FeedConfigurationSection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;

namespace ASC.Feed.Aggregator.Config
{
    public class FeedConfigurationSection : ConfigurationSection
    {
        [ConfigurationProperty("serverRoot", DefaultValue = "http://*/")]
        public string ServerRoot
        {
            get { return (string)this["serverRoot"]; }
            set { base["serverRoot"] = value; }
        }

        [ConfigurationProperty("aggregatePeriod", DefaultValue = "0:5:0")]
        public TimeSpan AggregatePeriod
        {
            get { return (TimeSpan)this["aggregatePeriod"]; }
        }

        [ConfigurationProperty("aggregateInterval", DefaultValue = "14.0:0:0")]
        public TimeSpan AggregateInterval
        {
            get { return (TimeSpan)this["aggregateInterval"]; }
        }

        [ConfigurationProperty("removePeriod", DefaultValue = "1.0:0:0")]
        public TimeSpan RemovePeriod
        {
            get { return (TimeSpan)this["removePeriod"]; }
        }


        public static FeedConfigurationSection GetFeedSection()
        {
            return (FeedConfigurationSection)ConfigurationManagerExtension.GetSection("feed");
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Cases.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.CRM.Core;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Controls.Cases;
using ASC.Web.CRM.Controls.Common;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.UserControls.Common.LoaderPage;
using ASC.Web.Studio.Utility;

namespace ASC.Web.CRM
{
    public partial class Cases : BasePage
    {
        #region Events

        protected override void PageLoad()
        {
            int caseID;

            if (int.TryParse(UrlParameters.ID, out caseID))
            {
                ASC.CRM.Core.Entities.Cases targetCase = DaoFactory.CasesDao.GetByID(caseID);

                if (targetCase == null || !CRMSecurity.CanAccessTo(targetCase))
                    Response.Redirect(PathProvider.StartURL() + "Cases.aspx");

                if (string.Compare(UrlParameters.Action, "manage", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    if (!CRMSecurity.CanEdit(targetCase))
                    {
                        Response.Redirect(PathProvider.StartURL() + "Cases.aspx");
                    }
                    ExecCasesActionView(targetCase);
                }
                else
                {
                    ExecCasesDetailsView(targetCase);
                }
            }
            else
            {
                if (string.Compare(UrlParameters.Action, "manage", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    ExecCasesActionView(null);
                }
                else if (string.Compare(UrlParameters.Action, "import", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    ExecImportView();
                }
                else
                {
                    ExecListCasesView();
                }
            }
        }

        #endregion

        #region Methods

        protected void ExecImportView()
        {
            var importViewControl = (ImportFromCSVView)LoadControl(ImportFromCSVView.Location);
            importViewControl.EntityType = EntityType.Case;
            CommonContainerHolder.Controls.Add(importViewControl);

            Master.CurrentPageCaption = CRMCasesResource.ImportCases;
            Title = HeaderStringHelper.GetPageTitle(CRMCasesResource.ImportCases);
        }

        protected void ExecListCasesView()
        {
            CommonContainerHolder.Controls.Add(LoadControl(ListCasesView.Location));
            Title = HeaderStringHelper.GetPageTitle(Master.CurrentPageCaption ?? CRMCasesResource.AllCases);
            loaderHolder.Controls.Add(LoadControl(LoaderPage.Location));
        }

        protected void ExecCasesDetailsView(ASC.CRM.Core.Entities.Cases targetCase)
        {
            var casesDetailsViewControl = (CasesDetailsView)LoadControl(CasesDetailsView.Location);
            casesDetailsViewControl.TargetCase = targetCase;
            CommonContainerHolder.Controls.Add(casesDetailsViewControl);

            var title = targetCase.Title;

            Master.CurrentPageCaption = title;

            Master.CommonContainerHeader = Global.RenderItemHeaderWithMenu(title.HtmlEncode(), EntityType.Case, CRMSecurity.IsPrivate(targetCase), true);

            TabsHolder.Visible = true;

            Title = HeaderStringHelper.GetPageTitle(title);
        }

        protected void ExecCasesActionView(ASC.CRM.Core.Entities.Cases targetCase)
        {
            var casesActionViewControl = (CasesActionView)LoadControl(CasesActionView.Location);

            casesActionViewControl.TargetCase = targetCase;
            CommonContainerHolder.Controls.Add(casesActionViewControl);

            var headerTitle = targetCase == null ? CRMCasesResource.CreateNewCase : String.Format(CRMCasesResource.EditCaseHeader, targetCase.Title);

            Master.CurrentPageCaption = headerTitle;
            Title = HeaderStringHelper.GetPageTitle(headerTitle);
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Masters/ClientScripts/ClientUserResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;

using ASC.Core;
using ASC.Core.Users;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Core;
using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.Core.Users;
using ASC.Web.Projects.Classes;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Web.Projects.Masters.ClientScripts
{
    public class ClientUserResources : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Projects.Master"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            var filter = new TaskFilter
            {
                SortBy = "title",
                SortOrder = true,
                ProjectStatuses = new List<ProjectStatus> { ProjectStatus.Open }
            };

            if (!ProjectsCommonSettings.Load().HideEntitiesInPausedProjects)
            {
                filter.ProjectStatuses.Add(ProjectStatus.Paused);
            }

            using (var scope = DIHelper.Resolve())
            {
                var engineFactory = scope.Resolve<EngineFactory>();
                var projectSecurity = scope.Resolve<ProjectSecurity>();
                var projects = engineFactory.ProjectEngine.GetByFilter(filter)
                    .Select(pr => new
                    {
                        id = pr.ID,
                        title = pr.Title,
                        responsible = pr.Responsible,
                        //created = (ApiDateTime) pr.CreateOn,
                        security = new
                        {
                            canCreateMilestone = projectSecurity.CanCreate<Milestone>(pr),
                            canCreateMessage = projectSecurity.CanCreate<Message>(pr),
                            canCreateTask = projectSecurity.CanCreate<Task>(pr),
                            canCreateTimeSpend = projectSecurity.CanCreate<TimeSpend>(pr),
                            canEditTeam = projectSecurity.CanEditTeam(pr),
                            canReadFiles = projectSecurity.CanReadFiles(pr),
                            canReadMilestones = projectSecurity.CanRead<Milestone>(pr),
                            canReadMessages = projectSecurity.CanRead<Message>(pr),
                            canReadTasks = projectSecurity.CanRead<Task>(pr),
                            isInTeam = projectSecurity.IsInTeam(pr, SecurityContext.CurrentAccount.ID, false),
                            canLinkContact = projectSecurity.CanLinkContact(pr)
                        },
                        isPrivate = pr.Private,
                        status = pr.Status,
                        taskCountTotal = pr.TaskCountTotal
                    }).ToList();

                var tags = engineFactory.TagEngine.GetTags()
                        .Select(r => new { value = r.Key, title = r.Value.HtmlEncode() })
                        .ToList();

                var result = new List<KeyValuePair<string, object>>(1)
                {
                    RegisterObject(
                        new
                        {
                            Global.EntryCountOnPage,
                            Global.VisiblePageCount,
                            Projects = new {response = projects},
                            Tags = new {response = tags},
                            ProjectsCount = engineFactory.ProjectEngine.GetByFilterCount(new TaskFilter())
                        })
                };

                filter = new TaskFilter
                {
                    SortBy = "deadline",
                    SortOrder = false,
                    MilestoneStatuses = new List<MilestoneStatus> { MilestoneStatus.Open }
                };

                var milestones = engineFactory.MilestoneEngine.GetByFilter(filter)
                    .Select(m => new
                    {
                        id = m.ID,
                        title = m.Title,
                        deadline = SetDate(m.DeadLine, TimeZoneInfo.Local),
                        projectOwner = new { id = m.Project.ID },
                        status = (int)m.Status
                    }).ToList();

                result.Add(RegisterObject(new { Milestones = new { response = milestones } }));

                return result;
            }
        }

        public static string SetDate(DateTime value, TimeZoneInfo timeZone)
        {
            var timeZoneOffset = TimeSpan.Zero;
            var utcTime = DateTime.MinValue;

            if (value.Kind == DateTimeKind.Local)
            {
                value = TimeZoneInfo.ConvertTimeToUtc(new DateTime(value.Ticks, DateTimeKind.Unspecified), timeZone);
            }

            if (value.Kind == DateTimeKind.Utc)
            {
                utcTime = value; //Set UTC time
                timeZoneOffset = timeZone.GetUtcOffset(value);
            }

            utcTime = utcTime.Add(timeZoneOffset);

            var dateString = utcTime.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffff", CultureInfo.InvariantCulture);
            var offsetString = timeZoneOffset.Ticks == 0 ? "Z" : string.Format("{0}{1,2:00}:{2,2:00}", timeZoneOffset.Ticks > 0 ? "+" : "", timeZoneOffset.Hours, timeZoneOffset.Minutes);
            return dateString + offsetString;
        }

        protected override string GetCacheHash()
        {
            using (var scope = DIHelper.Resolve())
            {
                var engineFactory = scope.Resolve<EngineFactory>();
                var currentUserId = SecurityContext.CurrentAccount.ID.ToString();
                var userLastModified = CoreContext.UserManager.GetMaxUsersLastModified().Ticks.ToString(CultureInfo.InvariantCulture);
                var projectMaxLastModified = engineFactory.ProjectEngine.GetMaxLastModified().ToString(CultureInfo.InvariantCulture);
                var milestoneMaxLastModified = engineFactory.MilestoneEngine.GetLastModified();
                var paused = ProjectsCommonSettings.LoadForCurrentUser().HideEntitiesInPausedProjects;
                return string.Format("{0}|{1}|{2}|{3}|{4}", currentUserId, userLastModified, projectMaxLastModified, milestoneMaxLastModified, paused);
            }
        }
    }

    public class ClientProjectResources : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Projects.Master"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            var currentProject = "0";

            if (context.Request.GetUrlRewriter() != null)
            {
                currentProject = HttpUtility.ParseQueryString(context.Request.GetUrlRewriter().Query)["prjID"];

                if (string.IsNullOrEmpty(currentProject) && context.Request.UrlReferrer != null)
                {
                    currentProject = HttpUtility.ParseQueryString(context.Request.UrlReferrer.Query)["prjID"];
                }
            }
            using (var scope = DIHelper.Resolve())
            {
                var engineFactory = scope.Resolve<EngineFactory>();

                var team = engineFactory.ProjectEngine.GetTeam(Convert.ToInt32(currentProject))
                    .Select(r => new
                    {
                        id = r.UserInfo.ID,
                        displayName = DisplayUserSettings.GetFullUserName(r.UserInfo.ID),
                        email = r.UserInfo.Email,
                        userName = r.UserInfo.UserName,
                        avatarSmall = UserPhotoManager.GetSmallPhotoURL(r.UserInfo.ID),
                        avatar = UserPhotoManager.GetBigPhotoURL(r.UserInfo.ID),
                        status = r.UserInfo.Status,
                        groups = CoreContext.UserManager.GetUserGroups(r.UserInfo.ID).Select(x => new
                        {
                            id = x.ID,
                            name = x.Name,
                            manager =
                                CoreContext.UserManager.GetUsers(CoreContext.UserManager.GetDepartmentManager(x.ID))
                                    .UserName
                        }).ToList(),
                        isVisitor = r.UserInfo.IsVisitor(),
                        isAdmin = r.UserInfo.IsAdmin(),
                        isOwner = r.UserInfo.IsOwner(),
                        isManager = r.IsManager,
                        canReadFiles = r.CanReadFiles,
                        canReadMilestones = r.CanReadMilestones,
                        canReadMessages = r.CanReadMessages,
                        canReadTasks = r.CanReadTasks,
                        canReadContacts = r.CanReadContacts,
                        title = r.UserInfo.Title,
                        profileUrl = r.UserInfo.GetUserProfilePageURL()
                    }).OrderBy(r => r.displayName).ToList();

                return new List<KeyValuePair<string, object>>(1)
                {
                    RegisterObject(
                        new
                        {
                            Team = new {response = team},
                            projectFolder = engineFactory.FileEngine.GetRoot(Convert.ToInt32(currentProject))
                        })
                };
            }
        }

        protected override string GetCacheHash()
        {
            var currentUserId = SecurityContext.CurrentAccount.ID;

            var currentProject = "0";

            if (HttpContext.Current.Request.GetUrlRewriter() != null)
            {
                currentProject = HttpUtility.ParseQueryString(HttpContext.Current.Request.GetUrlRewriter().Query)["prjID"];

                if (string.IsNullOrEmpty(currentProject) && HttpContext.Current.Request.UrlReferrer != null)
                {
                    currentProject = HttpUtility.ParseQueryString(HttpContext.Current.Request.UrlReferrer.Query)["prjID"];
                }
            }

            var teamMaxLastModified = DateTime.UtcNow;
            teamMaxLastModified = teamMaxLastModified.AddSeconds(-teamMaxLastModified.Second);

            return string.Format("{0}|{1}|{2}", currentUserId.ToString(), currentProject, teamMaxLastModified);
        }
    }

    public class ClientCurrentUserResources : ClientScript
    {
        protected override string BaseNamespace
        {
            get { return "ASC.Projects.Master"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            using (var scope = DIHelper.Resolve())
            {
                var projectSecurity = scope.Resolve<ProjectSecurity>();
                return new List<KeyValuePair<string, object>>(1)
                {
                    RegisterObject(
                        new
                        {
                            CanCreateProject = projectSecurity.CanCreate<Project>(null),
                            IsModuleAdmin = projectSecurity.CurrentUserAdministrator,
                            ProjectsCommonSettings.LoadForCurrentUser().StartModuleType,
                            WebItemManager.ProjectsProductID
                        })
                };
            }
        }

        protected override string GetCacheHash()
        {
            using (var scope = DIHelper.Resolve())
            {
                var projectSecurity = scope.Resolve<ProjectSecurity>();

                return SecurityContext.CurrentAccount.ID.ToString() +
                       CoreContext.UserManager.GetMaxUsersLastModified().Ticks.ToString(CultureInfo.InvariantCulture) +
                       CoreContext.UserManager.GetMaxGroupsLastModified().Ticks.ToString(CultureInfo.InvariantCulture) +
                       projectSecurity.CanCreate<Project>(null) +
                       ProjectsCommonSettings.LoadForCurrentUser().StartModuleType;
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/DIHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Threading.Tasks;
using System.Web;

using ASC.Common.Data;
using ASC.Common.DependencyInjection;
using ASC.Common.Logging;
using ASC.Common.Web;
using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Projects.Classes;
using ASC.Web.Studio.Utility;

using Autofac;
using Autofac.Core;
using Autofac.Core.Lifetime;
using Autofac.Core.Resolving;

namespace ASC.Web.Projects.Core
{
    public static class DIHelper
    {
        internal static IContainer Builder;
        private static bool isRegistered;
        private static readonly object Locker = new object();

        public static void Register()
        {
            if (isRegistered) return;

            lock (Locker)
            {
                if (isRegistered) return;

                var container = AutofacConfigLoader.Load("projects");

                container.Register(c => DbManager.FromHttpContext(Global.DbID))
                    .AsSelf()
                    .As<IDbManager>()
                    .InstancePerRequest();

                container.Register(c => new ProjectSecurityCommon())
                    .AsSelf()
                    .InstancePerRequest()
                    .PropertiesAutowired();

                container.Register(c => new ProjectSecurityProject())
                    .AsSelf()
                    .As<ProjectSecurityTemplate<Project>>()
                    .InstancePerRequest()
                    .PropertiesAutowired();

                container.Register(c => new ProjectSecurityTask())
                    .AsSelf()
                    .As<ProjectSecurityTemplate<ASC.Projects.Core.Domain.Task>>()
                    .InstancePerRequest()
                    .PropertiesAutowired();

                container.Register(c => new ProjectSecurityMilestone())
                    .AsSelf()
                    .As<ProjectSecurityTemplate<Milestone>>()
                    .InstancePerRequest()
                    .PropertiesAutowired();

                container.Register(c => new ProjectSecurityMessage())
                    .AsSelf()
                    .As<ProjectSecurityTemplate<Message>>()
                    .InstancePerRequest()
                    .PropertiesAutowired();

                container.Register(c => new ProjectSecurityTimeTracking())
                    .AsSelf()
                    .As<ProjectSecurityTemplate<TimeSpend>>()
                    .InstancePerRequest()
                    .PropertiesAutowired();

                Builder = container.Build();
                isRegistered = true;
            }
        }

        public static ILifetimeScope Resolve(bool disableNotification = false)
        {
            return Resolve(TenantProvider.CurrentTenantID, disableNotification);
        }

        public static ILifetimeScope Resolve(int tenantID, bool disableNotification = false)
        {
            Register();

            var scope = FromHttpContext();
            scope.Resolve<IDbManager>();

            var tenantParameter = new TypedParameter(typeof(int), tenantID);
            var disableNotificationParameter = new TypedParameter(typeof(bool), disableNotification);

            scope.Resolve<IDaoFactory>(tenantParameter);
            scope.Resolve<EngineFactory>(disableNotificationParameter);

            return scope;
        }

        private static ILifetimeScope FromHttpContext()
        {
            if (HttpContext.Current != null)
            {
                var scope = DisposableHttpContext.Current["scope"] as ILifetimeScope;
                if (scope == null)
                {
                    scope = ToHttpContext();
                }
                else
                {
                    scope = new LifeTimeScopeProxy(scope);
                    try
                    {
                        scope.Resolve<IDbManager>();
                    }
                    catch (ObjectDisposedException e)
                    {
                        LogManager.GetLogger("ASC").Error("FromHttpContext ObjectDisposedException", e);
                        scope = ToHttpContext();
                    }
                }

                return scope;
            }

            return Builder.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
        }

        private static ILifetimeScope ToHttpContext()
        {
            var scope = Builder.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
            var proxy = new LifeTimeScopeProxy(scope);
            DisposableHttpContext.Current["scope"] = scope;
            return proxy;
        }

        public static TypedParameter GetParameter<T>(T data)
        {
            return new TypedParameter(typeof(T), data);
        }
    }

    internal class LifeTimeScopeProxy : ILifetimeScope
    {
        private ILifetimeScope LifetimeScope { get; set; }

        public LifeTimeScopeProxy(ILifetimeScope lifetimeScope)
        {
            LifetimeScope = lifetimeScope;
            LifetimeScope.ChildLifetimeScopeBeginning += ChildLifetimeScopeBeginning;
            LifetimeScope.CurrentScopeEnding += CurrentScopeEnding;
            LifetimeScope.ResolveOperationBeginning += ResolveOperationBeginning;
        }

        public object ResolveComponent(ResolveRequest request)
        {
            return LifetimeScope.ResolveComponent(request);
        }

        public IComponentRegistry ComponentRegistry { get { return LifetimeScope.ComponentRegistry; } }
        public ValueTask DisposeAsync()
        {
            if (HttpContext.Current == null)
            {
                return LifetimeScope.DisposeAsync();
            }

            return default(ValueTask);
        }

        public void Dispose()
        {
            if (HttpContext.Current == null)
            {
                LifetimeScope.Dispose();
            }

        }

        public ILifetimeScope BeginLifetimeScope()
        {
            return LifetimeScope.BeginLifetimeScope();
        }

        public ILifetimeScope BeginLifetimeScope(object tag)
        {
            return LifetimeScope.BeginLifetimeScope(tag);
        }

        public ILifetimeScope BeginLifetimeScope(Action<ContainerBuilder> configurationAction)
        {
            return LifetimeScope.BeginLifetimeScope(configurationAction);
        }

        public ILifetimeScope BeginLifetimeScope(object tag, Action<ContainerBuilder> configurationAction)
        {
            return LifetimeScope.BeginLifetimeScope(tag, configurationAction);
        }

        public IDisposer Disposer { get { return LifetimeScope.Disposer; } }
        public object Tag { get { return LifetimeScope.Tag; } }

        public event EventHandler<LifetimeScopeBeginningEventArgs> ChildLifetimeScopeBeginning;
        public event EventHandler<LifetimeScopeEndingEventArgs> CurrentScopeEnding;
        public event EventHandler<ResolveOperationBeginningEventArgs> ResolveOperationBeginning;
    }
}

<|start_filename|>module/ASC.TelegramService/Commands/UserCommands.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Caching;
using System.Threading.Tasks;

using ASC.Core.Common.Notify.Telegram;
using ASC.TelegramService.Core;

namespace ASC.TelegramService.Commands
{
    public class UserCommands : CommandContext
    {
        [Command("start")]
        public async Task StartCommand(string token)
        {
            if (string.IsNullOrEmpty(token)) return;

            var user = MemoryCache.Default.Get(token);

            if (user != null)
            {
                MemoryCache.Default.Remove(token);
                MemoryCache.Default.Remove((string)user);
                var split = ((string)user).Split(':');

                var guid = Guid.Parse(split[0]);
                var tenant = int.Parse(split[1]);

                if (tenant == TenantId)
                {
                    CachedTelegramDao.Instance.RegisterUser(guid, tenant, Context.User.Id);
                    await ReplyAsync("Ok!");
                    return;
                }
            }

            await ReplyAsync("Error");
        }
    }
}

<|start_filename|>module/ASC.Mail/Services/ASC.Mail.Aggregator.CollectionService/Queue/Data/MailboxData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Runtime.Serialization;

namespace ASC.Mail.Aggregator.CollectionService.Queue.Data
{
    [DataContract]
    public class MailboxData
    {
        [DataMember(Name = "tenant")]
        public int TenantId { get; set; }

        [DataMember(Name = "user")]
        public string UserId { get; set; }

        [DataMember(Name = "id")]
        public int MailboxId { get; set; }

        [DataMember]
        public string EMail { get; set; }

        [DataMember(Name = "imap")]
        public bool Imap { get; set; }

        [DataMember(Name = "is_teamlab")]
        public bool IsTeamlab { get; set; }

        [DataMember(Name = "size")]
        public long Size { get; set; }

        [DataMember(Name = "messages_count")]
        public int MessagesCount { get; set; }
    }
}


<|start_filename|>module/ASC.AuditTrail/Mappers/ProjectsActionMapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.MessagingSystem;

namespace ASC.AuditTrail.Mappers
{
    internal class ProjectsActionsMapper
    {
        public static Dictionary<MessageAction, MessageMaps> GetMaps()
        {
            return new Dictionary<MessageAction, MessageMaps>
                {
                    #region projects

                    {
                        MessageAction.ProjectCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ProjectCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectCreatedFromTemplate, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ProjectCreatedFromTemplate",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ProjectUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectUpdatedStatus, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ProjectUpdatedStatus",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectFollowed, new MessageMaps
                            {
                                ActionTypeTextResourceName = "FollowActionType",
                                ActionTextResourceName = "ProjectFollowed",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectUnfollowed, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnfollowActionType",
                                ActionTextResourceName = "ProjectUnfollowed",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ProjectDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },

                    #endregion
                    
                    #region team 

                    {
                        MessageAction.ProjectDeletedMember, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ProjectDeletedMember",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectUpdatedTeam, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ProjectUpdatedTeam",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectUpdatedMemberRights, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateAccessActionType",
                                ActionTextResourceName = "ProjectUpdatedMemberRights",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },

                    #endregion

                    #region contacts

                    {
                        MessageAction.ProjectLinkedCompany, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "ProjectLinkedCompany",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectUnlinkedCompany, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "ProjectUnlinkedCompany",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectLinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "ProjectLinkedPerson",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectUnlinkedPerson, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "ProjectUnlinkedPerson",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },
                    {
                        MessageAction.ProjectLinkedContacts, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "ProjectLinkedContacts",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },

                    #endregion

                    #region milestones

                    {
                        MessageAction.MilestoneCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "MilestoneCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "MilestonesModule"
                            }
                    },
                    {
                        MessageAction.MilestoneUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "MilestoneUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "MilestonesModule"
                            }
                    },
                    {
                        MessageAction.MilestoneUpdatedStatus, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "MilestoneUpdatedStatus",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "MilestonesModule"
                            }
                    },
                    {
                        MessageAction.MilestoneDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "MilestoneDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "MilestonesModule"
                            }
                    },

                    #endregion

                    #region tasks

                    {
                        MessageAction.TaskCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "TaskCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskCreatedFromDiscussion, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "TaskCreatedFromDiscussion",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TaskUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskUpdatedStatus, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TaskUpdatedStatus",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskMovedToMilestone, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TaskMovedToMilestone",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskUnlinkedMilestone, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TaskUnlinkedMilestone",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskUpdatedFollowing, new MessageMaps
                            {
                                ActionTypeTextResourceName = "FollowActionType",
                                ActionTextResourceName = "TaskUpdatedFollowing",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskAttachedFiles, new MessageMaps
                            {
                                ActionTypeTextResourceName = "AttachActionType",
                                ActionTextResourceName = "TaskAttachedFiles",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskDetachedFile, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DetachActionType",
                                ActionTextResourceName = "TaskDetachedFile",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TasksLinked, new MessageMaps
                            {
                                ActionTypeTextResourceName = "LinkActionType",
                                ActionTextResourceName = "TasksLinked",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TasksUnlinked, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UnlinkActionType",
                                ActionTextResourceName = "TasksUnlinked",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "TaskDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskCommentCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "TaskCommentCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskCommentUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TaskCommentUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.TaskCommentDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "TaskCommentDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },

                    #endregion

                    #region subtasks

                    {
                        MessageAction.SubtaskCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "SubtaskCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.SubtaskUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "SubtaskUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.SubtaskUpdatedStatus, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "SubtaskUpdatedStatus",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },
                    {
                        MessageAction.SubtaskDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "SubtaskDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TasksModule"
                            }
                    },

                    #endregion

                    #region discussions

                    {
                        MessageAction.DiscussionCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "DiscussionCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "DiscussionUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionUpdatedFollowing, new MessageMaps
                            {
                                ActionTypeTextResourceName = "FollowActionType",
                                ActionTextResourceName = "DiscussionUpdatedFollowing",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionAttachedFiles, new MessageMaps
                            {
                                ActionTypeTextResourceName = "AttachActionType",
                                ActionTextResourceName = "DiscussionAttachedFiles",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionDetachedFile, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DetachActionType",
                                ActionTextResourceName = "DiscussionDetachedFile",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "DiscussionDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionCommentCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "DiscussionCommentCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionCommentUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "DiscussionCommentUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },
                    {
                        MessageAction.DiscussionCommentDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "DiscussionCommentDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "DiscussionsModule"
                            }
                    },

                    #endregion

                    #region time tracking

                    {
                        MessageAction.TaskTimeCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "TaskTimeCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TimeTrackingModule"
                            }
                    },
                    {
                        MessageAction.TaskTimeUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TaskTimeUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TimeTrackingModule"
                            }
                    },
                    {
                        MessageAction.TaskTimesUpdatedStatus, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "TaskTimesUpdatedStatus",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TimeTrackingModule"
                            }
                    },
                    {
                        MessageAction.TaskTimesDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "TaskTimesDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "TimeTrackingModule"
                            }
                    },

                    #endregion

                    #region reports

                    {
                        MessageAction.ReportTemplateCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ReportTemplateCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ReportsModule"
                            }
                    },
                    {
                        MessageAction.ReportTemplateUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ReportTemplateUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ReportsModule"
                            }
                    },
                    {
                        MessageAction.ReportTemplateDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ReportTemplateDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ReportsModule"
                            }
                    },

                    #endregion
 
                    #region settings
                    
                    {
                        MessageAction.ProjectTemplateCreated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "CreateActionType",
                                ActionTextResourceName = "ProjectTemplateCreated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ProjectTemplateUpdated, new MessageMaps
                            {
                                ActionTypeTextResourceName = "UpdateActionType",
                                ActionTextResourceName = "ProjectTemplateUpdated",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ProjectTemplateDeleted, new MessageMaps
                            {
                                ActionTypeTextResourceName = "DeleteActionType",
                                ActionTextResourceName = "ProjectTemplateDeleted",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsSettingsModule"
                            }
                    },
                    {
                        MessageAction.ProjectsImportedFromBasecamp, new MessageMaps
                            {
                                ActionTypeTextResourceName = "ImportActionType",
                                ActionTextResourceName = "ProjectsImportedFromBasecamp",
                                ProductResourceName = "ProjectsProduct",
                                ModuleResourceName = "ProjectsModule"
                            }
                    },

                    #endregion
                };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTP_Source_Local.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    #region usings

    using System;
    using System.Net;

    #endregion

    /// <summary>
    /// This class represents local source what we send.
    /// </summary>
    /// <remarks>Source indicates an entity sending packets, either RTP and/or RTCP.
    /// Sources what send RTP packets are called "active", only RTCP sending ones are "passive".
    /// </remarks>
    public class RTP_Source_Local : RTP_Source
    {
        #region Members

        private RTP_SendStream m_pStream;

        #endregion

        #region Properties

        /// <summary>
        /// Returns true.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this property is accessed.</exception>
        public override bool IsLocal
        {
            get
            {
                if (State == RTP_SourceState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }

                return true;
            }
        }

        /// <summary>
        /// Gets local participant. 
        /// </summary>
        public RTP_Participant_Local Participant
        {
            get { return Session.Session.LocalParticipant; }
        }

        /// <summary>
        /// Gets the stream we send. Value null means that source is passive and doesn't send any RTP data.
        /// </summary>
        public RTP_SendStream Stream
        {
            get { return m_pStream; }
        }

        /// <summary>
        /// Gets source CNAME. Value null means that source not binded to participant.
        /// </summary>
        internal override string CName
        {
            get
            {
                if (Participant != null)
                {
                    return null;
                }
                else
                {
                    return Participant.CNAME;
                }
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="session">Owner RTP session.</param>
        /// <param name="ssrc">Synchronization source ID.</param>
        /// <param name="rtcpEP">RTCP end point.</param>
        /// <param name="rtpEP">RTP end point.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>session</b>,<b>rtcpEP</b> or <b>rtpEP</b> is null reference.</exception>
        internal RTP_Source_Local(RTP_Session session, uint ssrc, IPEndPoint rtcpEP, IPEndPoint rtpEP)
            : base(session, ssrc)
        {
            if (rtcpEP == null)
            {
                throw new ArgumentNullException("rtcpEP");
            }
            if (rtpEP == null)
            {
                throw new ArgumentNullException("rtpEP");
            }

            SetRtcpEP(rtcpEP);
            SetRtpEP(rtpEP);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Sends specified application packet to the RTP session target(s).
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <param name="packet">Is raised when <b>packet</b> is null reference.</param>
        public void SendApplicationPacket(RTCP_Packet_APP packet)
        {
            if (State == RTP_SourceState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (packet == null)
            {
                throw new ArgumentNullException("packet");
            }

            packet.Source = SSRC;

            RTCP_CompoundPacket p = new RTCP_CompoundPacket();
            RTCP_Packet_RR rr = new RTCP_Packet_RR();
            rr.SSRC = SSRC;
            p.Packets.Add(packet);

            // Send APP packet.
            Session.SendRtcpPacket(p);
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Closes this source, sends BYE to remote party.
        /// </summary>
        /// <param name="closeReason">Stream closing reason text what is reported to the remote party. Value null means not specified.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        internal override void Close(string closeReason)
        {
            if (State == RTP_SourceState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }

            RTCP_CompoundPacket packet = new RTCP_CompoundPacket();
            RTCP_Packet_RR rr = new RTCP_Packet_RR();
            rr.SSRC = SSRC;
            packet.Packets.Add(rr);
            RTCP_Packet_BYE bye = new RTCP_Packet_BYE();
            bye.Sources = new[] {SSRC};
            if (!string.IsNullOrEmpty(closeReason))
            {
                bye.LeavingReason = closeReason;
            }
            packet.Packets.Add(bye);

            // Send packet.
            Session.SendRtcpPacket(packet);

            base.Close(closeReason);
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Creates RTP send stream for this source.
        /// </summary>
        /// <exception cref="InvalidOperationException">Is raised when this method is called more than 1 times(source already created).</exception>
        internal void CreateStream()
        {
            if (m_pStream != null)
            {
                throw new InvalidOperationException("Stream is already created.");
            }

            m_pStream = new RTP_SendStream(this);
            m_pStream.Disposed += delegate
                                      {
                                          m_pStream = null;
                                          Dispose();
                                      };

            SetState(RTP_SourceState.Active);
        }

        /// <summary>
        /// Sends specified RTP packet to the session remote party.
        /// </summary>
        /// <param name="packet">RTP packet.</param>
        /// <returns>Returns packet size in bytes.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>packet</b> is null reference.</exception>
        /// <exception cref="InvalidOperationException">Is raised when <b>CreateStream</b> method has been not called.</exception>
        internal int SendRtpPacket(RTP_Packet packet)
        {
            if (packet == null)
            {
                throw new ArgumentNullException("packet");
            }
            if (m_pStream == null)
            {
                throw new InvalidOperationException("RTP stream is not created by CreateStream method.");
            }

            SetLastRtpPacket(DateTime.Now);
            SetState(RTP_SourceState.Active);

            return Session.SendRtpPacket(m_pStream, packet);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Server/IMAP_SearchMatcher.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP.Server
{
    #region usings

    using System;
    using Mime;

    #endregion

    /// <summary>
    /// IMAP SEARCH message matcher. You can use this class to see if message values match to search criteria.
    /// </summary>
    public class IMAP_SearchMatcher
    {
        #region Members

        private readonly SearchGroup m_pSearchCriteria;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if header is needed for matching.
        /// </summary>
        public bool IsHeaderNeeded
        {
            get { return m_pSearchCriteria.IsHeaderNeeded(); }
        }

        /// <summary>
        /// Gets if body text is needed for matching.
        /// </summary>
        public bool IsBodyTextNeeded
        {
            get { return m_pSearchCriteria.IsBodyTextNeeded(); }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Deault constuctor.
        /// </summary>
        /// <param name="mainSearchGroup">SEARCH command main search group.</param>
        internal IMAP_SearchMatcher(SearchGroup mainSearchGroup)
        {
            m_pSearchCriteria = mainSearchGroup;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets if specified values match search criteria.
        /// </summary>
        /// <param name="no">Message sequence number.</param>
        /// <param name="uid">Message UID.</param>
        /// <param name="size">Message size in bytes.</param>
        /// <param name="internalDate">Message INTERNALDATE (dateTime when server stored message).</param>
        /// <param name="flags">Message flags.</param>
        /// <param name="header">Message header. This is only needed if this.IsHeaderNeeded is true.</param>
        /// <param name="bodyText">Message body text (must be decoded unicode text). This is only needed if this.IsBodyTextNeeded is true.</param>
        /// <returns></returns>
        public bool Matches(int no,
                            int uid,
                            int size,
                            DateTime internalDate,
                            IMAP_MessageFlags flags,
                            string header,
                            string bodyText)
        {
            // Parse header only if it's needed
            Mime m = null;
            if (m_pSearchCriteria.IsHeaderNeeded())
            {
                m = new Mime();
                m.MainEntity.Header.Parse(header);
            }

            return m_pSearchCriteria.Match(no, uid, size, internalDate, flags, m, bodyText);
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Forum/js/searchhelper.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var LoaderPath = StudioManager.GetImage('loader_16.gif');
var ContainerElementID ='container';

HelpItem = function(accord,value,rank,help)
{
        this.Accord=accord;
        this.Value = value;
        this.Help =help;
        this.Rank=rank;
        this.Helper=null;
        this.ID ='ish_0';
}

var hv = new Array(0);
var isDocumentLoad = false;
jq(document).ready(function(){
    isDocumentLoad = true;
})


var SearchHelper = function(inputID,hsItemClass,hsItemSelectClass,code,selectCode,ajaxClassHandler,serverFunc,serverParams,isAppend,isVisibleHelp)
{        
        var varName = 'hv['+hv.length+']';
        var helperID = 'sh_hv_'+hv.length+'_';
        if(isAppend!='undefined' && isAppend!=undefined)
            this.IsAppend=isAppend;
        else
            this.IsAppend = false;    
            
        if(isVisibleHelp!='undefined' && isVisibleHelp!=undefined)
            this.IsVisibleHelp=isVisibleHelp;
        else
            this.IsVisibleHelp = true;          
            
        this.AjaxClassHandler = ajaxClassHandler;
        this.SelectedItem = null;
        this.VarName=varName;
        this.InputID = inputID;
        this.ExecCode = code;
        this.IsExecCode=false;
        this.SelectCode = selectCode;
        this.ServerFunction = serverFunc;
        this.ServerParams = serverParams;
        this.ItemClass = hsItemClass;        
        this.ItemSelectClass= hsItemSelectClass;
        this.Items = new Array();
        this.IsCache = false;
        this.TempCache = new Array();
        this.CacheTitle ='';
        this.TimerHandler = null;        
        this.Cache =  new Object();
        this.ID = helperID;
        this.CurrentItemID=null; 
        this.IDLoader = helperID+'_loader';
        var el = jq('#'+inputID).get(0);        
        var z_index=jq(el).css('z-index');
        
        while(el.tagName.toLowerCase()!='body' && (z_index=='' || z_index==null || z_index=='undefined'))
        {            
            el = jq(el).parent().get(0);
            z_index=jq(el).css('z-index');
        }
        
        if(z_index==null || z_index=='undefined')
            z_index='';
        else 
            z_index='z-index:'+z_index+';';   
            
        hv.push(this); 
               
        if(isDocumentLoad)
        {            
            try{
                eval(varName+'=this;');                
                var bodySH = '<div id='+helperID+' style="'+z_index+' background-color:white; padding:0px; margin:0px; width:'+(jq('#'+inputID).width()+3)+'px; position:absolute; display:none;"></div>';
                var bodySHLoader = '<div id='+helperID+'_loader style="'+z_index+' padding:0px; margin:0px; position:absolute; display:none;"><img src="'+LoaderPath+'" alt=""></div>';
                if(jq('#'+helperID).length>0)
                {
                    jq('#'+helperID).remove();
                    jq('#'+helperID+'_loader').remove();
                }
                
                jq('#'+ContainerElementID).append(bodySH+bodySHLoader);
                eval('jq("#'+inputID+'").keyup(function(event){'+varName+'.Handler(event);})');
            }
            catch(e){};
        }
        else
        {
            jq(document).ready(function() 
            {
                try{               
                    eval('isDocumentLoad=true;');
                    var bodySH = '<div id='+helperID+' style="'+z_index+' background-color:white; padding:0px; margin:0px; width:'+(jq('#'+inputID).width()+3)+'px; position:absolute; display:none;"></div>';
                    var bodySHLoader = '<div id='+helperID+'_loader style="'+z_index+'padding:0px; margin:0px; position:absolute; display:none;"><img src="'+LoaderPath +'" alt=""></div>';                    
                    
                    jq('#'+ContainerElementID).append(bodySH+bodySHLoader);
                    eval('jq("#'+inputID+'").keyup(function(event){'+varName+'.Handler(event);})');
                }
                catch(e){};
            });
        }        
    
    this.Handler = function(e)
    {        
        var code;        
		if (!e) var e = window.event;
		if (e.keyCode) code = e.keyCode;
		else if (e.which) code = e.which;		
		
		var isVisible = jq('#'+this.ID).is(':visible');
		var text = jq.trim(jq('#'+this.InputID).val());
			
		if (code == 38 && isVisible)//up
		{
		    this.PrevItem();		    
		}
		else if (code == 40 && isVisible)//down
		{ 		    
			this.NextItem();
		}
		else if(code==13 && isVisible && this.IsPreSelected())
		{
		    this.SelectItem();
		}
		else if((code<=57 && code>=48)
		        || (code>=96 && code<=111) 
		        || (code>=65 && code<=90) 
		        || code==61 || code==220 || code==192 || code==219
		        || code==221 || code==59 || code==222
		        || code==188 || code==190 || code==191 || code==32
		        || (code==8 && isVisible) 
		        || (code==8 && text!='') 
		        || (code==46 && text!='')
		        || (code==46 && isVisible)) 
		{
		    if(text=='')	
		    {	     
		        this.Close();
		        return;
		    }
		        
		    this.IsCache = false;		   
		    if(this.Cache!=null)
		    {		        
		        for(property in this.Cache)
		        {   
		            if(text==property)
		            {			            
                       this.Items = new Array().concat(this.Cache[property]);		               
                       this.IsCache = true;
                       this.CacheTitle = 'from cache key='+property;
                       break;
                   }
                }
            }
            if(!this.IsCache)
            {         
                var pos =jq('#'+this.InputID).offset();
                var inputWidth =jq('#'+this.InputID).width();                
                var loaderWidth =jq('#'+this.IDLoader).width();
                
                jq('#'+this.IDLoader).css({ 
                    'left':pos.left+inputWidth-loaderWidth+'px',
                    'top':pos.top+'px'
                });
                
                var var_name = this.VarName;              
                        
                AjaxPro.onLoading = function(b)
                {        
                    if(b)
                    {
                        eval('jq("#"+'+var_name+'.IDLoader).show();');                       
                    }
                }    
                if(this.TimerHandler!=null)
                    clearTimeout(this.TimerHandler);                
                this.TimerHandler = setTimeout(this.AjaxClassHandler+'.'+this.ServerFunction+'('+this.ServerParams+'"'+text+'","'+this.VarName+'",'+this.VarName+'.SearchCallback);',200);
            }
            else
            {
                if(this.Items!=null && this.Items.length>0)
                    this.Show();
                else
                    this.Close();
            }
		}
		else if(code == 27 && isVisible)
		{
		    this.Close();
		}
		else if((code == 13 && !isVisible)
		        ||(code==13 && !this.IsPreSelected()) )
		{
		    this.Close();
		    this.IsExecCode=true;
		    eval(this.ExecCode);
		}	
    };
    
    this.ClearCache = function()
    {
         this.Cache = new Object();
    };
    
    this.SearchCallback = function(result)
    {
        var res = result.value;
         //---conflict zone (variable names)
        var res = result.value;
        var text = res.rs3;
        var var_name= res.rs4;
        var values =  res.rs1.split(',');
        var helps =  res.rs2.split(',');
        //-----------     
        
        eval(var_name+'.TempCache.clear();');
        eval('jq("#"+'+var_name+'.IDLoader).hide();');
        eval('if(jq("#"+'+var_name+'.InputID).val()=="'+ text+'") '+var_name+'.DeleteItems();');               
        for(var i =0; i<values.length;i++)
        {            
            if(values[i]!='' && values[i]!=null)
                eval(var_name+'.AddHelpItemToTempCache(new HelpItem("","'+values[i]+'",'+i+',"'+helps[i]+'"));');
        }   
       eval(var_name+'.Cache["'+text+'"]='+var_name+'.TempCache.concat(new Array());');
       eval('if(jq("#"+'+var_name+'.InputID).val()=="'+ text+'"){ '+var_name+'.Items = '+var_name+'.TempCache.concat(new Array()); if('+var_name+'.Items!=null && '+var_name+'.Items.length>0) '+var_name+'.Show(); else '+var_name+'.Close(); }');
    };
    
    this.IsPreSelected = function()
    {
        for(var i=0; i<this.Items.length;i++)
        {
            if(jq('#'+this.Items[i].ID).attr('class') == this.ItemSelectClass)
                return true;
        }
        return false;
    };
    
    this.AddHelpItem = function(helpItem)
    {
        helpItem.Helper=this;
        helpItem.ID=this.ID+'_ish_'+(this.Items.length+1);
        this.Items.push(helpItem); 
        this.Items.sort(this._compareItems);       
        
    };
    
    this.AddHelpItemToTempCache = function(helpItem)
    {
        helpItem.Helper=this;
        helpItem.ID=this.ID+'_ish_'+(this.TempCache.length+1);
        this.TempCache.push(helpItem); 
        this.TempCache.sort(this._compareItems);
    };
    
    this._compareItems = function(a,b)
    {
        if(a.Rank<b.Rank)
            return -1;
        if(a.Rank>b.Rank)
            return 1;
        return 0;
    };
    
    this.DeleteItems = function()
    {
        this.Items.clear();
    };
    
    this.MouseClick = function(event)
    {
        var elt = (event.target) ? event.target : event.srcElement;                
        if(elt!=jq('#'+this.InputID).get(0))
        {            
            this.Close();
        }
    };
    
    this.Close = function()
    {   
        jq('#'+this.ID).hide();     
        this.DeleteItems();
        jq("body").unbind("click");
    };
    
    this.GetItemById = function(idItem)
    {
        for(var i=0; i<this.Items.length; i++)
        {
            var item = this.Items[i];
            if(item.ID == idItem)
            {
                return item;
            }
        }
        return null;
    };
    
    this.ClearItems = function()
    {
        for(var i=0; i<this.Items.length;i++)        
            jq('#'+this.Items[i].ID).attr('class',this.ItemClass);        
    };
    
    this.NextItem = function()
    {
        if(this.Items.length>0)
        {
            var nextItemId = 0;
            for(var i=0; i<this.Items.length;i++)
            {
                if(jq('#'+this.Items[i].ID).attr('class') == this.ItemSelectClass)
                {                   
                   if(i== this.Items.length-1)
                        nextItemId=0;            
                   else
                        nextItemId=i+1;
                   break;                    
                }
            }
            this.ClearItems();
            jq('#'+this.Items[nextItemId].ID).attr('class', this.ItemSelectClass);
        }        
    };
    
    this.PrevItem = function()
    {
        if(this.Items.length>0)
        {
            var nextItemId = this.Items.length-1;
            for(var i=0; i<this.Items.length;i++)
            {
                if(jq('#'+this.Items[i].ID).attr('class') == this.ItemSelectClass)
                {                   
                   if(i== 0)
                        nextItemId=this.Items.length-1;            
                   else
                        nextItemId=i-1;
                   break;                    
                }
            }
            this.ClearItems();
            jq('#'+this.Items[nextItemId].ID).attr('class', this.ItemSelectClass);
        }
    };
    
    this.PreSelectItem = function(idItem)
    {
        this.ClearItems();
        var item = this.GetItemById(idItem);        
        jq('#'+item.ID).attr('class', this.ItemSelectClass);
    };
    
    this.SelectItem = function()
    {
        for(var i=0; i<this.Items.length;i++)
        {
            var item =this.Items[i];
            if(jq('#'+item.ID).attr('class')==this.ItemSelectClass)
            {                
                this.SelectedItem =item; 
                if(this.IsAppend)
                {
                    var vals =jq('#'+this.InputID).val().split(',');
                    var result = new String();
                    var isFirst = 1;
                    for(var i=0;i<vals.length-1;i++)
                    {
                        if(jq.trim(vals[i])!='')
                        {
                            if(isFirst==1)
                            {
                                result+=jq.trim(vals[i]);
                                isFirst=0;
                            }
                            else
                            {
                                result+=','+jq.trim(vals[i]);
                            }
                        }
                    }
                    if(isFirst==1)
                    {
                        result+=item.Value;
                        isFirst=0;
                    }
                    else
                    {
                        result+=','+item.Value;
                    }
                    jq('#'+this.InputID).val(result+',');
                }
                else
                    jq('#'+this.InputID).val(item.Value);
                    
                eval(this.SelectCode);
                this.Close();
                break;
            }
        }
    };
    
    this.LeaveItem = function(idItem)
    {
       this.ClearItems();
       var item = this.GetItemById(idItem);       
       jq('#'+item.ID).attr('class', this.ItemClass);
    };
        
    this.Show = function()
    {
        //if(this.IsExecCode)
          //  return;

        this.SelectedItem = null;
        var pos =jq('#'+this.InputID).offset();
	    var inputHeight =jq('#'+this.InputID).height();
	    
	    jq('#'+this.ID).css({ 
            'left':pos.left+'px',
            'top':pos.top+inputHeight+4 +'px'
        });
        var items_context='';             
        for(var i=0; i<this.Items.length; i++)
        {
            var item = this.Items[i];
            items_context+='<div class=\''+this.ItemClass+'\' id=\''+item.ID+
                            '\' onmouseover=\'javascript:'+this.VarName+'.PreSelectItem("'+item.ID+'");\''+                             
                            ' onclick=\'javascript:'+this.VarName+'.SelectItem();\'><table width=100% cellspacing=0 cellpadding=3><tr><td>'+item.Value+'</td><td style="text-align:right; color:gray;">'+
                            '<div style="float:right;'+(this.IsVisibleHelp?'':' display:none;')+'">'+item.Help+'</div></td></tr></table></div>';
                                      
        }               
        jq('#'+this.ID).html(items_context);
        jq('#'+this.ID).show();
        
        jq("body").unbind("click");
        
        var varName = this.VarName;
        jq('body').click(function(event){
            eval(varName + '.Close();');
        });
    };
}


<|start_filename|>module/ASC.Feed/Data/FeedReadedDataProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;

namespace ASC.Feed.Data
{
    public class FeedReadedDataProvider
    {
        private const string dbId = Constants.FeedDbId;


        public DateTime GetTimeReaded()
        {
            return GetTimeReaded(GetUser(), "all", GetTenant());
        }

        public DateTime GetTimeReaded(string module)
        {
            return GetTimeReaded(GetUser(), module, GetTenant());
        }

        public DateTime GetTimeReaded(Guid user, string module, int tenant)
        {
            var query = new SqlQuery("feed_readed")
                .SelectMax("timestamp")
                .Where("tenant_id", tenant)
                .Where("user_id", user.ToString())
                .Where("module", module);

            using (var db = GetDb())
            {
                return db.ExecuteScalar<DateTime>(query);
            }
        }

        public void SetTimeReaded()
        {
            SetTimeReaded(GetUser(), DateTime.UtcNow, "all", GetTenant());
        }

        public void SetTimeReaded(string module)
        {
            SetTimeReaded(GetUser(), DateTime.UtcNow, module, GetTenant());
        }

        public void SetTimeReaded(Guid user)
        {
            SetTimeReaded(user, DateTime.UtcNow, "all", GetTenant());
        }

        public void SetTimeReaded(Guid user, DateTime time, string module, int tenant)
        {
            if (string.IsNullOrEmpty(module)) return;

            var query = new SqlInsert("feed_readed", true)
                .InColumns("user_id", "timestamp", "module", "tenant_id")
                .Values(user.ToString(), time, module, tenant);

            using (var db = GetDb())
            {
                db.ExecuteNonQuery(query);
            }
        }

        public IEnumerable<string> GetReadedModules(DateTime fromTime)
        {
            return GetReadedModules(GetUser(), GetTenant(), fromTime);
        }

        public IEnumerable<string> GetReadedModules(Guid user, int tenant, DateTime fromTime)
        {
            var query = new SqlQuery("feed_readed")
                .Select("module")
                .Where("tenant_id", tenant)
                .Where("user_id", user)
                .Where(Exp.Gt("timestamp", fromTime));

            using (var db = GetDb())
            {
                return db.ExecuteList(query).ConvertAll(r => (string)r[0]);
            }
        }


        private static DbManager GetDb()
        {
            return new DbManager(dbId);
        }

        private static int GetTenant()
        {
            return CoreContext.TenantManager.GetCurrentTenant().TenantId;
        }

        private static Guid GetUser()
        {
            return SecurityContext.CurrentAccount.ID;
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/Calendars/ProjectCalendar.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Core.Calendars;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Api.Projects.Calendars
{
    public sealed class ProjectCalendar : BaseCalendar
    {
        [AllDayLongUTCAttribute]
        private class Event : BaseEvent
        {
        }

        private readonly Project project;
        private readonly bool following;

        public ProjectCalendar(Project project, string backgroundColor, string textColor, SharingOptions sharingOptions, bool following)
        {
            this.project = project;
            this.following = following;

            Context.HtmlBackgroundColor = backgroundColor;
            Context.HtmlTextColor = textColor;
            Context.CanChangeAlertType = false;
            Context.CanChangeTimeZone = false;
            Context.GetGroupMethod = () => Web.Projects.Resources.ProjectsCommonResource.ProductName;
            Id = this.project.UniqID;
            EventAlertType = EventAlertType.Hour;
            Name = this.project.Title;
            Description = this.project.Description;
            SharingOptions = sharingOptions;
        }

        public override List<IEvent> LoadEvents(Guid userId, DateTime startDate, DateTime endDate)
        {
            using (var scope = DIHelper.Resolve())
            {
                var engine = scope.Resolve<EngineFactory>();
                var tasks = new List<Task>();
                if (!following)
                    tasks.AddRange(engine.TaskEngine.GetByProject(project.ID, TaskStatus.Open, userId));

                var milestones = engine.MilestoneEngine.GetByStatus(project.ID, MilestoneStatus.Open);

                var events = milestones
                    .Select(m => new Event
                    {
                        AlertType = EventAlertType.Never,
                        CalendarId = Id,
                        UtcStartDate = m.DeadLine,
                        UtcEndDate = m.DeadLine,
                        AllDayLong = true,
                        Id = m.UniqID,
                        Name = Web.Projects.Resources.MilestoneResource.Milestone + ": " + m.Title,
                        Description = m.Description
                    })
                    .Where(e => IsVisibleEvent(startDate, endDate, e.UtcStartDate, e.UtcEndDate))
                    .Cast<IEvent>()
                    .ToList();

                foreach (var t in tasks)
                {
                    var start = t.StartDate;

                    if (!t.Deadline.Equals(DateTime.MinValue))
                    {
                        start = start.Equals(DateTime.MinValue) ? t.Deadline : t.StartDate;
                    }
                    else
                    {
                        start = DateTime.MinValue;
                    }

                    var projectEvent = new Event
                    {
                        AlertType = EventAlertType.Never,
                        CalendarId = Id,
                        UtcStartDate = start,
                        UtcEndDate = t.Deadline,
                        AllDayLong = true,
                        Id = t.UniqID,
                        Name = Web.Projects.Resources.TaskResource.Task + ": " + t.Title,
                        Description = t.Description
                    };

                    if (IsVisibleEvent(startDate, endDate, projectEvent.UtcStartDate, projectEvent.UtcEndDate))
                        events.Add(projectEvent);
                }

                return events;
            }
        }

        public override TimeZoneInfo TimeZone
        {
            get { return CoreContext.TenantManager.GetCurrentTenant().TimeZone; }
        }

        private bool IsVisibleEvent(DateTime startDate, DateTime endDate, DateTime eventStartDate, DateTime eventEndDate)
        {
            return (startDate <= eventStartDate && eventStartDate <= endDate) ||
                   (startDate <= eventEndDate && eventEndDate <= endDate) ||
                   (eventStartDate < startDate && eventEndDate > endDate);
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/ServerMailgroupEngine.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Security;

using ASC.Common.Logging;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Server.Core.Entities;
using ASC.Mail.Utils;
using ASC.Web.Core;

using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Mail.Core.Engine
{
    public class ServerMailgroupEngine
    {
        public int Tenant { get; private set; }
        public string User { get; private set; }

        public ILog Log { get; private set; }

        public ServerMailgroupEngine(int tenant, string user, ILog log = null)
        {
            Tenant = tenant;
            User = user;

            Log = log ?? LogManager.GetLogger("ASC.Mail.ServerMailgroupEngine");
        }

        public List<ServerDomainGroupData> GetMailGroups()
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            var list = new List<ServerDomainGroupData>();

            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                var domains = serverDomainDao.GetDomains();

                var serverGroupDao = daoFactory.CreateServerGroupDao(Tenant);

                var groups = serverGroupDao.GetList();

                var serverAddressDao = daoFactory.CreateServerAddressDao(Tenant);

                list.AddRange(from serverGroup in groups
                              let address = serverAddressDao.Get(serverGroup.AddressId)
                              let domain = domains.FirstOrDefault(d => d.Id == address.DomainId)
                              where domain != null
                              let serverGroupAddress = ServerMailboxEngine.ToServerDomainAddressData(address, domain)
                              let serverGroupAddresses =
                                  serverAddressDao.GetGroupAddresses(serverGroup.Id)
                                      .ConvertAll(a => ServerMailboxEngine.ToServerDomainAddressData(a, domain))
                              select ToServerDomainGroupData(serverGroup.Id, serverGroupAddress, serverGroupAddresses));
            }

            return list;
        }

        public ServerDomainGroupData CreateMailGroup(string name, int domainId, List<int> addressIds)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (string.IsNullOrEmpty(name))
                throw new ArgumentException(@"Invalid mailgroup name.", "name");

            if (domainId < 0)
                throw new ArgumentException(@"Invalid domain id.", "domainId");

            if (name.Length > 64)
                throw new ArgumentException(@"Local part of mailgroup exceed limitation of 64 characters.", "name");

            if (!Parser.IsEmailLocalPartValid(name))
                throw new ArgumentException(@"Incorrect group name.", "name");

            if (!addressIds.Any())
                throw new ArgumentException(@"Empty collection of address_ids.", "addressIds");

            var mailgroupName = name.ToLowerInvariant();

            using (var daoFactory = new DaoFactory())
            {
                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                var serverDomain = serverDomainDao.GetDomain(domainId);

                if (serverDomain.Tenant == Defines.SHARED_TENANT_ID)
                    throw new InvalidOperationException("Creating mail group is not allowed for shared domain.");

                var serverAddressDao = daoFactory.CreateServerAddressDao(Tenant);

                if (serverAddressDao.IsAddressAlreadyRegistered(mailgroupName, serverDomain.Name))
                {
                    throw new DuplicateNameException("You want to create a group with already existing address.");
                }

                var utcNow = DateTime.UtcNow;

                var address = new ServerAddress
                {
                    Id = 0,
                    Tenant = Tenant,
                    MailboxId = -1,
                    DomainId = serverDomain.Id,
                    AddressName = mailgroupName,
                    IsAlias = false,
                    IsMailGroup = true,
                    DateCreated = utcNow
                };

                var groupEmail = string.Format("{0}@{1}", mailgroupName, serverDomain.Name);

                var groupAddressData = ServerMailboxEngine.ToServerDomainAddressData(address, groupEmail);

                var newGroupMembers = serverAddressDao.GetList(addressIds);

                var newGroupMemberIds = newGroupMembers.ConvertAll(m => m.Id);

                var newGroupMemberDataList =
                    newGroupMembers.ConvertAll(m =>
                        ServerMailboxEngine.ToServerDomainAddressData(m,
                            string.Format("{0}@{1}", m.AddressName, serverDomain.Name)));

                var goTo = string.Join(",",
                    newGroupMembers.Select(m => string.Format("{0}@{1}", m.AddressName, serverDomain.Name)));

                var serverDao = daoFactory.CreateServerDao();
                var server = serverDao.Get(Tenant);

                var engine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);

                var group = new ServerGroup
                {
                    Id = 0,
                    Tenant = Tenant,
                    Address = groupEmail,
                    AddressId = 0,
                    DateCreated = utcNow
                };

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    address.Id = serverAddressDao.Save(address);

                    group.AddressId = address.Id;

                    var serverGroupDao = daoFactory.CreateServerGroupDao(Tenant);

                    group.Id = serverGroupDao.Save(group);

                    serverAddressDao.AddAddressesToMailGroup(group.Id, newGroupMemberIds);

                    var serverAddress = new Alias
                    {
                        Name = "",
                        Address = groupEmail,
                        GoTo = goTo,
                        Domain = serverDomain.Name,
                        IsActive = true,
                        IsGroup = true,
                        Modified = utcNow,
                        Created = utcNow
                    };

                    engine.SaveAlias(serverAddress);

                    tx.Commit();
                }

                CacheEngine.ClearAll();

                return ToServerDomainGroupData(group.Id, groupAddressData, newGroupMemberDataList);
            }
        }

        public ServerDomainGroupData AddMailGroupMember(int mailgroupId, int addressId)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (addressId < 0)
                throw new ArgumentException(@"Invalid address id.", "addressId");

            if (mailgroupId < 0)
                throw new ArgumentException(@"Invalid mailgroup id.", "mailgroupId");

            using (var daoFactory = new DaoFactory())
            {
                var serverGroupDao = daoFactory.CreateServerGroupDao(Tenant);

                var group = serverGroupDao.Get(mailgroupId);

                if (group == null)
                    throw new Exception("Group not found");

                var serverAddressDao = daoFactory.CreateServerAddressDao(Tenant);

                var groupMembers = serverAddressDao.GetGroupAddresses(mailgroupId);

                if (groupMembers.Exists(a => a.Id == addressId))
                    throw new DuplicateNameException("Member already exists");

                var newMemberAddress = serverAddressDao.Get(addressId);

                if (newMemberAddress == null)
                    throw new Exception("Member not found");

                var serverDao = daoFactory.CreateServerDao();
                var server = serverDao.Get(Tenant);

                var engine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);

                var utcNow = DateTime.UtcNow;

                ServerAddress groupAddress;
                string groupEmail;
                List<ServerDomainAddressData> newGroupMemberDataList;

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    serverAddressDao.AddAddressesToMailGroup(mailgroupId, new List<int> { addressId });

                    groupMembers.Add(newMemberAddress);

                    groupAddress = serverAddressDao.Get(group.AddressId);

                    var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                    var serverDomain = serverDomainDao.GetDomain(groupAddress.DomainId);

                    var goTo = string.Join(",",
                        groupMembers.Select(m => string.Format("{0}@{1}", m.AddressName, serverDomain.Name)));

                    groupEmail = string.Format("{0}@{1}", groupAddress.AddressName, serverDomain.Name);

                    newGroupMemberDataList =
                        groupMembers.ConvertAll(m =>
                            ServerMailboxEngine.ToServerDomainAddressData(m,
                                string.Format("{0}@{1}", m.AddressName, serverDomain.Name)));

                    var serverAddress = new Alias
                    {
                        Name = "",
                        Address = groupEmail,
                        GoTo = goTo,
                        Domain = serverDomain.Name,
                        IsActive = true,
                        IsGroup = true,
                        Modified = utcNow,
                        Created = utcNow
                    };

                    engine.SaveAlias(serverAddress);

                    tx.Commit();
                }

                var groupAddressData = ServerMailboxEngine.ToServerDomainAddressData(groupAddress, groupEmail);

                CacheEngine.ClearAll();

                return ToServerDomainGroupData(group.Id, groupAddressData, newGroupMemberDataList);
            }
        }

        public void RemoveMailGroupMember(int mailgroupId, int addressId)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (addressId < 0)
                throw new ArgumentException(@"Invalid address id.", "addressId");

            if (mailgroupId < 0)
                throw new ArgumentException(@"Invalid mailgroup id.", "mailgroupId");

            using (var daoFactory = new DaoFactory())
            {
                var serverGroupDao = daoFactory.CreateServerGroupDao(Tenant);

                var group = serverGroupDao.Get(mailgroupId);

                if (group == null)
                    throw new Exception("Group not found");

                var serverAddressDao = daoFactory.CreateServerAddressDao(Tenant);

                var groupMembers = serverAddressDao.GetGroupAddresses(mailgroupId);

                var removeMember = groupMembers.FirstOrDefault(a => a.Id == addressId);

                if (removeMember == null)
                    throw new ArgumentException("Member not found");

                groupMembers.Remove(removeMember);

                if (groupMembers.Count == 0)
                    throw new Exception("Can't remove last member; Remove group.");

                var serverDao = daoFactory.CreateServerDao();
                var server = serverDao.Get(Tenant);

                var groupAddress = serverAddressDao.Get(group.AddressId);

                var serverDomainDao = daoFactory.CreateServerDomainDao(Tenant);

                var serverDomain = serverDomainDao.GetDomain(groupAddress.DomainId);

                var engine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);

                var utcNow = DateTime.UtcNow;

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    serverAddressDao.DeleteAddressFromMailGroup(mailgroupId, addressId);

                    var goTo = string.Join(",",
                        groupMembers.Select(m => string.Format("{0}@{1}", m.AddressName, serverDomain.Name)));

                    var groupEmail = string.Format("{0}@{1}", groupAddress.AddressName, serverDomain.Name);

                    var serverAddress = new Alias
                    {
                        Name = "",
                        Address = groupEmail,
                        GoTo = goTo,
                        Domain = serverDomain.Name,
                        IsActive = true,
                        IsGroup = true,
                        Modified = utcNow,
                        Created = group.DateCreated
                    };

                    engine.SaveAlias(serverAddress);

                    tx.Commit();
                }
            }

            CacheEngine.ClearAll();
        }

        public void RemoveMailGroup(int id)
        {
            if (!IsAdmin)
                throw new SecurityException("Need admin privileges.");

            if (id < 0)
                throw new ArgumentException(@"Invalid mailgroup id.", "id");

            using (var daoFactory = new DaoFactory())
            {
                var serverGroupDao = daoFactory.CreateServerGroupDao(Tenant);

                var group = serverGroupDao.Get(id);

                if (group == null)
                    throw new Exception("Group not found");

                var serverAddressDao = daoFactory.CreateServerAddressDao(Tenant);

                var serverDao = daoFactory.CreateServerDao();
                var server = serverDao.Get(Tenant);

                var engine = new Server.Core.ServerEngine(server.Id, server.ConnectionString);

                using (var tx = daoFactory.DbManager.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    serverGroupDao.Delete(id);

                    serverAddressDao.DeleteAddressesFromMailGroup(id);

                    serverAddressDao.Delete(group.AddressId);

                    engine.RemoveAlias(group.Address);

                    tx.Commit();
                }
            }

            CacheEngine.ClearAll();
        }

        public static ServerDomainGroupData ToServerDomainGroupData(int groupId, ServerDomainAddressData address, List<ServerDomainAddressData> addresses)
        {
            var group = new ServerDomainGroupData
            {
                Id = groupId,
                Address = address,
                Addresses = addresses
            };

            return group;
        }

        private static bool IsAdmin
        {
            get
            {
                return WebItemSecurity.IsProductAdministrator(WebItemManager.MailProductID, SecurityContext.CurrentAccount.ID);
            }
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Billing/Tariff.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Diagnostics;

using ASC.Core.Tenants;

namespace ASC.Core.Billing
{
    [DebuggerDisplay("{QuotaId} ({State} before {DueDate})")]
    [Serializable]
    public class Tariff
    {
        public int QuotaId { get; set; }

        public TariffState State { get; set; }

        public DateTime DueDate { get; set; }

        public DateTime DelayDueDate { get; set; }

        public DateTime LicenseDate { get; set; }

        public bool Autorenewal { get; set; }

        public bool Prolongable { get; set; }

        public int Quantity { get; set; }


        public static Tariff CreateDefault()
        {
            return new Tariff
            {
                QuotaId = Tenant.DEFAULT_TENANT,
                State = TariffState.Paid,
                DueDate = DateTime.MaxValue,
                DelayDueDate = DateTime.MaxValue,
                LicenseDate = DateTime.MaxValue,
                Quantity = 1
            };
        }


        public override int GetHashCode()
        {
            return QuotaId.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            var t = obj as Tariff;
            return t != null && t.QuotaId == QuotaId;
        }

        public bool EqualsByParams(Tariff t)
        {
            return t != null
                && t.QuotaId == QuotaId
                && t.DueDate == DueDate
                && t.Quantity == Quantity;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Users/AuthCommunications/AuthCommunications.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;
using System.Net.Mail;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.MessagingSystem;
using ASC.Web.Core.Security;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Core.Notify;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls
{
    [AjaxNamespace("AuthCommunicationsController")]
    public partial class AuthCommunications : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Users/AuthCommunications/AuthCommunications.ascx"; }
        }

        protected bool ShowSeparator { get; private set; }

        public bool DisableJoin;

        private bool EnabledJoin
        {
            get
            {
                if (DisableJoin) return false;
                var t = CoreContext.TenantManager.GetCurrentTenant();
                return (t.TrustedDomainsType == TenantTrustedDomainsType.Custom && t.TrustedDomains.Count > 0) ||
                       t.TrustedDomainsType == TenantTrustedDomainsType.All;
            }
        }

        private static bool EnableAdmMess
        {
            get
            {
                var setting = StudioAdminMessageSettings.Load();
                return setting.Enable || TenantStatisticsProvider.IsNotPaid();
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            _joinBlock.Visible = EnabledJoin;

            _sendAdmin.Visible = EnableAdmMess;

            if (EnabledJoin || EnableAdmMess)
                AjaxPro.Utility.RegisterTypeForAjax(GetType());

            ShowSeparator = _joinBlock.Visible && _sendAdmin.Visible;

            Page.RegisterBodyScripts("~/UserControls/Users/AuthCommunications/js/authcommunications.js");
        }

        [SecurityPassthrough]
        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object SendAdmMail(string email, string message)
        {
            try
            {
                if (!EnableAdmMess)
                    throw new MethodAccessException("Method not available");

                if (!email.TestEmailRegex())
                    throw new Exception(Resource.ErrorNotCorrectEmail);

                if (string.IsNullOrEmpty(message))
                    throw new Exception(Resource.ErrorEmptyMessage);

                var key = HttpContext.Current.Request.UserHostAddress + "adminmessages";
                var count = Convert.ToInt32(HttpContext.Current.Cache[key]);
                if (10 < count)
                    throw new Exception(Resource.ErrorRequestLimitExceeded);

                HttpContext.Current.Cache.Insert(key, ++count, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
                                                 TimeSpan.FromMinutes(2));

                StudioNotifyService.Instance.SendMsgToAdminFromNotAuthUser(email, message);
                MessageService.Send(HttpContext.Current.Request, MessageAction.ContactAdminMailSent);

                return new { Status = 1, Message = Resource.AdminMessageSent };
            }
            catch (Exception ex)
            {
                return new { Status = 0, Message = ex.Message.HtmlEncode() };
            }
        }

        [SecurityPassthrough]
        [AjaxMethod(HttpSessionStateRequirement.ReadWrite)]
        public object SendJoinInviteMail(string email)
        {
            try
            {
                if (!EnabledJoin)
                    throw new MethodAccessException("Method not available");

                if (!email.TestEmailRegex())
                    throw new Exception(Resource.ErrorNotCorrectEmail);

                var user = CoreContext.UserManager.GetUserByEmail(email);
                if (!user.ID.Equals(Constants.LostUser.ID))
                    throw new Exception(CustomNamingPeople.Substitute<Resource>("ErrorEmailAlreadyExists"));

                var tenant = CoreContext.TenantManager.GetCurrentTenant();
                var settings = IPRestrictionsSettings.Load();

                if (settings.Enable && !IPSecurity.IPSecurity.Verify(tenant))
                    throw new Exception(Resource.ErrorAccessRestricted);

                var trustedDomainSettings = StudioTrustedDomainSettings.Load();
                var emplType = trustedDomainSettings.InviteUsersAsVisitors ? EmployeeType.Visitor : EmployeeType.User;
                var enableInviteUsers = TenantStatisticsProvider.GetUsersCount() <
                                        TenantExtra.GetTenantQuota().ActiveUsers;

                if (!enableInviteUsers)
                    emplType = EmployeeType.Visitor;

                switch (tenant.TrustedDomainsType)
                {
                    case TenantTrustedDomainsType.Custom:
                    {
                        var address = new MailAddress(email);
                        if (
                            tenant.TrustedDomains.Any(
                                d => address.Address.EndsWith("@" + d.Replace("*", ""), StringComparison.InvariantCultureIgnoreCase)))
                        {
                            StudioNotifyService.Instance.SendJoinMsg(email, emplType);
                            MessageService.Send(HttpContext.Current.Request, MessageInitiator.System,
                                                MessageAction.SentInviteInstructions, email);
                            return new { Status = 1, Message = Resource.FinishInviteJoinEmailMessage };
                        }

                        throw new Exception(Resource.ErrorEmailDomainNotAllowed);
                    }
                    case TenantTrustedDomainsType.All:
                    {
                        StudioNotifyService.Instance.SendJoinMsg(email, emplType);
                        MessageService.Send(HttpContext.Current.Request, MessageInitiator.System,
                                            MessageAction.SentInviteInstructions, email);
                        return new { Status = 1, Message = Resource.FinishInviteJoinEmailMessage };
                    }
                    default:
                        throw new Exception(Resource.ErrorNotCorrectEmail);
                }
            }
            catch (FormatException)
            {
                return new { Status = 0, Message = Resource.ErrorNotCorrectEmail };
            }
            catch (Exception e)
            {
                return new { Status = 0, Message = e.Message.HtmlEncode() };
            }
        }

        public static string RenderTrustedDominTitle()
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();

            switch (tenant.TrustedDomainsType)
            {
                case TenantTrustedDomainsType.Custom:
                {
                    var domains = "<strong>" +
                                  string.Join("</strong>, <strong>", tenant.TrustedDomains) +
                                  "</strong>";
                    return String.Format(Resource.TrustedDomainsInviteTitle.HtmlEncode(), domains);
                }
                case TenantTrustedDomainsType.All:
                    return Resource.SignInFromAnyDomainInviteTitle.HtmlEncode();
            }

            return string.Empty;
        }
    }
}

<|start_filename|>common/ASC.Common/Notify/Engine/SingleRecipientInterceptor.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Notify.Recipients;

namespace ASC.Notify.Engine
{
    class SingleRecipientInterceptor : ISendInterceptor
    {
        private const string prefix = "__singlerecipientinterceptor";
        private readonly List<IRecipient> sendedTo = new List<IRecipient>(10);


        public string Name { get; private set; }

        public InterceptorPlace PreventPlace { get { return InterceptorPlace.GroupSend | InterceptorPlace.DirectSend; } }

        public InterceptorLifetime Lifetime { get { return InterceptorLifetime.Call; } }


        internal SingleRecipientInterceptor(string name)
        {
            if (String.IsNullOrEmpty(name)) throw new ArgumentException("name");
            Name = name;
        }

        public bool PreventSend(NotifyRequest request, InterceptorPlace place)
        {
            var sendTo = request.Recipient;
            if (!sendedTo.Exists(rec => Equals(rec, sendTo)))
            {
                sendedTo.Add(sendTo);
                return false;
            }
            return true;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/TariffSettings/TariffStandalone.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;

using AjaxPro;

using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Tenants;
using ASC.MessagingSystem;
using ASC.Web.Core;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Statistics;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Management
{
    [AjaxNamespace("TariffStandaloneController")]
    public partial class TariffStandalone : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Management/TariffSettings/TariffStandalone.ascx"; }
        }

        protected int UsersCount;
        protected Tariff CurrentTariff;
        protected TenantQuota CurrentQuota;
        protected AdditionalWhiteLabelSettings Settings;
        protected int TenantCount;

        protected bool RequestLicenseAccept
        {
            get { return !TariffSettings.LicenseAccept && Settings.LicenseAgreementsEnabled; }
        }

        protected bool PeopleModuleAvailable
        {
            get
            {
                var peopleProduct = WebItemManager.Instance[WebItemManager.PeopleProductID];
                return peopleProduct != null && !peopleProduct.IsDisabled();
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page
                .RegisterBodyScripts(
                    "~/js/uploader/jquery.fileupload.js",
                    "~/UserControls/Management/TariffSettings/js/tariffstandalone.js")
                .RegisterStyle("~/UserControls/Management/TariffSettings/css/tariff.less",
                    "~/UserControls/Management/TariffSettings/css/tariffstandalone.less");

            UsersCount = TenantStatisticsProvider.GetUsersCount();
            CurrentTariff = TenantExtra.GetCurrentTariff();
            CurrentQuota = TenantExtra.GetTenantQuota();
            TenantCount = CoreContext.TenantManager.GetTenants().Count();

            Settings = AdditionalWhiteLabelSettings.Instance;
            Settings.LicenseAgreementsUrl = CommonLinkUtility.GetRegionalUrl(Settings.LicenseAgreementsUrl, CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
            Settings.FeedbackAndSupportUrl = CommonLinkUtility.GetRegionalUrl(Settings.FeedbackAndSupportUrl, CultureInfo.CurrentCulture.TwoLetterISOLanguageName);

            AjaxPro.Utility.RegisterTypeForAjax(GetType());
        }

        protected string TariffDescription()
        {
            if (TenantExtra.UpdatedWithoutLicense)
            {
                return String.Format(UserControlsCommonResource.TariffUpdateWithoutLicense.HtmlEncode(),
                                     "<span class='tariff-marked'>",
                                     "</span>",
                                     "<br />");
            }

            if (CurrentQuota.Trial)
            {
                if (CurrentTariff.State == TariffState.Trial)
                {
                    return "<b>" + Resource.TariffTrial + "</b> "
                           + (CurrentTariff.DueDate.Date != DateTime.MaxValue.Date
                                  ? string.Format(Resource.TariffExpiredDateStandaloneV11, CurrentTariff.DueDate.Date.ToLongDateString())
                                  : string.Empty);
                }
                return String.Format(Resource.TariffTrialOverdue.HtmlEncode(),
                                     "<span class='tarifff-marked'>",
                                     "</span>",
                                     "<br />", string.Empty, string.Empty);
            }

            if (TenantExtra.EnterprisePaid
                && CurrentTariff.DueDate.Date >= DateTime.Today)
            {
                return "<b>" + (CoreContext.Configuration.CustomMode ? CustomModeResource.TariffPaidStandaloneCustomMode.HtmlEncode() : UserControlsCommonResource.TariffPaidStandalone.HtmlEncode()) + "</b> "
                       + (CurrentTariff.DueDate.Date != DateTime.MaxValue.Date
                              ? string.Format(Resource.TariffExpiredDateStandaloneV11, CurrentTariff.DueDate.Date.ToLongDateString())
                              : string.Empty);
            }

            if (CurrentTariff.LicenseDate == DateTime.MaxValue)
            {
                return String.Format(
                CoreContext.Configuration.CustomMode
                    ? CustomModeResource.TariffNotPaidStandaloneCustomMode.HtmlEncode()
                    : CurrentQuota.Update
                        ? UserControlsCommonResource.TariffNotPaidStandaloneSupport.HtmlEncode()
                        : UserControlsCommonResource.TariffNotPaidStandalone2.HtmlEncode(),
                                 "<span class='tariff-marked'>",
                                 "</span>");
            }

            return String.Format(
                CoreContext.Configuration.CustomMode
                    ? CustomModeResource.TariffOverdueStandaloneCustomMode.HtmlEncode()
                    : CurrentQuota.Update
                        ? UserControlsCommonResource.TariffOverdueStandaloneSupport.HtmlEncode()
                        : UserControlsCommonResource.TariffOverdueStandalone2.HtmlEncode(),
                                 "<span class='tariff-marked'>",
                                 "</span>",
                                 CurrentTariff.LicenseDate.Date.ToLongDateString());
        }

        [AjaxMethod]
        public object ActivateLicenseKey()
        {
            if (!CoreContext.Configuration.Standalone) throw new NotSupportedException();

            TariffSettings.LicenseAccept = true;
            MessageService.Send(HttpContext.Current.Request, MessageAction.LicenseKeyUploaded);

            try
            {
                LicenseReader.RefreshLicense();

                return new { Status = 1 };
            }
            catch (BillingNotFoundException)
            {
                return new { Status = 0, Message = UserControlsCommonResource.LicenseKeyNotFound };
            }
            catch (BillingNotConfiguredException)
            {
                return new { Status = 0, Message = UserControlsCommonResource.LicenseKeyNotCorrect };
            }
            catch (BillingException)
            {
                return new { Status = 0, Message = UserControlsCommonResource.LicenseException };
            }
            catch (Exception ex)
            {
                return new { Status = 0, Message = ex.Message };
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/Core/Business/IBookmarkingService.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Usings

using System;
using System.Collections.Generic;

using ASC.Bookmarking.Pojo;
using ASC.Core.Users;
using ASC.Notify.Model;

#endregion

namespace ASC.Bookmarking.Business
{
    public interface IBookmarkingService
    {
        IList<Bookmark> GetAllBookmarks(int firstResult, int maxResults);
        IList<Bookmark> GetAllBookmarks();

        Bookmark AddBookmark(Bookmark b, IList<Tag> tags);

        Bookmark UpdateBookmark(UserBookmark userBookmark, IList<Tag> tags);
        Bookmark UpdateBookmark(Bookmark bookmark, IList<Tag> tags);

        UserInfo GetCurrentUser();

        IList<Tag> GetAllTags(string startSymbols, int limit);

        IList<Tag> GetAllTags();

        Bookmark GetBookmarkByUrl(string url);

        Bookmark GetBookmarkByID(long id);


        IList<UserBookmark> GetUserBookmarks(Bookmark b);

        UserBookmark GetCurrentUserBookmark(Bookmark b);

        Bookmark GetBookmarkWithUserBookmarks(string url);



        Bookmark RemoveBookmarkFromFavourite(long bookmarkID, Guid? userID = null);

        IList<Bookmark> GetFavouriteBookmarksSortedByRaiting(int firstResult, int maxResults);
        IList<Bookmark> GetFavouriteBookmarksSortedByDate(int firstResult, int maxResults);


        IList<Bookmark> GetMostRecentBookmarks(int firstResult, int maxResults);
        IList<Bookmark> GetMostRecentBookmarksWithRaiting(int firstResult, int maxResults);
        IList<Bookmark> GetTopOfTheDay(int firstResult, int maxResults);
        IList<Bookmark> GetTopOfTheWeek(int firstResult, int maxResults);
        IList<Bookmark> GetTopOfTheMonth(int firstResult, int maxResults);
        IList<Bookmark> GetTopOfTheYear(int firstResult, int maxResults);

        #region Tags		

        IList<Bookmark> GetMostPopularBookmarksByTag(Tag t);
        IList<Bookmark> GetMostPopularBookmarksByTag(IList<Tag> tags);
        IList<Tag> GetBookmarkTags(Bookmark b);
        IList<Tag> GetUserBookmarkTags(UserBookmark b);

        #endregion

        #region Comments

        Comment GetCommentById(Guid commentID);

        void AddComment(Comment comment);

        void UpdateComment(Guid commentID, string text);

        void RemoveComment(Guid commentID);

        long GetCommentsCount(long bookmarkID);

        IList<Comment> GetBookmarkComments(Bookmark b);

        IList<Comment> GetChildComments(Comment c);

        #endregion

        void Subscribe(string objectID, INotifyAction notifyAction);

        bool IsSubscribed(string objectID, INotifyAction notifyAction);

        void UnSubscribe(string objectID, INotifyAction notifyAction, Guid? userID = null);

        #region Search

        IList<Bookmark> SearchBookmarks(IList<string> searchStringList, int firstResult, int maxResults);

        IList<Bookmark> SearchAllBookmarks(IList<string> searchStringList);

        IList<Bookmark> SearchBookmarksSortedByRaiting(IList<string> searchStringList, int firstResult, int maxResults);

        IList<Bookmark> SearchBookmarksByTag(string searchString, int firstResult, int maxResults);

        IList<Bookmark> SearchMostPopularBookmarksByTag(string tagName, int firstResult, int maxResults);

        #endregion

        IList<Bookmark> GetBookmarksCreatedByUser(Guid userID, int firstResult, int maxResults);

        IList<Bookmark> GetMostPopularBookmarksCreatedByUser(Guid userID, int firstResult, int maxResults);

        long GetBookmarksCountCreatedByUser(Guid userID);


        IList<Bookmark> GetFullBookmarksInfo(IList<long> bookmarkIds);

        IList<Bookmark> GetFullBookmarksInfo(IList<Bookmark> bookmarks);

        void SetBookmarkTags(Bookmark b);
    }
}


<|start_filename|>common/ASC.Core.Common/Notify/Telegram/TelegramServiceClient.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Module;
using ASC.Notify.Messages;

namespace ASC.Core.Common.Notify
{
    public class TelegramServiceClient : BaseWcfClient<ITelegramService>, ITelegramService, IDisposable
    {
        public void SendMessage(NotifyMessage m)
        {
            Channel.SendMessage(m);
        }

        public void RegisterUser(string userId, int tenantId, string token)
        {
            Channel.RegisterUser(userId, tenantId, token);
        }

        public bool CheckConnection(int tenantId, string token, int tokenLifespan, string proxy)
        {
            return Channel.CheckConnection(tenantId, token, tokenLifespan, proxy);
        }

        public string RegistrationToken(string userId, int tenantId)
        {
            return Channel.RegistrationToken(userId, tenantId);
        }
    }
}


<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Models/IServiceRepository.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

namespace ASC.HealthCheck.Models
{
    public interface IServiceRepository
    {
        void Add(ServiceEnum serviceName);

        void Remove(ServiceEnum serviceName);

        bool HasAtempt(ServiceEnum serviceName);

        void SetStates(ServiceEnum serviceName, string status, string message);

        Service GetService(ServiceEnum serviceName);

        List<object> GetServices();

        List<Service> GetServicesSnapshot();

        void DropAttempt(ServiceEnum serviceName);

        bool ShouldRestart(ServiceEnum serviceName);
    }
}


<|start_filename|>module/ASC.Radicale/Launcher.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Reflection;

using ASC.Common.Logging;
using ASC.Common.Module;
using ASC.Core;


namespace ASC.Radicale
{
    public class Launcher : IServiceController
    {
        private static Process proc;
        private static ProcessStartInfo startInfo;
        private static readonly ILog Logger = LogManager.GetLogger("ASC");
        public void Start()
        {
            try
            {
                var cfg = (RadicaleCfgSectionHandler)ConfigurationManagerExtension.GetSection("radicale");
                var pythonName = "python";

                if (WorkContext.IsMono)
                {
                    pythonName = "python3";
                }

                startInfo = new ProcessStartInfo
                {
                    CreateNoWindow = false,
                    UseShellExecute = false,
                    FileName = pythonName,
                    WindowStyle = ProcessWindowStyle.Hidden,
                    Arguments = string.Format("-m radicale --config \"{0}\"",
                                                Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "radicale.config"))),
                    WorkingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)
                };

                StartRedicale();
            }
            catch (Exception e)
            {
                Logger.Error(e);
            }
        }

        public void Stop()
        {
            StopRadicale();
        }

        private static void StartRedicale()
        {
            StopRadicale();
            proc = Process.Start(startInfo);

        }

        private static void StopRadicale()
        {
            try
            {
                if (proc != null && !proc.HasExited)
                {
                    proc.Kill();
                    if (!proc.WaitForExit(10000))
                    {
                        Logger.Warn("The process does not wait for completion.");
                    }
                    proc.Close();
                    proc.Dispose();
                    proc = null;
                }
            }
            catch (Exception e)
            {
                Logger.Error("Radicale failed stop", e);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/People/js/peoplecore.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


jQuery.extend({
    /**
    * Returns get parameters.
    *
    * If the desired param does not exist, null will be returned
    *
    * @example value = jq.getAnchorParam("paramName", url);
    */

    getAnchorParam: function(paramName, url) {
        var url = url || window.location.href.toLowerCase();
        var regex = new RegExp("[#&]" + paramName + "=([^&]*)");
        var results = regex.exec('#' + url);
        if (results == null) {
            return "";
        } else {
            return results[1];
        }
    },
    hasParam: function(paramName, url) {
        var regex = new RegExp('(\\#|&|^)' + paramName + '=', 'g'); //matches `#param=` or `&param=` or `param=`
        return regex.test(url);
    },
    removeParam: function(paramName, url) {
        if (url === '')
            return '';

        var regex = new RegExp("(\\#|&|^)" + paramName + "=([^&]*)");
        return url.replace(regex, '');
    },
    addParam: function(paramsList, name, value) {
        if (paramsList.length) paramsList += '&';
        paramsList = paramsList + name + '=' + value;
        return paramsList;
    },
    changeParamValue: function(paramsList, name, value) {
        var symbols = ['\\#', '&', '^'];
        if (jq.hasParam(name, paramsList)) {
            for (var i = 0; i < symbols.length; i++) {

                var regex = new RegExp(symbols[i] + name + "[=][0-9a-z\-]*");
                var s = symbols[i] == '^' ? '' : symbols[i];
                paramsList = paramsList.replace(regex, s + name + '=' + value);


            }
            return paramsList;
        } else {
            return jq.addParam(paramsList, name, value);
        }
    },
    clearUrl: function() {
        var url = window.location.href;
        if (url.indexOf("#") == -1)
            return url;
        return url.split("#")[0];
    },

    mergeAnchors: function mergeAnchors(a1, a2) {
        var a = {};
        for (var fld in a1) {
            if (a1.hasOwnProperty(fld)) {
                a[fld] = a1[fld];
            }
        }

        for (var fld in a2) {
            if (a2.hasOwnProperty(fld)) {
                a[fld] = a2[fld];
            }
        }
        return a;
    },

    anchorToObject: function (s) {
        s = s.charAt(0) === '#' ? s.substring(1) : s;

        var o = {};
        s = s.split('&');
        for (var i = 0, n = s.length; i < n; i++) {
            s[i] = s[i].split('=');
            if (s[i].length === 2) {
                o[s[i][0]] = s[i][1];
            }
        }
        return o;
    },
    objectToAnchor: function (o) {
        var s = [];
        for (var fld in o) {
            if (o.hasOwnProperty(fld)) {
                s.push(fld + '=' + o[fld]);
            }
        }
        return s.join('&');
    },
    isEqualAnchors: function (a1, a2) {
        for (var fld in a1) {
            if (a1.hasOwnProperty(fld) && !a2.hasOwnProperty(fld) || a1[fld] !== a2[fld]) {
                return false;
            }
        }

        for (var fld in a2) {
            if (a2.hasOwnProperty(fld) && !a1.hasOwnProperty(fld) || a2[fld] !== a1[fld]) {
                return false;
            }
        }
        return true;
    }
});

String.prototype.htmlEncode = function () {
    return jQuery(document.createElement('div')).text(this.toString()).html();
};

if (typeof(ASC) == 'undefined')
    ASC = {};
    
ASC.People = ASC.People || {};
ASC.People.model = ASC.People.model || {};

ASC.People.eventSource = {
  document: 'document',
  filter: 'filter',
  anchor: 'anchor',
  navigator: 'navigator'
};

ASC.People.model.groups = ASC.People.model.groups || [];
ASC.People.model.profiles = ASC.People.model.profiles || [];

ASC.People.eventHandler = {
  create: function (s, handler) {
    handler.prototype = {
      source: s,
      handle: function (type, data) {
        if (this.source && this.source === data.source) {
          return;
        } else if (typeof this[type] === 'function') {
          this[type](data);
        }
      }
    };
    return new handler();
  }
};

ASC.People.controller = {
  registryHandler: function (handler) {
    this.subscribers[this.subscribers.length] = handler;
  },

  publish: function (eventSource, type, data) {
    for (var i = 0, n = this.subscribers.length; i < n; i++) {
      if (typeof this.subscribers[i].handle === 'function') {
        this.subscribers[i].handle(type, data);
      }
    }
  },

  make: function(controller, handlers) {
    for (var i in this) {
      controller.prototype[i] = this[i];
    }
    controller.prototype.subscribers = [];

    if (typeof handlers === 'object' && typeof handlers.length !== 'undefined') {
      for (var i = 0, n = handlers.length; i < n; i++) {
        controller.prototype.subscribers.push(handlers[i]);
      }
    } else if (typeof views === 'object') {
      controller.prototype.subscribers.push(handlers);
    }

    return new controller();
  }
};

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_ContentCoding.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Implements SIP "content-coding" value. Defined in RFC 3261.
    /// </summary>
    /// <remarks>
    /// <code>
    /// RFC 3261 Syntax:
    ///     content-coding = token
    /// </code>
    /// </remarks>
    public class SIP_t_ContentCoding : SIP_t_Value
    {
        #region Members

        private string m_Encoding = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets content encoding.
        /// </summary>
        public string Encoding
        {
            get { return m_Encoding; }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("Property Encoding value may not be null or empty !");
                }
                if (!TextUtils.IsToken(value))
                {
                    throw new ArgumentException("Encoding value may be 'token' only !");
                }

                m_Encoding = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "content-coding" from specified value.
        /// </summary>
        /// <param name="value">SIP "content-coding" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>value</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "content-coding" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            /*
                content-coding = token
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // Get Method
            string word = reader.ReadWord();
            if (word == null)
            {
                throw new SIP_ParseException("Invalid 'content-coding' value, value is missing !");
            }
            m_Encoding = word;
        }

        /// <summary>
        /// Converts this to valid "content-coding" value.
        /// </summary>
        /// <returns>Returns "content-coding" value.</returns>
        public override string ToStringValue()
        {
            return m_Encoding;
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Core.Common/Notify/Telegram/Dao/CachedTelegramDao.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Caching;

namespace ASC.Core.Common.Notify.Telegram
{
    public class CachedTelegramDao
    {
        private TelegramDao tgDao { get; set; }
        private ICache cache { get; set; }
        private TimeSpan Expiration { get; set; }

        private string PairKeyFormat { get; set; }
        private string SingleKeyFormat { get; set; }

        private static CachedTelegramDao _instance;
        public static CachedTelegramDao Instance
        {
            get
            {
                if (_instance != null) return _instance;

                _instance = new CachedTelegramDao("default");
                return _instance;
            }
        }

        private CachedTelegramDao(string dbid)
        {
            tgDao = new TelegramDao(dbid);
            cache = AscCache.Memory;
            Expiration = TimeSpan.FromMinutes(20);

            PairKeyFormat = "tgUser:{0}:{1}";
            SingleKeyFormat = "tgUser:{0}";
        }

        public void Delete(Guid userId, int tenantId)
        {
            cache.Remove(string.Format(PairKeyFormat, userId, tenantId));
            tgDao.Delete(userId, tenantId);
        }

        public void Delete(int telegramId)
        {
            cache.Remove(string.Format(SingleKeyFormat, telegramId));
            tgDao.Delete(telegramId);
        }

        public TelegramUser GetUser(Guid userId, int tenantId)
        {
            var key = string.Format(PairKeyFormat, userId, tenantId);

            var user = cache.Get<TelegramUser>(key);
            if (user != null) return user;

            user = tgDao.GetUser(userId, tenantId);
            if (user != null) cache.Insert(key, user, Expiration);
            return user;
        }

        public List<TelegramUser> GetUser(int telegramId)
        {
            var key = string.Format(SingleKeyFormat, telegramId);

            var users = cache.Get<List<TelegramUser>>(key);
            if (users != null) return users;

            users = tgDao.GetUser(telegramId);
            if (users.Any()) cache.Insert(key, users, Expiration);
            return users;
        }

        public void RegisterUser(Guid userId, int tenantId, int telegramId)
        {
            tgDao.RegisterUser(userId, tenantId, telegramId);

            var key = string.Format(PairKeyFormat, userId, tenantId);
            cache.Insert(key, new TelegramUser() { PortalUserId = userId, TenantId = tenantId, TelegramId = telegramId }, Expiration);
        }
    }
}


<|start_filename|>common/ASC.Data.Storage.Encryption/NotifyHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Logging;
using ASC.Core.Notify;

namespace ASC.Data.Storage.Encryption
{
    internal class NotifyHelper
    {
        private const string NotifyService = "ASC.Web.Studio.Core.Notify.StudioNotifyService, ASC.Web.Studio";

        private readonly string ServerRootPath;

        public NotifyHelper(string serverRootPath)
        {
            ServerRootPath = serverRootPath;
        }

        public void SendStorageEncryptionStart(int tenantId)
        {
            SendStorageEncryptionNotification("SendStorageEncryptionStart", tenantId);
        }

        public void SendStorageEncryptionSuccess(int tenantId)
        {
            SendStorageEncryptionNotification("SendStorageEncryptionSuccess", tenantId);
        }

        public void SendStorageEncryptionError(int tenantId)
        {
            SendStorageEncryptionNotification("SendStorageEncryptionError", tenantId);
        }

        public void SendStorageDecryptionStart(int tenantId)
        {
            SendStorageEncryptionNotification("SendStorageDecryptionStart", tenantId);
        }

        public void SendStorageDecryptionSuccess(int tenantId)
        {
            SendStorageEncryptionNotification("SendStorageDecryptionSuccess", tenantId);
        }

        public void SendStorageDecryptionError(int tenantId)
        {
            SendStorageEncryptionNotification("SendStorageDecryptionError", tenantId);
        }

        private void SendStorageEncryptionNotification(string method, int tenantId)
        {
            try
            {
                using (var notifyClient = new NotifyServiceClient())
                {
                    notifyClient.InvokeSendMethod(NotifyService, method, tenantId, ServerRootPath);
                }
            }
            catch (Exception error)
            {
                LogManager.GetLogger("ASC").Warn("Error while sending notification", error);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/tags/dropdown.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.tagsDropdown = (function($) {
    var popup,
        popupId = '#addTagsPanel',
        isInit = false,
        showButton;

    function init() {
        if (isInit === false) {
            isInit = true;

            popup = $(popupId);
        }
    }

    function prepareOptions(opts) {
        if (!opts)
            opts = {};

        var options = {};

        options.hideMarkRecipients = typeof opts !== "object" ||
            typeof opts.hideMarkRecipients === "undefined" ||
            opts.hideMarkRecipients === null
            ? false
            : opts.hideMarkRecipients;

        options.onSelect = typeof opts !== "object" ||
            typeof opts.onSelect === "undefined" ||
            typeof opts.onSelect !== "function"
            ? function (e, tag) {
                console.log("Default onSelect callback has been called", tag);
            }
            : opts.onSelect;

        options.onDeselect = typeof opts !== "object" ||
            typeof opts.onDeselect === "undefined" ||
            typeof opts.onDeselect !== "function"
            ? function (e, tag) {
                console.log("Default onDeselect callback has been called", tag);
            }
            : opts.onDeselect;

        options.getUsedTagsIds = typeof opts !== "object" ||
            typeof opts.getUsedTagsIds === "undefined" ||
            typeof opts.getUsedTagsIds !== "function"
            ? function () {
                console.log("Default getUsedTagsIds callback has been called");
                return [];
            }
            : opts.getUsedTagsIds;

        return options;
    }

    function draw() {
        var offset = $(showButton).offset();
        popup.css({ left: offset.left, top: offset.top + $(showButton).height() }).show();
    }

    function showMarkRecipientsCheckbox() {
        var cbx = popup.find("#markallrecipients");
        cbx.prop('checked', false);
        cbx.show();
        cbx.unbind('click').bind('click', manageCrmTags);

        var cbxLbl = popup.find("#markallrecipientsLabel");
        cbxLbl.show();

        var fromAddress = messagePage.getFromAddress(messagePage.getActualConversationLastMessageId());
        fromAddress = ASC.Mail.Utility.ParseAddress(fromAddress).email;

        if (accountsManager.getAccountByAddress(fromAddress)) {
            cbxLbl.text(MailScriptResource.MarkAllRecipientsLabel);
        } else {
            cbxLbl.text(MailScriptResource.MarkAllSendersLabel);
        }
    }

    function hideMarkRecipientsCheckbox() {
        var cbx = popup.find("#markallrecipients");
        cbx.prop('checked', false);
        cbx.hide();

        var cbxLbl = popup.find("#markallrecipientsLabel");
        cbxLbl.hide();
    }

    function manageCrmTags(e) {
        var tags = popup.find("#tagsPanelContent .tag");

        tags.each(function() {
            var el = $(this);
            if (e.target.checked) {
                if (el.attr('tag_id') < 0) {
                    el.addClass("disabled");
                }
            } else {
                if (el.attr('tag_id') < 0) {
                    el.removeClass("disabled");
                }
            }
        });
    }

    function getTagContent(options) {
        var tags = tagsManager.getAllTags();
        var usedTagsIds = options.getUsedTagsIds();

        for (var i = 0; i < tags.length; i++) {
            tags[i].used = usedTagsIds.length > 0 ? ($.inArray(tags[i].id, usedTagsIds) > -1) : false;
        }

        var res = $.tmpl('tagInPanelTmpl', tags, { htmlEncode: TMMail.htmlEncode });
        return res;
    }

    // Rerurns flag value. Flag: Is needed to set tag for all messages sended from that user.
    function checked() {
        var cbx = popup.find("#markallrecipients");
        return cbx.prop('checked');
    }

    function createLabel(options) {
        hide();

        tagsModal.showCreate({
            onSuccess: function (tag) {
                options.onSelect(
                {
                    id: tag.id,
                    name: tag.name
                });
            }
        });
    }

    function filteredHide(event) {
        var elt = (event.target) ? event.target : event.srcElement;
        if (!($(elt).is(popupId + ' *') || $(elt).is(popupId) || $(elt).is('div[colorstyle]'))) {
            hide();
        }
    }

    // shows add tags panel near obj element depending on current page
    function show(obj, opts) {
        if (popup.is(":visible")) {
            hide();
            return;
        }

        var options = prepareOptions(opts);

        var tagContent = getTagContent(options);

        popup.find(".existsTags").html(tagContent);

        var $tag = popup.find(".tag.inactive");
        $tag.unbind('click').bind('click', function (e) {
            var el = $(this);

            if (el.hasClass("disabled")) return;

            options.onSelect.call(e,
                {
                    id: el.attr('tag_id'),
                    name: el.text()
                });
            hide();
        });

        $tag = popup.find(".tag.tagArrow");
        $tag.unbind('click').bind('click', function (e) {
            var el = $(this);

            if (el.hasClass("disabled")) return;

            options.onDeselect.call(e,
                {
                    id: el.attr('tag_id'),
                    name: el.text()
                });
            hide();
        });

        if (options.hideMarkRecipients) {
            hideMarkRecipientsCheckbox();
        } else {
            showMarkRecipientsCheckbox();
        }

        TMMail.setRequiredError('addTagsPanel', false);

        showButton = obj;

        draw();

        popup.find('.popup-corner').removeClass('bottom');

        dropdown.regHide(filteredHide);
        dropdown.regScroll(draw);

        popup.find('.entertag_button')
            .unbind('click')
            .bind('click',
                function () {
                    createLabel(options);
                });
    }

    function hide() {
        popup.hide();
        tagsColorsPopup.hide();
        dropdown.unregHide(filteredHide);
        dropdown.unregHide(draw);
        popup.find('.entertag_button').unbind('click');
    }

    return {
        init: init,
        show: show,
        hide: hide,

        isMarkChecked: checked
    };
})(jQuery);

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/ABNF/ABNF_Repetition.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.ABNF
{
    #region usings

    using System;
    using System.IO;
    using System.Text;

    #endregion

    /// <summary>
    /// This class represent ABNF "repetition". Defined in RFC 5234 4.
    /// </summary>
    public class ABNF_Repetition
    {
        #region Members

        private readonly int m_Max = int.MaxValue;
        private readonly int m_Min;
        private readonly ABNF_Element m_pElement;

        #endregion

        #region Properties

        /// <summary>
        /// Gets minimum repetitions.
        /// </summary>
        public int Min
        {
            get { return m_Min; }
        }

        /// <summary>
        /// Gets maximum repetitions.
        /// </summary>
        public int Max
        {
            get { return m_Max; }
        }

        /// <summary>
        /// Gets repeated element.
        /// </summary>
        public ABNF_Element Element
        {
            get { return m_pElement; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="min">Minimum repetitions.</param>
        /// <param name="max">Maximum repetitions.</param>
        /// <param name="element">Repeated element.</param>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>element</b> is null reference.</exception>
        public ABNF_Repetition(int min, int max, ABNF_Element element)
        {
            if (min < 0)
            {
                throw new ArgumentException("Argument 'min' value must be >= 0.");
            }
            if (max < 0)
            {
                throw new ArgumentException("Argument 'max' value must be >= 0.");
            }
            if (min > max)
            {
                throw new ArgumentException("Argument 'min' value must be <= argument 'max' value.");
            }
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            m_Min = min;
            m_Max = max;
            m_pElement = element;
        }

        #endregion

        #region Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static ABNF_Repetition Parse(StringReader reader)
        {
            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            /*
                repetition     =  [repeat] element
                repeat         =  1*DIGIT / (*DIGIT "*" *DIGIT)
                element        =  rulename / group / option / char-val / num-val / prose-val
            */

            int min = 0;
            int max = int.MaxValue;

            // --- range ------------------------------------
            if (char.IsDigit((char) reader.Peek()))
            {
                StringBuilder minString = new StringBuilder();
                while (char.IsDigit((char) reader.Peek()))
                {
                    minString.Append((char) reader.Read());
                }
                min = Convert.ToInt32(minString.ToString());
            }
            if (reader.Peek() == '*')
            {
                reader.Read();
            }
            if (char.IsDigit((char) reader.Peek()))
            {
                StringBuilder maxString = new StringBuilder();
                while (char.IsDigit((char) reader.Peek()))
                {
                    maxString.Append((char) reader.Read());
                }
                max = Convert.ToInt32(maxString.ToString());
            }
            //-----------------------------------------------

            // End of stream reached.
            if (reader.Peek() == -1)
            {
                return null;
            }
                // We have rulename.
            else if (char.IsLetter((char) reader.Peek()))
            {
                return new ABNF_Repetition(min, max, ABNF_RuleName.Parse(reader));
            }
                // We have group.
            else if (reader.Peek() == '(')
            {
                return new ABNF_Repetition(min, max, ABFN_Group.Parse(reader));
            }
                // We have option.
            else if (reader.Peek() == '[')
            {
                return new ABNF_Repetition(min, max, ABNF_Option.Parse(reader));
            }
                // We have char-val.
            else if (reader.Peek() == '\"')
            {
                return new ABNF_Repetition(min, max, ABNF_CharVal.Parse(reader));
            }
                // We have num-val.
            else if (reader.Peek() == '%')
            {
                // Eat '%'.
                reader.Read();

                if (reader.Peek() == 'd')
                {
                    return new ABNF_Repetition(min, max, ABNF_DecVal.Parse(reader));
                }
                else
                {
                    throw new ParseException("Invalid 'num-val' value '" + reader.ReadToEnd() + "'.");
                }
            }
                // We have prose-val.
            else if (reader.Peek() == '<')
            {
                return new ABNF_Repetition(min, max, ABNF_ProseVal.Parse(reader));
            }

            return null;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/Resources/MailActionCompleteResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Mail.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class MailActionCompleteResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal MailActionCompleteResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Mail.Resources.MailActionCompleteResource", typeof(MailActionCompleteResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New contact was added successfully..
        /// </summary>
        public static string AddContactSuccess {
            get {
                return ResourceManager.GetString("AddContactSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailbox &quot;{0}&quot; was added successfully..
        /// </summary>
        public static string AddMailboxSuccess {
            get {
                return ResourceManager.GetString("AddMailboxSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail group &quot;{0}&quot; was added successfully..
        /// </summary>
        public static string AddMailGroupSuccess {
            get {
                return ResourceManager.GetString("AddMailGroupSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The %folder% has been emptied..
        /// </summary>
        public static string clearFolder {
            get {
                return ResourceManager.GetString("clearFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All selected conversations have been deleted..
        /// </summary>
        public static string deleteFilteredConversations {
            get {
                return ResourceManager.GetString("deleteFilteredConversations", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All selected messages have been deleted..
        /// </summary>
        public static string deleteFilteredMessages {
            get {
                return ResourceManager.GetString("deleteFilteredMessages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %count% contacts have been deleted..
        /// </summary>
        public static string DeleteManyContacts {
            get {
                return ResourceManager.GetString("DeleteManyContacts", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %count% conversations have been deleted..
        /// </summary>
        public static string deleteManyConversations {
            get {
                return ResourceManager.GetString("deleteManyConversations", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %count% messages have been deleted..
        /// </summary>
        public static string deleteManyMessages {
            get {
                return ResourceManager.GetString("deleteManyMessages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The contact has been deleted..
        /// </summary>
        public static string DeleteOneContact {
            get {
                return ResourceManager.GetString("DeleteOneContact", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The conversation has been deleted..
        /// </summary>
        public static string deleteOneConversation {
            get {
                return ResourceManager.GetString("deleteOneConversation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The message has been deleted..
        /// </summary>
        public static string deleteOneMessage {
            get {
                return ResourceManager.GetString("deleteOneMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The contact has been successfully changed..
        /// </summary>
        public static string EditContactSuccess {
            get {
                return ResourceManager.GetString("EditContactSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All selected conversations have been moved to the %folder%..
        /// </summary>
        public static string moveFilteredConversationsTo {
            get {
                return ResourceManager.GetString("moveFilteredConversationsTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All selected messages have been moved to the %folder%..
        /// </summary>
        public static string moveFilteredMessagesTo {
            get {
                return ResourceManager.GetString("moveFilteredMessagesTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %count% conversations have been moved to the %folder%..
        /// </summary>
        public static string moveManyConversationsTo {
            get {
                return ResourceManager.GetString("moveManyConversationsTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %count% messages have been moved to the %folder%..
        /// </summary>
        public static string moveManyMessagesTo {
            get {
                return ResourceManager.GetString("moveManyMessagesTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The conversation has been moved to the %folder%..
        /// </summary>
        public static string moveOneConversationTo {
            get {
                return ResourceManager.GetString("moveOneConversationTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The message has been moved to the %folder%..
        /// </summary>
        public static string moveOneMessageTo {
            get {
                return ResourceManager.GetString("moveOneMessageTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The domain &quot;{0}&quot; was removed successfully..
        /// </summary>
        public static string RemoveDomainSuccess {
            get {
                return ResourceManager.GetString("RemoveDomainSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailbox &quot;{0}&quot; was removed successfully..
        /// </summary>
        public static string RemoveMailboxSuccess {
            get {
                return ResourceManager.GetString("RemoveMailboxSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mail group &quot;{0}&quot; was removed successfully..
        /// </summary>
        public static string RemoveMailGroupSuccess {
            get {
                return ResourceManager.GetString("RemoveMailGroupSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All selected conversations have been restored..
        /// </summary>
        public static string restoreFilteredConversations {
            get {
                return ResourceManager.GetString("restoreFilteredConversations", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All selected messages have been restored..
        /// </summary>
        public static string restoreFilteredMessages {
            get {
                return ResourceManager.GetString("restoreFilteredMessages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %count% conversations have been restored..
        /// </summary>
        public static string restoreManyConversations {
            get {
                return ResourceManager.GetString("restoreManyConversations", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to %count% messages have been restored..
        /// </summary>
        public static string restoreManyMessages {
            get {
                return ResourceManager.GetString("restoreManyMessages", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The conversation has been restored to the %folder%..
        /// </summary>
        public static string restoreOneConversationTo {
            get {
                return ResourceManager.GetString("restoreOneConversationTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The message has been restored to the %folder%..
        /// </summary>
        public static string restoreOneMessageTo {
            get {
                return ResourceManager.GetString("restoreOneMessageTo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailbox &quot;{0}&quot; was updated successfully..
        /// </summary>
        public static string updateMailboxSuccess {
            get {
                return ResourceManager.GetString("updateMailboxSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Mailgroup &quot;{0}&quot; was updated successfully..
        /// </summary>
        public static string updateMailGroupSuccess {
            get {
                return ResourceManager.GetString("updateMailGroupSuccess", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Helpers/WordpressHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Logging;
using ASC.FederatedLogin;
using ASC.FederatedLogin.LoginProviders;
using ASC.Web.Files.Classes;
using ASC.Web.Files.ThirdPartyApp;

namespace ASC.Web.Files.Helpers
{
    public class WordpressToken
    {
        public static ILog Log = Global.Logger;
        public const string AppAttr = "wordpress";

        public static OAuth20Token GetToken()
        {
            return Token.GetToken(AppAttr);
        }

        public static void SaveToken(OAuth20Token token)
        {
            if (token == null) throw new ArgumentNullException("token");
            Token.SaveToken(new Token(token, AppAttr));
        }
        public static void DeleteToken(OAuth20Token token)
        {
            if (token == null) throw new ArgumentNullException("token");
            Token.DeleteToken(AppAttr);

        }
    }
    public class WordpressHelper
    {
        public static ILog Log = Global.Logger;
        public enum WordpressStatus
        {
            draft = 0,
            publish = 1
        }

        public static string GetWordpressMeInfo(string token)
        {
            try
            {
                return WordpressLoginProvider.GetWordpressMeInfo(token);
            }
            catch (Exception ex)
            {
                Log.Error("Get Wordpress info about me ", ex);
                return "";
            }

        }

        public static bool CreateWordpressPost(string title, string content, int status, string blogId, OAuth20Token token)
        {
            try
            {
                var wpStatus = ((WordpressStatus)status).ToString();
                WordpressLoginProvider.CreateWordpressPost(title, content, wpStatus, blogId, token);
                return true;
            }
            catch (Exception ex)
            {
                Log.Error("Create Wordpress post ", ex);
                return false;
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IMAP/Server/IMAP_Message.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IMAP.Server
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// IMAP message info.
    /// </summary>
    public class IMAP_Message:IDisposable
    {
        #region Members

        private readonly string m_ID = "";
        private readonly DateTime m_InternalDate = DateTime.Now;
        private readonly IMAP_MessageCollection m_pOwner;
        private readonly long m_Size;
        private readonly long m_UID;
        private IMAP_MessageFlags m_Flags = IMAP_MessageFlags.None;

        #endregion

        #region Properties

        /// <summary>
        /// Gets message 1 based sequence number in the collection. This property is slow, use with care, never use in big for loops !
        /// </summary>
        public int SequenceNo
        {
            get { return m_pOwner.IndexOf(this) + 1; }
        }

        /// <summary>
        /// Gets message ID.
        /// </summary>
        public string ID
        {
            get { return m_ID; }
        }

        /// <summary>
        /// Gets message IMAP UID value.
        /// </summary>
        public long UID
        {
            get { return m_UID; }
        }

        /// <summary>
        /// Gets message store date.
        /// </summary>
        public DateTime InternalDate
        {
            get { return m_InternalDate; }
        }

        /// <summary>
        /// Gets message size in bytes.
        /// </summary>
        public long Size
        {
            get { return m_Size; }
        }

        /// <summary>
        /// Gets message flags.
        /// </summary>
        public IMAP_MessageFlags Flags
        {
            get { return m_Flags; }
        }

        /// <summary>
        /// Gets message flags string. For example: "\DELETES \SEEN".
        /// </summary>
        public string FlagsString
        {
            get { return IMAP_Utils.MessageFlagsToString(m_Flags); }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="onwer">Owner collection.</param>
        /// <param name="id">Message ID.</param>
        /// <param name="uid">Message IMAP UID value.</param>
        /// <param name="internalDate">Message store date.</param>
        /// <param name="size">Message size in bytes.</param>
        /// <param name="flags">Message flags.</param>
        internal IMAP_Message(IMAP_MessageCollection onwer,
                              string id,
                              long uid,
                              DateTime internalDate,
                              long size,
                              IMAP_MessageFlags flags)
        {
            m_pOwner = onwer;
            m_ID = id;
            m_UID = uid;
            m_InternalDate = internalDate;
            m_Size = size;
            m_Flags = flags;
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Sets message flags.
        /// </summary>
        /// <param name="flags">Message flags.</param>
        internal void SetFlags(IMAP_MessageFlags flags)
        {
            m_Flags = flags;
        }

        #endregion

        public void Dispose()
        {
            
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/ProjectApi.Messages.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Api.Attributes;
using ASC.Api.Documents;
using ASC.Api.Employee;
using ASC.Api.Exceptions;
using ASC.Api.Projects.Wrappers;
using ASC.Api.Utils;
using ASC.MessagingSystem;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Specific;
using ASC.Web.Studio.Utility.HtmlUtility;

namespace ASC.Api.Projects
{
    public partial class ProjectApi
    {
        ///<summary>
        ///Returns the list with the detailed information about all the message matching the filter parameters specified in the request
        ///</summary>
        ///<short>
        /// Get message by filter
        ///</short>
        ///<category>Discussions</category>
        ///<param name="projectid" optional="true"> Project ID</param>
        ///<param name="tag" optional="true">Project Tag</param>
        ///<param name="departament" optional="true">Departament GUID</param>
        ///<param name="participant" optional="true">Participant GUID</param>
        ///<param name="createdStart" optional="true">Minimum value of message creation date</param>
        ///<param name="createdStop" optional="true">Maximum value of message creation date</param>
        ///<param name="lastId">Last message ID</param>
        ///<param name="myProjects">Messages in my projects</param>
        ///<param name="follow">Followed messages</param>
        ///<param name="status"></param>
        ///<returns>List of messages</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"message/filter")]
        public IEnumerable<MessageWrapper> GetMessageByFilter(int projectid, int tag, Guid departament, Guid participant,
                                                              ApiDateTime createdStart, ApiDateTime createdStop, int lastId,
                                                              bool myProjects, bool follow, MessageStatus? status)
        {
            var messageEngine = EngineFactory.MessageEngine;
            var filter = CreateFilter(EntityType.Message);

            filter.DepartmentId = departament;
            filter.UserId = participant;
            filter.FromDate = createdStart;
            filter.ToDate = createdStop;
            filter.TagId = tag;
            filter.MyProjects = myProjects;
            filter.LastId = lastId;
            filter.Follow = follow;
            filter.MessageStatus = status;

            if (projectid != 0)
                filter.ProjectIds.Add(projectid);

            SetTotalCount(messageEngine.GetByFilterCount(filter));

            return messageEngine.GetByFilter(filter).NotFoundIfNull().Select(MessageWrapperSelector).ToList();
        }

        ///<summary>
        ///Returns the list of all the messages in the discussions within the project with the ID specified in the request
        ///</summary>
        ///<short>
        ///Messages
        ///</short>
        ///<category>Discussions</category>
        ///<param name="projectid">Project ID</param>
        ///<returns>List of messages</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"{projectid:[0-9]+}/message")]
        public IEnumerable<MessageWrapper> GetProjectMessages(int projectid)
        {
            var project = EngineFactory.ProjectEngine.GetByID(projectid).NotFoundIfNull();

            if (!ProjectSecurity.CanRead<Message>(project)) throw ProjectSecurity.CreateSecurityException();

            return EngineFactory.MessageEngine.GetByProject(projectid).Select(MessageWrapperSelector).ToList();
        }

        ///<summary>
        ///Adds a message to the selected discussion within the project with the ID specified in the request
        ///</summary>
        ///<short>
        ///Add message
        ///</short>
        ///<category>Discussions</category>
        ///<param name="projectid">Project ID</param>
        ///<param name="title">Discussion title</param>
        ///<param name="content">Message text</param>
        ///<param name="participants">IDs (GUIDs) of users separated with ','</param>
        ///<param name="notify">Notify participants</param>
        ///<returns></returns>
        ///<exception cref="ArgumentException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        [Create(@"{projectid:[0-9]+}/message")]
        public MessageWrapper AddProjectMessage(int projectid, string title, string content, string participants, bool? notify)
        {
            if (string.IsNullOrEmpty(title)) throw new ArgumentException(@"title can't be empty", "title");
            if (string.IsNullOrEmpty(content)) throw new ArgumentException(@"description can't be empty", "content");

            var project = EngineFactory.ProjectEngine.GetByID(projectid).NotFoundIfNull();
            ProjectSecurity.DemandCreate<Message>(project);

            var messageEngine = EngineFactory.MessageEngine;
            var discussion = new Message
            {
                Description = content,
                Title = title,
                Project = project,
            };

            messageEngine.SaveOrUpdate(discussion, notify.HasValue ? notify.Value : true, ToGuidList(participants));
            MessageService.Send(Request, MessageAction.DiscussionCreated, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title);

            return MessageWrapperSelector(discussion);
        }

        ///<summary>
        ///Updates the selected message in the discussion within the project with the ID specified in the request
        ///</summary>
        ///<short>
        ///Update message
        ///</short>
        ///<category>Discussions</category>
        ///<param name="messageid">Message ID</param>
        ///<param name="projectid">Project ID</param>
        ///<param name="title">Discussion title</param>
        ///<param name="content">Message text</param>
        ///<param name="participants">IDs (GUIDs) of users separated with ','</param>
        ///<param name="notify">Notify participants</param>
        ///<returns></returns>
        ///<exception cref="ArgumentException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        [Update(@"message/{messageid:[0-9]+}")]
        public MessageWrapperFull UpdateProjectMessage(int messageid, int projectid, string title, string content, string participants, bool? notify)
        {
            var messageEngine = EngineFactory.MessageEngine;

            var discussion = messageEngine.GetByID(messageid).NotFoundIfNull();
            var project = EngineFactory.ProjectEngine.GetByID(projectid).NotFoundIfNull();
            ProjectSecurity.DemandEdit(discussion);

            discussion.Project = Update.IfNotEmptyAndNotEquals(discussion.Project, project);
            discussion.Description = Update.IfNotEmptyAndNotEquals(discussion.Description, content);
            discussion.Title = Update.IfNotEmptyAndNotEquals(discussion.Title, title);

            messageEngine.SaveOrUpdate(discussion, notify.HasValue ? notify.Value : true, ToGuidList(participants));
            MessageService.Send(Request, MessageAction.DiscussionUpdated, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title);

            return new MessageWrapperFull(this, discussion, new ProjectWrapperFull(this, discussion.Project, EngineFactory.FileEngine.GetRoot(discussion.Project.ID)), GetProjectMessageSubscribers(messageid));
        }

        ///<summary>
        ///Updates the selected message status
        ///</summary>
        ///<short>
        ///Update message status
        ///</short>
        ///<category>Discussions</category>
        ///<param name="messageid">Message ID</param>
        ///<param name="status">Project ID</param>
        ///<returns></returns>
        ///<exception cref="ArgumentException"></exception>
        ///<exception cref="ItemNotFoundException"></exception>
        [Update(@"message/{messageid:[0-9]+}/status")]
        public MessageWrapper UpdateProjectMessage(int messageid, MessageStatus status)
        {
            var messageEngine = EngineFactory.MessageEngine;
            var discussion = messageEngine.GetByID(messageid).NotFoundIfNull();
            ProjectSecurity.DemandEdit(discussion);

            discussion.Status = status;
            messageEngine.ChangeStatus(discussion);
            MessageService.Send(Request, MessageAction.DiscussionUpdated, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title);

            return MessageWrapperSelector(discussion);
        }

        ///<summary>
        ///Deletes the message with the ID specified in the request from a project discussion
        ///</summary>
        ///<short>
        ///Delete message
        ///</short>
        ///<category>Discussions</category>
        ///<param name="messageid">Message ID</param>
        ///<returns></returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Delete(@"message/{messageid:[0-9]+}")]
        public MessageWrapper DeleteProjectMessage(int messageid)
        {
            var discussionEngine = EngineFactory.MessageEngine;

            var discussion = discussionEngine.GetByID(messageid).NotFoundIfNull();
            ProjectSecurity.DemandEdit(discussion);

            discussionEngine.Delete(discussion);
            MessageService.Send(Request, MessageAction.DiscussionDeleted, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title);

            return MessageWrapperSelector(discussion);
        }

        private static IEnumerable<Guid> ToGuidList(string participants)
        {
            return participants != null ?
                 participants.Equals(string.Empty) ? new List<Guid>() : participants.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => new Guid(x))
                : null;
        }

        ///<summary>
        ///Returns the detailed information about the message with the ID specified in the request
        ///</summary>
        ///<short>
        ///Message
        ///</short>
        ///<category>Discussions</category>
        ///<param name="messageid">Message ID</param>
        ///<returns>Message</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"message/{messageid:[0-9]+}")]
        public MessageWrapperFull GetProjectMessage(int messageid)
        {
            var discussion = EngineFactory.MessageEngine.GetByID(messageid).NotFoundIfNull();
            var project = ProjectWrapperFullSelector(discussion.Project, EngineFactory.FileEngine.GetRoot(discussion.Project.ID));
            var subscribers = GetProjectMessageSubscribers(messageid);
            var files = EngineFactory.MessageEngine.GetFiles(discussion).Select(FileWrapperSelector);
            var comments = EngineFactory.CommentEngine.GetComments(discussion);
            return new MessageWrapperFull(this, discussion, project, subscribers, files, comments.Where(r => r.Parent.Equals(Guid.Empty)).Select(x => GetCommentInfo(comments, x, discussion)).ToList());
        }

        ///<summary>
        ///Returns the detailed information about files attached to the message with the ID specified in the request
        ///</summary>
        ///<short>
        ///Message files
        ///</short>
        ///<category>Files</category>
        ///<param name="messageid">Message ID</param>
        ///<returns> List of message files</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"message/{messageid:[0-9]+}/files")]
        public IEnumerable<FileWrapper> GetMessageFiles(int messageid)
        {
            var messageEngine = EngineFactory.MessageEngine;
            var message = messageEngine.GetByID(messageid).NotFoundIfNull();

            ProjectSecurity.DemandReadFiles(message.Project);

            return messageEngine.GetFiles(message).Select(FileWrapperSelector);
        }

        ///<summary>
        ///Uploads the file specified in the request to the selected message
        ///</summary>
        ///<short>
        ///Upload file to message
        ///</short>
        ///<category>Files</category>
        ///<param name="messageid">Message ID</param>
        ///<param name="files">File ID</param>
        ///<returns>Message</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Create(@"message/{messageid:[0-9]+}/files")]
        public MessageWrapper UploadFilesToMessage(int messageid, IEnumerable<int> files)
        {
            var messageEngine = EngineFactory.MessageEngine;
            var fileEngine = EngineFactory.FileEngine;

            var discussion = messageEngine.GetByID(messageid).NotFoundIfNull();
            ProjectSecurity.DemandReadFiles(discussion.Project);

            var filesList = files.ToList();
            var attachments = new List<Files.Core.File>();
            foreach (var fileid in filesList)
            {
                var file = fileEngine.GetFile(fileid).NotFoundIfNull();
                attachments.Add(file);
                messageEngine.AttachFile(discussion, file.ID, true);
            }

            MessageService.Send(Request, MessageAction.DiscussionAttachedFiles, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title, attachments.Select(x => x.Title));

            return MessageWrapperSelector(discussion);
        }

        ///<summary>
        ///Detaches the selected file from the message with the ID specified in the request
        ///</summary>
        ///<short>
        ///Detach file from message
        ///</short>
        ///<category>Files</category>
        ///<param name="messageid">Message ID</param>
        ///<param name="fileid">File ID</param>
        ///<returns>Message</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Delete(@"message/{messageid:[0-9]+}/files")]
        public MessageWrapper DetachFileFromMessage(int messageid, int fileid)
        {
            var messageEngine = EngineFactory.MessageEngine;

            var discussion = messageEngine.GetByID(messageid).NotFoundIfNull();
            ProjectSecurity.DemandReadFiles(discussion.Project);

            var file = EngineFactory.FileEngine.GetFile(fileid).NotFoundIfNull();

            messageEngine.DetachFile(discussion, fileid);
            MessageService.Send(Request, MessageAction.DiscussionDetachedFile, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title, file.Title);

            return MessageWrapperSelector(discussion);
        }

        ///<summary>
        ///Detaches the selected file from the message with the ID specified in the request
        ///</summary>
        ///<short>
        ///Detach file from message
        ///</short>
        ///<category>Files</category>
        ///<param name="messageid">Message ID</param>
        ///<param name="files">File ID</param>
        ///<returns>Message</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        ///<visible>false</visible>
        [Delete(@"message/{messageid:[0-9]+}/filesmany")]
        public MessageWrapper DetachFileFromMessage(int messageid, IEnumerable<int> files)
        {
            var messageEngine = EngineFactory.MessageEngine;
            var fileEngine = EngineFactory.FileEngine;

            var discussion = messageEngine.GetByID(messageid).NotFoundIfNull();
            ProjectSecurity.DemandReadFiles(discussion.Project);

            var filesList = files.ToList();
            var attachments = new List<Files.Core.File>();
            foreach (var fileid in filesList)
            {
                var file = fileEngine.GetFile(fileid).NotFoundIfNull();
                attachments.Add(file);
                messageEngine.DetachFile(discussion, fileid);
            }

            MessageService.Send(Request, MessageAction.DiscussionDetachedFile, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title, attachments.Select(x => x.Title));

            return MessageWrapperSelector(discussion);
        }

        ///<summary>
        ///Returns the list of latest messages in the discussions within the project with the ID specified in the request
        ///</summary>
        ///<short>
        ///Latest messages
        ///</short>
        ///<category>Discussions</category>
        ///<returns>List of messages</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"message")]
        public IEnumerable<MessageWrapper> GetProjectRecentMessages()
        {
            return EngineFactory.MessageEngine.GetMessages((int)StartIndex, (int)Count).Select(MessageWrapperSelector);
        }

        ///<summary>
        ///Returns the list of comments to the messages in the discussions within the project with the ID specified in the request
        ///</summary>
        ///<short>
        ///Message comments
        ///</short>
        ///<category>Comments</category>
        ///<param name="messageid">Message ID</param>
        ///<returns>Comments for message</returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"message/{messageid:[0-9]+}/comment")]
        public IEnumerable<CommentWrapper> GetProjectMessagesComments(int messageid)
        {
            var messageEngine = EngineFactory.MessageEngine;
            var message = messageEngine.GetByID(messageid).NotFoundIfNull();

            return EngineFactory.CommentEngine.GetComments(message).Select(x => new CommentWrapper(this, x, message));
        }

        ///<summary>
        ///Adds a comment to the selected message in a discussion within the project with the content specified in the request. The parent comment ID can also be selected.
        ///</summary>
        ///<short>
        ///Add message comment
        ///</short>
        ///<category>Comments</category>
        ///<param name="messageid">Message ID</param>
        ///<param name="content">Comment content</param>
        ///<param name="parentId">Parrent comment ID</param>
        ///<returns></returns>
        ///<exception cref="ItemNotFoundException"></exception>
        [Create(@"message/{messageid:[0-9]+}/comment")]
        public CommentWrapper AddProjectMessagesComment(int messageid, string content, Guid parentId)
        {
            if (string.IsNullOrEmpty(content)) throw new ArgumentException(@"Comment text is empty", content);
            if (parentId != Guid.Empty && EngineFactory.CommentEngine.GetByID(parentId) == null) throw new ItemNotFoundException("parent comment not found");

            var comment = new Comment
            {
                Content = content,
                TargetUniqID = ProjectEntity.BuildUniqId<Message>(messageid),
                CreateBy = CurrentUserId,
                CreateOn = Core.Tenants.TenantUtil.DateTimeNow()
            };

            if (parentId != Guid.Empty)
            {
                comment.Parent = parentId;
            }

            var message = EngineFactory.CommentEngine.GetEntityByTargetUniqId(comment).NotFoundIfNull();

            EngineFactory.CommentEngine.SaveOrUpdateComment(message, comment);

            MessageService.Send(Request, MessageAction.DiscussionCommentCreated, MessageTarget.Create(comment.ID), message.Project.Title, message.Title);

            return new CommentWrapper(this, comment, message);
        }

        ///<summary>
        ///Subscribe to notifications about the actions performed with the task with the ID specified in the request
        ///</summary>
        ///<short>
        ///Subscribe to message action
        ///</short>
        ///<category>Discussions</category>
        ///<returns>Discussion</returns>
        ///<param name="messageid">Message ID</param>
        ///<exception cref="ItemNotFoundException"></exception>
        [Update(@"message/{messageid:[0-9]+}/subscribe")]
        public MessageWrapper SubscribeToMessage(int messageid)
        {
            var discussionEngine = EngineFactory.MessageEngine;
            var discussion = discussionEngine.GetByID(messageid).NotFoundIfNull();

            ProjectSecurity.DemandAuthentication();

            discussionEngine.Follow(discussion);
            MessageService.Send(Request, MessageAction.DiscussionUpdatedFollowing, MessageTarget.Create(discussion.ID), discussion.Project.Title, discussion.Title);

            return new MessageWrapperFull(this, discussion, ProjectWrapperFullSelector(discussion.Project, EngineFactory.FileEngine.GetRoot(discussion.Project.ID)), GetProjectMessageSubscribers(messageid));
        }

        ///<summary>
        ///Checks subscription to notifications about the actions performed with the discussion with the ID specified in the request
        ///</summary>
        ///<short>
        ///Check subscription to discussion action
        ///</short>
        ///<category>Discussions</category>
        ///<param name="messageid">Message ID</param>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"message/{messageid:[0-9]+}/subscribe")]
        public bool IsSubscribedToMessage(int messageid)
        {
            var messageEngine = EngineFactory.MessageEngine;

            var message = messageEngine.GetByID(messageid).NotFoundIfNull();

            ProjectSecurity.DemandAuthentication();

            return messageEngine.IsSubscribed(message);
        }

        ///<summary>
        ///Get subscribers
        ///</summary>
        ///<short>
        ///Get subscribers
        ///</short>
        ///<category>Discussions</category>
        ///<param name="messageid">Message ID</param>
        ///<exception cref="ItemNotFoundException"></exception>
        [Read(@"message/{messageid:[0-9]+}/subscribes")]
        public IEnumerable<EmployeeWraperFull> GetProjectMessageSubscribers(int messageid)
        {
            var messageEngine = EngineFactory.MessageEngine;

            var message = messageEngine.GetByID(messageid).NotFoundIfNull();

            ProjectSecurity.DemandAuthentication();

            return messageEngine.GetSubscribers(message).Select(r => GetEmployeeWraperFull(new Guid(r.ID)))
                .OrderBy(r => r.DisplayName).ToList();
        }

        ///<summary>
        ///Get preview
        ///</summary>
        ///<short>
        ///Get preview
        ///</short>
        ///<category>Discussions</category>
        ///<param name="htmltext">html to create preview</param>
        [Create(@"message/discussion/preview")]
        public string GetPreview(string htmltext)
        {
            return HtmlUtility.GetFull(htmltext);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Masters/ClientScripts/ClientLocalizationResources.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Web;

using ASC.Web.Core.Client.HttpHandlers;
using ASC.Web.CRM.Classes;
using ASC.Web.CRM.Resources;
using ASC.Web.Studio.Core.Users;
using ASC.Web.Studio.PublicResources;

namespace ASC.Web.CRM.Masters.ClientScripts
{
    public class ClientLocalizationResources : ClientScriptLocalization
    {
        protected override string BaseNamespace
        {
            get { return "ASC.CRM.Resources"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            return new List<KeyValuePair<string, object>>(11)
            {
                RegisterResourceSet("CRMJSResource", CRMJSResource.ResourceManager),
                RegisterResourceSet("CRMCommonResource", CRMCommonResource.ResourceManager),
                RegisterResourceSet("CRMContactResource", CRMContactResource.ResourceManager),
                RegisterResourceSet("CRMDealResource", CRMDealResource.ResourceManager),
                RegisterResourceSet("CRMInvoiceResource", CRMInvoiceResource.ResourceManager),
                RegisterResourceSet("CRMTaskResource", CRMTaskResource.ResourceManager),
                RegisterResourceSet("CRMCasesResource", CRMCasesResource.ResourceManager),
                RegisterResourceSet("CRMEnumResource", CRMEnumResource.ResourceManager),
                RegisterResourceSet("CRMSettingResource", CRMSettingResource.ResourceManager),
                RegisterResourceSet("CRMSocialMediaResource", CRMSocialMediaResource.ResourceManager),
                RegisterResourceSet("CRMVoipResource", CRMVoipResource.ResourceManager),
                RegisterResourceSet("CRMReportResource", CRMReportResource.ResourceManager),
                RegisterObject(new
                {
                    DealMilestoneStatus = new
                    {
                        Open = new
                        {
                            num = (int)ASC.CRM.Core.DealMilestoneStatus.Open,
                            str = ASC.CRM.Core.DealMilestoneStatus.Open.ToLocalizedString()
                        },
                        ClosedAndWon = new
                        {
                            num = (int)ASC.CRM.Core.DealMilestoneStatus.ClosedAndWon,
                            str = ASC.CRM.Core.DealMilestoneStatus.ClosedAndWon.ToLocalizedString()
                        },
                        ClosedAndLost = new
                        {
                            num = (int)ASC.CRM.Core.DealMilestoneStatus.ClosedAndLost,
                            str = ASC.CRM.Core.DealMilestoneStatus.ClosedAndLost.ToLocalizedString()
                        }
                    },
                    smtpQuotas = string.Format(CRMSettingResource.InternalSMTP, MailSender.GetQuotas())
                })
            };
        }
    }

    public class ClientCustomResources : ClientScriptCustom
    {
        protected override string BaseNamespace
        {
            get { return "ASC.CRM.Resources"; }
        }

        protected override IEnumerable<KeyValuePair<string, object>> GetClientVariables(HttpContext context)
        {
            return new List<KeyValuePair<string, object>>(1)
                   {
                       RegisterObject(
                       new
                       {
                           AddUser = CustomNamingPeople.Substitute<CRMCommonResource>("AddUser").HtmlEncode(),
                           AddGroup = CustomNamingPeople.Substitute<CRMCommonResource>("AddGroup").HtmlEncode(),
                           CurrentUser = CustomNamingPeople.Substitute<CRMCommonResource>("CurrentUser").HtmlEncode(),
                           PrivatePanelAccessListLable = CustomNamingPeople.Substitute<CRMCommonResource>("PrivatePanelAccessListLable").HtmlEncode(),
                           PrivatePanelDescription = CustomNamingPeople.Substitute<CRMCommonResource>("PrivatePanelDescription").HtmlEncode(),
                           SocialMediaAccountNotFoundTwitter = CRMSocialMediaResource.SocialMediaAccountNotFoundTwitter.HtmlEncode(),
                           DisabledEmployeeTitle = Resource.DisabledEmployeeTitle.HtmlEncode()
                       })
                   };
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Birthdays/Default.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Web.Community.Modules.Birthdays.Resources;
using ASC.Web.Studio;
using ASC.Web.Studio.Controls.Common;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Community.Birthdays
{
    public partial class Default : MainPage
    {

        protected List<UserInfo> todayBirthdays;
        protected List<BirthdayWrapper> upcomingBirthdays;

        protected void Page_Load(object sender, EventArgs e)
        {
            RenderScripts();

            todayBirthdays = GetTodayBirthdays();
            upcomingBirthdays = GetUpcomingBirthdays().ToList();

            if (upcomingBirthdays == null || !upcomingBirthdays.Any())
            {
                upcomingEmptyContent.Controls.Add(new EmptyScreenControl
                {
                    ImgSrc = VirtualPathUtility.ToAbsolute("~/Products/Community/Modules/Birthdays/App_Themes/default/images/birthday.png"),
                    Header = BirthdaysResource.BirthdayEmptyScreenCaption,
                    Describe = BirthdaysResource.BirthdaysEmptyModuleDescription
                });
            }

            Title = HeaderStringHelper.GetPageTitle(BirthdaysResource.BirthdaysModuleTitle);
        }

        protected void RenderScripts()
        {
            Page
                .RegisterStyle("~/Products/Community/Modules/Birthdays/App_Themes/default/birthdays.css")
                .RegisterBodyScripts("~/Products/Community/Modules/Birthdays/js/birthdays.js");
        }

        private static List<UserInfo> GetTodayBirthdays()
        {
            var today = TenantUtil.DateTimeNow();
            return (from u in CoreContext.UserManager.GetUsers(EmployeeStatus.Active, EmployeeType.User)
                    where u.BirthDate.HasValue && u.BirthDate.Value.Month.Equals(today.Month) && u.BirthDate.Value.Day.Equals(today.Day)
                    orderby u.DisplayUserName()
                    select u)
                .ToList();
        }

        private class BirthDateComparer : IComparer<DateTime>
        {
            public int Compare(DateTime x, DateTime y)
            {
                var today = TenantUtil.DateTimeNow();
                var leap = new DateTime(2000, today.Month, today.Day);

                var dx = new DateTime(2000, x.Month, x.Day).DayOfYear - leap.DayOfYear;
                var dy = new DateTime(2000, y.Month, y.Day).DayOfYear - leap.DayOfYear;

                if (dx < 0 && dy >= 0) return 1;
                if (dx >= 0 && dy < 0) return -1;

                return dx.CompareTo(dy);
            }
        }

        private static IEnumerable<BirthdayWrapper> GetUpcomingBirthdays()
        {
            var today = TenantUtil.DateTimeNow();

            return CoreContext.UserManager.GetUsers(EmployeeStatus.Active, EmployeeType.User)
                              .Where(x => x.BirthDate.HasValue)
                              .OrderBy(x => x.BirthDate.Value, new BirthDateComparer())
                              .GroupBy(x => new DateTime(2000, x.BirthDate.Value.Month, x.BirthDate.Value.Day)) // 29 february
                              .Select(x => new BirthdayWrapper { Date = x.Key, Users = x.ToList() })
                              .SkipWhile(x => x.Date.Month.Equals(today.Month) && x.Date.Day.Equals(today.Day))
                              .Take(10);
        }

        protected bool IsInRemindList(Guid userID)
        {
            return BirthdaysNotifyClient.Instance.IsSubscribe(SecurityContext.CurrentAccount.ID, userID);
        }

        protected class BirthdayWrapper
        {
            public DateTime Date;
            public List<UserInfo> Users;
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/vCard/Item.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Mime.vCard
{
    #region usings

    using System;
    using System.Text;

    #endregion

    /// <summary>
    /// vCard structure item.
    /// </summary>
    public class Item
    {
        #region Members

        private readonly string m_Name = "";
        private string m_Parameters = "";
        private string m_Value = "";

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="name">Item name.</param>
        /// <param name="parameters">Item parameters.</param>
        /// <param name="value">Item encoded value value.</param>
        internal Item(string name, string parameters, string value)
        {
            m_Name = name;
            m_Parameters = parameters;
            m_Value = value;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets item decoded value. If param string specifies Encoding and/or Charset, 
        /// item.Value will be decoded accordingly.
        /// </summary>
        public string DecodedValue
        {
            /* RFC 2426 vCrad 5. Differences From vCard v2.1              
                The CRLF character sequence in a text type value is specified 
                with the backslash character sequence "\n" or "\N".
             
                Any COMMA or SEMICOLON in a text type value must be backslash escaped.
            */

            get
            {
                string data = m_Value;
                string encoding = null;
                string charset = null;
                string[] parameters = m_Parameters.ToLower().Split(';');
                foreach (string parameter in parameters)
                {
                    string[] name_value = parameter.Split('=');
                    if (name_value[0] == "encoding" && name_value.Length > 1)
                    {
                        encoding = name_value[1];
                    }
                    else if (name_value[0] == "charset" && name_value.Length > 1)
                    {
                        charset = name_value[1];
                    }
                }

                // Encoding specified, decode data.
                if (encoding != null)
                {
                    if (encoding == "quoted-printable")
                    {
                        data = Core.QuotedPrintableDecode(data,Encoding.Default);
                    }
                    else if (encoding == "b")
                    {
                        data = Encoding.Default.GetString(Core.Base64Decode(Encoding.Default.GetBytes(data)));
                    }
                    else
                    {
                        throw new Exception("Unknown data encoding '" + encoding + "' !");
                    }
                }
                // Charset specified, convert data to specified charset.
                if (charset != null)
                {
                    data = Encoding.GetEncoding(charset).GetString(Encoding.Default.GetBytes(data));
                }

                // FIX ME: this must be done with structured fields
                //data = data.Replace("\\n","\r\n");
                //data = TextUtils.UnEscapeString(data); Messes up structured fields

                return data;
            }
        }

        /// <summary>
        /// Gest item name.
        /// </summary>
        public string Name
        {
            get { return m_Name; }
        }

        /// <summary>
        /// Gets or sets item parameters.
        /// </summary>
        public string ParametersString
        {
            get { return m_Parameters; }

            set { m_Parameters = value; }
        }

        /// <summary>
        /// Gets or sets item encoded value. NOTE: If you set this property value, you must encode data 
        /// by yourself and also set right ENCODING=encoding; and CHARSET=charset; prameter in item.ParametersString !!!
        /// Normally use method item.SetDecodedStringValue method instead, this does all you need.
        /// </summary>
        public string Value
        {
            get { return m_Value; }

            set { m_Value = value; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Sets item decoded value. Value will be encoded as needed and stored to item.Value property.
        /// Also property item.ParametersString is updated to reflect right encoding(always base64, required by rfc) and charset (utf-8).
        /// </summary>
        /// <param name="value"></param>
        public void SetDecodedValue(string value)
        {
            /* RFC 2426 vCrad 5. Differences From vCard v2.1
                The QUOTED-PRINTABLE inline encoding has been eliminated.
                Only the "B" encoding of [RFC 2047] is an allowed value for
                the ENCODING parameter.
              
                The CRLF character sequence in a text type value is specified 
                with the backslash character sequence "\n" or "\N".
             
                Any COMMA or SEMICOLON in a text type value must be backslash escaped.
            */

            // FIX ME: this must be done with structured fields
            //value = value.Replace("\r\n","\n").Replace("\n","\\n");
            //value = TextUtils.EscapeString(value,new char[]{',',';'});

            bool needEncode = false;
            if (!Core.IsAscii(value))
            {
                needEncode = true;
            }

            if (needEncode)
            {
                // Remove encoding and charset parameters
                string newParmString = "";
                string[] parameters = m_Parameters.ToLower().Split(';');
                foreach (string parameter in parameters)
                {
                    string[] name_value = parameter.Split('=');
                    if (name_value[0] == "encoding" || name_value[0] == "charset") {}
                    else if (parameter.Length > 0)
                    {
                        newParmString += parameter + ";";
                    }
                }
                // Add encoding parameter
                newParmString += "ENCODING=b;CHARSET=utf-8";

                ParametersString = newParmString;
                Value = Convert.ToBase64String(Encoding.UTF8.GetBytes(value));
            }
            else
            {
                Value = value;
            }
        }

        #endregion

        #region Internal methods

        /// <summary>
        /// Converts item to vCal item string.
        /// </summary>
        /// <returns></returns>
        internal string ToItemString()
        {
            if (m_Parameters.Length > 0)
            {
                return m_Name + ";" + m_Parameters + ":" + MimeUtils.FoldData(m_Value);
            }
            else
            {
                return m_Name + ":" + MimeUtils.FoldData(m_Value);
            }
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/helpcenter/page.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.helpPage = (function($) {
    var isInit = false,
        page;

    var init = function() {
        if (isInit === false) {
            isInit = true;
            page = $('#helpPanel');
        }
    };

    var show = function(helpId) {
        var params = { helpId: helpId };

        if (!page.text().trim().length) {
            params.update = true;
            serviceManager.getHelpCenterHtml(params, { success: onGetHelpCenterHtml }, ASC.Resources.Master.ResourceJS.LoadingProcessing);
        } else {
            onGetHelpCenterHtml(params, null);
        }
    };

    var onGetHelpCenterHtml = function(params, html) {
        if (params.update) {
            page.html(html);
            messagePage.initImageZoom();
        }

        page.show();

        showHelpPage(params.helpId);
        mailBox.hideLoadingMask();
    };

    var hide = function() {
        page.hide();
    };

    return {
        init: init,
        show: show,
        hide: hide
    };
})(jQuery);

<|start_filename|>common/ASC.ActiveDirectory/Base/Data/LdapCertificateConfirmRequest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Net.Security;
using System.Runtime.Serialization;
using System.Security.Cryptography.X509Certificates;

using ASC.Common.Logging;

namespace ASC.ActiveDirectory.Base.Data
{
    [Serializable]
    [DataContract]
    public class LdapCertificateConfirmRequest
    {
        private volatile bool _approved;
        private volatile bool _requested;
        private volatile string _serialNumber;
        private volatile string _issuerName;
        private volatile string _subjectName;
        private volatile string _hash;
        private volatile int[] _certificateErrors;

        [DataMember]
        public bool Approved { get { return _approved; } set { _approved = value; } }

        [DataMember]
        public bool Requested { get { return _requested; } set { _requested = value; } }

        [DataMember]
        public string SerialNumber { get { return _serialNumber; } set { _serialNumber = value; } }

        [DataMember]
        public string IssuerName { get { return _issuerName; } set { _issuerName = value; } }

        [DataMember]
        public string SubjectName { get { return _subjectName; } set { _subjectName = value; } }

        [DataMember]
        public DateTime ValidFrom { get; set; }

        [DataMember]
        public DateTime ValidUntil { get; set; }

        [DataMember]
        public string Hash { get { return _hash; } set { _hash = value; } }

        [DataMember]
        public int[] CertificateErrors { get { return _certificateErrors; } set { _certificateErrors = value; } }

        private enum LdapCertificateProblem
        {
            CertExpired = -2146762495,
            CertCnNoMatch = -2146762481,
            // ReSharper disable once UnusedMember.Local
            CertIssuerChaining = -2146762489,
            CertUntrustedCa = -2146762478,
            // ReSharper disable once UnusedMember.Local
            CertUntrustedRoot = -2146762487,
            CertMalformed = -2146762488,
            CertUnrecognizedError = -2146762477
        }

        public static int[] GetLdapCertProblems(X509Certificate certificate, X509Chain chain,
            SslPolicyErrors sslPolicyErrors, ILog log = null)
        {
            var certificateErrors = new List<int>();
            try
            {
                if (sslPolicyErrors == SslPolicyErrors.None)
                {
                    return certificateErrors.ToArray();
                }

                var expDate = DateTime.Parse(certificate.GetExpirationDateString()).ToUniversalTime();
                var utcNow = DateTime.UtcNow;
                if (expDate < utcNow && expDate.AddDays(1) >= utcNow)
                {
                    certificateErrors.Add((int)LdapCertificateProblem.CertExpired);
                }

                if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors))
                {
                    certificateErrors.Add((int)LdapCertificateProblem.CertMalformed);
                }

                if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
                {
                    if (log != null)
                    {
                        log.WarnFormat("GetLdapCertProblems: {0}",
                            Enum.GetName(typeof(SslPolicyErrors), LdapCertificateProblem.CertCnNoMatch));
                    }

                    certificateErrors.Add((int)LdapCertificateProblem.CertCnNoMatch);
                }

                if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable))
                {
                    if (log != null)
                    {
                        log.WarnFormat("GetLdapCertProblems: {0}",
                            Enum.GetName(typeof(SslPolicyErrors), LdapCertificateProblem.CertCnNoMatch));
                    }

                    certificateErrors.Add((int)LdapCertificateProblem.CertUntrustedCa);
                }
            }
            catch (Exception ex)
            {
                if (log != null)
                    log.ErrorFormat("GetLdapCertProblems() failed. Error: {0}", ex);
                certificateErrors.Add((int)LdapCertificateProblem.CertUnrecognizedError);
            }

            return certificateErrors.ToArray();
        }

        public static LdapCertificateConfirmRequest FromCert(X509Certificate certificate, X509Chain chain,
            SslPolicyErrors sslPolicyErrors, bool approved = false, bool requested = false, ILog log = null)
        {
            var certificateErrors = GetLdapCertProblems(certificate, chain, sslPolicyErrors, log);

            try
            {
                string serialNumber = "", issuerName = "", subjectName = "", hash = "";
                DateTime validFrom = DateTime.UtcNow, validUntil = DateTime.UtcNow;

                LdapUtils.SkipErrors(() => serialNumber = certificate.GetSerialNumberString(), log);
                LdapUtils.SkipErrors(() => issuerName = certificate.Issuer, log);
                LdapUtils.SkipErrors(() => subjectName = certificate.Subject, log);
                LdapUtils.SkipErrors(() => validFrom = DateTime.Parse(certificate.GetEffectiveDateString()), log);
                LdapUtils.SkipErrors(() => validUntil = DateTime.Parse(certificate.GetExpirationDateString()), log);
                LdapUtils.SkipErrors(() => hash = certificate.GetCertHashString(), log);

                var certificateConfirmRequest = new LdapCertificateConfirmRequest
                {
                    SerialNumber = serialNumber,
                    IssuerName = issuerName,
                    SubjectName = subjectName,
                    ValidFrom = validFrom,
                    ValidUntil = validUntil,
                    Hash = hash,
                    CertificateErrors = certificateErrors,
                    Approved = approved,
                    Requested = requested
                };

                return certificateConfirmRequest;
            }
            catch (Exception ex)
            {
                if (log != null)
                    log.ErrorFormat("LdapCertificateConfirmRequest.FromCert() failed. Error: {0}", ex);
                return null;
            }
        }
    }
}


<|start_filename|>module/ASC.Feed/Data/FeedAggregateDataProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;

using Newtonsoft.Json;

namespace ASC.Feed.Data
{
    public class FeedAggregateDataProvider
    {
        public static DateTime GetLastTimeAggregate(string key)
        {
            var q = new SqlQuery("feed_last")
                .Select("last_date")
                .Where("last_key", key);

            using (var db = new DbManager(Constants.FeedDbId))
            {
                var value = db.ExecuteScalar<DateTime>(q);
                return value != default(DateTime) ? value.AddSeconds(1) : value;
            }
        }

        public static void SaveFeeds(IEnumerable<FeedRow> feeds, string key, DateTime value)
        {
            using (var db = new DbManager(Constants.FeedDbId))
            {
                db.ExecuteNonQuery(new SqlInsert("feed_last", true).InColumnValue("last_key", key).InColumnValue("last_date", value));
            }

            const int feedsPortionSize = 1000;
            var aggregatedDate = DateTime.UtcNow;

            var feedsPortion = new List<FeedRow>();
            foreach (var feed in feeds)
            {
                feedsPortion.Add(feed);
                if (feedsPortion.Sum(f => f.Users.Count) <= feedsPortionSize) continue;

                SaveFeedsPortion(feedsPortion, aggregatedDate);
                feedsPortion.Clear();
            }
            if (feedsPortion.Any())
            {
                SaveFeedsPortion(feedsPortion, aggregatedDate);
            }
        }

        private static void SaveFeedsPortion(IEnumerable<FeedRow> feeds, DateTime aggregatedDate)
        {
            using (var db = new DbManager(Constants.FeedDbId))
            using (var tx = db.BeginTransaction())
            {
                var i = new SqlInsert("feed_aggregate", true)
                    .InColumns("id", "tenant", "product", "module", "author", "modified_by", "group_id", "created_date",
                        "modified_date", "json", "keywords", "aggregated_date");
                var i2 = new SqlInsert("feed_users", true).InColumns("feed_id", "user_id");

                var hasValues = false;

                foreach (var f in feeds)
                {
                    if (0 >= f.Users.Count) continue;

                    hasValues = true;

                    i.Values(f.Id, f.Tenant, f.ProductId, f.ModuleId, f.AuthorId, f.ModifiedById, f.GroupId, f.CreatedDate, f.ModifiedDate, f.Json, f.Keywords, aggregatedDate);

                    if (f.ClearRightsBeforeInsert)
                    {
                        db.ExecuteNonQuery(
                            new SqlDelete("feed_users")
                                .Where("feed_id", f.Id)
                            );
                    }

                    foreach (var u in f.Users)
                    {
                        i2.Values(f.Id, u.ToString());
                    }
                }

                if (hasValues)
                {
                    db.ExecuteNonQuery(i);
                    db.ExecuteNonQuery(i2);

                    tx.Commit();
                }
            }
        }

        public static void RemoveFeedAggregate(DateTime fromTime)
        {
            using (var db = new DbManager(Constants.FeedDbId))
            using (var command = db.Connection.CreateCommand())
            using (var tx = db.Connection.BeginTransaction(IsolationLevel.ReadUncommitted))
            {
                command.Transaction = tx;
                command.CommandTimeout = 60 * 60; // a hour
                var dialect = DbRegistry.GetSqlDialect(Constants.FeedDbId);
                if (dialect.SupportMultiTableUpdate)
                {
                    command.ExecuteNonQuery("delete from feed_aggregate, feed_users using feed_aggregate, feed_users where id = feed_id and aggregated_date < @date", new { date = fromTime });
                }
                else
                {
                    command.ExecuteNonQuery(new SqlDelete("feed_users").Where(Exp.In("feed_id", new SqlQuery("feed_aggregate").Select("id").Where(Exp.Lt("aggregated_date", fromTime)))), dialect);
                    command.ExecuteNonQuery(new SqlDelete("feed_aggregate").Where(Exp.Lt("aggregated_date", fromTime)), dialect);
                }
                tx.Commit();
            }
        }

        public static List<FeedResultItem> GetFeeds(FeedApiFilter filter)
        {
            var filterOffset = filter.Offset;
            var filterLimit = filter.Max > 0 && filter.Max < 1000 ? filter.Max : 1000;

            var feeds = new Dictionary<string, List<FeedResultItem>>();

            var tryCount = 0;
            List<FeedResultItem> feedsIteration;
            do
            {
                feedsIteration = GetFeedsInternal(filter);
                foreach (var feed in feedsIteration)
                {
                    if (feeds.ContainsKey(feed.GroupId))
                    {
                        feeds[feed.GroupId].Add(feed);
                    }
                    else
                    {
                        feeds[feed.GroupId] = new List<FeedResultItem> { feed };
                    }
                }
                filter.Offset += feedsIteration.Count;
            } while (feeds.Count < filterLimit
                     && feedsIteration.Count == filterLimit
                     && tryCount++ < 5);

            filter.Offset = filterOffset;
            return feeds.Take(filterLimit).SelectMany(group => group.Value).ToList();
        }

        private static List<FeedResultItem> GetFeedsInternal(FeedApiFilter filter)
        {
            var query = new SqlQuery("feed_aggregate a")
                .InnerJoin("feed_users u", Exp.EqColumns("a.id", "u.feed_id"))
                .Select("a.json, a.module, a.author, a.modified_by, a.group_id, a.created_date, a.modified_date, a.aggregated_date")
                .Where("a.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where(
                    !Exp.Eq("a.modified_by", SecurityContext.CurrentAccount.ID) &
                    Exp.Eq("u.user_id", SecurityContext.CurrentAccount.ID)
                )
                .OrderBy("a.modified_date", false)
                .SetFirstResult(filter.Offset)
                .SetMaxResults(filter.Max);

            if (filter.OnlyNew)
            {
                query.Where(Exp.Ge("a.aggregated_date", filter.From));
            }
            else
            {
                if (1 < filter.From.Year)
                {
                    query.Where(Exp.Ge("a.modified_date", filter.From));
                }
                if (filter.To.Year < 9999)
                {
                    query.Where(Exp.Le("a.modified_date", filter.To));
                }
            }

            if (!string.IsNullOrEmpty(filter.Product))
            {
                query.Where("a.product", filter.Product);
            }
            if (filter.Author != Guid.Empty)
            {
                query.Where("a.modified_by", filter.Author);
            }
            if (filter.SearchKeys != null && filter.SearchKeys.Length > 0)
            {
                var exp = filter.SearchKeys
                                .Where(s => !string.IsNullOrEmpty(s))
                                .Select(s => s.Replace("\\", "\\\\").Replace("%", "\\%").Replace("_", "\\_"))
                                .Aggregate(Exp.False, (cur, s) => cur | Exp.Like("a.keywords", s, SqlLike.AnyWhere));
                query.Where(exp);
            }

            using (var db = new DbManager(Constants.FeedDbId))
            {
                var news = db
                    .ExecuteList(query)
                    .ConvertAll(r => new FeedResultItem(
                                         Convert.ToString(r[0]),
                                         Convert.ToString(r[1]),
                                         new Guid(Convert.ToString(r[2])),
                                         new Guid(Convert.ToString(r[3])),
                                         Convert.ToString(r[4]),
                                         TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[5])),
                                         TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[6])),
                                         TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[7]))));
                return news;
            }
        }

        public static int GetNewFeedsCount(DateTime lastReadedTime)
        {
            var q = new SqlQuery("feed_aggregate a")
                .Select("id")
                .Where("a.tenant", CoreContext.TenantManager.GetCurrentTenant().TenantId)
                .Where(!Exp.Eq("a.modified_by", SecurityContext.CurrentAccount.ID))
                .InnerJoin("feed_users u", Exp.EqColumns("a.id", "u.feed_id"))
                .Where("u.user_id", SecurityContext.CurrentAccount.ID)
                .SetMaxResults(1001);

            if (1 < lastReadedTime.Year)
            {
                q.Where(Exp.Ge("a.aggregated_date", lastReadedTime));
            }

            using (var db = new DbManager(Constants.FeedDbId))
            {
                return db.ExecuteList(q).Count();
            }
        }

        public IEnumerable<int> GetTenants(TimeInterval interval)
        {
            using (var db = new DbManager(Constants.FeedDbId))
            {
                var q = new SqlQuery("feed_aggregate")
                    .Select("tenant")
                    .Where(Exp.Between("aggregated_date", interval.From, interval.To))
                    .GroupBy(1);
                return db.ExecuteList(q).ConvertAll(r => Convert.ToInt32(r[0]));
            }
        }

        public static FeedResultItem GetFeedItem(string id)
        {
            var query = new SqlQuery("feed_aggregate a")
                .Select("a.json, a.module, a.author, a.modified_by, a.group_id, a.created_date, a.modified_date, a.aggregated_date")
                .Where("a.id", id);

            using (var db = new DbManager(Constants.FeedDbId))
            {
                var news = db
                    .ExecuteList(query)
                    .ConvertAll(r => new FeedResultItem(
                                         Convert.ToString(r[0]),
                                         Convert.ToString(r[1]),
                                         new Guid(Convert.ToString(r[2])),
                                         new Guid(Convert.ToString(r[3])),
                                         Convert.ToString(r[4]),
                                         TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[5])),
                                         TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[6])),
                                         TenantUtil.DateTimeFromUtc(Convert.ToDateTime(r[7]))));

                return news.FirstOrDefault();
            }
        }

        public static void RemoveFeedItem(string id)
        {
            using (var db = new DbManager(Constants.FeedDbId))
            using (var command = db.Connection.CreateCommand())
            using (var tx = db.Connection.BeginTransaction(IsolationLevel.ReadUncommitted))
            {
                command.Transaction = tx;
                command.CommandTimeout = 60 * 60; // a hour

                var dialect = DbRegistry.GetSqlDialect(Constants.FeedDbId);

                command.ExecuteNonQuery(new SqlDelete("feed_users").Where("feed_id", id), dialect);
                command.ExecuteNonQuery(new SqlDelete("feed_aggregate").Where("id", id), dialect);

                tx.Commit();
            }
        }
    }


    public class FeedResultItem
    {
        public FeedResultItem(
            string json,
            string module,
            Guid authorId,
            Guid modifiedById,
            string groupId,
            DateTime createdDate,
            DateTime modifiedDate,
            DateTime aggregatedDate)
        {
            var now = TenantUtil.DateTimeFromUtc(DateTime.UtcNow);

            Json = json;
            Module = module;

            AuthorId = authorId;
            ModifiedById = modifiedById;

            GroupId = groupId;

            if (now.Year == createdDate.Year && now.Date == createdDate.Date)
            {
                IsToday = true;
            }
            else if (now.Year == createdDate.Year && now.Date == createdDate.Date.AddDays(1))
            {
                IsYesterday = true;
            }

            CreatedDate = createdDate;
            ModifiedDate = modifiedDate;
            AggregatedDate = aggregatedDate;
        }

        public string Json { get; private set; }

        public string Module { get; private set; }

        public Guid AuthorId { get; private set; }

        public Guid ModifiedById { get; private set; }

        public string GroupId { get; private set; }

        public bool IsToday { get; private set; }

        public bool IsYesterday { get; private set; }

        public DateTime CreatedDate { get; private set; }

        public DateTime ModifiedDate { get; private set; }

        public DateTime AggregatedDate { get; private set; }

        public FeedMin ToFeedMin()
        {
            var feedMin = JsonConvert.DeserializeObject<FeedMin>(Json);
            feedMin.Author = new FeedMinUser { UserInfo = CoreContext.UserManager.GetUsers(feedMin.AuthorId) };
            feedMin.CreatedDate = CreatedDate;

            if (feedMin.Comments == null) return feedMin;

            foreach (var comment in feedMin.Comments)
            {
                comment.Author = new FeedMinUser { UserInfo = CoreContext.UserManager.GetUsers(comment.AuthorId) };
            }
            return feedMin;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/SecurityAdapter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Files.Core;
using ASC.Files.Core.Security;
using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;
using ASC.Web.Projects.Core;

using Autofac;

namespace ASC.Web.Projects.Classes
{
    public class SecurityAdapter : IFileSecurity
    {
        private readonly Project project;

        public SecurityAdapter(int projectId)
        {
            using (var scope = DIHelper.Resolve())
            {
                project = scope.Resolve<EngineFactory>().ProjectEngine.GetByID(projectId);
            }
        }

        public SecurityAdapter(Project project)
        {
            this.project = project;
        }

        public bool CanRead(FileEntry entry, Guid userId)
        {
            return Can(entry, userId, SecurityAction.Read);
        }

        public bool CanCustomFilterEdit(FileEntry file, Guid userId)
        {
            return CanEdit(file, userId);
        }

        public bool CanComment(FileEntry entry, Guid userId)
        {
            return Can(entry, userId, SecurityAction.Edit);
        }

        public bool CanFillForms(FileEntry entry, Guid userId)
        {
            return Can(entry, userId, SecurityAction.Edit);
        }

        public bool CanReview(FileEntry entry, Guid userId)
        {
            return Can(entry, userId, SecurityAction.Edit);
        }

        public bool CanCreate(FileEntry entry, Guid userId)
        {
            return Can(entry, userId, SecurityAction.Create);
        }

        public bool CanDelete(FileEntry entry, Guid userId)
        {
            return Can(entry, userId, SecurityAction.Delete);
        }

        public bool CanEdit(FileEntry entry, Guid userId)
        {
            return Can(entry, userId, SecurityAction.Edit);
        }

        private bool Can(FileEntry entry, Guid userId, SecurityAction action)
        {
            if (entry == null || project == null) return false;

            using (var scope = DIHelper.Resolve())
            {
                var projectSecurity = scope.Resolve<ProjectSecurity>();
                if (!projectSecurity.CanReadFiles(project, userId)) return false;

                if (project.Status == ProjectStatus.Closed
                    && action != SecurityAction.Read)
                    return false;

                if (projectSecurity.IsAdministrator(userId)) return true;

                var projectEngine = scope.Resolve<EngineFactory>().ProjectEngine;

                var inTeam = projectEngine.IsInTeam(project.ID, userId);

                switch (action)
                {
                    case SecurityAction.Read:
                        return !project.Private || inTeam;
                    case SecurityAction.Create:
                    case SecurityAction.Edit:
                        Folder folder;
                        return inTeam
                               && (!projectSecurity.IsVisitor(userId)
                                   || (folder = entry as Folder) != null && folder.FolderType == FolderType.BUNCH);
                    case SecurityAction.Delete:
                        return inTeam
                               && !projectSecurity.IsVisitor(userId)
                               && (project.Responsible == userId ||
                                   (entry.CreateBy == userId
                                    && ((folder = entry as Folder) == null || folder.FolderType == FolderType.DEFAULT)));
                    default:
                        return false;
                }
            }
        }

        public IEnumerable<Guid> WhoCanRead(FileEntry entry)
        {
            using (var scope = DIHelper.Resolve())
            {
                return scope.Resolve<EngineFactory>().ProjectEngine.GetTeam(project.ID).Select(p => p.ID).ToList();
            }
        }

        private enum SecurityAction
        {
            Read,
            Create,
            Edit,
            Delete,
        };
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Resources/ProjectsFilterResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Projects.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class ProjectsFilterResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal ProjectsFilterResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Projects.Resources.ProjectsFilterResource", typeof(ProjectsFilterResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Author.
        /// </summary>
        public static string Author {
            get {
                return ResourceManager.GetString("Author", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to By.
        /// </summary>
        public static string By {
            get {
                return ResourceManager.GetString("By", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comments.
        /// </summary>
        public static string ByComments {
            get {
                return ResourceManager.GetString("ByComments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creation date.
        /// </summary>
        public static string ByCreateDate {
            get {
                return ResourceManager.GetString("ByCreateDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creator.
        /// </summary>
        public static string ByCreator {
            get {
                return ResourceManager.GetString("ByCreator", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Date.
        /// </summary>
        public static string ByDate {
            get {
                return ResourceManager.GetString("ByDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Due date.
        /// </summary>
        public static string ByDeadline {
            get {
                return ResourceManager.GetString("ByDeadline", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Time.
        /// </summary>
        public static string ByHours {
            get {
                return ResourceManager.GetString("ByHours", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestone.
        /// </summary>
        public static string ByMilestone {
            get {
                return ResourceManager.GetString("ByMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Description.
        /// </summary>
        public static string ByNote {
            get {
                return ResourceManager.GetString("ByNote", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Order.
        /// </summary>
        public static string ByOrder {
            get {
                return ResourceManager.GetString("ByOrder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Participant.
        /// </summary>
        public static string ByParticipant {
            get {
                return ResourceManager.GetString("ByParticipant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Priority.
        /// </summary>
        public static string ByPriority {
            get {
                return ResourceManager.GetString("ByPriority", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Project.
        /// </summary>
        public static string ByProject {
            get {
                return ResourceManager.GetString("ByProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Responsible.
        /// </summary>
        public static string ByResponsible {
            get {
                return ResourceManager.GetString("ByResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Start date.
        /// </summary>
        public static string ByStartDate {
            get {
                return ResourceManager.GetString("ByStartDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Status.
        /// </summary>
        public static string ByStatus {
            get {
                return ResourceManager.GetString("ByStatus", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to With tag.
        /// </summary>
        public static string ByTag {
            get {
                return ResourceManager.GetString("ByTag", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string ByTitle {
            get {
                return ResourceManager.GetString("ByTitle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Reset filter.
        /// </summary>
        public static string ClearFilter {
            get {
                return ResourceManager.GetString("ClearFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Custom period.
        /// </summary>
        public static string CustomPeriod {
            get {
                return ResourceManager.GetString("CustomPeriod", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Due date.
        /// </summary>
        public static string DueDate {
            get {
                return ResourceManager.GetString("DueDate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Subscribed discussions.
        /// </summary>
        public static string FollowDiscussions {
            get {
                return ResourceManager.GetString("FollowDiscussions", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Followed.
        /// </summary>
        public static string FollowProjects {
            get {
                return ResourceManager.GetString("FollowProjects", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Group.
        /// </summary>
        public static string Group {
            get {
                return ResourceManager.GetString("Group", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Groups.
        /// </summary>
        public static string Groups {
            get {
                return ResourceManager.GetString("Groups", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Me.
        /// </summary>
        public static string Me {
            get {
                return ResourceManager.GetString("Me", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to My discussions.
        /// </summary>
        public static string MyDiscussions {
            get {
                return ResourceManager.GetString("MyDiscussions", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Milestones with My Tasks.
        /// </summary>
        public static string MyMilestones {
            get {
                return ResourceManager.GetString("MyMilestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to My projects.
        /// </summary>
        public static string MyProjects {
            get {
                return ResourceManager.GetString("MyProjects", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to My Tasks.
        /// </summary>
        public static string MyTasks {
            get {
                return ResourceManager.GetString("MyTasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to No responsible.
        /// </summary>
        public static string NoResponsible {
            get {
                return ResourceManager.GetString("NoResponsible", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other.
        /// </summary>
        public static string Other {
            get {
                return ResourceManager.GetString("Other", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other milestones.
        /// </summary>
        public static string OtherMilestones {
            get {
                return ResourceManager.GetString("OtherMilestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other participant.
        /// </summary>
        public static string OtherParticipant {
            get {
                return ResourceManager.GetString("OtherParticipant", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other projects.
        /// </summary>
        public static string OtherProjects {
            get {
                return ResourceManager.GetString("OtherProjects", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other users.
        /// </summary>
        public static string OtherUsers {
            get {
                return ResourceManager.GetString("OtherUsers", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Overdue.
        /// </summary>
        public static string Overdue {
            get {
                return ResourceManager.GetString("Overdue", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Billed.
        /// </summary>
        public static string PaymentStatusBilled {
            get {
                return ResourceManager.GetString("PaymentStatusBilled", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not billed.
        /// </summary>
        public static string PaymentStatusNotBilled {
            get {
                return ResourceManager.GetString("PaymentStatusNotBilled", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Not chargeable.
        /// </summary>
        public static string PaymentStatusNotChargeable {
            get {
                return ResourceManager.GetString("PaymentStatusNotChargeable", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Previous month.
        /// </summary>
        public static string PreviousMonth {
            get {
                return ResourceManager.GetString("PreviousMonth", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Previous week.
        /// </summary>
        public static string PreviousWeek {
            get {
                return ResourceManager.GetString("PreviousWeek", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Project manager.
        /// </summary>
        public static string ProjectMenager {
            get {
                return ResourceManager.GetString("ProjectMenager", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Last 7 days.
        /// </summary>
        public static string Recent {
            get {
                return ResourceManager.GetString("Recent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select.
        /// </summary>
        public static string Select {
            get {
                return ResourceManager.GetString("Select", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All closed.
        /// </summary>
        public static string StatusAllClosedTask {
            get {
                return ResourceManager.GetString("StatusAllClosedTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All open.
        /// </summary>
        public static string StatusAllOpenTask {
            get {
                return ResourceManager.GetString("StatusAllOpenTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Archived.
        /// </summary>
        public static string StatusArchivedDiscussion {
            get {
                return ResourceManager.GetString("StatusArchivedDiscussion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string StatusClosedMilestone {
            get {
                return ResourceManager.GetString("StatusClosedMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string StatusClosedProject {
            get {
                return ResourceManager.GetString("StatusClosedProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Closed.
        /// </summary>
        public static string StatusClosedTask {
            get {
                return ResourceManager.GetString("StatusClosedTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string StatusOpenDiscussion {
            get {
                return ResourceManager.GetString("StatusOpenDiscussion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string StatusOpenMilestone {
            get {
                return ResourceManager.GetString("StatusOpenMilestone", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Active.
        /// </summary>
        public static string StatusOpenProject {
            get {
                return ResourceManager.GetString("StatusOpenProject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Open.
        /// </summary>
        public static string StatusOpenTask {
            get {
                return ResourceManager.GetString("StatusOpenTask", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Paused.
        /// </summary>
        public static string StatusSuspend {
            get {
                return ResourceManager.GetString("StatusSuspend", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tag.
        /// </summary>
        public static string Tag {
            get {
                return ResourceManager.GetString("Tag", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Tasks.
        /// </summary>
        public static string Tasks {
            get {
                return ResourceManager.GetString("Tasks", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Team member.
        /// </summary>
        public static string TeamMember {
            get {
                return ResourceManager.GetString("TeamMember", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Time Period.
        /// </summary>
        public static string TimePeriod {
            get {
                return ResourceManager.GetString("TimePeriod", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Today.
        /// </summary>
        public static string Today {
            get {
                return ResourceManager.GetString("Today", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upcoming.
        /// </summary>
        public static string Upcoming {
            get {
                return ResourceManager.GetString("Upcoming", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upcoming.
        /// </summary>
        public static string UpcomingMilestones {
            get {
                return ResourceManager.GetString("UpcomingMilestones", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Without tag.
        /// </summary>
        public static string WithoutTag {
            get {
                return ResourceManager.GetString("WithoutTag", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/People/Classes/ImportParameters.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ASC.Web.People.Core.Import;
using ASC.Web.People.Resources;

namespace ASC.Web.People.Classes
{
    internal class ImportParameters
    {
        internal Enum Id { get; private set; }
        internal Func<string> Title { get; private set; }

        protected ImportParameters(Enum id, Func<string> title)
        {
            Id = id;
            Title = title;
        }
    }

    internal abstract class ImportParameters<T> : ImportParameters
    {
        internal T Value { get; private set; }

        protected ImportParameters(Enum id, Func<string> title, T value) : base(id, title)
        {
            Value = value;
        }
    }

    internal class SeparatorParameters : ImportParameters<string>
    {
        internal static List<SeparatorParameters> Separator = new List<SeparatorParameters>
        {
            new SeparatorParameters(SeparatorEnum.Comma, () => PeopleResource.ImportSeparatorComma, ","),
            new SeparatorParameters(SeparatorEnum.Semicolon, () => PeopleResource.ImportSeparatorSemicolon, ";"),
            new SeparatorParameters(SeparatorEnum.Colon, () => PeopleResource.ImportSeparatorColon, ":"),
            new SeparatorParameters(SeparatorEnum.Tab, () => PeopleResource.ImportSeparatorTab, "\t"),
            new SeparatorParameters(SeparatorEnum.Space, () => PeopleResource.ImportSeparatorSpace, " ")
        };

        private SeparatorParameters(Enum id, Func<string> title, string value)
            : base(id, title, value)
        {
        }

        internal static string GetById(int id)
        {
            var item = Separator.FirstOrDefault(r => r != null && Convert.ToInt32(r.Id) == id);

            return (item ?? Separator[0]).Value;
        }
    }

    internal class EncodingParameters : ImportParameters<Encoding>
    {
        internal static List<EncodingParameters> Encodng = new List<EncodingParameters>
        {
            new EncodingParameters(EncodingEnum.UTF8, () => PeopleResource.ImportEncodingUTF8, Encoding.UTF8),
            new EncodingParameters(EncodingEnum.ASCII, () => PeopleResource.ImportEncodingASCII, Encoding.ASCII),
            new EncodingParameters(EncodingEnum.Windows1251, () => PeopleResource.ImportEncodingWindows1251, Encoding.GetEncoding(1251)),
            new EncodingParameters(EncodingEnum.CP866, () => PeopleResource.ImportEncodingCP866, Encoding.GetEncoding(866)),
            new EncodingParameters(EncodingEnum.KOI8R, () => PeopleResource.ImportEncodingKOI8R, Encoding.GetEncoding(20866))
        };

        private EncodingParameters(Enum id, Func<string> title, Encoding value)
            : base(id, title, value)
        {
        }

        internal static Encoding GetById(int id)
        {
            var item = Encodng.FirstOrDefault(r => r != null && Convert.ToInt32(r.Id) == id);

            return (item ?? Encodng[0]).Value;
        }
    }

    internal class DelimiterParameters : ImportParameters<string>
    {
        internal static List<DelimiterParameters> Delimiter = new List<DelimiterParameters>
        {
            new DelimiterParameters(DelimiterEnum.Doublequote, () => PeopleResource.ImportDelimiterDQ, "\""),
            new DelimiterParameters(DelimiterEnum.Singlequote, () => PeopleResource.ImportDelimiterSQ, "'")
        };

        private DelimiterParameters(Enum id, Func<string> title, string value)
            : base(id, title, value)
        {
        }

        internal static string GetById(int id)
        {
            var item = Delimiter.FirstOrDefault(r => r != null && Convert.ToInt32(r.Id) == id);

            return (item ?? Delimiter[0]).Value;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Configuration/FilesSettings.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Core;
using ASC.Core.Common.Settings;
using ASC.Files.Core;

namespace ASC.Web.Files.Classes
{
    [Serializable]
    [DataContract]
    public class FilesSettings : BaseSettings<FilesSettings>
    {
        [DataMember(Name = "EnableThirdpartySettings")]
        public bool EnableThirdpartySetting { get; set; }

        [DataMember(Name = "FastDelete")]
        public bool FastDeleteSetting { get; set; }

        [DataMember(Name = "StoreOriginalFiles")]
        public bool StoreOriginalFilesSetting { get; set; }

        [DataMember(Name = "UpdateIfExist")]
        public bool UpdateIfExistSetting { get; set; }

        [DataMember(Name = "ConvertNotify")]
        public bool ConvertNotifySetting { get; set; }

        [DataMember(Name = "SortedBy")]
        public SortedByType DefaultSortedBySetting { get; set; }

        [DataMember(Name = "SortedAsc")]
        public bool DefaultSortedAscSetting { get; set; }

        [DataMember(Name = "HideConfirmConvertSave")]
        public bool HideConfirmConvertSaveSetting { get; set; }

        [DataMember(Name = "HideConfirmConvertOpen")]
        public bool HideConfirmConvertOpenSetting { get; set; }

        [DataMember(Name = "Forcesave")]
        public bool ForcesaveSetting { get; set; }

        [DataMember(Name = "StoreForcesave")]
        public bool StoreForcesaveSetting { get; set; }

        [DataMember(Name = "HideRecent")]
        public bool HideRecentSetting { get; set; }

        [DataMember(Name = "HideFavorites")]
        public bool HideFavoritesSetting { get; set; }

        [DataMember(Name = "HideTemplates")]
        public bool HideTemplatesSetting { get; set; }

        [DataMember(Name = "DownloadZip")]
        private bool DownloadTarGzSetting { get; set; }

        public override ISettings GetDefault()
        {
            return new FilesSettings
            {
                FastDeleteSetting = false,
                EnableThirdpartySetting = true,
                StoreOriginalFilesSetting = true,
                UpdateIfExistSetting = false,
                ConvertNotifySetting = true,
                DefaultSortedBySetting = SortedByType.DateAndTime,
                DefaultSortedAscSetting = false,
                HideConfirmConvertSaveSetting = false,
                HideConfirmConvertOpenSetting = false,
                ForcesaveSetting = false,
                StoreForcesaveSetting = false,
                HideFavoritesSetting = false,
                HideRecentSetting = false,
                HideTemplatesSetting = false,
                DownloadTarGzSetting = false,
            };
        }

        public override Guid ID
        {
            get { return new Guid("{03B382BD-3C20-4f03-8AB9-5A33F016316E}"); }
        }

        public static bool ConfirmDelete
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.FastDeleteSetting = !value;
                setting.SaveForCurrentUser();
            }
            get { return !LoadForCurrentUser().FastDeleteSetting; }
        }

        public static bool EnableThirdParty
        {
            set
            {
                var setting = Load();
                setting.EnableThirdpartySetting = value;
                setting.Save();
            }
            get { return Load().EnableThirdpartySetting; }
        }

        public static bool StoreOriginalFiles
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.StoreOriginalFilesSetting = value;
                setting.SaveForCurrentUser();
            }
            get { return LoadForCurrentUser().StoreOriginalFilesSetting; }
        }

        public static bool UpdateIfExist
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.UpdateIfExistSetting = value;
                setting.SaveForCurrentUser();
            }
            get { return LoadForCurrentUser().UpdateIfExistSetting; }
        }

        public static bool ConvertNotify
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.ConvertNotifySetting = value;
                setting.SaveForCurrentUser();
            }
            get { return LoadForCurrentUser().ConvertNotifySetting; }
        }

        public static bool HideConfirmConvertSave
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.HideConfirmConvertSaveSetting = value;
                setting.SaveForCurrentUser();
            }
            get { return LoadForCurrentUser().HideConfirmConvertSaveSetting; }
        }

        public static bool HideConfirmConvertOpen
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.HideConfirmConvertOpenSetting = value;
                setting.SaveForCurrentUser();
            }
            get { return LoadForCurrentUser().HideConfirmConvertOpenSetting; }
        }

        public static OrderBy DefaultOrder
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.DefaultSortedBySetting = value.SortedBy;
                setting.DefaultSortedAscSetting = value.IsAsc;
                setting.SaveForCurrentUser();
            }
            get
            {
                var setting = LoadForCurrentUser();
                return new OrderBy(setting.DefaultSortedBySetting, setting.DefaultSortedAscSetting);
            }
        }

        public static bool Forcesave
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.ForcesaveSetting = value;
                setting.SaveForCurrentUser();
            }
            get { return LoadForCurrentUser().ForcesaveSetting; }
        }

        public static bool StoreForcesave
        {
            set
            {
                if (CoreContext.Configuration.Personal) throw new NotSupportedException();
                var setting = Load();
                setting.StoreForcesaveSetting = value;
                setting.Save();
            }
            get { return !CoreContext.Configuration.Personal && Load().StoreForcesaveSetting; }
        }

        public static bool RecentSection
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.HideRecentSetting = !value;
                setting.SaveForCurrentUser();
            }
            get { return !LoadForCurrentUser().HideRecentSetting; }
        }

        public static bool FavoritesSection
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.HideFavoritesSetting = !value;
                setting.SaveForCurrentUser();
            }
            get { return !LoadForCurrentUser().HideFavoritesSetting; }
        }

        public static bool TemplatesSection
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.HideTemplatesSetting = !value;
                setting.SaveForCurrentUser();
            }
            get { return !LoadForCurrentUser().HideTemplatesSetting; }
        }

        public static bool DownloadTarGz
        {
            set
            {
                var setting = LoadForCurrentUser();
                setting.DownloadTarGzSetting = value;
                setting.SaveForCurrentUser();
            }
            get => LoadForCurrentUser().DownloadTarGzSetting;
        }
    }
}

<|start_filename|>common/ASC.Common/Notify/NotifyResult.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Text;

using ASC.Notify.Messages;

namespace ASC.Notify
{
    public class NotifyResult
    {
        public SendResult Result { get; internal set; }

        public List<SendResponse> Responses { get; set; }


        internal NotifyResult(SendResult result, List<SendResponse> responses)
        {
            Result = result;
            Responses = responses ?? new List<SendResponse>();
        }

        public override string ToString()
        {
            var sb = new StringBuilder();
            sb.AppendFormat("SendResult: {0} whith {1} sub-results", Result, Responses.Count);
            foreach (SendResponse responce in Responses)
            {
                string recipient = "<recipient:nomessage>";
                string error = "";
                if (responce.NoticeMessage != null)
                {
                    if (responce.NoticeMessage.Recipient != null)
                    {
                        recipient = responce.NoticeMessage.Recipient.Addresses.Length > 0 ?
                            responce.NoticeMessage.Recipient.Addresses[0] :
                            "<no-address>";
                    }
                    else
                    {
                        recipient = "<null-address>";
                    }
                }
                if (responce.Exception != null) error = responce.Exception.Message;
                sb.AppendLine();
                sb.AppendFormat("   {3}->{0}({1})={2} {4}", recipient, responce.SenderName, responce.Result, responce.NotifyAction.ID, error);
            }
            return sb.ToString();
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Blogs/js/blogs.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


var BlogsManager = new function() {
    this.ratingsSortField = 'Name';
    this.ratingsSortDirection = true; // true - asc; false - desc
    this.isSubscribe = false;
    this.groupid = null;
    this.userid = null;
    this.mSearchDefaultString = "";
    this.blogsEditor = null;

    this.BlockButtons = function () {
        LoadingBanner.showLoaderBtn("#actionBlogPage");
    };

    this.UnBlockButtons = function () {
        LoadingBanner.hideLoaderBtn("#actionBlogPage");
    };
    this.CheckData = function() {
        var titleText = jq("input[id$='PageContent_CommunityPageContent_txtTitle']").val();
        if (jq.trim(titleText) == "") {
            ShowRequiredError(jq("input[id$='PageContent_CommunityPageContent_txtTitle']"));
            BlogsManager.UnBlockButtons();
        }
        else {
            window.onbeforeunload = null;
            __doPostBack('', '');
        }
    };

    this.OnClickCancel = function () {
        window.onbeforeunload = null;
        BlogsManager.BlockButtons();
    };
    this.ShowPreview = function (titleid) {
        if (jq("#btnPreview").hasClass("disable")) return;

        Teamlab.getCmtPreview({},
            { title: jq('#' + titleid).val(), content: BlogsManager.blogsEditor.getData() },
            {
                before: function () { BlogsManager.BlockButtons(); },
                after: function () { BlogsManager.UnBlockButtons(); },
                success: function (params, response) {
                    jq('#previewBody').html(response.content);
                    jq('#previewTitle').html(response.title);
                    jq('#previewHolder').show();
                    var scroll_to = jq('#previewHolder').position();
                    jq.scrollTo(scroll_to.top, { speed: 500 });
                }
            });
    };


    this.HidePreview = function() {
        jq('#previewHolder').hide();
        var scroll_to = jq('#postHeader').position();
        jq.scrollTo(scroll_to.top, { speed: 500 });
    };

    this.SubscribeOnGroupBlog = function(groupID) {
        AjaxPro.onLoading = function(b) { if (b) { jq.blockUI(); } else { jq.unblockUI(); } };
        this.groupid = groupID;

        var subscribe;

        var elements = document.getElementsByName(groupID);
        if (elements[0].value == 1) {
            subscribe = true;
        }
        else {
            subscribe = false;
        }

        Default.SubscribeOnNewPostCorporate(groupID, subscribe, this.callbackSubscribeOnGroupBlog);
    };

    this.callbackSubscribeOnGroupBlog = function(result) {
        var elements = document.getElementsByName(BlogsManager.userid);
        var elementsLinks = document.getElementsByName('subscriber_' + BlogsManager.groupid);
        var subscribe = elements[0].value;

        for (var i = 0; i < elements.length; i++) {
            if (subscribe == 1)
                elements[i].value = 0;
            else
                elements[i].value = 1;

            elementsLinks[i].innerHTML = result.value;
        }
    };


    this.RatingSort = function(filedName) {
        if (this.ratingsSortField == filedName) {
            this.ratingsSortDirection = !this.ratingsSortDirection;
        }
        else {
            this.ratingsSortDirection = true;
        }

        this.ratingsSortField = filedName;

        AjaxPro.onLoading = function(b) { if (b) { jq('#blg_ratings').block(); } else { jq('#blg_ratings').unblock(); } };
        RatingList.Sort(this.ratingsSortField, this.ratingsSortDirection, this.callBackSort);
    };

    this.callBackSort = function(result) {
        if (result.value != null)
            jq('#blg_rating_list').html(result.value);
    };

    this.BlogTblSort = function(filedID) {
        if (this.ratingsSortField == filedID) {
            this.ratingsSortDirection = !this.ratingsSortDirection;
        }
        else {
            this.ratingsSortDirection = true;
        }

        this.ratingsSortField = filedID;

        AjaxPro.onLoading = function(b) { if (b) { jq('#blg_ratings').block(); } else { jq('#blg_ratings').unblock(); } };
        AllBlogs.Sort(this.ratingsSortField, this.ratingsSortDirection, this.callBackSort);
    };

    this.SubmitData = function (btnObj) {
        if (jq(btnObj).hasClass("disable"))
            return;
        
        BlogsManager.BlockButtons();
        BlogsManager.CheckData();
    };
};


BlogsManager.ratingsSortField = 'Name';
BlogsManager.ratingsSortDirection = true;

BlogSubscriber = new function() {
    this.SubscribeOnComments = function(blogID, state) {
        AjaxPro.onLoading = function(b) {
            if (b)
                LoadingBanner.displayLoading();
            else
                LoadingBanner.hideLoading();
        };

        Subscriber.SubscribeOnComments(blogID, state, function(result) {
            var res = result.value;
            jq('#blogs_subcribeOnCommentsBox').replaceWith(res.rs2);
        });
    };

    this.SubscribeOnBlogComments = function(blogID, state, link) {
        AjaxPro.onLoading = function(b) {
            if (b)
                LoadingBanner.displayLoading();
            else
                LoadingBanner.hideLoading();
        }
        
        Subscriber.SubscribeOnBlogComments(blogID, state, function(result) {
            var res = result.value;
            jq(link).replaceWith(res.rs2);
        });
        jq("#blogActionsMenuPanel").hide();
    };

    this.SubscribeOnPersonalBlog = function(userID, state) {
        AjaxPro.onLoading = function(b) {
            if (b)
                LoadingBanner.displayLoading();
            else
                LoadingBanner.hideLoading();
        }

        Subscriber.SubscribeOnPersonalBlog(userID, state, function(result) {
            var res = result.value;
            jq('#blogs_subcribeOnPersonalBlogBox').replaceWith(res.rs2);
        });
    };

    this.SubscribePersonalBlog = function(userID, state, link) {
        AjaxPro.onLoading = function(b) {
            if (b)
                LoadingBanner.displayLoading();
            else
                LoadingBanner.hideLoading();
        }

        Subscriber.SubscribePersonalBlog(userID, state, function(result) {
            var res = result.value;
            jq(link).replaceWith(res.rs2);
        });
    };

    this.SubscribeOnNewPosts = function(state) {
        AjaxPro.onLoading = function(b) {
            if (b)
                LoadingBanner.displayLoading();
            else
                LoadingBanner.hideLoading();
        }

        Subscriber.SubscribeOnNewPosts(state, function(result) {
            var res = result.value;
            jq('#blogs_subcribeOnNewPostsBox').replaceWith(res.rs2);
        });
    };

};


function blogTagsAutocompleteInputOnKeyDown(event) {
	//Enter key was pressed
	if (event.keyCode == 13) {
		return false;
	}
	return true;
};

function getURLParam(strParamName) {

        strParamName = strParamName.toLowerCase();

        var strReturn = "";
        var strHref = window.location.href.toLowerCase();
        var bFound = false;

        var cmpstring = strParamName + "=";
        var cmplen = cmpstring.length;

        if (strHref.indexOf("?") > -1) {
            var strQueryString = strHref.substr(strHref.indexOf("?") + 1);
            var aQueryString = strQueryString.split("&");
            for (var iParam = 0; iParam < aQueryString.length; iParam++) {
                if (aQueryString[iParam].substr(0, cmplen) == cmpstring) {
                    var aParam = aQueryString[iParam].split("=");
                    strReturn = aParam[1];
                    bFound = true;
                    break;
                }

            }
        }
        if (bFound == false) return null;

        if (strReturn.indexOf("#") > -1)
            return strReturn.split("#")[0];

        return strReturn;
}

function changeBlogsCountOfRows (val) {    
    var page = getURLParam("page");
    var search = getURLParam("search");
    var href = window.location.href.split("?")[0]+"?";
    href += "&size=" + val;
    if(page!=null)
        href += "&page=1";
    if(search!=null)
        href += "&search=" + search;
    window.location.href = href;
}

function resizeContent() {

    var windowWidth = jq(window).width() - 24 * 2,
           newWidth = windowWidth,
           mainBlockWidth = parseInt(jq(".mainPageLayout").css("min-width"));
    if (windowWidth < mainBlockWidth) {
        newWidth = mainBlockWidth;
    }

    jq(".BlogsBodyBlock, .ContentMainBlog, .container-list").each(
        function() {
            jq(this).css("max-width", newWidth - jq(".mainPageTableSidePanel").width() - 24 * 2 + "px");
        }
    );
       
};

jq(document).ready(function() {
    jq.dropdownToggle({
        dropdownID: "blogActionsMenuPanel",
        switcherSelector: ".BlogsHeaderBlock .menu-small",
        addLeft: -11,
        showFunction: function(switcherObj, dropdownItem) {
            jq('.BlogsHeaderBlock .menu-small.active').removeClass('active');
            if (dropdownItem.is(":hidden")) {
                switcherObj.addClass('active');
            }
        },
        hideFunction: function() {
            jq('.BlogsHeaderBlock .menu-small.active').removeClass('active');
        }
    });
    resizeContent();

    jq(window).resize(function() {
        resizeContent();
    });

    var elemParent = jq('.container-list .content-list div.asccut').parents(".content-list");
    for (var i = 0; i < elemParent.length; i++) {
        var href = jq(elemParent[i]).find('#postIndividualLink').text();
        jq(elemParent[i]).find(".comment-list").before('<div><a href="' + href + '" class="read-more"><font>' + ASC.Community.BlogsJSResource.ReadMoreLink + '</font></a></div>');
    }
    jq(".content-list p").filter(function(index) { return jq(this).html() == ("&nbsp;" && ""); }).remove();

    if (jq("#blogActionsMenuPanel .dropdown-content li").length == 0) {
        jq(".menu-small").hide();
    }
    var anchor = ASC.Controls.AnchorController.getAnchor();

    if (anchor && CommentsManagerObj) {
        CommentsManagerObj.onLoadComplete = function() {
            var parent = jq(jq("body").css("overflow") == "hidden" ? '.mainPageContent' : window);
            if (anchor == "addcomment") {
                ckeditorConnector.load(CommentsManagerObj.AddNewComment());
            } else if (anchor == "comments") {
                parent.scrollTo('#commentsTitle', 500);
            } else {
                parent.scrollTo('#' + anchor, 500);
            }
        };
    }

    if (jq("#actionBlogPage").length) {
        jq.confirmBeforeUnload();
    }
    var textInput = jq("input[id$='CommunityPageContent_txtTitle']");
    if (textInput.length)
        textInput.focus();
});


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Engine/Operations/ApplyFilterOperation.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Linq;

using ASC.Common.Logging;
using ASC.Common.Security.Authentication;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Mail.Core.Engine.Operations.Base;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Enums.Filter;

namespace ASC.Mail.Core.Engine.Operations
{
    public class ApplyFilterOperation : MailOperation
    {
        public EngineFactory Factory { get; private set; }

        public MailSieveFilterData Filter { get; set; }

        public ILog Log { get; set; }

        public override MailOperationType OperationType
        {
            get { return MailOperationType.ApplyFilter; }
        }

        public ApplyFilterOperation(Tenant tenant, IAccount user, int filterId)
            : base(tenant, user)
        {
            Factory = new EngineFactory(CurrentTenant.TenantId, CurrentUser.ID.ToString());

            var filter = Factory.FilterEngine.Get(filterId);

            if (filter == null)
                throw new ArgumentException("Filter not found");

            Filter = filter;

            Log = LogManager.GetLogger("ASC.Mail.ApplyFilterOperation");

            SetSource(filter.Id.ToString());
        }

        protected override void Do()
        {
            try
            {
                SetProgress((int?)MailOperationApplyFilterProgress.Init, "Setup tenant and user");

                CoreContext.TenantManager.SetCurrentTenant(CurrentTenant);

                SecurityContext.AuthenticateMe(CurrentUser);

                SetProgress((int?)MailOperationApplyFilterProgress.Filtering, "Filtering");

                long total;
                const int size = 100;
                var page = 0;

                var messages = Factory.MessageEngine.GetFilteredMessages(Filter, page, size, out total);

                while (messages.Any())
                {
                    SetProgress((int?)MailOperationApplyFilterProgress.FilteringAndApplying, "Filtering and applying action");

                    var ids = messages.Select(m => m.Id).ToList();

                    foreach (var action in Filter.Actions)
                    {
                        Factory.FilterEngine.ApplyAction(ids, action);
                    }

                    if (messages.Count < size)
                        break;

                    if (!Filter.Actions.Exists(a => a.Action == ActionType.DeleteForever || a.Action == ActionType.MoveTo))
                    {
                        page++;
                    }

                    messages = Factory.MessageEngine.GetFilteredMessages(Filter, page, size, out total);
                }

                SetProgress((int?)MailOperationApplyFilterProgress.Finished);
            }
            catch (Exception e)
            {
                Logger.Error("Mail operation error -> Remove user folder: {0}", e);
                Error = "InternalServerError";
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/js/timetracking.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.Projects.TimeSpendActionPage = (function() {
    var isTask = false,
        isInit = false,
        self,
        currentProjectId,
        currentUserId,
        currentTimesCount,
        filterTimesCount = 0,
        $totalTimeContainer,
        $timerList;

    var baseObject = ASC.Projects,
        resources = baseObject.Resources,
        projectsJsResource = resources.ProjectsJSResource,
        projectsFilterResource = resources.ProjectsFilterResource,
        TimeTrackingResource = resources.TimeTrackingResource,
        filter = baseObject.ProjectsAdvansedFilter,
        common = baseObject.Common,
        teamlab,
        loadingBanner,
        $emptyListTimers,
        $studioActionPanel;

    var clickEventName = "click",
        checkedAttr = "checked";

    var filteredTimes = [], __filter, currentProject;

    var init = function () {
        $timerList = jq("#timeSpendsList");
        teamlab = Teamlab;
        currentProjectId = jq.getURLParam("prjID");
        currentUserId = teamlab.profile.id;
        isTask = jq.getURLParam("id") != null;

        if (isInit === false) {
            isInit = true;
            self = this;

            function canCreateTimeSpend(prj) {
                return prj.canCreateTimeSpend && prj.taskCountTotal > 0;
            }

            var actions = [
                {
                    id: "gaBilled",
                    title: TimeTrackingResource.PaymentStatusBilled,
                    handler: changePaymentSatusByCheckedTimers.bind(null, "billed", 2),
                    checker: function (item) {
                        return item.canEditPaymentStatus;
                    }
                },
                {
                    id: "gaNotBilled",
                    title: TimeTrackingResource.PaymentStatusNotBilled,
                    handler: changePaymentSatusByCheckedTimers.bind(null, "not-billed", 1),
                    checker: function (item) {
                        return item.canEditPaymentStatus;
                    }
                },
                {
                    id: "gaNotChargeable",
                    title: TimeTrackingResource.PaymentStatusNotChargeable,
                    handler: changePaymentSatusByCheckedTimers.bind(null, "not-chargeable", 0),
                    checker: function (item) {
                        return item.canEditPaymentStatus;
                    }
                },
                {
                    id: "gaDelete",
                    title: resources.ProjectsCommonResource.Delete,
                    handler: showQuestionWindow,
                    checker: function (item) {
                        return item.canEdit;
                    }
                }
            ];

            self.showOrHideData = self.showOrHideData.bind(self, {
                $container: $timerList.find("tbody"),
                tmplName: "projects_timeTrackingTmpl",
                baseEmptyScreen: {
                    img: "time_tracking",
                    header: resources.TimeTrackingResource.NoTtimers,
                    description: resources.TimeTrackingResource.NoTimersNote,
                    button: {
                        title: resources.TimeTrackingResource.StartTimer,
                        onclick: function () {
                            if (isTask) {
                                var taskId = jq.getURLParam("ID");
                                common.showTimer(currentProjectId, taskId);
                            } else {
                                if (currentProjectId != null) {
                                    common.showTimer(currentProjectId);
                                } else {
                                    common.showTimer();
                                }
                            }
                        },
                        canCreate: function () {
                            return currentProjectId ?
                                canCreateTimeSpend(currentProject) :
                                baseObject.Master.Projects.some(canCreateTimeSpend);
                        }
                    }
                },
                filterEmptyScreen: {
                    header: resources.TimeTrackingResource.NoTimersFilter,
                    description: resources.TimeTrackingResource.DescrEmptyListTimersFilter
                },
                groupMenu: {
                    actions: actions,
                    getItemByCheckbox: getFilteredTimeByTarget,
                    getLineByCondition: function(condition) {
                        return filteredTimes
                            .filter(condition)
                            .map(function(item) {
                                return $timerList.find("[timeid=" + item.id + "]");
                            });
                    },
                    multiSelector: [
                    {
                        id: "gasBilled",
                        title: projectsFilterResource.PaymentStatusBilled,
                        condition: function (item) {
                            return item.paymentStatus === 2;
                        }
                    },
                    {
                        id: "gasNotBilled",
                        title: projectsFilterResource.PaymentStatusNotBilled,
                        condition: function (item) {
                            return item.paymentStatus === 1;
                        }
                    },
                    {
                        id: "gasNotChargeable",
                        title: projectsFilterResource.PaymentStatusNotChargeable,
                        condition: function (item) {
                            return item.paymentStatus === 0;
                        }
                    }]
                }
            });
            if (!self.$commonListContainer.find("#totalTimeText").length) {
                $totalTimeContainer = jq.tmpl("projects_totalTimeText", {}).insertBefore(self.$groupeMenu);
            }
            self.getData = self.getData.bind(self, teamlab.getPrjTime, onGetTimes);
        }
        
        loadingBanner = LoadingBanner;
        var eventConstructor = ASC.Projects.Event,
            events = teamlab.events;

        self.baseInit({
                moduleTitle: resources.ProjectsCommonResource.TimeTracking
            },
            isTask ? undefined : { pagination: "timeKeyForPagination" },
            {
                handler: changePaymentStatus,
                getItem: getFilteredTimeByTarget,
                statuses: [
                    { cssClass: "not-chargeable", text: projectsFilterResource.PaymentStatusNotChargeable, id: 0 },
                    { cssClass: "not-billed", text: projectsFilterResource.PaymentStatusNotBilled, id: 1 },
                    { cssClass: "billed", text: projectsFilterResource.PaymentStatusBilled, id: 2 }
                ]
            },
            showEntityMenu,
            [
                eventConstructor(events.updatePrjTime, onUpdateTime),
                eventConstructor(events.getPrjProject,
                    function(params, project) {
                        currentProject = project;

                        if (isTask) {
                            teamlab.getPrjTaskTime({}, jq.getURLParam("id"), { success: onGetTaskTime });
                        }
                    })
            ],
            {
                getItem: function (target) { return getFilteredTimeByTarget(target).task; },
                selector: '.pm-ts-noteColumn a'
            }
        );

        
        $emptyListTimers = jq("#emptyListTimers");
        $studioActionPanel = jq(".studio-action-panel");

        var projectid = jq.getURLParam("prjid"),
            textSpan = $totalTimeContainer.find("span").first(),
            totalTimeText = "";

        if (isTask) {
            teamlab.getPrjProject({}, projectid);
            totalTimeText = TimeTrackingResource.TimeSpentForTask;
        } else {
            filter.createAdvansedFilterForTimeTracking(self);

            $timerList.addClass("forProject");
            totalTimeText = TimeTrackingResource.TotalTimeNote;
        }
        textSpan.text(totalTimeText);

        function showEntityMenu(selectedActionCombobox) {
            var timeid = selectedActionCombobox.attr("timeid");

            return {
                menuItems: [
                    { id: "ta_edit", text: resources.TaskResource.Edit, handler: taEditHandler.bind(null, timeid), classname: "edit" },
                    { id: "ta_remove", text: resources.ProjectsCommonResource.Delete, handler: taRemoveHandler.bind(null, timeid), classname: "delete" }
                ]
            };
        }

        $timerList.on(clickEventName, ".pm-ts-personColumn span", function (event) {
            var time = getFilteredTimeByTarget(event.target);
            filter.addUser('tasks_responsible', time.person != null ? time.person.id : time.createdBy.id, ['noresponsible']);
        });
    };

    function taEditHandler(id) {
        var time = getFilteredTimeById(id),
            task = time.task,
            recordNote = time.note,
            date = time.date,
            separateTime = jq.timeFormat(time.hours).split(':'),
            responsible = (time.person || time.createdBy).id,
            prjId = time.task.projectOwner.id;

        baseObject.TimeTrakingEdit.showPopup(prjId, task, id, { hours: parseInt(separateTime[0], 10), minutes: parseInt(separateTime[1], 10), seconds: parseInt(separateTime[2], 10) }, date, recordNote, responsible);
    }
    function taRemoveHandler(id) {
        teamlab.removePrjTime({ timeid: id }, { timeids: [id] }, { success: onRemoveTime, error: onUpdatePrjTimeError });
    }

    function showQuestionWindow(timerIds) {
        self.showCommonPopup("trackingRemoveWarning", function () {
            loadingBanner.displayLoading();
            teamlab.removePrjTime({}, { timeids: timerIds },
            {
                success: function () {
                    jq.unblockUI();
                    common.displayInfoPanel(projectsJsResource.TimesRemoved);
                    self.getData();
                }
            });
            jq.unblockUI();
        });
    };

    function changePaymentSatusByCheckedTimers(textStatus, status, timersIds) {
        loadingBanner.displayLoading();
        teamlab.changePaymentStatus({ textStatus: textStatus }, { status: status, timeIds: timersIds }, onChangePaymentStatus);
    };

    function changePaymentStatus(timeId, status) {
        loadingBanner.displayLoading();
        teamlab.changePaymentStatus({}, { status: status, timeIds: [timeId] }, onChangePaymentStatus);
    };

    function onChangePaymentStatus(params, times) {
        var newClass = ASC.Projects.StatusList.getById(times[0].paymentStatus).cssClass;
        for (var i = 0, j = times.length; i < j; i++) {
            var time = times[i];
            jq('.timeSpendRecord[timeid=' + time.id + '] .changeStatusCombobox span:first').attr('class', newClass);
            setFilteredTime(time);
        }

        updateTextFilter();

        loadingBanner.hideLoading();
    };

    function showTotalCountForTask(times) {
        var timesCount = times.length;
        if (!timesCount) return;
        var totalTime = 0;
        var billedTime = 0;
        for (var i = 0; i < timesCount; i++) {
            totalTime += times[i].hours;

            if (times[i].paymentStatus == 2) {
                billedTime += times[i].hours;
            }
        }

        var taskTotalTime = jq.timeFormat(totalTime).split(":");
        $totalTimeContainer.find(".total-count .hours").text(taskTotalTime[0]);
        $totalTimeContainer.find(".total-count .minutes").text(taskTotalTime[1]);

        var taskBilledTime = jq.timeFormat(billedTime).split(":");
        $totalTimeContainer.find(".billed-count .hours").text(taskBilledTime[0]);
        $totalTimeContainer.find(".billed-count .minutes").text(taskBilledTime[1]);

        $totalTimeContainer.addClass("float-none");
        $totalTimeContainer.css("visibility", "visible");
    };

    function showEmptyScreen() {
        self.showOrHideData(filteredTimes, filterTimesCount);

        if (!filteredTimes.length) {
            $totalTimeContainer.css("visibility", "hidden");
        }
    };

    function getTotalTimeByFilter() {
        __filter.Count = 31;
        __filter.StartIndex = currentTimesCount;

        if (!filter.status) {
            delete __filter.status;
            teamlab.getTotalTimeByFilter({}, { filter: __filter, success: onGetTotalTime });

            __filter.status = 2;
            teamlab.getTotalTimeByFilter({}, { filter: __filter, success: onGetTotalBilledTime });
        } else {
            teamlab.getTotalTimeByFilter({}, { filter: __filter, success: onGetTotalTime });
            $totalTimeContainer.find(".billed-count").hide();
        }
    };

    function onGetTimes(params, data) {
        __filter = params.__filter;

        if (Object.keys(__filter).length > 4) {
            $totalTimeContainer = jq.tmpl("projects_totalTimeText", {}).insertBefore(self.$groupeMenu);
            
            getTotalTimeByFilter();

            var textSpan = $totalTimeContainer.find("span").first(),
                totalTimeText = isTask ? TimeTrackingResource.TimeSpentForTask : TimeTrackingResource.TotalTimeNote;
            
            textSpan.text(totalTimeText);
        }


        filteredTimes = data;
        currentTimesCount += data.length;

        if (params.mode != 'next') {
            $timerList.find('tbody').html('');
        }


        filterTimesCount = params.__total != undefined ? params.__total : 0;

        if (!filteredTimes.length) {
            $totalTimeContainer.css("visibility", "hidden");
        }

        self.showOrHideData(filteredTimes, filterTimesCount);
    };

    function onGetTotalTime(params, time) {
        if (time != 0 && filteredTimes.length) {
            var fotmatedTime = jq.timeFormat(time).split(":");
            $totalTimeContainer.find(".total-count .hours").text(fotmatedTime[0]);
            $totalTimeContainer.find(".total-count .minutes").text(fotmatedTime[1]);

            $totalTimeContainer.find(".billed-count .hours").text("0");
            $totalTimeContainer.find(".billed-count .minutes").text("00");

            $totalTimeContainer.css("visibility", "visible");
        } else {
            $totalTimeContainer.css("visibility", "hidden");
        }
    };

    function onGetTotalBilledTime(params, time) {
        var $billedTimeContainer = $totalTimeContainer.find(".billed-count");
        if (time != 0) {
            var fotmatedTime = jq.timeFormat(time).split(":");
            $billedTimeContainer.find(".hours").text(fotmatedTime[0]);
            $billedTimeContainer.find(".minutes").text(fotmatedTime[1]);
        } else {
            $billedTimeContainer.find(".hours").text("0");
            $billedTimeContainer.find(".minutes").text("00");
        }
    };

    function onUpdateTime(params, time) {
        common.displayInfoPanel(projectsJsResource.TimeUpdated);
        $timerList.find('.timeSpendRecord[timeid=' + time.id + ']').replaceWith(jq.tmpl("projects_timeTrackingTmpl", time));
        setFilteredTime(time);

        updateTextFilter();
    };

    function onRemoveTime(params, data) {
        var totalTime = 0;
        for (var i = 0; i < data.length; i++) {
            var timer = jq("#timeSpendRecord" + data[i].id);
            totalTime += data[i].hours;
            timer.animate({ opacity: "hide" }, 500);
            filterTimesCount--;
            timer.remove();
            filteredTimes = filteredTimes.filter(function (t) { return t.id !== data[i].id });
            showEmptyScreen();
        }

        loadingBanner.hideLoading();
        common.displayInfoPanel(projectsJsResource.TimeRemoved);
    };

    function onGetTaskTime(data, times) {
        if (!times.length) {
            showEmptyScreen();
            return;
        }

        showTotalCountForTask(times);

        var task = times[0].task;
        var taskData = {
            icon: "tasks",
            title: task.title
        };

        ASC.Projects.InfoContainer.init(taskData);
        filteredTimes = times;
        filterTimesCount = data.__total != undefined ? data.__total : 0;
        showEmptyScreen();
    }

    function setFilteredTime(time) {
        for (var i = 0, max = filteredTimes.length; i < max; i++) {
            if (filteredTimes[i].id == time.id) {
                filteredTimes[i] = time;
                break;
            }
        }
    };
    
    function getFilteredTimeById(timeId) {
        return filteredTimes.find(function(item) { return item.id == timeId});
    };
    
    function getFilteredTimeByTarget($targetObject) {
        return getFilteredTimeById(jq($targetObject).parents("tr.timeSpendRecord").attr("timeid"));
    };

    function updateTextFilter() {
        if (!isTask) {
            getTotalTimeByFilter({}, __filter);
        } else {
            showTotalCountForTask(filteredTimes);
        }
    }

    function onUpdatePrjTimeError(params, data) {
        jq("div.entity-menu[timeid=" + params.timeid + "]").hide();
    };

    function unbindListEvents() {
        if (!isInit) return;
        $timerList.unbind();
        self.unbindEvents();
        ASC.Projects.GroupActionPanel.hide();
    };

    return jq.extend({
        init: init,
        unbindListEvents: unbindListEvents
    }, ASC.Projects.Base);
})(jQuery);


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Classes/ProjectsCommonSettings.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Core.Common.Settings;
using ASC.Web.Projects.Resources;

namespace ASC.Web.Projects
{
    [Serializable]
    [DataContract]
    public class ProjectsCommonSettings : BaseSettings<ProjectsCommonSettings>
    {
        [DataMember(Name = "EverebodyCanCreate")]
        public bool EverebodyCanCreate { get; set; }

        [DataMember(Name = "HideEntitiesInPausedProjects")]
        public bool HideEntitiesInPausedProjects { get; set; }

        [DataMember]
        public StartModuleType StartModuleType { get; set; }

        [DataMember(Name = "FolderId")]
        private object folderId;

        public object FolderId
        {
            get
            {
                return folderId ?? Files.Classes.Global.FolderMy;
            }
            set
            {
                folderId = value ?? Files.Classes.Global.FolderMy;
            }
        }

        public override Guid ID
        {
            get { return new Guid("{F833803D-0A84-4156-A73F-7680F522FE07}"); }
        }

        public override ISettings GetDefault()
        {
            return new ProjectsCommonSettings
            {
                EverebodyCanCreate = false,
                StartModuleType = StartModuleType.Tasks,
                HideEntitiesInPausedProjects = true
            };
        }
    }

    public enum StartModuleType
    {
        Projects,
        Tasks,
        Discussions,
        TimeTracking
    }

    public class StartModule
    {
        public StartModuleType StartModuleType { get; private set; }
        public Func<string> Title { get; private set; }
        public string Page { get; private set; }

        public static StartModule ProjectsModule = new StartModule(StartModuleType.Projects, () => ProjectResource.Projects, "Projects.aspx");
        public static StartModule TaskModule = new StartModule(StartModuleType.Tasks, () => TaskResource.Tasks, "Tasks.aspx");
        public static StartModule DiscussionModule = new StartModule(StartModuleType.Discussions, () => MessageResource.Messages, "Messages.aspx");
        public static StartModule TimeTrackingModule = new StartModule(StartModuleType.TimeTracking, () => ProjectsCommonResource.TimeTracking, "TimeTracking.aspx");


        private StartModule(StartModuleType startModuleType, Func<string> title, string page)
        {
            StartModuleType = startModuleType;
            Title = title;
            Page = page;
        }
    }


}

<|start_filename|>module/ASC.Feed.Aggregator/FeedAggregatorService.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using System.Web;

using ASC.Common.Caching;
using ASC.Common.Data;
using ASC.Common.Logging;
using ASC.Common.Web;
using ASC.Core;
using ASC.Core.Notify.Signalr;
using ASC.Feed.Aggregator.Config;
using ASC.Feed.Aggregator.Modules;
using ASC.Feed.Aggregator.Modules.Community;
using ASC.Feed.Aggregator.Modules.CRM;
using ASC.Feed.Aggregator.Modules.Documents;
using ASC.Feed.Aggregator.Modules.Projects;
using ASC.Feed.Data;
using ASC.Projects.Core.Services.NotifyService;
using ASC.Web.Core;
using ASC.Web.Studio.Utility;


namespace ASC.Feed.Aggregator
{
    public class FeedAggregatorService
    {
        private static readonly ILog log = LogManager.GetLogger("ASC.Feed.Agregator");
        private static readonly SignalrServiceClient signalrServiceClient = new SignalrServiceClient("counters");

        public static readonly List<IFeedModule> Modules = new List<IFeedModule>
            {
                new BlogsModule(),
                new BookmarksModule(),
                new ForumTopicsModule(),
                new ForumPostsModule(),
                new EventsModule(),
                new ContactsModule(),
                new CrmTasksModule(),
                new DealsModule(),
                new CasesModule(),
                new ProjectsModule(),
                new ParticipantsModule(),
                new MilestonesModule(),
                new DiscussionsModule(),
                new TasksModule(),
                new FilesModule(),
                new FoldersModule()
            };

        private Timer aggregateTimer;
        private Timer removeTimer;

        private volatile bool isStopped;
        private readonly object aggregateLock = new object();
        private readonly object removeLock = new object();
        private ServiceHost _healthCheckServiceHost;

        public void Start()
        {
            var cfg = FeedConfigurationSection.GetFeedSection();

            isStopped = false;
            DbRegistry.Configure();
            CommonLinkUtility.Initialize(cfg.ServerRoot);
            WebItemManager.Instance.LoadItems();

            aggregateTimer = new Timer(AggregateFeeds, cfg.AggregateInterval, TimeSpan.Zero, cfg.AggregatePeriod);
            removeTimer = new Timer(RemoveFeeds, cfg.AggregateInterval, cfg.RemovePeriod, cfg.RemovePeriod);
            _healthCheckServiceHost = new ServiceHost(typeof(HealthCheckService));
            _healthCheckServiceHost.Open();
        }

        public void Stop()
        {
            isStopped = true;

            if (aggregateTimer != null)
            {
                aggregateTimer.Change(Timeout.Infinite, Timeout.Infinite);
                aggregateTimer.Dispose();
                aggregateTimer = null;
            }

            if (removeTimer != null)
            {
                removeTimer.Change(Timeout.Infinite, Timeout.Infinite);
                removeTimer.Dispose();
                removeTimer = null;
            }

            if (_healthCheckServiceHost != null)
            {
                _healthCheckServiceHost.Close();
                _healthCheckServiceHost = null;
            }
        }

        private void AggregateFeeds(object interval)
        {
            if (!Monitor.TryEnter(aggregateLock)) return;

            try
            {
                var start = DateTime.UtcNow;
                log.DebugFormat("Start of collecting feeds...");

                var unreadUsers = new Dictionary<int, Dictionary<Guid, int>>();

                foreach (var module in Modules)
                {
                    var result = new List<FeedRow>();
                    var fromTime = FeedAggregateDataProvider.GetLastTimeAggregate(module.GetType().Name);
                    if (fromTime == default(DateTime)) fromTime = DateTime.UtcNow.Subtract((TimeSpan)interval);
                    var toTime = DateTime.UtcNow;

                    var tenants = Attempt(10, () => module.GetTenantsWithFeeds(fromTime)).ToList();
                    log.DebugFormat("Find {1} tenants for module {0}.", module.GetType().Name, tenants.Count());

                    foreach (var tenant in tenants)
                    {
                        // Warning! There is hack here!
                        // clearing the cache to get the correct acl
                        var cache = AscCache.Memory;
                        cache.Remove("acl" + tenant);
                        cache.Remove("/webitemsecurity/" + tenant);
                        cache.Remove(string.Format("sub/{0}/{1}/{2}", tenant, "6045b68c-2c2e-42db-9e53-c272e814c4ad", NotifyConstants.Event_NewCommentForMessage.ID));

                        HttpContext.Current = null;
                        try
                        {
                            if (CoreContext.TenantManager.GetTenant(tenant) == null)
                            {
                                continue;
                            }

                            CoreContext.TenantManager.SetCurrentTenant(tenant);
                            var users = CoreContext.UserManager.GetUsers();
                            // fake httpcontext break configuration manager for mono
                            if (!WorkContext.IsMono)
                            {
                                HttpContext.Current = new HttpContext(
                                new HttpRequest("hack", CommonLinkUtility.GetFullAbsolutePath("/"), string.Empty),
                                new HttpResponse(new StringWriter()));
                            }

                            var feeds = Attempt(10, () => module.GetFeeds(new FeedFilter(fromTime, toTime) { Tenant = tenant }).Where(r => r.Item1 != null).ToList());
                            log.DebugFormat("{0} feeds in {1} tenant.", feeds.Count, tenant);

                            var tenant1 = tenant;
                            var module1 = module;
                            var feedsRow = feeds
                                .Select(tuple => new Tuple<FeedRow, object>(new FeedRow(tuple.Item1)
                                {
                                    Tenant = tenant1,
                                    ProductId = module1.Product
                                }, tuple.Item2))
                                .ToList();

                            foreach (var u in users)
                            {
                                if (isStopped)
                                {
                                    return;
                                }
                                if (!TryAuthenticate(u.ID))
                                {
                                    continue;
                                }

                                module.VisibleFor(feedsRow, u.ID);
                            }

                            result.AddRange(feedsRow.Select(r => r.Item1));
                        }
                        catch (Exception ex)
                        {
                            log.ErrorFormat("Tenant: {0}, {1}", tenant, ex);
                        }
                        finally
                        {
                            // fake httpcontext break configuration manager for mono
                            if (!WorkContext.IsMono)
                            {
                                if (HttpContext.Current != null)
                                {
                                    new DisposableHttpContext(HttpContext.Current).Dispose();
                                    HttpContext.Current = null;
                                }
                            }
                        }
                    }

                    FeedAggregateDataProvider.SaveFeeds(result, module.GetType().Name, toTime);

                    foreach (var res in result)
                    {
                        foreach (var userGuid in res.Users.Where(userGuid => !userGuid.Equals(res.ModifiedById)))
                        {
                            Dictionary<Guid, int> dictionary;
                            if (!unreadUsers.TryGetValue(res.Tenant, out dictionary))
                            {
                                dictionary = new Dictionary<Guid, int>();
                            }
                            if (dictionary.ContainsKey(userGuid))
                            {
                                ++dictionary[userGuid];
                            }
                            else
                            {
                                dictionary.Add(userGuid, 1);
                            }

                            unreadUsers[res.Tenant] = dictionary;
                        }
                    }
                }

                signalrServiceClient.SendUnreadUsers(unreadUsers);

                log.DebugFormat("Time of collecting news: {0}", DateTime.UtcNow - start);
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
            finally
            {
                Monitor.Exit(aggregateLock);
            }
        }

        private void RemoveFeeds(object interval)
        {
            if (!Monitor.TryEnter(removeLock)) return;

            try
            {
                log.DebugFormat("Start of removing old news");
                FeedAggregateDataProvider.RemoveFeedAggregate(DateTime.UtcNow.Subtract((TimeSpan)interval));
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
            finally
            {
                Monitor.Exit(removeLock);
            }
        }

        private static T Attempt<T>(int count, Func<T> action)
        {
            var counter = 0;
            while (true)
            {
                try
                {
                    return action();
                }
                catch
                {
                    if (count < ++counter)
                    {
                        throw;
                    }
                }
            }
        }

        private static bool TryAuthenticate(Guid userid)
        {
            try
            {
                SecurityContext.AuthenticateMe(CoreContext.Authentication.GetAccountByID(userid));
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/RTP/RTCP_Packet_ReportBlock.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.RTP
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class represents RTCP sender report(SR) or reciver report(RR) packet report block.
    /// </summary>
    public class RTCP_Packet_ReportBlock
    {
        #region Members

        private uint m_CumulativePacketsLost;
        private uint m_DelaySinceLastSR;
        private uint m_ExtHighestSeqNumber;
        private uint m_FractionLost;
        private uint m_Jitter;
        private uint m_LastSR;
        private uint m_SSRC;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the SSRC identifier of the source to which the information in this reception report block pertains.
        /// </summary>
        public uint SSRC
        {
            get { return m_SSRC; }
        }

        /// <summary>
        /// Gets or sets the fraction of RTP data packets from source SSRC lost since the previous SR or 
        /// RR packet was sent.
        /// </summary>
        public uint FractionLost
        {
            get { return m_FractionLost; }

            set { m_FractionLost = value; }
        }

        /// <summary>
        /// Gets or sets total number of RTP data packets from source SSRC that have
        /// been lost since the beginning of reception.
        /// </summary>
        public uint CumulativePacketsLost
        {
            get { return m_CumulativePacketsLost; }

            set { m_CumulativePacketsLost = value; }
        }

        /// <summary>
        /// Gets or sets extended highest sequence number received.
        /// </summary>
        public uint ExtendedHighestSeqNo
        {
            get { return m_ExtHighestSeqNumber; }

            set { m_ExtHighestSeqNumber = value; }
        }

        /// <summary>
        /// Gets or sets an estimate of the statistical variance of the RTP data packet
        /// interarrival time, measured in timestamp units and expressed as an unsigned integer.
        /// </summary>
        public uint Jitter
        {
            get { return m_Jitter; }

            set { m_Jitter = value; }
        }

        /// <summary>
        /// Gets or sets The middle 32 bits out of 64 in the NTP timestamp (as explained in Section 4) received as part of 
        /// the most recent RTCP sender report (SR) packet from source SSRC_n. If no SR has been received yet, the field is set to zero.
        /// </summary>
        public uint LastSR
        {
            get { return m_LastSR; }

            set { m_LastSR = value; }
        }

        /// <summary>
        /// Gets or sets the delay, expressed in units of 1/65536 seconds, between receiving the last SR packet from 
        /// source SSRC_n and sending this reception report block.  If no SR packet has been received yet from SSRC_n, 
        /// the DLSR field is set to zero.
        /// </summary>
        public uint DelaySinceLastSR
        {
            get { return m_DelaySinceLastSR; }

            set { m_DelaySinceLastSR = value; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="ssrc">Source ID.</param>
        internal RTCP_Packet_ReportBlock(uint ssrc)
        {
            m_SSRC = ssrc;
        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        internal RTCP_Packet_ReportBlock() {}

        #endregion

        #region Methods

        /// <summary>
        /// Parses RTCP report block (part of SR or RR packet) from specified buffer.
        /// </summary>
        /// <param name="buffer">Buffer from where to read report block.</param>
        /// <param name="offset">Offset in buffer.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public void Parse(byte[] buffer, int offset)
        {
            /* RFC 3550 6.4.1. 
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            report |                 SSRC_1 (SSRC of first source)                 |
            block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              1    | fraction lost |       cumulative number of packets lost       |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |           extended highest sequence number received           |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                      interarrival jitter                      |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                         last SR (LSR)                         |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                   delay since last SR (DLSR)                  |
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            */

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0)
            {
                throw new ArgumentException("Argument 'offset' value must be >= 0.");
            }

            m_SSRC =
                (uint)
                (buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);
            m_FractionLost = buffer[offset++];
            m_CumulativePacketsLost =
                (uint) (buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);
            m_ExtHighestSeqNumber =
                (uint)
                (buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);
            m_Jitter =
                (uint)
                (buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);
            m_LastSR =
                (uint)
                (buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);
            m_DelaySinceLastSR =
                (uint)
                (buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]);
        }

        /// <summary>
        /// Stores report block to the specified buffer.
        /// </summary>
        /// <param name="buffer">Buffer where to store data.</param>
        /// <param name="offset">Offset in buffer.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public void ToByte(byte[] buffer, ref int offset)
        {
            /* RFC 3550 6.4.1. 
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            report |                 SSRC_1 (SSRC of first source)                 |
            block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              1    | fraction lost |       cumulative number of packets lost       |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |           extended highest sequence number received           |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                      interarrival jitter                      |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                         last SR (LSR)                         |
                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                   |                   delay since last SR (DLSR)                  |
                   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
            */

            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0)
            {
                throw new ArgumentException("Argument 'offset' must be >= 0.");
            }
            if (offset + 24 > buffer.Length)
            {
                throw new ArgumentException("Argument 'buffer' has not enough room to store report block.");
            }

            // SSRC
            buffer[offset++] = (byte) ((m_SSRC >> 24) | 0xFF);
            buffer[offset++] = (byte) ((m_SSRC >> 16) | 0xFF);
            buffer[offset++] = (byte) ((m_SSRC >> 8) | 0xFF);
            buffer[offset++] = (byte) ((m_SSRC) | 0xFF);
            // fraction lost
            buffer[offset++] = (byte) m_FractionLost;
            // cumulative packets lost
            buffer[offset++] = (byte) ((m_CumulativePacketsLost >> 16) | 0xFF);
            buffer[offset++] = (byte) ((m_CumulativePacketsLost >> 8) | 0xFF);
            buffer[offset++] = (byte) ((m_CumulativePacketsLost) | 0xFF);
            // extended highest sequence number
            buffer[offset++] = (byte) ((m_ExtHighestSeqNumber >> 24) | 0xFF);
            buffer[offset++] = (byte) ((m_ExtHighestSeqNumber >> 16) | 0xFF);
            buffer[offset++] = (byte) ((m_ExtHighestSeqNumber >> 8) | 0xFF);
            buffer[offset++] = (byte) ((m_ExtHighestSeqNumber) | 0xFF);
            // jitter
            buffer[offset++] = (byte) ((m_Jitter >> 24) | 0xFF);
            buffer[offset++] = (byte) ((m_Jitter >> 16) | 0xFF);
            buffer[offset++] = (byte) ((m_Jitter >> 8) | 0xFF);
            buffer[offset++] = (byte) ((m_Jitter) | 0xFF);
            // last SR
            buffer[offset++] = (byte) ((m_LastSR >> 24) | 0xFF);
            buffer[offset++] = (byte) ((m_LastSR >> 16) | 0xFF);
            buffer[offset++] = (byte) ((m_LastSR >> 8) | 0xFF);
            buffer[offset++] = (byte) ((m_LastSR) | 0xFF);
            // delay since last SR
            buffer[offset++] = (byte) ((m_DelaySinceLastSR >> 24) | 0xFF);
            buffer[offset++] = (byte) ((m_DelaySinceLastSR >> 16) | 0xFF);
            buffer[offset++] = (byte) ((m_DelaySinceLastSR >> 8) | 0xFF);
            buffer[offset++] = (byte) ((m_DelaySinceLastSR) | 0xFF);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/MIME/MIME_h.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.MIME
{
    #region usings

    using System;
    using System.Text;

    #endregion

    /// <summary>
    /// This is base class for MIME header fields. Defined in RFC 2045 3.
    /// </summary>
    public abstract class MIME_h
    {
        #region Properties

        /// <summary>
        /// Gets if this header field is modified since it has loaded.
        /// </summary>
        /// <remarks>All new added header fields has <b>IsModified = true</b>.</remarks>
        /// <exception cref="ObjectDisposedException">Is riased when this class is disposed and this property is accessed.</exception>
        public abstract bool IsModified { get; }

        /// <summary>
        /// Gets header field name. For example "Content-Type".
        /// </summary>
        public abstract string Name { get; }

        #endregion

        #region Methods

        /// <summary>
        /// Returns header field as string.
        /// </summary>
        /// <returns>Returns header field as string.</returns>
        public override string ToString()
        {
            return ToString(null, null);
        }

        /// <summary>
        /// Returns header field as string.
        /// </summary>
        /// <param name="wordEncoder">8-bit words ecnoder. Value null means that words are not encoded.</param>
        /// <param name="parmetersCharset">Charset to use to encode 8-bit characters. Value null means parameters not encoded.
        /// If encoding needed, UTF-8 is strongly reccomended if not sure.</param>
        /// <returns>Returns header field as string.</returns>
        public abstract string ToString(MIME_Encoding_EncodedWord wordEncoder, Encoding parmetersCharset);

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailMessageData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Net.Mail;
using System.Runtime.Serialization;
using System.Text;

using ASC.Mail.Enums;
using ASC.Mail.Extensions;
using ASC.Mail.Utils;
using ASC.Specific;

namespace ASC.Mail.Data.Contracts
{
    [DataContract(Namespace = "")]
    public class MailMessageData
    {
        public MailMessageData()
        {
            ToList = new List<MailAddress>();
            CcList = new List<MailAddress>();
            BccList = new List<MailAddress>();
        }

        ~MailMessageData()
        {
            if (HtmlBodyStream != null)
                HtmlBodyStream.Dispose();
        }

        [DataMember(EmitDefaultValue = false)]
        public List<MailAttachmentData> Attachments { get; set; }

        [DataMember(EmitDefaultValue = false)]
        public string Introduction { get; set; }

        private string _htmlBody;

        [DataMember(EmitDefaultValue = false)]
        public string HtmlBody
        {
            get
            {
                if (HtmlBodyStream == null || HtmlBodyStream.Length <= 0)
                    return _htmlBody;

                HtmlBodyStream.Seek(0, SeekOrigin.Begin);
                _htmlBody = Encoding.UTF8.GetString(HtmlBodyStream.ReadToEnd());
                HtmlBodyStream.Seek(0, SeekOrigin.Begin);

                return _htmlBody;
            }
            set { _htmlBody = value; }
        }

        [DataMember]
        public bool ContentIsBlocked { get; set; }

        [DataMember]
        public bool Important { get; set; }

        [DataMember]
        public string Subject { get; set; }

        [DataMember]
        public bool HasAttachments { get; set; }

        [DataMember(EmitDefaultValue = false)]
        public string Bcc { get; set; }

        [DataMember(EmitDefaultValue = false)]
        public string Cc { get; set; }

        [DataMember]
        public string To { get; set; }

        [DataMember]
        public string Address { get; set; }

        [DataMember]
        public string From { get; set; }

        public string FromEmail { get; set; }

        [DataMember(EmitDefaultValue = false)]
        public string ReplyTo { get; set; }

        [DataMember]
        public int Id { get; set; }

        [DataMember(EmitDefaultValue = false)]
        public string ChainId { get; set; }

        public DateTime ChainDate { get; set; }

        [DataMember(Name = "ChainDate")]
        public string ChainDateString
        {
            get { return ChainDate.ToString("G", CultureInfo.InvariantCulture); }
            set
            {
                DateTime date;
                if (DateTime.TryParseExact(value, "g", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out date))
                {
                    ChainDate = date;
                }
            }
        }

        public DateTime Date { get; set; }

        [DataMember(Name = "Date")]
        public string DateString
        {
            get { return Date.ToString("G", CultureInfo.InvariantCulture); }
            set
            {
                DateTime date;
                if (DateTime.TryParseExact(value, "g", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out date))
                {
                    Date = date;
                }
            }
        }

        [DataMember(Name = "DateDisplay")]
        public string DateDisplay
        {
            get { return Date.ToVerbString(); }
        }

        [DataMember(EmitDefaultValue = false)]
        public List<int> TagIds { get; set; }

        public string LabelsString
        {
            set
            {
                TagIds = new List<int>(MailUtil.GetLabelsFromString(value));
            }
        }

        [DataMember(Name = "LabelsInString")]
        public string LabelsInString
        {
            get { return MailUtil.GetStringFromLabels(TagIds); }
        }

        [DataMember]
        public bool IsNew { get; set; }

        [DataMember]
        public bool IsAnswered { get; set; }

        [DataMember]
        public bool IsForwarded { get; set; }

        [DataMember]
        public bool TextBodyOnly { get; set; }

        [DataMember]
        public long Size { get; set; }

        [DataMember]
        // ReSharper disable once InconsistentNaming
        public string EMLLink { get; set; }

        [DataMember]
        public string StreamId { get; set; }

        [DataMember]
        public FolderType RestoreFolderId { get; set; }

        [DataMember]
        public FolderType Folder { get; set; }

        [DataMember]
        public uint? UserFolderId { get; set; }

        [DataMember]
        public int ChainLength { get; set; }

        [DataMember]
        public bool WasNew { get; set; }

        [DataMember]
        public bool IsToday { get; set; }

        [DataMember]
        public bool IsYesterday { get; set; }

        [DataMember]
        public ApiDateTime ReceivedDate
        {
            get { return (ApiDateTime)Date; }
        }

        public int MailboxId { get; set; }

        public List<CrmContactData> LinkedCrmEntityIds { get; set; }

        [DataMember]
        public bool IsBodyCorrupted { get; set; }

        [DataMember]
        public bool HasParseError { get; set; }

        [DataMember]
        public string MimeMessageId { get; set; }

        [DataMember]
        public string MimeReplyToId { get; set; }

        [DataMember]
        public string CalendarUid { get; set; }

        [IgnoreDataMember]
        public int CalendarId { get; set; }

        [IgnoreDataMember]
        public string CalendarEventCharset { get; set; }

        [IgnoreDataMember]
        public string CalendarEventMimeType { get; set; }

        [IgnoreDataMember]
        public string CalendarEventIcs { get; set; }

        [IgnoreDataMember]
        public List<MailAddress> ToList { get; set; }

        [IgnoreDataMember]
        public List<MailAddress> CcList { get; set; }

        [IgnoreDataMember]
        public List<MailAddress> BccList { get; set; }

        [IgnoreDataMember]
        public NameValueCollection HeaderFieldNames { get; set; }

        [IgnoreDataMember]
        public Stream HtmlBodyStream { get; set; }

        [IgnoreDataMember]
        public string Uidl { get; set; }

        public class Options
        {
            public Options()
            {
                OnlyUnremoved = true;
                NeedSanitizer = true;
            }

            public bool LoadImages { get; set; }
            public bool LoadBody { get; set; }
            public bool NeedProxyHttp { get; set; }
            public bool NeedSanitizer { get; set; }
            public bool OnlyUnremoved { get; set; }
            public bool LoadEmebbedAttachements { get; set; }

            public string ProxyHttpHandlerUrl { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/BookmarkInfoUserControl.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Web.Community.Modules.Bookmarking.UserControls.Resources;
using ASC.Web.Studio.UserControls.Common.ViewSwitcher;
using ASC.Web.UserControls.Bookmarking.Common;
using ASC.Web.UserControls.Bookmarking.Common.Presentation;

namespace ASC.Web.UserControls.Bookmarking
{
    public partial class BookmarkInfoUserControl : BookmarkInfoBase
    {

        public override void InitUserControl()
        {
            var singleBookmarkUserControl = LoadControl(BookmarkUserControlPath.SingleBookmarkUserControlPath) as BookmarkInfoBase;
            singleBookmarkUserControl.Bookmark = Bookmark;
            singleBookmarkUserControl.UserBookmark = UserBookmark;
            BookmarkInfoHolder.Controls.Add(singleBookmarkUserControl);

            var sortControl = new ViewSwitcher();
            sortControl.TabItems.Add(new ViewSwitcherTabItem
            {
                TabName = BookmarkingUCResource.BookmarkedBy,
                DivID = "BookmarkedByPanel",
                IsSelected = ServiceHelper.SelectedTab == 1,
                SkipRender = true
            });

            sortControl.TabItems.Add(new ViewSwitcherTabItem
            {
                TabName = BookmarkingUCResource.Comments + String.Format(" ({0})", CommentsCount),
                DivID = "BookmarkCommentsPanel",
                IsSelected = ServiceHelper.SelectedTab == 0,
                SkipRender = true
            });

            BookmarkInfoTabsContainer.Controls.Add(sortControl);

            //Init comments
            using (var c = LoadControl(BookmarkUserControlPath.CommentsUserControlPath) as CommentsUserControl)
            {
                c.BookmarkID = Bookmark.ID;
                c.BookmarkComments = ServiceHelper.GetBookmarkComments(Bookmark);
                c.InitComments();
                CommentsHolder.Controls.Add(c);
            }
            if (Bookmark != null)
            {
                var userBookmarks = Bookmark.UserBookmarks;
                if (userBookmarks != null && userBookmarks.Count > 0)
                {
                    //Init added by list
                    AddedByRepeater.DataSource = userBookmarks;
                    AddedByRepeater.DataBind();
                }
            }
        }

        public string GetAddedByTableItem(bool TintFlag, string UserImage, string UserPageLink, string UserBookmarkDescription, string DateAddedAsString, object userID)
        {
            return new BookmarkAddedByUserContorl().GetAddedByTableItem(TintFlag, UserImage, UserPageLink, UserBookmarkDescription, DateAddedAsString, userID);
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Projects/Wrappers/MilestoneWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Api.Employee;
using ASC.Projects.Core.Domain;
using ASC.Specific;

namespace ASC.Api.Projects.Wrappers
{
    [DataContract(Name = "milestone", Namespace = "")]
    public class MilestoneWrapper : ObjectWrapperFullBase
    {
        [DataMember(Order = 14)]
        public SimpleProjectWrapper ProjectOwner { get; set; }

        [DataMember(Order = 20)]
        public ApiDateTime Deadline { get; set; }

        [DataMember(Order = 20)]
        public bool IsKey { get; set; }

        [DataMember(Order = 20)]
        public bool IsNotify { get; set; }

        [DataMember]
        public bool CanEdit { get; set; }

        [DataMember]
        public bool CanDelete { get; set; }

        [DataMember(Order = 20)]
        public int ActiveTaskCount { get; set; }

        [DataMember(Order = 20)]
        public int ClosedTaskCount { get; set; }


        private MilestoneWrapper()
        {
        }

        public MilestoneWrapper(ProjectApiBase projectApiBase, Milestone milestone)
        {
            Id = milestone.ID;
            ProjectOwner = new SimpleProjectWrapper(milestone.Project);
            Title = milestone.Title;
            Description = milestone.Description;
            Created = (ApiDateTime)milestone.CreateOn;
            Updated = (ApiDateTime)milestone.LastModifiedOn;
            Status = (int)milestone.Status;
            Deadline = new ApiDateTime(milestone.DeadLine, TimeZoneInfo.Local);
            IsKey = milestone.IsKey;
            IsNotify = milestone.IsNotify;
            CanEdit = projectApiBase.ProjectSecurity.CanEdit(milestone);
            CanDelete = projectApiBase.ProjectSecurity.CanDelete(milestone);
            ActiveTaskCount = milestone.ActiveTaskCount;
            ClosedTaskCount = milestone.ClosedTaskCount;

            if (projectApiBase.Context.GetRequestValue("simple") != null)
            {
                CreatedById = milestone.CreateBy;
                UpdatedById = milestone.LastModifiedBy;
                if (!milestone.Responsible.Equals(Guid.Empty))
                {
                    ResponsibleId = milestone.Responsible;
                }
            }
            else
            {
                CreatedBy = projectApiBase.GetEmployeeWraper(milestone.CreateBy);
                if (milestone.CreateBy != milestone.LastModifiedBy)
                {
                    UpdatedBy = projectApiBase.GetEmployeeWraper(milestone.LastModifiedBy);
                }
                if (!milestone.Responsible.Equals(Guid.Empty))
                {
                    Responsible = projectApiBase.GetEmployeeWraper(milestone.Responsible);
                }
            }
        }

        public static MilestoneWrapper GetSample()
        {
            return new MilestoneWrapper
            {
                Id = 10,
                ProjectOwner = SimpleProjectWrapper.GetSample(),
                Title = "Sample Title",
                Description = "Sample description",
                Created = ApiDateTime.GetSample(),
                CreatedBy = EmployeeWraper.GetSample(),
                Updated = ApiDateTime.GetSample(),
                UpdatedBy = EmployeeWraper.GetSample(),
                Responsible = EmployeeWraper.GetSample(),
                Status = (int)MilestoneStatus.Open,
                Deadline = ApiDateTime.GetSample(),
                IsKey = false,
                IsNotify = false,
                CanEdit = true,
                ActiveTaskCount = 15,
                ClosedTaskCount = 5
            };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/Data/_DataPage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Data.lsDB
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// Data page.
    /// </summary>
    internal class DataPage
    {
        #region Members

        private readonly byte[] m_Data;
        private readonly int m_DataAreaSize = 1000;
        private readonly long m_OwnerID;
        private readonly DbFile m_pOwnerDB;
        private readonly long m_StartPointer;
        private readonly bool m_Used;
        private long m_NextDataPagePointer;
        private long m_OwnerDataPagePointer;
        private int m_StoredDataLength;

        #endregion

        #region Properties

        /// <summary>
        /// Gets data page size on disk in bytes.
        /// </summary>
        public int DataPageSize
        {
            get { return 33 + DataAreaSize; }
        }

        /// <summary>
        /// Gets this data page address (offset in database file).
        /// </summary>
        public long Pointer
        {
            get { return m_StartPointer; }
        }

        /// <summary>
        /// Gets or sets if data page used or free space.
        /// </summary>
        public bool Used
        {
            get { return m_Used; }

            set
            {
                m_pOwnerDB.SetFilePosition(m_StartPointer + 2);
                m_pOwnerDB.WriteToFile(new[] {Convert.ToByte(value)}, 0, 1);
            }
        }

        /// <summary>
        /// Gets owner object id what owns this data page.
        /// </summary>
        public long OwnerID
        {
            get { return m_OwnerID; }
        }

        /// <summary>
        /// Gets or sets owner data page pointer.
        /// Returns 0 if this is first data page of multiple data pages or only data page.
        /// </summary>
        public long OwnerDataPagePointer
        {
            get { return m_OwnerDataPagePointer; }

            set
            {
                // owner data page pointer
                m_pOwnerDB.SetFilePosition(m_StartPointer + 11);
                m_pOwnerDB.WriteToFile(ldb_Utils.LongToByte(value), 0, 8);

                m_OwnerDataPagePointer = value;
            }
        }

        /// <summary>
        /// Gets or sets pointer to data page what continues this data page.
        /// Returns 0 if data page has enough room for data and there isn't continuing data page.
        /// </summary>
        public long NextDataPagePointer
        {
            get { return m_NextDataPagePointer; }

            set
            {
                // continuing data page pointer
                m_pOwnerDB.SetFilePosition(m_StartPointer + 19);
                m_pOwnerDB.WriteToFile(ldb_Utils.LongToByte(value), 0, 8);

                m_NextDataPagePointer = value;
            }
        }

        /*
		/// <summary>
		/// Gets or sets data that data page holds. Maximum size is this.DataAreaSize. Returns null if no data stored.
		/// </summary>
		public byte[] Data
		{
			get{ 
				byte[] data = new byte[m_StoredDataLength];
				m_pDbFileStream.Position = m_StartPointer + 33;
				m_pDbFileStream.Read(data,0,data.Length);

				return data; 
			}

			set{
				if(value.Length > this.DataAreaSize){
					throw new Exception("Data page can't store more than " + this.DataAreaSize + " bytes, use mutliple data pages !");
				}
		
				// Set stored data length
				m_pDbFileStream.Position = m_StartPointer + 27;
				byte[] dataLength = ldb_Utils.IntToByte(value.Length);
				m_pDbFileStream.Write(dataLength,0,dataLength.Length);
				
                // Store data
				m_pDbFileStream.Position = m_StartPointer + 33;
				m_pDbFileStream.Write(value,0,value.Length);

				m_StoredDataLength = value.Length;
			}
		}
*/

        /// <summary>
        /// Gets how many data data page can store.
        /// </summary>
        public int DataAreaSize
        {
            get { return m_DataAreaSize; }
        }

        /// <summary>
        /// Gets stored data length.
        /// </summary>
        public int StoredDataLength
        {
            get { return m_StoredDataLength; }
        }

        /// <summary>
        /// Gets how much free data space is availabe in data page.
        /// </summary>
        public long SpaceAvailable
        {
            get { return DataAreaSize - m_StoredDataLength; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="dataPageDataAreaSize">Specifies how much data data page can store.</param>
        /// <param name="ownerDB">Owner DB file..</param>
        /// <param name="startOffset">Data page start offset pointer.</param>
        public DataPage(int dataPageDataAreaSize, DbFile ownerDB, long startOffset)
        {
            /* DataPage structure
			   2 bytes                 - CRLF
			   1 byte                  - used (f - unused,u - used)
			   8 byte	               - owner object id
			   8 bytes                 - owner data page pointer
			   8 bytes                 - continuing data page pointer
			   4 bytes                 - stored data length in data area
			   2 bytes                 - CRLF
			   1000 bytes              - data area
			*/

            m_DataAreaSize = dataPageDataAreaSize;
            m_pOwnerDB = ownerDB;
            m_StartPointer = startOffset;

            byte[] dataPageInfo = new byte[33];
            ownerDB.SetFilePosition(startOffset);
            ownerDB.ReadFromFile(dataPageInfo, 0, dataPageInfo.Length);
            m_Data = new byte[dataPageDataAreaSize];
            ownerDB.ReadFromFile(m_Data, 0, dataPageDataAreaSize);

            // CRLF
            if (dataPageInfo[0] != (byte) '\r')
            {
                throw new Exception(
                    "Not right data page startOffset, or invalid data page <CR> is expected but is '" +
                    (int) dataPageInfo[0] + "' !");
            }
            if (dataPageInfo[1] != (byte) '\n')
            {
                throw new Exception(
                    "Not right data page startOffset, or invalid data page <LF> is expected but is '" +
                    (int) dataPageInfo[1] + "' !");
            }

            // used
            if (dataPageInfo[2] == (byte) 'u')
            {
                m_Used = true;
            }
            else
            {
                m_Used = false;
            }

            // owner object id
            m_OwnerID = ldb_Utils.ByteToLong(dataPageInfo, 3);

            // owner data page pointer
            m_OwnerDataPagePointer = ldb_Utils.ByteToLong(dataPageInfo, 11);

            // continuing data page pointer
            m_NextDataPagePointer = ldb_Utils.ByteToLong(dataPageInfo, 19);

            // stored data length in data area
            m_StoredDataLength = ldb_Utils.ByteToInt(dataPageInfo, 27);

            // CRLF
            if (dataPageInfo[31] != (byte) '\r')
            {
                throw new Exception(
                    "Not right data page startOffset, or invalid data page <CR> is expected but is '" +
                    (int) dataPageInfo[31] + "' !");
            }
            if (dataPageInfo[32] != (byte) '\n')
            {
                throw new Exception(
                    "Not right data page startOffset, or invalid data page <LF> is expected but is '" +
                    (int) dataPageInfo[32] + "' !");
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates new data page structure.
        /// </summary>
        /// <param name="dataPageDataAreaSize">Specifies how much data can data page store.</param>
        /// <param name="used">Specifies if data page is used or free space. If this value is false, all toher parameters aren't stored.</param>
        /// <param name="ownerID">Owner data object ID.</param>
        /// <param name="ownerDataPagePointer">This data page owner data page pointer. This value can be 0, if no owner.</param>
        /// <param name="nextDataPagePointer">Data page pointer, what continues this data page. This value can be 0 if, data page won't spread to multiple data pages.</param>
        /// <param name="data">Data what data page stores. Maximum length is dataPageDataAreaSize.</param>
        /// <returns></returns>
        public static byte[] CreateDataPage(int dataPageDataAreaSize,
                                            bool used,
                                            long ownerID,
                                            long ownerDataPagePointer,
                                            long nextDataPagePointer,
                                            byte[] data)
        {
            /* DataPage structure
			   2 bytes                    - CRLF
			   1 byte                     - used (f - unused,u - used)
			   8 byte	                  - owner object id
			   8 bytes                    - owner data page pointer
			   8 bytes                    - continuing data page pointer
			   4 bytes                    - stored data length in data area
			   2 bytes                    - CRLF
			   dataPageDataAreaSize bytes - data area
			*/

            if (data.Length > dataPageDataAreaSize)
            {
                throw new Exception("Data page can store only " + dataPageDataAreaSize +
                                    " bytes, data conatins '" + data.Length + "' bytes !");
            }

            byte[] dataPage = new byte[dataPageDataAreaSize + 33];
            // CRLF
            dataPage[0] = (byte) '\r';
            dataPage[1] = (byte) '\n';
            if (used)
            {
                // used
                dataPage[2] = (byte) 'u';
                // owner object id
                Array.Copy(ldb_Utils.LongToByte(ownerID), 0, dataPage, 3, 8);
                // owner data page pointer
                Array.Copy(ldb_Utils.LongToByte(ownerDataPagePointer), 0, dataPage, 11, 8);
                // continuing data page pointer
                Array.Copy(ldb_Utils.LongToByte(nextDataPagePointer), 0, dataPage, 19, 8);
                // stored data length in data area
                Array.Copy(ldb_Utils.IntToByte(data.Length), 0, dataPage, 27, 4);
                // CRLF
                dataPage[31] = (byte) '\r';
                dataPage[32] = (byte) '\n';
                // data area
                Array.Copy(data, 0, dataPage, 33, data.Length);
            }
            else
            {
                // used
                dataPage[2] = (byte) 'f';
                // CRLF
                dataPage[31] = (byte) '\r';
                dataPage[32] = (byte) '\n';
            }

            return dataPage;
        }

        /// <summary>
        /// Reads specified amount data to buffer.
        /// </summary>
        /// <param name="buffer">Buffer where to store data.</param>
        /// <param name="startIndexInBuffer">Start index in buffer where data storing begins. Start index is included.</param>
        /// <param name="length">Number of bytes to read.</param>
        /// <param name="startOffset">Zero based offset of data area.</param>
        /// <returns></returns>
        public void ReadData(byte[] buffer, int startIndexInBuffer, int length, int startOffset)
        {
            if (startOffset < 0)
            {
                throw new Exception("startOffset can't negative value !");
            }
            if ((length + startOffset) > DataAreaSize)
            {
                throw new Exception("startOffset and length are out of range data page data area !");
            }
            if ((length + startOffset) > m_StoredDataLength)
            {
                throw new Exception(
                    "There isn't so much data stored in data page as requested ! Stored data length = " +
                    m_StoredDataLength + "; start offset = " + startOffset + "; length wanted = " + length);
            }

            Array.Copy(m_Data, startOffset, buffer, startIndexInBuffer, length);
        }

        /// <summary>
        /// Reads data page data. Offset byte is included.
        /// </summary>
        /// <param name="startOffset">Zero based offset of data area.</param>
        /// <param name="length">Specifies how much data to read.</param>
        /// <returns></returns>
        public byte[] ReadData(int startOffset, int length)
        {
            if (startOffset < 0)
            {
                throw new Exception("startOffset can't negative value !");
            }
            if ((length + startOffset) > DataAreaSize)
            {
                throw new Exception("startOffset and length are out of range data page data area !");
            }
            if ((length + startOffset) > m_StoredDataLength)
            {
                throw new Exception(
                    "There isn't so much data stored in data page as requested ! Stored data length = " +
                    m_StoredDataLength + "; start offset = " + startOffset + "; length wanted = " + length);
            }

            byte[] data = new byte[length];
            Array.Copy(m_Data, startOffset, data, 0, length);

            return data;
        }

        /// <summary>
        /// Writed data to data page.
        /// </summary>
        /// <param name="data">Data to write.</param>
        public void WriteData(byte[] data)
        {
            if (data.Length > DataAreaSize)
            {
                throw new Exception("Data page can't store more than " + DataAreaSize +
                                    " bytes, use mutliple data pages !");
            }

            // Set stored data length
            m_pOwnerDB.SetFilePosition(m_StartPointer + 27);
            m_pOwnerDB.WriteToFile(ldb_Utils.IntToByte(data.Length), 0, 4);

            // Store data
            m_pOwnerDB.SetFilePosition(m_StartPointer + 33);
            m_pOwnerDB.WriteToFile(data, 0, data.Length);

            m_StoredDataLength = data.Length;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/ThirdParty/ImportContacts/Import.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Web.Core;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.ThirdParty.ImportContacts
{
    public partial class Import : BasePage
    {
        public static string Location
        {
            get { return CommonLinkUtility.ToAbsolute("~/ThirdParty/ImportContacts/Import.aspx"); }
        }

        public static bool Enable
        {
            get { return Google.Enable || Yahoo.Enable; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
        }
    }
}

<|start_filename|>module/ASC.Notify/ASC.Notify/Config/NotifyServiceCfg.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Reflection;

using ASC.Core.Notify.Senders;

namespace ASC.Notify.Config
{
    public static class NotifyServiceCfg
    {
        public static string ConnectionStringName
        {
            get;
            private set;
        }

        public static IDictionary<string, INotifySender> Senders
        {
            get;
            private set;
        }

        public static int MaxThreads
        {
            get;
            private set;
        }

        public static int BufferSize
        {
            get;
            private set;
        }

        public static int MaxAttempts
        {
            get;
            private set;
        }

        public static TimeSpan AttemptsInterval
        {
            get;
            private set;
        }

        public static IDictionary<string, MethodInfo> Schedulers
        {
            get;
            private set;
        }

        public static string ServerRoot
        {
            get;
            private set;
        }

        public static int StoreMessagesDays
        {
            get;
            private set;
        }

        static NotifyServiceCfg()
        {
            var section = ConfigurationManagerExtension.GetSection("notify") as NotifyServiceCfgSectionHandler;
            if (section == null)
            {
                throw new ConfigurationErrorsException("Section notify not found.");
            }

            ConnectionStringName = section.ConnectionStringName;
            Senders = new Dictionary<string, INotifySender>();
            foreach (NotifyServiceCfgSenderElement element in section.Senders)
            {
                var sender = (INotifySender)Activator.CreateInstance(Type.GetType(element.Type, true));
                sender.Init(element.Properties);
                Senders.Add(element.Name, sender);
            }
            MaxThreads = section.Process.MaxThreads == 0 ? Environment.ProcessorCount : section.Process.MaxThreads;
            BufferSize = section.Process.BufferSize;
            MaxAttempts = section.Process.MaxAttempts;
            AttemptsInterval = section.Process.AttemptsInterval;

            Schedulers = new Dictionary<string, MethodInfo>();
            foreach (NotifyServiceCfgSchedulerElement element in section.Schedulers)
            {
                var typeName = element.Register.Substring(0, element.Register.IndexOf(','));
                var assemblyName = element.Register.Substring(element.Register.IndexOf(','));
                var type = Type.GetType(typeName.Substring(0, typeName.LastIndexOf('.')) + assemblyName, true);
                Schedulers[element.Name] = type.GetMethod(typeName.Substring(typeName.LastIndexOf('.') + 1), BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
            }
            ServerRoot = section.Schedulers.ServerRoot;
            StoreMessagesDays = section.StoreMessagesDays;
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/vCard/DeliveryAddressCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.Mime.vCard
{
    #region usings

    using System.Collections;
    using System.Collections.Generic;

    #endregion

    /// <summary>
    /// vCard delivery address collection implementation.
    /// </summary>
    public class DeliveryAddressCollection : IEnumerable
    {
        #region Members

        private readonly List<DeliveryAddress> m_pCollection;
        private readonly vCard m_pOwner;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner vCard.</param>
        internal DeliveryAddressCollection(vCard owner)
        {
            m_pOwner = owner;
            m_pCollection = new List<DeliveryAddress>();

            foreach (Item item in owner.Items.Get("ADR"))
            {
                m_pCollection.Add(DeliveryAddress.Parse(item));
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets number of items in the collection.
        /// </summary>
        public int Count
        {
            get { return m_pCollection.Count; }
        }

        /// <summary>
        /// Gets item at the specified index.
        /// </summary>
        /// <param name="index">Index of item which to get.</param>
        /// <returns></returns>
        public DeliveryAddress this[int index]
        {
            get { return m_pCollection[index]; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Add new delivery address to the collection.
        /// </summary>
        /// <param name="type">Delivery address type. Note: This value can be flagged value !</param>
        /// <param name="postOfficeAddress">Post office address.</param>
        /// <param name="extendedAddress">Extended address.</param>
        /// <param name="street">Street name.</param>
        /// <param name="locality">Locality(city).</param>
        /// <param name="region">Region.</param>
        /// <param name="postalCode">Postal code.</param>
        /// <param name="country">Country.</param>
        public void Add(DeliveryAddressType_enum type,
                        string postOfficeAddress,
                        string extendedAddress,
                        string street,
                        string locality,
                        string region,
                        string postalCode,
                        string country)
        {
            string value = "" + postOfficeAddress + ";" + extendedAddress + ";" + street + ";" + locality +
                           ";" + region + ";" + postalCode + ";" + country;

            Item item = m_pOwner.Items.Add("ADR", DeliveryAddress.AddressTypeToString(type), "");
            item.SetDecodedValue(value);
            m_pCollection.Add(new DeliveryAddress(item,
                                                  type,
                                                  postOfficeAddress,
                                                  extendedAddress,
                                                  street,
                                                  locality,
                                                  region,
                                                  postalCode,
                                                  country));
        }

        /// <summary>
        /// Removes specified item from the collection.
        /// </summary>
        /// <param name="item">Item to remove.</param>
        public void Remove(DeliveryAddress item)
        {
            m_pOwner.Items.Remove(item.Item);
            m_pCollection.Remove(item);
        }

        /// <summary>
        /// Removes all items from the collection.
        /// </summary>
        public void Clear()
        {
            foreach (DeliveryAddress email in m_pCollection)
            {
                m_pOwner.Items.Remove(email.Item);
            }
            m_pCollection.Clear();
        }

        /// <summary>
        /// Gets enumerator.
        /// </summary>
        /// <returns></returns>
        public IEnumerator GetEnumerator()
        {
            return m_pCollection.GetEnumerator();
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Classes/SubscriptionManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;

using ASC.Core;
using ASC.Notify.Model;
using ASC.Web.Core.Subscriptions;
using ASC.Web.CRM.Resources;
using ASC.Web.CRM.Services.NotifyService;

#endregion

namespace ASC.Web.CRM
{

    public class ProductSubscriptionManager : IProductSubscriptionManager
    {

        private readonly Guid _setAccess = new Guid("{D4D58C55-D32E-41dc-9D22-D123AFAFC7E7}");
        private readonly Guid _responsibleForTask = new Guid("{2479B115-EAEB-4d9a-86DA-51BD708DEFDC}");
        private readonly Guid _responsibleForOpprotunity = new Guid("{73720A31-1981-480f-AB34-074E8BAEDBA9}");
        private readonly Guid _addRelationshipEvent = new Guid("{4E16DBC5-A427-469e-9EF7-A8DEA0F61310}");
        private readonly Guid _exportCompleted = new Guid("{88D3DC5E-3E46-46a1-9FEF-6B8FFF020BA4}");
        private readonly Guid _importCompleted = new Guid("{6A717AAD-16AE-4713-A782-B887766BEB9F}");
        private readonly Guid _createNewContact = new Guid("{ADAC1E70-4163-41c1-8968-67A44E4D24E7}");

        public List<SubscriptionObject> GetSubscriptionObjects(Guid subItem)
        {
            return new List<SubscriptionObject>();
        }

        public List<SubscriptionType> GetSubscriptionTypes()
        {
            return new List<SubscriptionType>
                       {
                           new SubscriptionType
                           {
                               ID = _setAccess,
                               Name = CRMCommonResource.SubscriptionType_SetAccess,
                               NotifyAction = NotifyConstants.Event_SetAccess,
                               Single = true,
                               CanSubscribe = true
                           },
                           new SubscriptionType
                               {
                                   ID = _responsibleForTask,
                                   Name = CRMCommonResource.SubscriptionType_ResponsibleForTask,
                                   NotifyAction = NotifyConstants.Event_ResponsibleForTask,
                                   Single = true,
                                   CanSubscribe = true
                            },
                           new SubscriptionType
                               {
                                   ID = _responsibleForOpprotunity,
                                   Name = CRMCommonResource.SubscriptionType_ResponsibleForOpportunity,
                                   NotifyAction = NotifyConstants.Event_ResponsibleForOpportunity,
                                   Single = true,
                                   CanSubscribe = true
                           },
                           new SubscriptionType
                           {
                               ID = _addRelationshipEvent,
                               Name = CRMCommonResource.SubscriptionType_AddRelationshipEvent,
                               NotifyAction = NotifyConstants.Event_AddRelationshipEvent,
                               Single = true,
                               CanSubscribe = true
                           },
                            new SubscriptionType
                           {
                               ID = _exportCompleted,
                               Name = CRMCommonResource.SubscriptionType_ExportCompleted,
                               NotifyAction = CoreContext.Configuration.CustomMode ? NotifyConstants.Event_ExportCompletedCustomMode : NotifyConstants.Event_ExportCompleted,
                               Single = true,
                               CanSubscribe = true
                           },
                            new SubscriptionType
                           {
                               ID = _importCompleted,
                               Name = CRMCommonResource.SubscriptionType_ImportCompleted,
                               NotifyAction = CoreContext.Configuration.CustomMode ? NotifyConstants.Event_ImportCompletedCustomMode : NotifyConstants.Event_ImportCompleted,
                               Single = true,
                               CanSubscribe = true
                           },
                            new SubscriptionType
                           {
                               ID = _createNewContact,
                               Name = CRMCommonResource.SubscriptionType_CreateNewContact,
                               NotifyAction = NotifyConstants.Event_CreateNewContact,
                               Single = true,
                               CanSubscribe = true
                           }
                       };
        }

        public ISubscriptionProvider SubscriptionProvider
        {
            get { return NotifySource.Instance.GetSubscriptionProvider(); }
        }

        public GroupByType GroupByType
        {
            get { return GroupByType.Simple; }
        }

        public List<SubscriptionGroup> GetSubscriptionGroups()
        {
            return new List<SubscriptionGroup>();
        }
    }

}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/Monitoring/LogHelper.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;

using ASC.Web.Studio.Utility;

using Ionic.Zip;

namespace ASC.Web.Studio.UserControls.Management
{
    [ManagementControl(ManagementType.Monitoring, Location, SortOrder = 100)]
    public partial class LogHelper : UserControl
    {
        public const string Location = "~/UserControls/Management/Monitoring/LogHelper.ascx";

        protected string HelpLink { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            Page.RegisterBodyScripts("~/UserControls/Management/Monitoring/js/loghelper.js")
                .RegisterStyle("~/uUserControls/Management/Monitoring/css/monitoring.less");

            if (IsDownloadRequest())
                DownloadArchive();

            HelpLink = CommonLinkUtility.GetHelpLink();
        }

        private void DownloadArchive()
        {
            var archiveName = GetArchiveName();
            Response.ContentType = MimeMapping.GetMimeMapping(archiveName);
            Response.AddHeader("Content-Disposition", "attachment; filename=" + archiveName);
            CreateArchive(Response.OutputStream);
            Response.End();
        }

        private void CreateArchive(Stream outputStream)
        {
            using (var zip = new ZipFile())
            {
                zip.AddFiles(EnumerateLogFiles(GetStartDate(), GetEndDate()), true, "");
                zip.Save(outputStream);
            }
        }

        private string GetArchiveName()
        {
            return string.Format("teamlab_office_logs_{0:yyyy-MM-dd}_{1:yyyy-MM-dd}.zip", GetStartDate(), GetEndDate());
        }

        private bool IsDownloadRequest()
        {
            return HttpContext.Current.Request["download"] == "true";
        }

        private DateTime GetStartDate()
        {
            string startDate = HttpContext.Current.Request["start"];
            return !string.IsNullOrEmpty(startDate) ? Convert.ToDateTime(startDate) : DateTime.MinValue;
        }

        private DateTime GetEndDate()
        {
            string endDate = HttpContext.Current.Request["end"];
            return !string.IsNullOrEmpty(endDate) ? Convert.ToDateTime(endDate) : DateTime.MaxValue;
        }

        private IEnumerable<string> EnumerateLogFiles(DateTime startDate, DateTime endDate)
        {
            return GetLogFolders()
                .SelectMany(logFolder => Directory.EnumerateFiles(logFolder, "*.log", SearchOption.AllDirectories)
                                                  .Where(logFile => IsLogMatchingDate(logFile, startDate, endDate)));
        }

        private IEnumerable<string> GetLogFolders()
        {
            var paths = ConfigurationManagerExtension.AppSettings["monitoring.log-folder"] ?? @"..\Logs\";
            return paths.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
                        .Select(path =>
                            {
                                if (!Path.IsPathRooted(path))
                                    path = Path.Combine(Request.PhysicalApplicationPath, path);
                                return path;
                            })
                        .Where(Directory.Exists);
        }

        private bool IsLogMatchingDate(string logFile, DateTime startDate, DateTime endDate)
        {
            var fileInfo = new FileInfo(logFile);
            return fileInfo.LastWriteTimeUtc.Date >= startDate && fileInfo.LastWriteTimeUtc.Date <= endDate;
        }
    }
}

<|start_filename|>module/ASC.HealthCheck/ASC.HealthCheck/Models/Service.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using System.Reflection;
using System.Threading;
using ASC.Common.Utils;
using ASC.Core;
using ASC.Core.Common.Contracts;
using ASC.Core.Configuration;
using ASC.Core.Notify;
using ASC.Core.Notify.Jabber;
using ASC.CRM.Core;
using ASC.CRM.Core.Dao;
using ASC.CRM.Core.Entities;
using ASC.ElasticSearch;
using ASC.Feed.Aggregator.Config;
using ASC.Feed.Data;
using ASC.HealthCheck.Classes;
using ASC.HealthCheck.Resources;
using ASC.Notify.Messages;
using ASC.Web.CRM.Core;
using Autofac;
using log4net;

namespace ASC.HealthCheck.Models
{
    public abstract class Service : ICloneable
    {
        public int Attempt { get; set; }
        public ServiceEnum ServiceName { get; set; }
        public string Status { get; set; }
        public string Message { get; set; }
        public abstract string Title { get; }

        protected ILog log;

        protected readonly string fakeUserId = HealthCheckRunner.FakeUserId;
        protected readonly string hubUrl = ConfigurationManager.AppSettings["web.hub"] ?? "http://localhost:9899/";
        protected const int StateOnline = 1;

        protected Service(ServiceEnum serviceName)
        {
            ServiceName = serviceName;
            Message = string.Empty;
            Status = ServiceStatus.Running.GetStringStatus();
            log = LogManager.GetLogger(typeof(Service));
        }

        public abstract string Check(int tenantId);

        public object Clone()
        {
            return MemberwiseClone();
        }

        public static Service CreateNewService(ServiceEnum serviceEnum)
        {
            switch (serviceEnum)
            {
                case ServiceEnum.OnlyofficeJabber:
                    return new OnlyofficeJabberService();
                case ServiceEnum.OnlyofficeSignalR:
                    return new OnlyofficeSignalRService();
                case ServiceEnum.OnlyofficeNotify:
                    return new OnlyofficeNotifyService();
                case ServiceEnum.OnlyofficeBackup:
                    return new OnlyofficeBackupService();
                case ServiceEnum.OnlyofficeFeed:
                    return new OnlyofficeFeedService();
                case ServiceEnum.OnlyofficeMailAggregator:
                    return new OnlyofficeMailAggregatorService();
                case ServiceEnum.OnlyofficeMailWatchdog:
                    return new OnlyofficeMailWatchdogService();
                case ServiceEnum.OnlyofficeAutoreply:
                    return new OnlyofficeAutoreplyService();
                case ServiceEnum.OnlyofficeIndex:
                    return new OnlyofficeIndexService();
                case ServiceEnum.EditorsFileConverter:
                    return new EditorsFileConverterService();
                case ServiceEnum.EditorsCoAuthoring:
                    return new EditorsCoAuthoringService();
                case ServiceEnum.EditorsSpellChecker:
                    return new EditorsSpellCheckerService();
                case ServiceEnum.MiniChat:
                    return new MiniChatService();
            }
            return null;
        }
    }

    public class OnlyofficeJabberService : Service
    {
        public OnlyofficeJabberService() : base(ServiceEnum.OnlyofficeJabber)
        {
        }

        public override string Title { get { return HealthCheckResource.JabberServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                log.Debug("CheckJabberState");
                using (var jabberServiceClient = new JabberServiceClientWcf())
                {
                    jabberServiceClient.Open();
                    var userGuid = new Guid(fakeUserId);
                    var user = CoreContext.UserManager.GetUsers(userGuid);
                    var status = jabberServiceClient.HealthCheck(user.UserName, tenantId);
                    if (status == string.Empty)
                    {
                        log.Debug("Jabber is OK!");
                        return string.Empty;
                    }

                    log.ErrorFormat("Jabber is failed! {0}", status);
                    return status;
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Jabber is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.ServiceCheckFailed;
            }
        }
    }

    public class OnlyofficeSignalRService : Service
    {
        public OnlyofficeSignalRService() : base(ServiceEnum.OnlyofficeSignalR)
        {
        }

        public override string Title { get { return HealthCheckResource.SignalRServiceTitle; } }

        public override string Check(int tenantId)
        {
            return "";
            //HubConnection hubConnection = null;
            //try
            //{
            //    log.Debug("CheckMiniChatState");
            //    IDictionary<string, string> queryString = new Dictionary<string, string>();
            //    var fakeTenant = CoreContext.TenantManager.GetTenant(tenantId);
            //    queryString["token"] =
            //        Signature.Create(string.Join(",", fakeTenant.TenantId, fakeUserId, fakeTenant.TenantAlias));
            //    hubConnection = new HubConnection(hubUrl, queryString);
            //    var hubProxy = hubConnection.CreateHubProxy("c"); // Chat
            //    ServicePointManager.DefaultConnectionLimit = 10;
            //    hubConnection.Start(new LongPollingTransport()).Wait();
            //    // initDataRetrieved
            //    hubProxy.On<string, string, UserClass[], int, string>("idr",
            //        (uName, displayUserName, users, userTenant, domain) => hubConnection.Stop());

            //    hubProxy.Invoke("cu", StateOnline).Wait(); // ConnectUser
            //    // hubProxy.Invoke("gid").Wait(); // GetInitData

            //    log.Debug("MiniChat is OK!");
            //    return string.Empty;
            //}
            //catch (Exception ex)
            //{
            //    log.ErrorFormat("SignalR is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
            //        ex.InnerException != null ? ex.InnerException.Message : string.Empty);
            //    return HealthCheckResource.ServiceCheckFailed;
            //}
            //finally
            //{
            //    if (hubConnection != null)
            //    {
            //        hubConnection.Stop();
            //    }
            //}
        }
    }

    public class OnlyofficeNotifyService : Service
    {
        public OnlyofficeNotifyService() : base(ServiceEnum.OnlyofficeNotify) { }

        public override string Title { get { return HealthCheckResource.NotifyServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                log.Debug("CheckNotifyState");
                using (var notifyServiceClient = new NotifyServiceClient())
                {
                    var userGuid = new Guid(fakeUserId);
                    var user = CoreContext.UserManager.GetUsers(userGuid);
                    notifyServiceClient.SendNotifyMessage(new NotifyMessage
                    {
                        To = user.UserName,
                        Subject = "Subject",
                        ContentType = "ContentType",
                        Content = "Content",
                        Sender = Constants.NotifyMessengerSenderSysName,
                        CreationDate = DateTime.UtcNow
                    });
                }
                log.Debug("Notify is OK!");
                return string.Empty;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Notify is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.ServiceCheckFailed;
            }
        }
    }

    public class OnlyofficeBackupService : Service
    {
        public OnlyofficeBackupService() : base(ServiceEnum.OnlyofficeBackup) { }

        public override string Title { get { return HealthCheckResource.BackupServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                log.Debug("CheckBackupState");
                using (var backupServiceClient = new BackupServiceClient())
                {
                    var status = backupServiceClient.StartBackup(new StartBackupRequest
                    {
                        TenantId = tenantId,
                        StorageType = BackupStorageType.DataStore
                    });
                    try
                    {
                        while (!status.IsCompleted)
                        {
                            Thread.Sleep(1000);
                            status = backupServiceClient.GetBackupProgress(tenantId);
                        }
                    }
                    catch (Exception ex)
                    {
                        log.ErrorFormat("Backup is failed! {0} {1} {2}", status.Error, ex.Message, ex.StackTrace);
                        return HealthCheckResource.BackupServiceWorksIncorrectMsg;
                    }

                    log.Debug("Backup is OK!");
                    return string.Empty;
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Backup is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.BackupServiceWorksIncorrectMsg;
            }
        }
    }

    public class OnlyofficeFeedService : Service
    {
        public OnlyofficeFeedService() : base(ServiceEnum.OnlyofficeFeed) { }

        public override string Title { get { return HealthCheckResource.FeedServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                log.Debug("CheckFeedState");
                var userGuid = new Guid(fakeUserId);
                CoreContext.TenantManager.SetCurrentTenant(tenantId);
                SecurityContext.AuthenticateMe(userGuid);

                var person = new Person
                {
                    FirstName = "Homer",
                    LastName = "Simpson",
                    JobTitle = "Software engineer",
                    About = "Cool dude"
                };

                int personId;

                using (var scope = DIHelper.Resolve(tenantId))
                {
                    var dao = scope.Resolve<DaoFactory>().ContactDao;
                    personId = dao.SaveContact(person);

                    CRMSecurity.SetAccessTo(person, new List<Guid> {userGuid});

                    // waiting while service is collecting news
                    var feedCfg = FeedConfigurationSection.GetFeedSection();

                    Thread.Sleep(feedCfg.AggregatePeriod + TimeSpan.FromSeconds(30));

                    var feedItemId = string.Format("person_{0}", personId);

                    var feedItem = FeedAggregateDataProvider.GetFeedItem(feedItemId);
                    if (feedItem == null)
                    {
                        log.ErrorFormat("Error! Feed Item is null, feedItemId = {0}", feedItemId);
                        dao.DeleteContact(personId);
                        FeedAggregateDataProvider.RemoveFeedItem(feedItemId);
                        return HealthCheckResource.FeedService_NewsGenerationError;
                    }

                    dao.DeleteContact(personId);
                    FeedAggregateDataProvider.RemoveFeedItem(feedItemId);
                    log.Debug("Feed is OK!");
                    return string.Empty;
                }
            }
            catch (Exception ex)
            {
                log.ErrorFormat("Feed is failed! {0}, innerException = {1}", ex,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.ServiceCheckFailed;
            }
        }
    }

    public class OnlyofficeMailAggregatorService : Service
    {
        public OnlyofficeMailAggregatorService() : base(ServiceEnum.OnlyofficeMailAggregator) { }

        public override string Title { get { return HealthCheckResource.MailAggregatorServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                log.Debug("CheckMailAggregatorState");
                /*var userGuid = new Guid(fakeUserId);
                var user = CoreContext.UserManager.GetUsers(userGuid);
                var asc_auth_key = SecurityContext.AuthenticateMe(userGuid);
                string portalUrl = "http://localhost/";
                var client = new RestClient(portalUrl);
                var request = new RestRequest("/api/2.0/mail/messages/send.json", Method.PUT);
                request.AddCookie("asc_auth_key", asc_auth_key);
                request.AddParameter("id", 0, ParameterType.QueryString);
                request.AddParameter("from", user.Email, ParameterType.QueryString);
                request.AddParameter("to[]", "<" + user.Email + ">", ParameterType.QueryString);
                request.AddParameter("subject", "test-subject", ParameterType.QueryString);
                request.AddParameter("body", "<p>test-body</p>", ParameterType.QueryString);
                request.AddParameter("streamId", Guid.NewGuid().ToString("N").ToLower(), ParameterType.QueryString);
                request.AddParameter("mimeMessageId", string.Empty, ParameterType.QueryString);
                request.AddParameter("mimeReplyToId", string.Empty, ParameterType.QueryString);
                request.AddParameter("importance", false, ParameterType.QueryString);

                // execute the request
                var response = client.Execute(request);
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    throw new Exception("Can't send mail using API. Response code = " + response.StatusCode, response.ErrorException);
                }
                var jObject = JObject.Parse(response.Content);

                // waiting for the end of the MailAggregator service activity
                Thread.Sleep(TimeSpan.FromSeconds(30));

                request = new RestRequest(string.Format("/api/2.0/mail/messages/{0}.json", jObject["response"]), Method.GET);
                request.AddCookie("asc_auth_key", asc_auth_key);
                response = client.Execute(request);
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    throw new Exception("Can't get mail information using API. Response code = "
                                        + response.StatusCode, response.ErrorException);
                }
                jObject = JObject.Parse(response.Content);
                var folderObject = jObject["response"]["folder"];
                if (folderObject == null)
                {
                    throw new Exception("Can't get mail information using API. Wrong Json content: " + response.Content);
                }
                var folder = folderObject.ToString();

                if (folder != INBOX_FOLDER)
                {
                    throw new Exception("Can't get mail information from inbox folder. Wrong Json content: " + response.Content);
                }
                log.Debug("MailAggregator is OK!");*/
                return string.Empty;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("MailAggregator is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.ServiceCheckFailed;
            }
        }
    }

    public class OnlyofficeMailWatchdogService : Service
    {
        public OnlyofficeMailWatchdogService() : base(ServiceEnum.OnlyofficeMailWatchdog) { }

        public override string Title { get { return HealthCheckResource.MailWatchdogServiceTitle; } }

        public override string Check(int tenantId)
        {
            return string.Empty;
        }
    }

    public class OnlyofficeAutoreplyService : Service
    {
        public OnlyofficeAutoreplyService() : base(ServiceEnum.OnlyofficeAutoreply)
        {
        }

        public override string Title { get { return HealthCheckResource.AutoreplyServiceTitle; } }

        public override string Check(int tenantId)
        {
            return "";
        }
    }

    public class OnlyofficeIndexService : Service
    {
        public OnlyofficeIndexService() : base(ServiceEnum.OnlyofficeIndex) { }

        public override string Title { get { return HealthCheckResource.IndexServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                return FactoryIndexer.CheckState()
                    ? HealthCheckResource.FullTextIndexServiceWorksCorrectMsg
                    : HealthCheckResource.FullTextIndexServiceWorksIncorrectMsg;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("TextIndexer is failed! {0}, innerException = {1}", ex,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                ReflectionTypeLoadException reflectionTypeLoadException = ex as ReflectionTypeLoadException;
                if (reflectionTypeLoadException != null)
                {
                    foreach (var loaderException in reflectionTypeLoadException.LoaderExceptions)
                    {
                        log.ErrorFormat("loaderException = {0}", loaderException.ToString());
                    }
                }
                return HealthCheckResource.FullTextIndexServiceWorksIncorrectMsg;
            }
        }
    }

    public class EditorsFileConverterService : Service
    {
        public EditorsFileConverterService() : base(ServiceEnum.EditorsFileConverter) { }

        public override string Title { get { return HealthCheckResource.FileConverterServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                using (var client = new WebClient())
                {
                    var html = client.DownloadString(ConfigurationManager.AppSettings["editors-canvas-service-url"]);

                    return !string.IsNullOrWhiteSpace(html)
                        ? string.Empty
                        : HealthCheckResource.EditorsFileConverter_AccessError;
                }
            }
            catch (WebException)
            {
                return HealthCheckResource.EditorsFileConverter_AccessError;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("EditorsFileConverter is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.ServiceCheckFailed;
            }
        }
    }

    public class EditorsCoAuthoringService : Service
    {
        public EditorsCoAuthoringService() : base(ServiceEnum.EditorsCoAuthoring) { }

        public override string Title { get { return HealthCheckResource.CoAuthoringServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                using (var client = new WebClient())
                {
                    var html = client.DownloadString(ConfigurationManager.AppSettings["editors-coauthoring-service-url"]);
                    return html.IndexOf("Server is functioning normally", StringComparison.OrdinalIgnoreCase) > -1
                        ? string.Empty
                        : HealthCheckResource.EditorsCoAuthoring_AccessError;
                }
            }
            catch (WebException)
            {
                return HealthCheckResource.EditorsCoAuthoring_AccessError;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("EditorsCoAuthoring is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.ServiceCheckFailed;
            }
        }
    }

    public class EditorsSpellCheckerService : Service
    {
        public EditorsSpellCheckerService() : base(ServiceEnum.EditorsSpellChecker) { }

        public override string Title { get { return HealthCheckResource.SpellCheckerServiceTitle; } }

        public override string Check(int tenantId)
        {
            try
            {
                using (var client = new WebClient())
                {
                    var html =
                        client.DownloadString(ConfigurationManager.AppSettings["editors-spellchecker-service-url"]);
                    return html.IndexOf("Server is functioning normally", StringComparison.OrdinalIgnoreCase) > -1
                        ? string.Empty
                        : HealthCheckResource.EditorsSpellchecker_AccessError;
                }
            }
            catch (WebException)
            {
                return HealthCheckResource.EditorsSpellchecker_AccessError;
            }
            catch (Exception ex)
            {
                log.ErrorFormat("EditorsSpellchecker is failed! {0} {1} {2}", ex.Message, ex.StackTrace,
                    ex.InnerException != null ? ex.InnerException.Message : string.Empty);
                return HealthCheckResource.ServiceCheckFailed;
            }
        }
    }

    public class MiniChatService : Service
    {
        public MiniChatService() : base(ServiceEnum.MiniChat) { }

        public override string Title { get { return HealthCheckResource.MiniChatServiceTitle; } }

        public override string Check(int tenantId)
        {
            return new OnlyofficeSignalRService().Check(tenantId);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Utility/WhiteLabelHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Common.Settings;
using ASC.Core.Configuration;
using ASC.Data.Storage;
using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Core;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace ASC.Web.Studio.Utility
{
    public class WhiteLabelHelper
    {
        private readonly static ILog Log = LogManager.GetLogger("ASC");

        private const string Base64StartPng = "data:image/png;base64,";

        private const string PngExt = ".png";

        private const string JsonDataFilePath = "json-data.txt";

        private const string LogoPattern = "logo_*";

        public static void ApplyPartnerWhiteLableSettings()
        {
            if (!TenantExtra.Enterprise && !CoreContext.Configuration.CustomMode) return;

            var firstVisit = CompanyWhiteLabelSettings.Instance.IsDefault &&
                             AdditionalWhiteLabelSettings.Instance.IsDefault &&
                             MailWhiteLabelSettings.Instance.IsDefault;

            try
            {
                var partnerdataStorage = StorageFactory.GetStorage(string.Empty, "static_partnerdata");

                if (partnerdataStorage == null) return;

                if (!partnerdataStorage.IsFile(JsonDataFilePath)) return;

                JObject jsonObject;

                using (var stream = partnerdataStorage.GetReadStream(JsonDataFilePath))
                using (var reader = new StreamReader(stream))
                {
                    jsonObject = JObject.Parse(reader.ReadToEnd());
                }

                if (jsonObject == null) return;

                SaveSettings<CompanyWhiteLabelSettings>(jsonObject, "CompanyWhiteLabelSettings");
                SaveSettings<AdditionalWhiteLabelSettings>(jsonObject, "AdditionalWhiteLabelSettings");
                SaveSettings<MailWhiteLabelSettings>(jsonObject, "MailWhiteLabelSettings");
                SaveSettings<TenantWhiteLabelSettings>(jsonObject, "TenantWhiteLabelSettings");

                var smtpSettingsStr = (jsonObject["SmtpSettings"] ?? "").ToString();
                var defaultCultureName = (jsonObject["DefaultCulture"] ?? "").ToString();

                if (!String.IsNullOrEmpty(smtpSettingsStr))
                {
                    try
                    {
                        SmtpSettings.Deserialize(smtpSettingsStr);
                        CoreContext.Configuration.SaveSetting("SmtpSettings", smtpSettingsStr);
                    }
                    catch (Exception e)
                    {
                        Log.Error(e.Message, e);
                    }
                }

                if (!String.IsNullOrEmpty(defaultCultureName))
                {
                    var defaultCulture = CultureInfo.GetCultureInfo(defaultCultureName);

                    if (SetupInfo.EnabledCultures.Find(culture => String.Equals(culture.Name, defaultCulture.Name, StringComparison.InvariantCultureIgnoreCase)) != null)
                    {
                        var tenant = CoreContext.TenantManager.GetCurrentTenant();
                        tenant.Language = defaultCulture.Name;
                        CoreContext.TenantManager.SaveTenant(tenant);
                    }
                }

                var logoImages = partnerdataStorage.ListFiles(String.Empty, LogoPattern, false);

                if (!logoImages.Any())
                {
                    MakeLogoFiles(partnerdataStorage, jsonObject);
                }

                if (!firstVisit) return;

                var tenantInfoSettings = TenantInfoSettings.Load();
                tenantInfoSettings.RestoreDefaultTenantName();
            }
            catch (Exception e)
            {
                Log.Error(e.Message, e);
            }
        }

        private static void SaveSettings<T>(JObject jsonObject, string prop) where T : class, ISettings
        {
            var jsonObjectToken = jsonObject[prop];

            if (jsonObjectToken == null) return;

            var settings = JsonConvert.DeserializeObject<T>(jsonObjectToken.ToString()) as BaseSettings<T>;

            if (settings == null) return;

            settings.SaveForDefaultTenant();
        }

        private static void MakeLogoFiles(IDataStore store, JObject jObject)
        {
            var settings = jObject["WhiteLabelLogos"];

            if (settings == null) return;

            var propNames = new[]
                {
                    "LogoDarkGeneral",
                    "LogoDark",
                    "LogoDocseditorGeneral",
                    "LogoDocseditor",
                    "LogoFaviconGeneral",
                    "LogoFavicon",
                    "LogoLightSmallGeneral",
                    "LogoLightSmall"
                };

            foreach (var prop in propNames)
            {
                MakeLogoFile(store, prop, settings[prop].ToString());
            }
        }

        private static void MakeLogoFile(IDataStore store, String prop, String value)
        {
            if (String.IsNullOrEmpty(value)) return;

            var fileName = prop.Replace("Logo", "logo_").Replace("General", "_general").ToLower() + PngExt;

            Uri validUri;
            var isValidUri = Uri.TryCreate(value, UriKind.Absolute, out validUri) && (validUri.Scheme == Uri.UriSchemeHttp || validUri.Scheme == Uri.UriSchemeHttps);

            if (isValidUri)
            {
                var request = WebRequest.Create(validUri);

                using (var response = request.GetResponse())
                using (var stream = response.GetResponseStream())
                {
                    store.Save(fileName, stream);
                }
            }
            else
            {
                if (!value.StartsWith(Base64StartPng)) return;

                var bytes = Convert.FromBase64String(value.Substring(Base64StartPng.Length));

                using (var stream = new MemoryStream(bytes))
                {
                    store.Save(fileName, stream);
                }
            }
        }
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Stack/SIP_ResponseReceivedEventArgs.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Stack
{
    #region usings

    using System;

    #endregion

    /// <summary>
    /// This class provides data for ResponseReceived events.
    /// </summary>
    public class SIP_ResponseReceivedEventArgs : EventArgs
    {
        #region Members

        private readonly SIP_Response m_pResponse;
        private readonly SIP_Stack m_pStack;
        private readonly SIP_ClientTransaction m_pTransaction;

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stack">Reference to SIP stack.</param>
        /// <param name="transaction">Client transaction what response it is. This value can be null if no matching client response.</param>
        /// <param name="response">Received response.</param>
        internal SIP_ResponseReceivedEventArgs(SIP_Stack stack,
                                               SIP_ClientTransaction transaction,
                                               SIP_Response response)
        {
            m_pStack = stack;
            m_pResponse = response;
            m_pTransaction = transaction;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets client transaction which response it is. This value is null if no matching client transaction.
        /// If this core is staless proxy then it's allowed, otherwise core MUST discard that response.
        /// </summary>
        public SIP_ClientTransaction ClientTransaction
        {
            get { return m_pTransaction; }
        }

        /// <summary>
        /// Gets SIP dialog where Response belongs to. Returns null if Response doesn't belong any dialog.
        /// </summary>
        public SIP_Dialog Dialog
        {
            get { return m_pStack.TransactionLayer.MatchDialog(m_pResponse); }
        }

        /// <summary>
        /// Gets response received by SIP stack.
        /// </summary>
        public SIP_Response Response
        {
            get { return m_pResponse; }
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/BackupFileInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Xml.Linq;

using ASC.Data.Backup.Extensions;

namespace ASC.Data.Backup.Tasks
{
    public class BackupFileInfo
    {
        public string Domain { get; set; }
        public string Module { get; set; }
        public string Path { get; set; }
        public int Tenant { get; set; }

        public BackupFileInfo()
        {
        }

        public BackupFileInfo(string domain, string module, string path, int tenant = -1)
        {
            Domain = domain;
            Module = module;
            Path = path;
            Tenant = tenant;
        }

        public XElement ToXElement()
        {
            var xElement = new XElement("file",
                                new XElement("domain", Domain),
                                new XElement("module", Module),
                                new XElement("path", Path));

            if (Tenant != -1)
            {
                xElement.Add(new XElement("tenant", Tenant));
            }

            return xElement;
        }

        public static BackupFileInfo FromXElement(XElement el)
        {
            return new BackupFileInfo
            {
                Domain = el.Element("domain").ValueOrDefault(),
                Module = el.Element("module").ValueOrDefault(),
                Path = el.Element("path").ValueOrDefault(),
                Tenant = Convert.ToInt32(el.Element("tenant").ValueOrDefault() ?? "-1")
            };
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/administration/error.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


window.administrationError = (function() {

    function getErrorHandler(header) {
        return function(e, error) {
            showErrorToastr(header, error);
        };
    }

    function showErrorToastr(header, error) {
        if (!error) {
            return;
        }

        var text;
        if (error.length > 1) {
            text = getErrorText(header, error);
        } else {
            text = error[0];
        }

        window.toastr.error(text);
    }

    function getErrorText(header, error) {
        if (!error || !error.length || error.length == 1) {
            return null;
        }

        switch (error[1].hresult) {
            case ASC.Mail.Constants.Errors.COR_E_SECURITY:
                return error[1].message === "Not available in unpaid version"
                    ? MailApiErrorsResource.ErrorUnpaidAccessDenied
                    : MailApiErrorsResource.ErrorAccessDenied;
            case ASC.Mail.Constants.Errors.COR_E_ARGUMENT:
                return argumentExceptionProcessing(header);
            case ASC.Mail.Constants.Errors.COR_E_ARGUMENTOUTOFRANGE:
                return argumentOutOfRangeProcessing(header);
            case ASC.Mail.Constants.Errors.COR_E_INVALIDDATA:
                return invalidDataProcessing(header);
            case ASC.Mail.Constants.Errors.COR_E_DUPLICATENANE:
                return duplicateNameProcessing(header);
            case ASC.Mail.Constants.Errors.COR_E_INVALIDOPERATION:
                return invalidOperationProcessing(header);
            default:
                return MailApiErrorsResource.ErrorInternalServer;
        }
    }

    function invalidDataProcessing(header) {
        var text;
        switch (header) {
            case "addMailDomain":
                text = MailApiErrorsResource.ErrorDkimPublicKeyInUse;
                break;
            case "addMailbox":
                text = MailApiErrorsResource.ErrorUnknownUser;
                break;
            default:
                text = MailApiErrorsResource.ErrorInternalServer;
        }
        return text;
    }

    function invalidOperationProcessing(header) {
        var text;
        switch (header) {
            case "createMailGroup":
            case "addMailboxAlias":
                text = MailApiErrorsResource.InvalidOpearationForSharedDomain;
                break;
            case "addMailDomain":
                text = MailAdministrationResource.DomainWizardDomainNotVerified.format(window.createDomainModal.getCurrentDomainName());
                break;
            default:
                text = MailApiErrorsResource.ErrorInternalServer;
        }
        return text;
    }

    function duplicateNameProcessing(header) {
        var text;
        switch (header) {
            case "addMailDomain":
                text = MailApiErrorsResource.ErrorDuplicateDomain;
                break;
            case "updateMailbox":
                text = MailApiErrorsResource.ErrorDuplicateAlias;
                break;
            case "addMailbox":
                text = MailApiErrorsResource.ErrorDuplicateMailbox;
                break;
            case "updateMailgroup":
                text = MailApiErrorsResource.ErrorDuplicateMailGroupAddress;
                break;
            case "addMailGroup":
                text = MailApiErrorsResource.ErrorDuplicateGroup;
                break;
            default:
                text = MailApiErrorsResource.ErrorInternalServer;
        }
        return text;
    }

    function argumentOutOfRangeProcessing(header) {
        var text;
        switch (header) {
            case "addMailbox":
                text = MailApiErrorsResource.ErrorMailboxLimit;
                break;
            default:
                text = MailApiErrorsResource.ErrorInternalServer;
        }
        return text;
    }

    function argumentExceptionProcessing(header) {
        var text;
        switch (header) {
            case "addMailDomain":
            case "checkDomainExistance":
            case "checkDomainOwnership":
                text = MailApiErrorsResource.ErrorInvalidDomain;
                break;
            case "addMailbox":
                text = MailApiErrorsResource.ErrorInvalidMailbox;
                break;
            case "updateMailbox":
                text = MailApiErrorsResource.ErrorInvalidAlias;
                break;
            case "updateMailgroup":
                text = MailApiErrorsResource.ErrorInvalidAddress;
                break;
            case "addMailGroup":
                text = MailApiErrorsResource.ErrorInvalidMailGroup;
                break;
            default:
                text = MailApiErrorsResource.ErrorInternalServer;
        }
        return text;
    }

    return {
        getErrorHandler: getErrorHandler,
        getErrorText: getErrorText,
        showErrorToastr: showErrorToastr
    };
})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Master/Community.Master.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;
using System.Web.UI;

using ASC.Web.Community.Controls;

namespace ASC.Web.Community
{
    public partial class CommunityMasterPage : MasterPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //Page.RegisterStyleControl(LoadControl(VirtualPathUtility.ToAbsolute("~/Products/Community/Master/Styles.ascx")));
            Page.RegisterBodyScripts(ResolveUrl, "~/Products/Community/js/common.js");

            CommunityCreateButtonContent.Controls.Add(LoadControl(ButtonSidePanel.Location));
            _sideNavigation.Controls.Add(LoadControl(NavigationSidePanel.Location));

            Master.AddClientScript(
                new ClientScripts.ClientLocalizationResources(),
                new ClientScripts.ClientTemplateResources());
        }

        //protected string GetFileStaticRelativePath(String fileName)
        //{
        //    if (fileName.EndsWith(".js"))
        //    {
        //        return ResolveUrl("~/Products/Community/js/" + fileName);
        //    }
        //    if (fileName.EndsWith(".ascx"))
        //    {
        //        return VirtualPathUtility.ToAbsolute("~/Products/Community/Controls/" + fileName);
        //    }
        //    if (fileName.EndsWith(".css"))
        //    {
        //        return ResolveUrl("~/Products/Community/App_Themes/default/" + fileName);
        //    }
        //    if (fileName.EndsWith(".png") || fileName.EndsWith(".gif") || fileName.EndsWith(".jpg"))
        //    {
        //        return WebPath.GetPath("/Products/Community/App_Themes/default/images/" + fileName);
        //    }
        //    return fileName;
        //}
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/calendar/UserControls/js/calendar_event_page.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function (jq) {

    var instances = [];

    function getInstance(obj) {
        var instance = null;

        jq.each(instances, function (index, item) {
            if (obj.is(item.input)) {
                instance = item;
                return false;
            }
            return true;
        });

        return instance;
    }

    function removeInstance(obj) {
        jq.each(instances, function (index, item) {
            if (obj.is(item.obj)) {
                instances.splice(index, 1);
                return false;
            }
            return true;
        });
    }

    function attendeesSelector(obj, options) {
        var self = this;

        this.input = obj;
        this.settings = options || {};
        this.container = options.container;
        this.organizer = options.organizer;
        this.cache = [];
        this.firstFailTerm = "";
        this.canEdit = true;

        this.Statuses = ["NEEDS-ACTION", "ACCEPTED", "DECLINED", "TENTATIVE"];
        
        this.Roles = ["REQ-PARTICIPANT", "OPT-PARTICIPANT"];

        this.convertAddressToAttendee = function (item) {
            var attendee = new ICAL.Property("attendee");
            
            attendee.setParameter("cutype", "INDIVIDUAL");
            attendee.setParameter("role", item.role || self.Roles[0]);
            attendee.setParameter("partstat", item.partstat || self.Statuses[0]);
            attendee.setParameter("rsvp", "TRUE");
            
            if (item.organizer)
                attendee.setParameter("x-organizer", "TRUE");

            if (item.name)
                attendee.setParameter("cn", item.name);

            attendee.setValue("mailto:" + item.email);

            return attendee.jCal;
        };

        this.parseEmails = function (value) {
            if (!value) return [];

            var attendees = [];

            if (typeof value === "string") {
                var addresses = ASC.Mail.Utility.ParseAddresses(value).addresses;
                jq.each(addresses, function (index, item) {
                    if (item.isValid) {
                        attendees.push(self.convertAddressToAttendee(item));
                    }
                });
            }

            if (jq.isArray(value))
                attendees = value;

            var result = [];

            jq.each(attendees, function (index, item) {
                if (typeof item === "object")
                    result.push(item);

                if (typeof item === "string")
                    result = result.concat(self.parseEmails(item));
            });

            return result;
        };

        this.addItem = function (value, insertOrganizer) {

            var hasValue = jq.isArray(value) ? value.length : value;

            var parsedItems = self.parseEmails(value);

            if (!parsedItems.length) {
                if (hasValue)
                    self.input.css("border-color", "#cc3300");
                else
                    self.input.css("border-color", "");
                return;
            } else {
                self.input.css("border-color", "");
            }

            var selectedEmails = jq.map(self.getItems(), function (selectedItem) {
                return selectedItem[3];
            });

            insertOrganizer = !selectedEmails.length && insertOrganizer;

            if (insertOrganizer) {
                var selectedAccountObj = self.organizer.find("option:selected");
                var selectedAccount = selectedAccountObj.length ? { email: selectedAccountObj.attr("value"), name: Encoder.htmlDecode(selectedAccountObj.attr("data-name")) } : ASC.Mail.DefaultAccount;

                var organizer = self.convertAddressToAttendee({
                    email: selectedAccount.email,
                    name: selectedAccount.name,
                    partstat: self.Statuses[1],
                    organizer: true
                });
                parsedItems.unshift(organizer);
            }

            jq.each(parsedItems, function (index, item) {
                if (!item) return;

                if (jq.inArray(item[3], selectedEmails) < 0) {
                    var data = {
                        canEdit: self.canEdit,
                        status: item[1].partstat,
                        email: item[3].replace(new RegExp("mailto:", "ig"), ""),
                        name: item[1].cn || "",
                        role: item[1].role || self.Roles[0]
                    };
                    jq("#attendeeTemplate").tmpl(data).data("item-data", item).appendTo(self.container);
                    self.container.removeClass("display-none");
                    self.container.find(".attendee-item:last .action select").val(data.role).tlcombobox();
                    selectedEmails.push(item[3]);
                    self.input.val("");
                }
            });
            
            self.resizeList();
        };

        this.getItems = function () {
            var items = [];
            
            jq.each(self.container.find(".attendee-item"), function (index, item) {
                items.push(jq(item).data("item-data"));
            });
            
            return items;
        };

        this.clearItems = function () {
            self.container.find(".attendee-item").remove();
            self.resizeList();
        };

        this.updateItemStatus = function(select) {
            var parent = select.parents(".attendee-item");
            var data = parent.data("item-data");
            data[1].role = select.val();
            parent.data("item-data", data);
        };

        this.removeItem = function (deleteBtn) {
            deleteBtn.parents(".attendee-item").remove();
            self.resizeList();
        };

        this.setBindings = function () {
            self.input.on("keyup", function (e) {
                if (e.keyCode == 13) {
                    self.addItem(jq(this).val().trim(), true);
                }
            });
            
            self.input.parents(".input-container").find(".button").on("click", function () {
                if (!jq(this).hasClass("disable"))
                    self.addItem(self.input.val().trim(), true);
            });

            self.container.on("click", ".removeItem", function () {
                self.removeItem(jq(this));
            });

            self.container.on("change", ".action select", function () {
                self.updateItemStatus(jq(this));
            });

            self.container.on("click", ".combobox-title", function () {
                if (jq(this).closest(".sharingItem").is(".attendees-user-list .sharingItem:gt(-3)")) {
                    self.container.scrollTo(jq(".sharingItem:has(.combobox-container:visible)"));
                }
            });
        };

        this.initAutocomplete = function () {

            self.input.autocomplete({
                minLength: 2,
                delay: 300,

                select: function (event, ui) {
                    self.addItem([ui.item], true);
                    return false;
                },

                search: function () {
                    return self.input.is(":visible");
                },

                source: function (request, response) {
                    if (self.settings.isInPopup) {
                        var ul = this.menu.element;
                        var popupParent = self.input.parents(".blockUI.blockPage:first");

                        if (popupParent.length != 0) {
                            if (popupParent.css("position") == "fixed") {
                                ul.css("position", "fixed");
                            } else {
                                ul.css("position", "absolute");
                            }
                        }
                    }

                    if (request.term in self.cache) {
                        var cachedItems = self.cache[request.term];
                        return response(cachedItems);
                    }

                    if (!request.term) {
                        self.firstFailTerm = "";
                        return response([]);
                    }

                    if (self.firstFailTerm) {
                        if (request.term.indexOf(self.firstFailTerm) === 0) {
                            return response([]);
                        } else
                            self.firstFailTerm = "";
                    }
                    
                    Teamlab.searchEmails({}, { term: request.term }, {
                        before: function() {
                            ASC.CalendarController.Search = true;
                        },
                        success: function (params, contacts) {
                            if (!contacts || contacts.length === 0) {
                                self.firstFailTerm = request.term;
                                return response([]);
                            }
                            
                            var items = self.parseEmails(contacts);
                            self.cache[request.term] = items;
                            return response(items);
                        },
                        error: function (params, error) {
                            console.log(error);
                        },
                        after: function () {
                            ASC.CalendarController.Search = false;
                        },
                    });
                },
                create: function() {
                    jq(window).resize(function () {
                        self.closeSelector();
                    });
                },
                focus: function() {
                    return false;
                }
            });

            self.input.data("ui-autocomplete")._renderMenu = function (ul, items) {
                var target = this;

                jq.each(items, function (index, item) {
                    target._renderItemData(ul, item);
                });

                if (self.settings.isInPopup && jq.browser.mobile && ul.parents(".blockUI.blockPage:first").length == 0) {
                    var popupParent = self.input.parents(".blockUI.blockPage:first");
                    if (popupParent.length != 0) {
                        ul.appendTo(popupParent.children());
                    }
                }
            };

            self.input.data("ui-autocomplete")._renderItem = function (ul, item) {
                var data = { email: item[3].replace(new RegExp("mailto:", "ig"), ""), name: item[1].cn || "" };
                return jq("#attendeeTemplateAutocomplete").tmpl(data).appendTo(ul);
            };

            self.input.data("ui-autocomplete")._resizeMenu = function () {
                this.menu.element.outerWidth(self.input.outerWidth());
            };

            self.input.data("ui-autocomplete")._suggest = function (items) {
                var ul = this.menu.element.empty().zIndex(100500);
                this._renderMenu(ul, items);
                this.menu.refresh();
                ul.show();
                this._resizeMenu();
                ul.position(jq.extend({ of: this.element }, this.options.position));
            };
        };

        this.init = function () {
            self.setBindings();
            self.initAutocomplete();
            self.clearItems();
            self.addItem(self.settings.items);
        };

        this.setItems = function (items, canEdit) {
            self.clearItems();
            self.canEdit = canEdit == undefined ? true : canEdit;
            self.addItem(items);
            
            if (self.canEdit) {
                self.input.removeAttr("disabled").parents(".input-container").removeClass("display-none").find(".button").removeClass("disable");
            } else {
                self.input.attr("disabled", true).parents(".input-container").addClass("display-none").find(".button").addClass("disable");
            }
            
            if (items.length){
                self.container.removeClass("display-none");
            } else {
                self.container.addClass("display-none");
            }
        };

        this.closeSelector = function() {
            var uiAutocomplete = self.input.data("ui-autocomplete");
            if (uiAutocomplete) {
                uiAutocomplete.close();
            }
        };

        this.resizeList = function() {
            var itemsCount = self.container.find(".sharingItem").length;

            if (itemsCount) {
                self.container.removeClass("display-none");
            } else {
                self.container.addClass("display-none");
            }

            if (itemsCount > 7) {
                self.container.addClass("scrollable");
            } else {
                self.container.removeClass("scrollable");
            }
        };
    }

    var methods = {
        init: function (options) {
            var obj = jq(this);
            removeInstance(obj);
            var instance = new attendeesSelector(obj, options);
            instances.push(instance);
            instance.init();
            return this;
        },
        get: function () {
            var obj = jq(this);
            var instance = getInstance(obj);
            return instance ? instance.getItems() : null;
        },
        set: function (data, canEdit) {
            var obj = jq(this);
            var instance = getInstance(obj);
            if (instance) {
                instance.setItems(data, canEdit);
            }
        }
    };

    jq.fn.AttendeesSelector = function (method) {

        if (this.length && methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        }

        return this;
    };

})(jQuery);


(function (jq) {

    var instances = [];

    function getInstance(obj) {
        var instance = null;

        jq.each(instances, function (index, item) {
            if (obj.is(item.selector)) {
                instance = item;
                return false;
            }
            return true;
        });

        return instance;
    }

    function removeInstance(obj) {
        jq.each(instances, function (index, item) {
            if (obj.is(item.obj)) {
                instances.splice(index, 1);
                return false;
            }
            return true;
        });
    }

    function shareUsersSelector(obj, options) {
        var self = this;

        this.selector = obj;
        this.permissions = options.permissions;
        this.container = options.container;
        this.canEdit = true;

        this.removeItem = function (itemId) {
            for (var i = 0; i < self.permissions.data.items.length; i++) {
                if (self.permissions.data.items[i].id == itemId) {
                    if (self.permissions.data.items[i].canEdit === false || self.permissions.data.items[i].hideRemove) {
                        return false;
                    }
                    
                    if (!self.permissions.data.items[i].isGroup) {
                        self.selector.useradvancedSelector("unselect", [itemId]);
                    }
                    
                    self.permissions.data.items.splice(i, 1);
                    break;
                }
            }

            self.container.find("#sharing_event_item_" + itemId).remove();

            self.resizeList();

            return true;
        };

        this.addUsers = function (e, users) { 
            var selectedIds = jq(users).map(function (index, user) {
                return user.id;
            }).toArray();

            for (var i = 0; i < self.permissions.data.items.length; i++) {
                var item = self.permissions.data.items[i];
                if (!item.isGroup) {
                    var num = jq.inArray(item.id, selectedIds);
                    if (num == -1) {
                        if (self.removeItem(item.id)) {
                            i--;
                        }
                    } else {
                        selectedIds.splice(num, 1);
                    }
                }
            }

            jq(users).each(function (j, user) {
                if (jq.inArray(user.id, selectedIds) != -1) {
                    self.addUserItem(user.id, user.title);
                }
            });
        };

        this.addUserItem = function (userId, userName) {
            var defAct = null;

            for (var i = 0; i < self.permissions.data.actions.length; i++) {
                if (self.permissions.data.actions[i].defaultAction) {
                    defAct = self.permissions.data.actions[i];
                    break;
                }
            }
            
            var newItem = { id: userId, name: userName, selectedAction: defAct, isGroup: false, canEdit: self.canEdit };

            self.permissions.data.items.push(newItem);

            jq("#sharingUserTemplate").tmpl({ items: [newItem], actions: self.permissions.data.actions }).appendTo(self.container);

            self.container.find(".action:last select").tlcombobox();

            self.resizeList();
        };

        this.getItems = function () {
            var permissions = new Array();
            for (var i = 0; i < self.permissions.data.items.length; i++) {
                var item = self.permissions.data.items[i];
                if (item.selectedAction.id == 'owner')
                    continue;

                permissions.push({ objectId: item.id, name: item.name });
            }
            
            return { users: permissions, data: self.permissions.data };
        };

        this.renderContainer = function () {
            self.container.empty();

            jq("#sharingUserTemplate").tmpl(self.permissions.data).appendTo(self.container);

            self.container.find(".action select").each(function () {
                jq(this).tlcombobox();
            });

            self.resizeList();

            self.selector.useradvancedSelector("reset");

            var userIds = new Array();
            var disableUserIds = new Array();
            
            for (var i = 0; i < self.permissions.data.items.length; i++) {
                var item = self.permissions.data.items[i];
                if (!item.isGroup) {
                    userIds.push(item.id);
                    if (item.hideRemove || !item.canEdit) {
                        disableUserIds.push(item.id);
                    }
                }
            }
            
            self.selector.useradvancedSelector("select", userIds);
            self.selector.useradvancedSelector("disable", disableUserIds);
        };

        this.changeItemAction = function (itemId, actionId) {
            var act = null;

            for (var i = 0; i < self.permissions.data.actions.length; i++) {
                if (self.permissions.data.actions[i].id == actionId) {
                    act = self.permissions.data.actions[i];
                    break;
                }
            }

            for (i = 0; i < self.permissions.data.items.length; i++) {
                if (self.permissions.data.items[i].id == itemId) {
                    self.permissions.data.items[i].selectedAction = act;
                    break;
                }
            }
        };

        this.setBindings = function () {

            self.container.on("click", ".removeItem", function () {
                self.removeItem(jq(this).attr("data"));
            });

            self.container.on("change", ".action select", function () {
                self.changeItemAction(jq(this).attr("data"), jq(this).val());
            });

            self.container.on("click", ".combobox-title", function () {
                if (jq(this).closest(".sharingItem").is(".shared-user-list .sharingItem:gt(-3)")) {
                    self.container.scrollTo(jq(".sharingItem:has(.combobox-container:visible)"));
                }
            });

            self.selector
                .useradvancedSelector(
                    {
                        showGroups: true
                    })
                .on("showList", self.addUsers);
        };

        this.init = function () {
            self.setBindings();
            self.renderContainer();
        };

        this.resizeList = function () {
            var itemsCount = self.container.find(".sharingItem").length;

            if (itemsCount) {
                self.container.removeClass("display-none");
            } else {
                self.container.addClass("display-none");
            }

            if (itemsCount > 7) {
                self.container.addClass("scrollable");
            } else {
                self.container.removeClass("scrollable");
            }
        };
    }

    var methods = {
        init: function (options) {
            var obj = jq(this);
            removeInstance(obj);
            var instance = new shareUsersSelector(obj, options);
            instances.push(instance);
            instance.init();
            return this;
        },
        get: function () {
            var obj = jq(this);
            var instance = getInstance(obj);
            return instance ? instance.getItems() : null;
        },
        set: function (data, canEdit) {
            var obj = jq(this);
            var instance = getInstance(obj);
            if (instance) {
                instance.permissions = data;
                instance.canEdit = canEdit == undefined ? true : canEdit;
                instance.renderContainer();
            }
        }
    };

    jq.fn.ShareUsersSelector = function (method) {

        if (this.length && methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        }

        return this;
    };

})(jQuery);

<|start_filename|>web/studio/ASC.Web.Studio/addons/calendar/Notification/CalendarSubscriptionManager.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Api.Calendar.Notification;
using ASC.Web.Core.Subscriptions;

namespace ASC.Web.Calendar.Notification
{
    public class CalendarSubscriptionManager : IProductSubscriptionManager
    {
        public SubscriptionType CalendarSharingSubscription
        {
            get
            {
                return new SubscriptionType
                {
                    ID = new Guid("{1CE43C40-72F4-4265-A4C6-8B55E29DB447}"),
                    Name = Resources.CalendarAddonResource.CalendarSharingSubscription,
                    NotifyAction = CalendarNotifySource.CalendarSharing,
                    Single = true,
                    CanSubscribe = true
                };
            }
        }

        public SubscriptionType EventAlertSubscription
        {
            get
            {
                return new SubscriptionType
                {
                    ID = new Guid("{862D17FE-7119-4aa0-B1AA-E3C23097CB69}"),
                    Name = Resources.CalendarAddonResource.EventAlertSubscription,
                    NotifyAction = CalendarNotifySource.EventAlert,
                    Single = true,
                    CanSubscribe = true
                };
            }
        }

        #region ISubscriptionManager Members

        public List<SubscriptionObject> GetSubscriptionObjects(Guid subItem)
        {
            return new List<SubscriptionObject>();
        }

        public List<SubscriptionType> GetSubscriptionTypes()
        {
            return new List<SubscriptionType> { CalendarSharingSubscription, EventAlertSubscription };
        }

        public Notify.Model.ISubscriptionProvider SubscriptionProvider
        {
            get { return CalendarNotifySource.Instance.GetSubscriptionProvider(); }
        }

        #endregion

        #region IProductSubscriptionManager Members

        public List<SubscriptionGroup> GetSubscriptionGroups()
        {
            return new List<SubscriptionGroup>();
        }

        public GroupByType GroupByType
        {
            get { return GroupByType.Simple; }
        }

        #endregion
    }
}


<|start_filename|>module/ASC.Files.Thirdparty/Sharpbox/SharpBoxDaoBase.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;

using AppLimit.CloudComputing.SharpBox;
using AppLimit.CloudComputing.SharpBox.Exceptions;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Files.Core;
using ASC.Files.Core.Security;
using ASC.Security.Cryptography;
using ASC.Web.Files.Classes;

namespace ASC.Files.Thirdparty.Sharpbox
{
    internal abstract class SharpBoxDaoBase : IDisposable
    {
        protected class ErrorEntry : ICloudDirectoryEntry
        {
            public ErrorEntry(Exception e, object id)
            {
                if (e != null) Error = e.Message;

                Id = String.IsNullOrEmpty((id ?? "").ToString()) ? "/" : (id ?? "").ToString();
            }

            public string Error { get; set; }

            public string Name
            {
                get { return "/"; }
            }

            public string Id { get; private set; }

            public long Length
            {
                get { return 0; }
            }

            public DateTime Modified
            {
                get { return DateTime.UtcNow; }
            }

            public string ParentID
            {
                get { return ""; }
                set { }
            }

            public ICloudDirectoryEntry Parent
            {
                get { return null; }
                set { }
            }

            public ICloudFileDataTransfer GetDataTransferAccessor()
            {
                return null;
            }

            public string GetPropertyValue(string key)
            {
                return null;
            }

            private readonly List<ICloudFileSystemEntry> _entries = new List<ICloudFileSystemEntry>(0);

            public IEnumerator<ICloudFileSystemEntry> GetEnumerator()
            {
                return _entries.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            public ICloudFileSystemEntry GetChild(string name)
            {
                return null;
            }

            public ICloudFileSystemEntry GetChild(string name, bool bThrowException)
            {
                if (bThrowException) throw new ArgumentNullException(name);
                return null;
            }

            public ICloudFileSystemEntry GetChild(string idOrName, bool bThrowException, bool firstByNameIfNotFound)
            {
                if (bThrowException) throw new ArgumentNullException(idOrName);
                return null;
            }

            public ICloudFileSystemEntry GetChild(int idx)
            {
                return null;
            }

            public int Count
            {
                get { return 0; }
            }

            public nChildState HasChildrens
            {
                get { return nChildState.HasNoChilds; }
            }
        }

        public int TenantID { get; private set; }

        protected SharpBoxDaoBase(SharpBoxDaoSelector.SharpBoxInfo sharpBoxInfo, SharpBoxDaoSelector sharpBoxDaoSelector)
        {
            SharpBoxProviderInfo = sharpBoxInfo.SharpBoxProviderInfo;
            PathPrefix = sharpBoxInfo.PathPrefix;
            SharpBoxDaoSelector = sharpBoxDaoSelector;
            TenantID = CoreContext.TenantManager.GetCurrentTenant().TenantId;
        }

        public void Dispose()
        {
            SharpBoxProviderInfo.Dispose();
        }

        protected DbManager GetDb()
        {
            return new DbManager(FileConstant.DatabaseId);
        }

        protected object MappingID(object id, bool saveIfNotExist)
        {
            if (id == null) return null;
            int n;

            var isNumeric = int.TryParse(id.ToString(), out n);

            if (isNumeric) return n;

            object result;
            using (var db = GetDb())
            {
                if (id.ToString().StartsWith("sbox"))
                    result = Regex.Replace(BitConverter.ToString(Hasher.Hash(id.ToString(), HashAlg.MD5)), "-", "").ToLower();
                else
                    result = db.ExecuteScalar<String>(Query("files_thirdparty_id_mapping")
                                                                 .Select("id")
                                                                 .Where(Exp.Eq("hash_id", id)));

                if (saveIfNotExist)
                    db.ExecuteNonQuery(Insert("files_thirdparty_id_mapping")
                                                  .InColumnValue("id", id)
                                                  .InColumnValue("hash_id", result));
            }
            return result;
        }

        protected object MappingID(object id)
        {
            return MappingID(id, false);
        }

        protected void UpdatePathInDB(String oldValue, String newValue)
        {
            if (oldValue.Equals(newValue)) return;

            using (var db = GetDb())
            using (var tx = db.BeginTransaction())
            {
                var oldIDs = db.ExecuteList(Query("files_thirdparty_id_mapping")
                                                       .Select("id")
                                                       .Where(Exp.Like("id", oldValue, SqlLike.StartWith)))
                                      .ConvertAll(x => x[0].ToString());

                foreach (var oldID in oldIDs)
                {
                    var oldHashID = MappingID(oldID);
                    var newID = oldID.Replace(oldValue, newValue);
                    var newHashID = MappingID(newID);

                    db.ExecuteNonQuery(Update("files_thirdparty_id_mapping")
                                                  .Set("id", newID)
                                                  .Set("hash_id", newHashID)
                                                  .Where(Exp.Eq("hash_id", oldHashID)));

                    db.ExecuteNonQuery(Update("files_security")
                                                  .Set("entry_id", newHashID)
                                                  .Where(Exp.Eq("entry_id", oldHashID)));

                    db.ExecuteNonQuery(Update("files_tag_link")
                                                  .Set("entry_id", newHashID)
                                                  .Where(Exp.Eq("entry_id", oldHashID)));
                }

                tx.Commit();
            }
        }

        protected readonly SharpBoxDaoSelector SharpBoxDaoSelector;
        public SharpBoxProviderInfo SharpBoxProviderInfo { get; private set; }
        public string PathPrefix { get; private set; }

        protected SqlQuery Query(string table)
        {
            return new SqlQuery(table).Where(GetTenantColumnName(table), TenantID);
        }

        protected SqlDelete Delete(string table)
        {
            return new SqlDelete(table).Where(GetTenantColumnName(table), TenantID);
        }

        protected SqlInsert Insert(string table)
        {
            return new SqlInsert(table, true).InColumns(GetTenantColumnName(table)).Values(TenantID);
        }

        protected SqlUpdate Update(string table)
        {
            return new SqlUpdate(table).Where(GetTenantColumnName(table), TenantID);
        }

        protected string GetTenantColumnName(string table)
        {
            const string tenant = "tenant_id";
            if (!table.Contains(" ")) return tenant;
            return table.Substring(table.IndexOf(" ", StringComparison.InvariantCulture)).Trim() + "." + tenant;
        }

        protected string MakePath(object entryId)
        {
            return string.Format("/{0}", Convert.ToString(entryId, CultureInfo.InvariantCulture).Trim('/'));
        }

        protected string MakeId(ICloudFileSystemEntry entry)
        {
            var path = string.Empty;
            if (entry != null && !(entry is ErrorEntry))
            {
                try
                {
                    path = SharpBoxProviderInfo.Storage.GetFileSystemObjectPath(entry);
                }
                catch (Exception ex)
                {
                    Global.Logger.Error("Sharpbox makeId error", ex);
                }
            }
            else if (entry != null)
            {
                path = entry.Id;
            }

            return string.Format("{0}{1}", PathPrefix, string.IsNullOrEmpty(path) || path == "/" ? "" : ("-" + path.Replace('/', '|')));
        }

        protected String MakeTitle(ICloudFileSystemEntry fsEntry)
        {
            if (fsEntry is ICloudDirectoryEntry && IsRoot(fsEntry as ICloudDirectoryEntry))
            {
                return SharpBoxProviderInfo.CustomerTitle;
            }

            return Global.ReplaceInvalidCharsAndTruncate(fsEntry.Name);
        }

        protected string PathParent(string path)
        {
            if (!string.IsNullOrEmpty(path))
            {
                var index = path.TrimEnd('/').LastIndexOf('/');
                if (index != -1)
                {
                    //Cut to it
                    return path.Substring(0, index);
                }
            }
            return path;
        }

        protected Folder ToFolder(ICloudDirectoryEntry fsEntry)
        {
            if (fsEntry == null) return null;
            if (fsEntry is ErrorEntry)
            {
                //Return error entry
                return ToErrorFolder(fsEntry as ErrorEntry);
            }

            //var childFoldersCount = fsEntry.OfType<ICloudDirectoryEntry>().Count();//NOTE: Removed due to performance isssues
            var isRoot = IsRoot(fsEntry);

            var folder = new Folder
            {
                ID = MakeId(fsEntry),
                ParentFolderID = isRoot ? null : MakeId(fsEntry.Parent),
                CreateBy = SharpBoxProviderInfo.Owner,
                CreateOn = isRoot ? SharpBoxProviderInfo.CreateOn : fsEntry.Modified,
                FolderType = FolderType.DEFAULT,
                ModifiedBy = SharpBoxProviderInfo.Owner,
                ModifiedOn = isRoot ? SharpBoxProviderInfo.CreateOn : fsEntry.Modified,
                ProviderId = SharpBoxProviderInfo.ID,
                ProviderKey = SharpBoxProviderInfo.ProviderKey,
                RootFolderCreator = SharpBoxProviderInfo.Owner,
                RootFolderId = MakeId(RootFolder()),
                RootFolderType = SharpBoxProviderInfo.RootFolderType,

                Shareable = false,
                Title = MakeTitle(fsEntry),
                TotalFiles = 0, /*fsEntry.Count - childFoldersCount NOTE: Removed due to performance isssues*/
                TotalSubFolders = 0, /*childFoldersCount NOTE: Removed due to performance isssues*/
            };

            if (folder.CreateOn != DateTime.MinValue && folder.CreateOn.Kind == DateTimeKind.Utc)
                folder.CreateOn = TenantUtil.DateTimeFromUtc(folder.CreateOn);

            if (folder.ModifiedOn != DateTime.MinValue && folder.ModifiedOn.Kind == DateTimeKind.Utc)
                folder.ModifiedOn = TenantUtil.DateTimeFromUtc(folder.ModifiedOn);

            return folder;
        }

        private static bool IsRoot(ICloudDirectoryEntry entry)
        {
            if (entry != null && entry.Name != null)
                return string.IsNullOrEmpty(entry.Name.Trim('/'));
            return false;
        }

        private File ToErrorFile(ErrorEntry fsEntry)
        {
            if (fsEntry == null) return null;

            return new File
            {
                ID = MakeId(fsEntry),
                CreateBy = SharpBoxProviderInfo.Owner,
                CreateOn = fsEntry.Modified,
                ModifiedBy = SharpBoxProviderInfo.Owner,
                ModifiedOn = fsEntry.Modified,
                ProviderId = SharpBoxProviderInfo.ID,
                ProviderKey = SharpBoxProviderInfo.ProviderKey,
                RootFolderCreator = SharpBoxProviderInfo.Owner,
                RootFolderId = MakeId(null),
                RootFolderType = SharpBoxProviderInfo.RootFolderType,
                Title = MakeTitle(fsEntry),
                Error = fsEntry.Error
            };
        }

        private Folder ToErrorFolder(ErrorEntry fsEntry)
        {
            if (fsEntry == null) return null;

            return new Folder
            {
                ID = MakeId(fsEntry),
                ParentFolderID = null,
                CreateBy = SharpBoxProviderInfo.Owner,
                CreateOn = fsEntry.Modified,
                FolderType = FolderType.DEFAULT,
                ModifiedBy = SharpBoxProviderInfo.Owner,
                ModifiedOn = fsEntry.Modified,
                ProviderId = SharpBoxProviderInfo.ID,
                ProviderKey = SharpBoxProviderInfo.ProviderKey,
                RootFolderCreator = SharpBoxProviderInfo.Owner,
                RootFolderId = MakeId(null),
                RootFolderType = SharpBoxProviderInfo.RootFolderType,
                Shareable = false,
                Title = MakeTitle(fsEntry),
                TotalFiles = 0,
                TotalSubFolders = 0,
                Error = fsEntry.Error
            };
        }

        protected File ToFile(ICloudFileSystemEntry fsEntry)
        {
            if (fsEntry == null) return null;

            if (fsEntry is ErrorEntry)
            {
                //Return error entry
                return ToErrorFile(fsEntry as ErrorEntry);
            }

            return new File
            {
                ID = MakeId(fsEntry),
                Access = FileShare.None,
                ContentLength = fsEntry.Length,
                CreateBy = SharpBoxProviderInfo.Owner,
                CreateOn = fsEntry.Modified.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(fsEntry.Modified) : fsEntry.Modified,
                FileStatus = FileStatus.None,
                FolderID = MakeId(fsEntry.Parent),
                ModifiedBy = SharpBoxProviderInfo.Owner,
                ModifiedOn = fsEntry.Modified.Kind == DateTimeKind.Utc ? TenantUtil.DateTimeFromUtc(fsEntry.Modified) : fsEntry.Modified,
                NativeAccessor = fsEntry,
                ProviderId = SharpBoxProviderInfo.ID,
                ProviderKey = SharpBoxProviderInfo.ProviderKey,
                Title = MakeTitle(fsEntry),
                RootFolderId = MakeId(RootFolder()),
                RootFolderType = SharpBoxProviderInfo.RootFolderType,
                RootFolderCreator = SharpBoxProviderInfo.Owner,
                Shared = false,
                Version = 1
            };
        }

        protected ICloudDirectoryEntry RootFolder()
        {
            return SharpBoxProviderInfo.Storage.GetRoot();
        }

        protected ICloudDirectoryEntry GetFolderById(object folderId)
        {
            try
            {
                var path = MakePath(folderId);
                return path == "/"
                           ? RootFolder()
                           : SharpBoxProviderInfo.Storage.GetFolder(path);
            }
            catch (SharpBoxException sharpBoxException)
            {
                if (sharpBoxException.ErrorCode == SharpBoxErrorCodes.ErrorFileNotFound)
                {
                    return null;
                }
                return new ErrorEntry(sharpBoxException, folderId);
            }
            catch (Exception ex)
            {
                return new ErrorEntry(ex, folderId);
            }
        }

        protected ICloudFileSystemEntry GetFileById(object fileId)
        {
            try
            {
                return SharpBoxProviderInfo.Storage.GetFile(MakePath(fileId), null);
            }
            catch (SharpBoxException sharpBoxException)
            {
                if (sharpBoxException.ErrorCode == SharpBoxErrorCodes.ErrorFileNotFound)
                {
                    return null;
                }
                return new ErrorEntry(sharpBoxException, fileId);
            }
            catch (Exception ex)
            {
                return new ErrorEntry(ex, fileId);
            }
        }

        protected IEnumerable<ICloudFileSystemEntry> GetFolderFiles(object folderId)
        {
            return GetFolderFiles(SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId)));
        }

        protected IEnumerable<ICloudFileSystemEntry> GetFolderSubfolders(object folderId)
        {
            return GetFolderSubfolders(SharpBoxProviderInfo.Storage.GetFolder(MakePath(folderId)));
        }

        protected IEnumerable<ICloudFileSystemEntry> GetFolderFiles(ICloudDirectoryEntry folder)
        {
            return folder.Where(x => !(x is ICloudDirectoryEntry));
        }

        protected IEnumerable<ICloudFileSystemEntry> GetFolderSubfolders(ICloudDirectoryEntry folder)
        {
            return folder.Where(x => (x is ICloudDirectoryEntry));
        }

        protected String GetAvailableTitle(String requestTitle, ICloudDirectoryEntry parentFolder, Func<string, ICloudDirectoryEntry, bool> isExist)
        {
            if (!isExist(requestTitle, parentFolder)) return requestTitle;

            var re = new Regex(@"( \(((?<index>[0-9])+)\)(\.[^\.]*)?)$");
            var match = re.Match(requestTitle);

            if (!match.Success)
            {
                var insertIndex = requestTitle.Length;
                if (requestTitle.LastIndexOf(".", StringComparison.InvariantCulture) != -1)
                {
                    insertIndex = requestTitle.LastIndexOf(".", StringComparison.InvariantCulture);
                }
                requestTitle = requestTitle.Insert(insertIndex, " (1)");
            }

            while (isExist(requestTitle, parentFolder))
            {
                requestTitle = re.Replace(requestTitle, MatchEvaluator);
            }
            return requestTitle;
        }

        private static String MatchEvaluator(Match match)
        {
            var index = Convert.ToInt32(match.Groups[2].Value);
            var staticText = match.Value.Substring(String.Format(" ({0})", index).Length);
            return String.Format(" ({0}){1}", index + 1, staticText);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/addons/mail/js/administration/plugin/jquery-domainadvansedselector.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


(function($) {
    var domainadvancedSelector = function(element, options) {
        this.$element = $(element);
        this.options = $.extend({}, $.fn.domainadvancedSelector.defaults, options);
        this.init();
    };

    domainadvancedSelector.prototype = $.extend({}, $.fn.advancedSelector.Constructor.prototype, {
        constructor: domainadvancedSelector,
        initAdvSelectorData: function() {
            var that = this,
                data = [];

            var domains = this.options.getDomains();
            for (var i = 0, length = domains.length; i < length; i++) {
                data.push({
                    title: domains[i].name,
                    id: domains[i].id
                });
            }
            if (data.length > 0) {
                that.rewriteObjectItem.call(that, data);
            }

            that.$element.unbind('click.onshow').bind('click.onshow', function() {
                that.refrashSelectorData();
            });
        },

        refrashSelectorData: function() {
            var that = this;
            var needRefrash = false;
            var domains = $.map(that.options.getDomains(), function(domain) {
                return {
                    title: domain.name,
                    id: domain.id
                };
            });
            var newItems = that.items.slice();

            for (var i = 0, length = domains.length; i < length; i++) {
                if (!that.getItemById(domains[i].id, that.items)) {
                    newItems.push(domains[i]);
                    needRefrash = true;
                }
            }

            for (i = 0, length = that.items.length; i < length; i++) {
                if (!that.getItemById(that.items[i].id, domains)) {
                    newItems.splice(i, 1);
                    needRefrash = true;
                }
            }

            if (needRefrash) {
                that.items = newItems;
                that.items = that.items.sort(SortData);
                that.$element.data('items', that.items);
                that.showItemsListAdvSelector.call(that);
            }
        },

        rewriteObjectItem: function(data) {
            var that = this;
            that.items = data;
            that.items = that.items.sort(SortData);
            that.$element.data('items', that.items);
            that.showItemsListAdvSelector.call(that);
        },

        getItemById: function(id, itemList) {
            for (var i = 0, len = itemList.length; i < len; i++) {
                if (id == itemList[i].id) {
                    return itemList[i];
                }
            }
            return undefined;
        }
    });

    $.fn.domainadvancedSelector = function(option) {
        var selfargs = Array.prototype.slice.call(arguments, 1);
        return this.each(function() {
            var $this = $(this),
                data = $this.data('domainadvancedSelector'),
                options = $.extend({},
                    $.fn.domainadvancedSelector.defaults,
                    $this.data(),
                    typeof option == 'object' && option);
            if (!data) {
                $this.data('domainadvancedSelector', (data = new domainadvancedSelector(this, options)));
            }
            if (typeof option == 'string') {
                data[option].apply(data, selfargs);
            }
        });
    };

    $.fn.domainadvancedSelector.defaults = $.extend({}, $.fn.advancedSelector.defaults, {});

})(jQuery, window, document, document.body);

<|start_filename|>module/ASC.Api/ASC.Api.Community/Blogs/BlogPostCommentWrapper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Api.Employee;
using ASC.Blogs.Core.Domain;
using ASC.Specific;

namespace ASC.Api.Blogs
{
    [DataContract(Name = "comment", Namespace = "")]
    public class BlogPostCommentWrapper : IApiSortableDate
    {
        public BlogPostCommentWrapper(Comment comment)
        {
            CreatedBy = EmployeeWraper.Get(Core.CoreContext.UserManager.GetUsers(comment.UserID));
            Updated = Created = (ApiDateTime)comment.Datetime;
            Id = comment.ID;
            Text = comment.Content;
            ParentId = comment.ParentId;

        }


        private BlogPostCommentWrapper()
        {

        }

        [DataMember(Order = 10)]
        public string Text { get; set; }

        [DataMember(Order = 6)]
        public ApiDateTime Created { get; set; }

        [DataMember(Order = 6)]
        public ApiDateTime Updated { get; set; }


        [DataMember(Order = 1)]
        public Guid Id { get; set; }

        [DataMember(Order = 9)]
        public EmployeeWraper CreatedBy { get; set; }

        [DataMember(Order = 16)]
        protected Guid ParentId { get; set; }

        public static BlogPostCommentWrapper GetSample()
        {
            return new BlogPostCommentWrapper
            {
                CreatedBy = EmployeeWraper.GetSample(),
                Created = ApiDateTime.GetSample(),
                Id = Guid.Empty,
                ParentId = Guid.Empty,
                Text = "comment text",
                Updated = ApiDateTime.GetSample()
            };
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Message/SIP_t_LanguageTag.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Message
{
    #region usings

    using System;
    using System.Text;

    #endregion

    /// <summary>
    /// Implements SIP "language-tag" value. Defined in RFC 3261.
    /// </summary>
    /// <remarks>
    /// <code>
    /// RFC 3261 Syntax:
    ///     language-tag = primary-tag *( "-" subtag )
    ///     primary-tag  = 1*8ALPHA
    ///     subtag       = 1*8ALPHA
    /// </code>
    /// </remarks>
    public class SIP_t_LanguageTag : SIP_t_ValueWithParams
    {
        #region Members

        private string m_LanguageTag = "";

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets language tag.
        /// </summary>
        public string LanguageTag
        {
            get { return m_LanguageTag; }

            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new ArgumentException("Property LanguageTag value can't be null or empty !");
                }

                m_LanguageTag = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses "language-tag" from specified value.
        /// </summary>
        /// <param name="value">SIP "language-tag" value.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>value</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public void Parse(string value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            Parse(new StringReader(value));
        }

        /// <summary>
        /// Parses "language-tag" from specified reader.
        /// </summary>
        /// <param name="reader">Reader from where to parse.</param>
        /// <exception cref="ArgumentNullException">Raised when <b>reader</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public override void Parse(StringReader reader)
        {
            /* 
                Content-Language =  "Content-Language" HCOLON language-tag *(COMMA language-tag)
                language-tag     =  primary-tag *( "-" subtag )
                primary-tag      =  1*8ALPHA
                subtag           =  1*8ALPHA
            */

            if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            // Parse content-coding
            string word = reader.ReadWord();
            if (word == null)
            {
                throw new SIP_ParseException("Invalid Content-Language value, language-tag value is missing !");
            }
            m_LanguageTag = word;

            // Parse parameters
            ParseParameters(reader);
        }

        /// <summary>
        /// Converts this to valid "language-tag" value.
        /// </summary>
        /// <returns>Returns "language-tag" value.</returns>
        public override string ToStringValue()
        {
            /* 
                Content-Language =  "Content-Language" HCOLON language-tag *(COMMA language-tag)
                language-tag     =  primary-tag *( "-" subtag )
                primary-tag      =  1*8ALPHA
                subtag           =  1*8ALPHA
            */

            StringBuilder retVal = new StringBuilder();
            retVal.Append(m_LanguageTag);
            retVal.Append(ParametersToString());

            return retVal.ToString();
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/DealMilestoneDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#region Import

using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Collections;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.CRM.Core.Entities;
using ASC.Web.CRM.Resources;

#endregion

namespace ASC.CRM.Core.Dao
{
    public class CachedDealMilestoneDao : DealMilestoneDao
    {
        private readonly HttpRequestDictionary<DealMilestone> _dealMilestoneCache =
            new HttpRequestDictionary<DealMilestone>("crm_deal_milestone");

        public CachedDealMilestoneDao(int tenantID)
            : base(tenantID)
        {

        }

        private void ResetCache(int id)
        {
            _dealMilestoneCache.Reset(id.ToString());
        }

        public override int Create(DealMilestone item)
        {
            item.ID = base.Create(item);

            _dealMilestoneCache.Add(item.ID.ToString(), item);

            return item.ID;
        }

        public override void Delete(int id)
        {
            ResetCache(id);

            base.Delete(id);
        }

        public override void Edit(DealMilestone item)
        {
            ResetCache(item.ID);

            base.Edit(item);
        }


        private DealMilestone GetByIDBase(int id)
        {
            return base.GetByID(id);
        }

        public override DealMilestone GetByID(int id)
        {
            return _dealMilestoneCache.Get(id.ToString(), () => GetByIDBase(id));
        }

        public override void Reorder(int[] ids)
        {
            _dealMilestoneCache.Clear();

            base.Reorder(ids);
        }
    }

    public class DealMilestoneDao : AbstractDao
    {

        #region Constructor

        public DealMilestoneDao(int tenantID)
            : base(tenantID)
        {


        }

        #endregion

        public virtual void Reorder(int[] ids)
        {
            using (var tx = Db.BeginTransaction())
            {
                for (int index = 0; index < ids.Length; index++)
                    Db.ExecuteNonQuery(Update("crm_deal_milestone")
                                             .Set("sort_order", index)
                                             .Where(Exp.Eq("id", ids[index])));

                tx.Commit();
            }
        }

        public int GetCount()
        {
            return Db.ExecuteScalar<int>(Query("crm_deal_milestone").SelectCount());
        }


        public Dictionary<int, int> GetRelativeItemsCount()
        {
            var sqlQuery = Query("crm_deal_milestone tbl_deal_milestone")
                          .Select("tbl_deal_milestone.id")
                          .OrderBy("tbl_deal_milestone.sort_order", true)
                          .GroupBy("tbl_deal_milestone.id");

            sqlQuery.LeftOuterJoin("crm_deal tbl_crm_deal",
                                      Exp.EqColumns("tbl_deal_milestone.id", "tbl_crm_deal.deal_milestone_id"))
                .Select("count(tbl_crm_deal.deal_milestone_id)");

            var queryResult = Db.ExecuteList(sqlQuery);
            return queryResult.ToDictionary(x => Convert.ToInt32(x[0]), y => Convert.ToInt32(y[1]));
        }

        public int GetRelativeItemsCount(int id)
        {

            var sqlQuery = Query("crm_deal")
                             .Select("count(*)")
                             .Where(Exp.Eq("deal_milestone_id", id));

            return Db.ExecuteScalar<int>(sqlQuery);
        }

        public virtual int Create(DealMilestone item)
        {

            if (String.IsNullOrEmpty(item.Title) || String.IsNullOrEmpty(item.Color))
                throw new ArgumentException();

            int id;

            using (var tx = Db.BeginTransaction())
            {
                if (item.SortOrder == 0)
                    item.SortOrder = Db.ExecuteScalar<int>(Query("crm_deal_milestone")
                                                            .SelectMax("sort_order")) + 1;

                id = Db.ExecuteScalar<int>(
                                  Insert("crm_deal_milestone")
                                 .InColumnValue("id", 0)
                                 .InColumnValue("title", item.Title)
                                 .InColumnValue("description", item.Description)
                                 .InColumnValue("color", item.Color)
                                 .InColumnValue("probability", item.Probability)
                                 .InColumnValue("status", (int)item.Status)
                                 .InColumnValue("sort_order", item.SortOrder)
                                 .Identity(1, 0, true));
                tx.Commit();
            }

            return id;

        }


        public virtual void ChangeColor(int id, String newColor)
        {
            Db.ExecuteNonQuery(Update("crm_deal_milestone")
                                        .Set("color", newColor)
                                        .Where(Exp.Eq("id", id)));
        }

        public virtual void Edit(DealMilestone item)
        {

            if (HaveContactLink(item.ID))
                throw new ArgumentException(String.Format("{0}. {1}.", CRMErrorsResource.BasicCannotBeEdited, CRMErrorsResource.DealMilestoneHasRelatedDeals));

            Db.ExecuteNonQuery(Update("crm_deal_milestone")
                                    .Set("title", item.Title)
                                    .Set("description", item.Description)
                                    .Set("color", item.Color)
                                    .Set("probability", item.Probability)
                                    .Set("status", (int)item.Status)
                                    .Where(Exp.Eq("id", item.ID)));
        }

        public bool HaveContactLink(int dealMilestoneID)
        {
            SqlQuery sqlQuery = Query("crm_deal")
                                .Where(Exp.Eq("deal_milestone_id", dealMilestoneID))
                                .SelectCount()
                                .SetMaxResults(1);

            return Db.ExecuteScalar<int>(sqlQuery) >= 1;
        }

        public virtual void Delete(int id)
        {
            if (HaveContactLink(id))
                throw new ArgumentException(String.Format("{0}. {1}.", CRMErrorsResource.BasicCannotBeDeleted, CRMErrorsResource.DealMilestoneHasRelatedDeals));

            Db.ExecuteNonQuery(Delete("crm_deal_milestone").Where(Exp.Eq("id", id)));
        }

        public virtual DealMilestone GetByID(int id)
        {
            var dealMilestones = Db.ExecuteList(GetDealMilestoneQuery(Exp.Eq("id", id))).ConvertAll(row => ToDealMilestone(row));

            if (dealMilestones.Count == 0)
                return null;

            return dealMilestones[0];
        }

        public Boolean IsExist(int id)
        {
            return Db.ExecuteScalar<bool>("select exists(select 1 from crm_deal_milestone where tenant_id = @tid and id = @id)",
                new { tid = TenantID, id = id });
        }

        public List<DealMilestone> GetAll(int[] id)
        {
            return Db.ExecuteList(GetDealMilestoneQuery(Exp.In("id", id))).ConvertAll(row => ToDealMilestone(row));
        }

        public List<DealMilestone> GetAll()
        {
            return Db.ExecuteList(GetDealMilestoneQuery(null)).ConvertAll(row => ToDealMilestone(row));
        }

        private SqlQuery GetDealMilestoneQuery(Exp where)
        {
            SqlQuery sqlQuery = Query("crm_deal_milestone")
                .Select("id",
                        "title",
                        "description",
                        "color",
                        "probability",
                        "status",
                        "sort_order")
                        .OrderBy("sort_order", true);

            if (where != null)
                sqlQuery.Where(where);

            return sqlQuery;

        }

        private static DealMilestone ToDealMilestone(object[] row)
        {
            return new DealMilestone
            {
                ID = Convert.ToInt32(row[0]),
                Title = Convert.ToString(row[1]),
                Description = Convert.ToString(row[2]),
                Color = Convert.ToString(row[3]),
                Probability = Convert.ToInt32(row[4]),
                Status = (DealMilestoneStatus)Convert.ToInt32(row[5]),
                SortOrder = Convert.ToInt32(row[6])
            };
        }



    }
}

<|start_filename|>module/ASC.Api/ASC.Api/Impl/ApiArgumentBuilder.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Reflection;
using System.Web;
using System.Web.Routing;
using System.Xml.Linq;

using ASC.Api.Collections;
using ASC.Api.Exceptions;
using ASC.Api.Interfaces;
using ASC.Api.Utils;

using Newtonsoft.Json;

using Binder = ASC.Api.Utils.Binder;

namespace ASC.Api.Impl
{
    public class ApiArgumentBuilder : IApiArgumentBuilder
    {
        public IEnumerable<object> BuildCallingArguments(RequestContext context, IApiMethodCall methodToCall)
        {
            var callArg = new List<object>();
            var requestParams = GetRequestParams(context);

            var methodParams = methodToCall.GetParams().Where(x => !x.IsRetval).OrderBy(x => x.Position);


            foreach (var parameterInfo in methodParams)
            {
                if (requestParams[parameterInfo.Name] != null)
                {
                    //convert
                    var values = requestParams.GetValues(parameterInfo.Name);
                    if (values != null && values.Any())
                    {
                        if (Binder.IsCollection(parameterInfo.ParameterType))
                        {
                            callArg.Add(Binder.Bind(parameterInfo.ParameterType, requestParams, parameterInfo.Name));
                            continue; //Go to next loop
                        }

                        try
                        {
                            callArg.Add(ConvertUtils.GetConverted(values.First(), parameterInfo)); //NOTE; Get first value!
                        }
                        catch (ApiArgumentMismatchException)
                        {
                            //Failed to convert. Try bind
                            callArg.Add(Binder.Bind(parameterInfo.ParameterType, requestParams, parameterInfo.Name));
                        }
                    }
                }
                else
                {
                    //try get request param first. It may be form\url-encoded
                    if (!"GET".Equals(context.HttpContext.Request.HttpMethod, StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrEmpty(context.HttpContext.Request[parameterInfo.Name]))
                    {
                        //Drop to
                        callArg.Add(ConvertUtils.GetConverted(context.HttpContext.Request[parameterInfo.Name], parameterInfo));
                    }
                    else if (parameterInfo.ParameterType == typeof(ContentType) && !string.IsNullOrEmpty(context.HttpContext.Request.ContentType))
                    {
                        callArg.Add(new ContentType(context.HttpContext.Request.ContentType));
                    }
                    else if (parameterInfo.ParameterType == typeof(ContentDisposition) && !string.IsNullOrEmpty(context.HttpContext.Request.Headers["Content-Disposition"]))
                    {
                        var disposition = new ContentDisposition(context.HttpContext.Request.Headers["Content-Disposition"]);
                        disposition.FileName = HttpUtility.UrlDecode(disposition.FileName); //Decode uri name
                        callArg.Add(disposition);
                    }
                    else if (parameterInfo.ParameterType.IsSubclassOf(typeof(HttpPostedFile)) && context.HttpContext.Request.Files[parameterInfo.Name] != null)
                    {
                        callArg.Add(context.HttpContext.Request.Files[parameterInfo.Name]);
                    }
                    else if (Binder.IsCollection(parameterInfo.ParameterType) && parameterInfo.ParameterType.IsGenericType && parameterInfo.ParameterType.GetGenericArguments().First() == typeof(HttpPostedFileBase))
                    {
                        //File catcher
                        var files = new List<HttpPostedFileBase>(context.HttpContext.Request.Files.Count);
                        files.AddRange(from string key in context.HttpContext.Request.Files select context.HttpContext.Request.Files[key]);
                        callArg.Add(files);
                    }
                    else
                    {
                        if (parameterInfo.ParameterType.IsSubclassOf(typeof(Stream)) || parameterInfo.ParameterType == typeof(Stream))
                        {
                            //First try get files
                            var file = context.HttpContext.Request.Files[parameterInfo.Name];
                            callArg.Add(file != null ? file.InputStream : context.HttpContext.Request.InputStream);
                        }
                        else
                        {
                            //Try bind
                            //Note: binding moved here
                            if (IsTypeBindable(parameterInfo.ParameterType))
                            {
                                //Custom type
                                var binded = Binder.Bind(parameterInfo.ParameterType,
                                                         requestParams,
                                                         parameterInfo.Name);

                                if (binded != null)
                                {
                                    callArg.Add(binded);
                                    continue; //Go to next loop
                                }
                            }
                            //Create null
                            var obj = parameterInfo.ParameterType.IsValueType ? Activator.CreateInstance(parameterInfo.ParameterType) : null;
                            callArg.Add(obj);
                        }


                    }
                }
            }
            return callArg;
        }

        private static bool IsTypeBindable(Type parameterInfo)
        {
            if (Binder.IsCollection(parameterInfo))
            {
                return true;
            }
            return parameterInfo.Namespace != null && !parameterInfo.Namespace.StartsWith("System", StringComparison.Ordinal);
        }

        private static NameValueCollection GetRequestParams(RequestContext context)
        {
            var collection = context.RouteData.Values.ToNameValueCollection();
            var request = context.HttpContext.Request;

            if (request == null) return collection;
            collection.Add(request.QueryString);

            var contentType = string.IsNullOrEmpty(request.ContentType) ? new ContentType("text/plain") : new ContentType(request.ContentType);

            switch (contentType.MediaType)
            {
                case Constants.XmlContentType:
                {
                    using (var stream = request.InputStream)
                    {
                        if (stream != null)
                        {
                            using (var reader = new StreamReader(stream))
                            {
                                var root = XDocument.Load(reader).Root;
                                if (root != null)
                                {
                                    FillCollectionFromXElement(root.Elements(), string.Empty, collection);
                                }
                            }
                        }
                    }
                }
                break;
                case Constants.JsonContentType:
                {
                    using (var stream = request.InputStream)
                    {
                        if (stream != null)
                        {
                            using (var reader = new StreamReader(request.InputStream))
                            {
                                var value = reader.ReadToEnd();
                                XDocument xdoc;
                                try
                                {
                                    xdoc = JsonConvert.DeserializeXNode(value, "request", false);
                                }
                                catch (Exception e)
                                {
                                    throw new TargetInvocationException(new ArgumentException("Unable to deserialize json", e));
                                }

                                XElement root;
                                if (xdoc != null && (root = xdoc.Root) != null)
                                {
                                    FillCollectionFromXElement(root.Elements(), string.Empty, collection);
                                }
                            }
                        }
                    }
                }
                break;
                default:
                    if (!"GET".Equals(request.HttpMethod, StringComparison.InvariantCultureIgnoreCase))
                    {
                        var form = request.Form;
                        if (form != null)
                        {
                            collection.Add(request.Form);
                        }
                    }
                    break;
            }
            return collection;
        }

        private static void FillCollectionFromXElement(IEnumerable<XElement> elements, string prefix, NameValueCollection collection)
        {
            foreach (var grouping in elements.GroupBy(x => x.Name))
            {
                if (grouping.Count() < 2)
                {
                    //Single element
                    var element = grouping.SingleOrDefault();
                    if (element != null)
                    {
                        if (!element.HasElements)
                        {
                            //Last one in tree
                            AddElement(prefix, collection, element);
                        }
                        else
                        {
                            FillCollectionFromXElement(element.Elements(), prefix + "." + element.Name.LocalName, collection);
                        }
                    }

                }
                else
                {
                    //Grouping has more than one
                    if (grouping.All(x => !x.HasElements))
                    {
                        //Simple collection
                        foreach (var element in grouping)
                        {
                            AddElement(prefix, collection, element);
                        }
                    }
                    else
                    {
                        var groupList = grouping.ToList();
                        for (var i = 0; i < groupList.Count; i++)
                        {
                            FillCollectionFromXElement(groupList[i].Elements(), prefix + "." + grouping.Key + "[" + i + "]", collection);
                        }
                    }
                }
            }
        }

        private static void AddElement(string prefix, NameValueCollection collection, XElement element)
        {
            if (string.IsNullOrEmpty(prefix))
                collection.Add(element.Name.LocalName, element.Value);
            else
            {
                var prefixes = prefix.TrimStart('.').Split('.');
                var additional = string.Empty;
                if (prefixes.Length > 1)
                {
                    additional = string.Join("", prefix.Skip(1).Select(x => "[" + x + "]").ToArray());
                }
                collection.Add(prefixes[0] + additional + "[" + element.Name.LocalName + "]", element.Value);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Sample/Properties/AssemblyInfo.cs<|end_filename|>
﻿using System.Reflection;
using System.Runtime.InteropServices;

using ASC.Web.Core;
using ASC.Web.Sample.Configuration;


[assembly: AssemblyTitle("ASC.Web.Sample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Ascensio System SIA")]
[assembly: AssemblyProduct("ASC.Web.Sample")]
[assembly: AssemblyCopyright("(c) Ascensio System SIA. All rights reserved")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("3d5900ae-111a-45be-96b3-d9e4606ca793")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Product(typeof(ProductEntryPoint))]


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Common/UserForum/UserForum.ascx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.Web.UI;

using ASC.Web.Core.WhiteLabel;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Common.UserForum
{
    public partial class UserForum : UserControl
    {
        public static string Location
        {
            get { return "~/UserControls/Common/UserForum/UserForum.ascx"; }
        }

        protected String UserForumLink
        {
            get
            {
                var settings = AdditionalWhiteLabelSettings.Instance;

                if (!settings.UserForumEnabled || String.IsNullOrEmpty(settings.UserForumUrl))
                    return null;

                return CommonLinkUtility.GetRegionalUrl(settings.UserForumUrl, CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {

        }
    }
}

<|start_filename|>common/ASC.Core.Common/Users/UserExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

namespace ASC.Core.Users
{
    public static class UserExtensions
    {
        public static bool IsOwner(this UserInfo ui)
        {
            if (ui == null) return false;

            var tenant = CoreContext.TenantManager.GetCurrentTenant();
            return tenant != null && tenant.OwnerId.Equals(ui.ID);
        }

        public static bool IsMe(this UserInfo ui)
        {
            return ui != null && ui.ID == SecurityContext.CurrentAccount.ID;
        }

        public static bool IsAdmin(this UserInfo ui)
        {
            return ui != null && CoreContext.UserManager.IsUserInGroup(ui.ID, Constants.GroupAdmin.ID);
        }

        public static bool IsVisitor(this UserInfo ui)
        {
            return ui != null && CoreContext.UserManager.IsUserInGroup(ui.ID, Constants.GroupVisitor.ID);
        }

        public static bool IsOutsider(this UserInfo ui)
        {
            return IsVisitor(ui) && ui.ID == Constants.OutsideUser.ID;
        }

        public static bool IsLDAP(this UserInfo ui)
        {
            if (ui == null) return false;

            return !string.IsNullOrEmpty(ui.Sid);
        }

        // ReSharper disable once InconsistentNaming
        public static bool IsSSO(this UserInfo ui)
        {
            if (ui == null) return false;

            return !string.IsNullOrEmpty(ui.SsoNameId);
        }

        private const string EXT_MOB_PHONE = "extmobphone";
        private const string MOB_PHONE = "mobphone";
        private const string EXT_MAIL = "extmail";
        private const string MAIL = "mail";

        public static void ConvertExternalContactsToOrdinary(this UserInfo ui)
        {
            var ldapUserContacts = ui.Contacts;

            var newContacts = new List<string>();

            for (int i = 0, m = ldapUserContacts.Count; i < m; i += 2)
            {
                if (i + 1 >= ldapUserContacts.Count)
                    continue;

                var type = ldapUserContacts[i];
                var value = ldapUserContacts[i + 1];

                switch (type)
                {
                    case EXT_MOB_PHONE:
                        newContacts.Add(MOB_PHONE);
                        newContacts.Add(value);
                        break;
                    case EXT_MAIL:
                        newContacts.Add(MAIL);
                        newContacts.Add(value);
                        break;
                    default:
                        newContacts.Add(type);
                        newContacts.Add(value);
                        break;
                }
            }

            ui.Contacts = newContacts;
        }
    }
}


<|start_filename|>common/ASC.Core.Common/BaseCommonLinkUtility.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Common.Logging;

namespace ASC.Core.Common
{
    public static class BaseCommonLinkUtility
    {
        private const string LOCALHOST = "localhost";

        private static UriBuilder _serverRoot;
        private static string _vpath;

        static BaseCommonLinkUtility()
        {
            try
            {
                var uriBuilder = new UriBuilder(Uri.UriSchemeHttp, LOCALHOST);
                if (HttpContext.Current != null && HttpContext.Current.Request != null)
                {
                    var u = HttpContext.Current.Request.GetUrlRewriter();
                    uriBuilder = new UriBuilder(u.Scheme, LOCALHOST, u.Port);
                }
                _serverRoot = uriBuilder;
            }
            catch (Exception error)
            {
                LogManager.GetLogger("ASC.Web").Error(error);
            }
        }

        public static void Initialize(string serverUri, bool localhost = true)
        {
            if (string.IsNullOrEmpty(serverUri))
            {
                throw new ArgumentNullException("serverUri");
            }

            var uri = new Uri(serverUri.Replace('*', 'x').Replace('+', 'x'));
            _serverRoot = new UriBuilder(uri.Scheme, localhost ? LOCALHOST : uri.Host, uri.Port);
            _vpath = "/" + uri.AbsolutePath.Trim('/');
        }

        public static string VirtualRoot
        {
            get { return ToAbsolute("~"); }
        }

        public static string ServerRootPath
        {
            get
            {
                var result = new UriBuilder(_serverRoot.Uri);

                // first, take from current request
                if (HttpContext.Current != null && HttpContext.Current.Request != null)
                {
                    var u = HttpContext.Current.Request.GetUrlRewriter();
                    result = new UriBuilder(u.Scheme, u.Host, u.Port);

                    if (CoreContext.Configuration.Standalone && !result.Uri.IsLoopback)
                    {
                        // save for stanalone
                        _serverRoot.Host = result.Host;
                    }
                }

                if (result.Uri.IsLoopback)
                {
                    // take values from db if localhost or no http context thread
                    var tenant = CoreContext.TenantManager.GetCurrentTenant();
                    result.Host = tenant.TenantDomain;

#if DEBUG
                    // for Visual Studio debug
                    if (tenant.TenantAlias == LOCALHOST)
                    {
                        result.Host = LOCALHOST;
                    }
#endif

                    if (!string.IsNullOrEmpty(tenant.MappedDomain))
                    {
                        var mapped = tenant.MappedDomain.ToLowerInvariant();
                        if (!mapped.Contains(Uri.SchemeDelimiter))
                        {
                            mapped = Uri.UriSchemeHttp + Uri.SchemeDelimiter + mapped;
                        }
                        result = new UriBuilder(mapped);
                    }
                }

                return result.Uri.ToString().TrimEnd('/');
            }
        }

        public static string GetFullAbsolutePath(string virtualPath)
        {
            if (String.IsNullOrEmpty(virtualPath))
                return ServerRootPath;

            if (virtualPath.StartsWith("http://", StringComparison.InvariantCultureIgnoreCase) ||
                virtualPath.StartsWith("mailto:", StringComparison.InvariantCultureIgnoreCase) ||
                virtualPath.StartsWith("javascript:", StringComparison.InvariantCultureIgnoreCase) ||
                virtualPath.StartsWith("https://", StringComparison.InvariantCultureIgnoreCase))
                return virtualPath;

            if (string.IsNullOrEmpty(virtualPath) || virtualPath.StartsWith("/"))
            {
                return ServerRootPath + virtualPath;
            }
            return ServerRootPath + VirtualRoot.TrimEnd('/') + "/" + virtualPath.TrimStart('~', '/');
        }

        public static string ToAbsolute(string virtualPath)
        {
            if (_vpath == null)
            {
                return VirtualPathUtility.ToAbsolute(virtualPath);
            }

            if (string.IsNullOrEmpty(virtualPath) || virtualPath.StartsWith("/"))
            {
                return virtualPath;
            }
            return (_vpath != "/" ? _vpath : string.Empty) + "/" + virtualPath.TrimStart('~', '/');
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Resources/FilesJSResource.Designer.cs<|end_filename|>
﻿//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace ASC.Web.Files.Resources {
    using System;
    
    
    /// <summary>
    ///   A strongly-typed resource class, for looking up localized strings, etc.
    /// </summary>
    // This class was auto-generated by the StronglyTypedResourceBuilder
    // class via a tool like ResGen or Visual Studio.
    // To add or remove a member, edit your .ResX file then rerun ResGen
    // with the /str option, or rebuild your VS project.
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public class FilesJSResource {
        
        private static global::System.Resources.ResourceManager resourceMan;
        
        private static global::System.Globalization.CultureInfo resourceCulture;
        
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal FilesJSResource() {
        }
        
        /// <summary>
        ///   Returns the cached ResourceManager instance used by this class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ASC.Web.Files.Resources.FilesJSResource", typeof(FilesJSResource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        
        /// <summary>
        ///   Overrides the current thread's CurrentUICulture property for all
        ///   resource lookups using this strongly typed resource class.
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        public static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Access Settings for {0}.
        /// </summary>
        public static string AccessSettingsHeader {
            get {
                return ResourceManager.GetString("AccessSettingsHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Comment.
        /// </summary>
        public static string AceStatusEnum_Comment {
            get {
                return ResourceManager.GetString("AceStatusEnum_Comment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Custom Filter.
        /// </summary>
        public static string AceStatusEnum_CustomFilter {
            get {
                return ResourceManager.GetString("AceStatusEnum_CustomFilter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Form Filling.
        /// </summary>
        public static string AceStatusEnum_FillForms {
            get {
                return ResourceManager.GetString("AceStatusEnum_FillForms", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Owner.
        /// </summary>
        public static string AceStatusEnum_Owner {
            get {
                return ResourceManager.GetString("AceStatusEnum_Owner", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Read Only.
        /// </summary>
        public static string AceStatusEnum_Read {
            get {
                return ResourceManager.GetString("AceStatusEnum_Read", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Full Access.
        /// </summary>
        public static string AceStatusEnum_ReadWrite {
            get {
                return ResourceManager.GetString("AceStatusEnum_ReadWrite", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deny Access.
        /// </summary>
        public static string AceStatusEnum_Restrict {
            get {
                return ResourceManager.GetString("AceStatusEnum_Restrict", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Review.
        /// </summary>
        public static string AceStatusEnum_Review {
            get {
                return ResourceManager.GetString("AceStatusEnum_Review", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Varies.
        /// </summary>
        public static string AceStatusEnum_Varies {
            get {
                return ResourceManager.GetString("AceStatusEnum_Varies", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Archives.
        /// </summary>
        public static string ButtonFilterArchive {
            get {
                return ResourceManager.GetString("ButtonFilterArchive", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Author.
        /// </summary>
        public static string ButtonFilterAuthor {
            get {
                return ResourceManager.GetString("ButtonFilterAuthor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Exclude subfolders.
        /// </summary>
        public static string ButtonFilterCurrentFolderOnly {
            get {
                return ResourceManager.GetString("ButtonFilterCurrentFolderOnly", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Documents.
        /// </summary>
        public static string ButtonFilterDocument {
            get {
                return ResourceManager.GetString("ButtonFilterDocument", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All files.
        /// </summary>
        public static string ButtonFilterFiles {
            get {
                return ResourceManager.GetString("ButtonFilterFiles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Folders.
        /// </summary>
        public static string ButtonFilterFolder {
            get {
                return ResourceManager.GetString("ButtonFilterFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Images.
        /// </summary>
        public static string ButtonFilterImage {
            get {
                return ResourceManager.GetString("ButtonFilterImage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to In content.
        /// </summary>
        public static string ButtonFilterInContent {
            get {
                return ResourceManager.GetString("ButtonFilterInContent", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Media.
        /// </summary>
        public static string ButtonFilterMedia {
            get {
                return ResourceManager.GetString("ButtonFilterMedia", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Search.
        /// </summary>
        public static string ButtonFilterOther {
            get {
                return ResourceManager.GetString("ButtonFilterOther", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Presentations.
        /// </summary>
        public static string ButtonFilterPresentation {
            get {
                return ResourceManager.GetString("ButtonFilterPresentation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Spreadsheets.
        /// </summary>
        public static string ButtonFilterSpreadsheet {
            get {
                return ResourceManager.GetString("ButtonFilterSpreadsheet", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Type.
        /// </summary>
        public static string ButtonFilterType {
            get {
                return ResourceManager.GetString("ButtonFilterType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show more {0}.
        /// </summary>
        public static string ButtonShowMore {
            get {
                return ResourceManager.GetString("ButtonShowMore", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uploading....
        /// </summary>
        public static string ButtonShowMoreLoad {
            get {
                return ResourceManager.GetString("ButtonShowMoreLoad", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Show more {0} of {1}.
        /// </summary>
        public static string ButtonShowMoreOf {
            get {
                return ResourceManager.GetString("ButtonShowMoreOf", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Author.
        /// </summary>
        public static string ButtonSortAuthor {
            get {
                return ResourceManager.GetString("ButtonSortAuthor", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creation date.
        /// </summary>
        public static string ButtonSortCreated {
            get {
                return ResourceManager.GetString("ButtonSortCreated", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Last modified date.
        /// </summary>
        public static string ButtonSortModifiedNew {
            get {
                return ResourceManager.GetString("ButtonSortModifiedNew", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Title.
        /// </summary>
        public static string ButtonSortName {
            get {
                return ResourceManager.GetString("ButtonSortName", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Size.
        /// </summary>
        public static string ButtonSortSize {
            get {
                return ResourceManager.GetString("ButtonSortSize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Type.
        /// </summary>
        public static string ButtonSortType {
            get {
                return ResourceManager.GetString("ButtonSortType", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Code has been copied to the clipboard.
        /// </summary>
        public static string CodeCopySuccess {
            get {
                return ResourceManager.GetString("CodeCopySuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to remove the {0} from the &apos;Documents&apos; module? This will not affect your {1} account in any way..
        /// </summary>
        public static string ConfirmDeleteThirdParty {
            get {
                return ResourceManager.GetString("ConfirmDeleteThirdParty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to empty the trash?.
        /// </summary>
        public static string ConfirmEmptyTrash {
            get {
                return ResourceManager.GetString("ConfirmEmptyTrash", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Are you sure you want to leave the current page? Downloading of files will be interrupted..
        /// </summary>
        public static string ConfirmLeavePage {
            get {
                return ResourceManager.GetString("ConfirmLeavePage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are about to delete this file? Please note, that if you have shared it with someone, it will become unavailable. Are you sure you want to continue?.
        /// </summary>
        public static string ConfirmRemoveFile {
            get {
                return ResourceManager.GetString("ConfirmRemoveFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are about to delete this folder? Please note, that if you have shared it with someone, it will become unavailable. Are you sure you want to continue?.
        /// </summary>
        public static string ConfirmRemoveFolder {
            get {
                return ResourceManager.GetString("ConfirmRemoveFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are about to delete these elements? Please note, that if you have shared these files/folders with someone, they will become unavailable. Are you sure you want to continue?.
        /// </summary>
        public static string ConfirmRemoveList {
            get {
                return ResourceManager.GetString("ConfirmRemoveList", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You are about to move elements from the {1} directory. In such a case, they will be deleted from your {1} account and will no longer be accessible to other users, in case these elements have previously been shared. {0}Are you sure you want to move the elements?.
        /// </summary>
        public static string ConfirmThirdPartyMoveMessage {
            get {
                return ResourceManager.GetString("ConfirmThirdPartyMoveMessage", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Common.
        /// </summary>
        public static string CorporateFiles {
            get {
                return ResourceManager.GetString("CorporateFiles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Custom format.
        /// </summary>
        public static string CustomFormat {
            get {
                return ResourceManager.GetString("CustomFormat", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Groups.
        /// </summary>
        public static string Departments {
            get {
                return ResourceManager.GetString("Departments", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Archiving Data.
        /// </summary>
        public static string DescriptBulkdownload {
            get {
                return ResourceManager.GetString("DescriptBulkdownload", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Change data.
        /// </summary>
        public static string DescriptChangeInfo {
            get {
                return ResourceManager.GetString("DescriptChangeInfo", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Finalizing version.
        /// </summary>
        public static string DescriptCompleteVersion {
            get {
                return ResourceManager.GetString("DescriptCompleteVersion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Copy.
        /// </summary>
        public static string DescriptCopy {
            get {
                return ResourceManager.GetString("DescriptCopy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Creation.
        /// </summary>
        public static string DescriptCreate {
            get {
                return ResourceManager.GetString("DescriptCreate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sign via DocuSign.
        /// </summary>
        public static string DescriptDocuSign {
            get {
                return ResourceManager.GetString("DescriptDocuSign", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Loading versions....
        /// </summary>
        public static string DescriptLoadVersion {
            get {
                return ResourceManager.GetString("DescriptLoadVersion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Marking as Read.
        /// </summary>
        public static string DescriptMarkAsRead {
            get {
                return ResourceManager.GetString("DescriptMarkAsRead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move.
        /// </summary>
        public static string DescriptMove {
            get {
                return ResourceManager.GetString("DescriptMove", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deleting....
        /// </summary>
        public static string DescriptRemove {
            get {
                return ResourceManager.GetString("DescriptRemove", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Rename.
        /// </summary>
        public static string DescriptRename {
            get {
                return ResourceManager.GetString("DescriptRename", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Updating version.
        /// </summary>
        public static string DescriptSetVersion {
            get {
                return ResourceManager.GetString("DescriptSetVersion", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Preparing file for encryption.
        /// </summary>
        public static string DesktopMessageDownloading {
            get {
                return ResourceManager.GetString("DesktopMessageDownloading", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Encrypting file.
        /// </summary>
        public static string DesktopMessageEncrypting {
            get {
                return ResourceManager.GetString("DesktopMessageEncrypting", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Saving encrypted file.
        /// </summary>
        public static string DesktopMessageStoring {
            get {
                return ResourceManager.GetString("DesktopMessageStoring", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Documents.
        /// </summary>
        public static string Documents {
            get {
                return ResourceManager.GetString("Documents", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sign document ({0}).
        /// </summary>
        public static string DocuSignDialogHeader {
            get {
                return ResourceManager.GetString("DocuSignDialogHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Select at least one folder/document to download.
        /// </summary>
        public static string EmptyListSelectedForDownload {
            get {
                return ResourceManager.GetString("EmptyListSelectedForDownload", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Enter a comment.
        /// </summary>
        public static string EnterComment {
            get {
                return ResourceManager.GetString("EnterComment", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You cannot upload a folder or an empty file.
        /// </summary>
        public static string ErrorMassage_EmptyFile {
            get {
                return ResourceManager.GetString("ErrorMassage_EmptyFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Conversion Error.
        /// </summary>
        public static string ErrorMassage_ErrorConvert {
            get {
                return ResourceManager.GetString("ErrorMassage_ErrorConvert", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to All fields are required to be filled in.
        /// </summary>
        public static string ErrorMassage_FieldsIsEmpty {
            get {
                return ResourceManager.GetString("ErrorMassage_FieldsIsEmpty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The maximum file size is exceeded.
        /// </summary>
        public static string ErrorMassage_FileSize {
            get {
                return ResourceManager.GetString("ErrorMassage_FileSize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You need to login to be able to add.
        /// </summary>
        public static string ErrorMassage_MustLogin {
            get {
                return ResourceManager.GetString("ErrorMassage_MustLogin", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sorry, this file format isn&apos;t supported.
        /// </summary>
        public static string ErrorMassage_NotSupportedFormat {
            get {
                return ResourceManager.GetString("ErrorMassage_NotSupportedFormat", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The password you entered is incorrect. Please try again..
        /// </summary>
        public static string ErrorMassage_PasswordFile {
            get {
                return ResourceManager.GetString("ErrorMassage_PasswordFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Please wait for the previous download to complete or cancel it.
        /// </summary>
        public static string ErrorMassage_SecondDownload {
            get {
                return ResourceManager.GetString("ErrorMassage_SecondDownload", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You don&apos;t have enough permission to perform the operation.
        /// </summary>
        public static string ErrorMassage_SecurityException {
            get {
                return ResourceManager.GetString("ErrorMassage_SecurityException", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You cannot perform such an action in this folder.
        /// </summary>
        public static string ErrorMassage_SecurityException_PrivateRoot {
            get {
                return ResourceManager.GetString("ErrorMassage_SecurityException_PrivateRoot", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The title cannot contain any of the following characters: {0}.
        /// </summary>
        public static string ErrorMassage_SpecCharacter {
            get {
                return ResourceManager.GetString("ErrorMassage_SpecCharacter", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The portal storage has run out of free space. You cannot upload files larger than {0}..
        /// </summary>
        public static string ErrorMassage_StorageSize {
            get {
                return ResourceManager.GetString("ErrorMassage_StorageSize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The file with the name {0} already exists in the folder {1}..
        /// </summary>
        public static string FileAlreadyExist {
            get {
                return ResourceManager.GetString("FileAlreadyExist", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Converted.
        /// </summary>
        public static string FileConverted {
            get {
                return ResourceManager.GetString("FileConverted", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Converting.
        /// </summary>
        public static string FileConverting {
            get {
                return ResourceManager.GetString("FileConverting", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} documents with the same name already exist in the folder {1}..
        /// </summary>
        public static string FilesAlreadyExist {
            get {
                return ResourceManager.GetString("FilesAlreadyExist", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uploaded.
        /// </summary>
        public static string FileUploaded {
            get {
                return ResourceManager.GetString("FileUploaded", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uploading.
        /// </summary>
        public static string FileUploading {
            get {
                return ResourceManager.GetString("FileUploading", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Box directory.
        /// </summary>
        public static string FolderTitleBoxNet {
            get {
                return ResourceManager.GetString("FolderTitleBoxNet", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to DocuSign account.
        /// </summary>
        public static string FolderTitleDocuSign {
            get {
                return ResourceManager.GetString("FolderTitleDocuSign", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Dropbox directory.
        /// </summary>
        public static string FolderTitleDropBox {
            get {
                return ResourceManager.GetString("FolderTitleDropBox", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Google directory.
        /// </summary>
        public static string FolderTitleGoogle {
            get {
                return ResourceManager.GetString("FolderTitleGoogle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to kDrive directory.
        /// </summary>
        public static string FolderTitlekDrive {
            get {
                return ResourceManager.GetString("FolderTitlekDrive", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to SharePoint directory.
        /// </summary>
        public static string FolderTitleSharePoint {
            get {
                return ResourceManager.GetString("FolderTitleSharePoint", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to OneDrive directory.
        /// </summary>
        public static string FolderTitleSkyDrive {
            get {
                return ResourceManager.GetString("FolderTitleSkyDrive", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to WebDAV Directory.
        /// </summary>
        public static string FolderTitleWebDav {
            get {
                return ResourceManager.GetString("FolderTitleWebDav", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Yandex Directory.
        /// </summary>
        public static string FolderTitleYandex {
            get {
                return ResourceManager.GetString("FolderTitleYandex", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Now &apos;{0}&apos; is the owner of &apos;{1}&apos;.
        /// </summary>
        public static string InfoChangeOwner {
            get {
                return ResourceManager.GetString("InfoChangeOwner", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Now &apos;{0}&apos; is the owner of {1} items.
        /// </summary>
        public static string InfoChangeOwnerArray {
            get {
                return ResourceManager.GetString("InfoChangeOwnerArray", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to &apos;{0}&apos; changed.
        /// </summary>
        public static string InfoChangeThirdParty {
            get {
                return ResourceManager.GetString("InfoChangeThirdParty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Copy {1}{0}{2}.
        /// </summary>
        public static string InfoCopyDescribe {
            get {
                return ResourceManager.GetString("InfoCopyDescribe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} copied elements.
        /// </summary>
        public static string InfoCopyGroup {
            get {
                return ResourceManager.GetString("InfoCopyGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to &apos;{0}&apos; copied.
        /// </summary>
        public static string InfoCopyItem {
            get {
                return ResourceManager.GetString("InfoCopyItem", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} elements.
        /// </summary>
        public static string InfoCountDescribe {
            get {
                return ResourceManager.GetString("InfoCountDescribe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New file &apos;{0}&apos; is created.
        /// </summary>
        public static string InfoCrateFile {
            get {
                return ResourceManager.GetString("InfoCrateFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The new &apos;{0}&apos; file is created in &apos;{1}&apos;.
        /// </summary>
        public static string InfoCrateFileIn {
            get {
                return ResourceManager.GetString("InfoCrateFileIn", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New folder &apos;{0}&apos; is created.
        /// </summary>
        public static string InfoCrateFolder {
            get {
                return ResourceManager.GetString("InfoCrateFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You cannot copy the folder to its subfolder.
        /// </summary>
        public static string InfoFolderCopyError {
            get {
                return ResourceManager.GetString("InfoFolderCopyError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You cannot move the folder to its subfolder.
        /// </summary>
        public static string InfoFolderMoveError {
            get {
                return ResourceManager.GetString("InfoFolderMoveError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You do not have access rights to move some file(s).
        /// </summary>
        public static string InfoMoveAccessError {
            get {
                return ResourceManager.GetString("InfoMoveAccessError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move {1}{0}{2}.
        /// </summary>
        public static string InfoMoveDescribe {
            get {
                return ResourceManager.GetString("InfoMoveDescribe", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} elements have been moved.
        /// </summary>
        public static string InfoMoveGroup {
            get {
                return ResourceManager.GetString("InfoMoveGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to &apos;{0}&apos; moved.
        /// </summary>
        public static string InfoMoveItem {
            get {
                return ResourceManager.GetString("InfoMoveItem", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The document &apos;{0}&apos; is deleted.
        /// </summary>
        public static string InfoRemoveFile {
            get {
                return ResourceManager.GetString("InfoRemoveFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The folder &apos;{0}&apos; is deleted.
        /// </summary>
        public static string InfoRemoveFolder {
            get {
                return ResourceManager.GetString("InfoRemoveFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to It was successfully deleted {0} from {1}.
        /// </summary>
        public static string InfoRemoveGroup {
            get {
                return ResourceManager.GetString("InfoRemoveGroup", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Third party &apos;{0}&apos; is disconnected.
        /// </summary>
        public static string InfoRemoveThirdParty {
            get {
                return ResourceManager.GetString("InfoRemoveThirdParty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The document &apos;{0}&apos; is renamed to &apos;{1}&apos;.
        /// </summary>
        public static string InfoRenameFile {
            get {
                return ResourceManager.GetString("InfoRenameFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to The folder &apos;{0}&apos; is renamed to &apos;{1}&apos;.
        /// </summary>
        public static string InfoRenameFolder {
            get {
                return ResourceManager.GetString("InfoRenameFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to &apos;{0}&apos; added to &apos;{1}&apos;.
        /// </summary>
        public static string InfoSaveThirdParty {
            get {
                return ResourceManager.GetString("InfoSaveThirdParty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Files added to Templates.
        /// </summary>
        public static string InfoTemplateAdd {
            get {
                return ResourceManager.GetString("InfoTemplateAdd", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Files removed from Templates.
        /// </summary>
        public static string InfoTemplateRemove {
            get {
                return ResourceManager.GetString("InfoTemplateRemove", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} documents are successfully uploaded.
        /// </summary>
        public static string InfoUploadedSuccess {
            get {
                return ResourceManager.GetString("InfoUploadedSuccess", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to My documents.
        /// </summary>
        public static string MyFiles {
            get {
                return ResourceManager.GetString("MyFiles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Original format.
        /// </summary>
        public static string OriginalFormat {
            get {
                return ResourceManager.GetString("OriginalFormat", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Other.
        /// </summary>
        public static string Other {
            get {
                return ResourceManager.GetString("Other", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Presentations.
        /// </summary>
        public static string Presentations {
            get {
                return ResourceManager.GetString("Presentations", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Failed to upload file {0} to display.
        /// </summary>
        public static string PreviewError {
            get {
                return ResourceManager.GetString("PreviewError", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Private Room.
        /// </summary>
        public static string PrivacyRoom {
            get {
                return ResourceManager.GetString("PrivacyRoom", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to In projects.
        /// </summary>
        public static string ProjectFiles {
            get {
                return ResourceManager.GetString("ProjectFiles", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to revisions: {0}.
        /// </summary>
        public static string RevisionCount {
            get {
                return ResourceManager.GetString("RevisionCount", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have been granted access to the {0} document. Click the link below to open the document right now: {1}.
        /// </summary>
        public static string shareLinkMailBody {
            get {
                return ResourceManager.GetString("shareLinkMailBody", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to You have been granted access to the {0} document.
        /// </summary>
        public static string shareLinkMailSubject {
            get {
                return ResourceManager.GetString("shareLinkMailSubject", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0}.
        /// </summary>
        public static string SharingSettingsCount {
            get {
                return ResourceManager.GetString("SharingSettingsCount", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Add users and groups to share documents with them.{0} Set their permissions for reading,  editing, etc..
        /// </summary>
        public static string SharingSettingsEmpty {
            get {
                return ResourceManager.GetString("SharingSettingsEmpty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Sharing Settings for {0}.
        /// </summary>
        public static string SharingSettingsHeader {
            get {
                return ResourceManager.GetString("SharingSettingsHeader", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Spreadsheets.
        /// </summary>
        public static string Spreedsheets {
            get {
                return ResourceManager.GetString("Spreedsheets", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Archiving Data.
        /// </summary>
        public static string TasksOperationBulkdownload {
            get {
                return ResourceManager.GetString("TasksOperationBulkdownload", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Copying.
        /// </summary>
        public static string TasksOperationCopy {
            get {
                return ResourceManager.GetString("TasksOperationCopy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Deleting.
        /// </summary>
        public static string TasksOperationDelete {
            get {
                return ResourceManager.GetString("TasksOperationDelete", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Marking as Read.
        /// </summary>
        public static string TasksOperationMarkAsRead {
            get {
                return ResourceManager.GetString("TasksOperationMarkAsRead", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} operations.
        /// </summary>
        public static string TasksOperationMixed {
            get {
                return ResourceManager.GetString("TasksOperationMixed", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Move.
        /// </summary>
        public static string TasksOperationMove {
            get {
                return ResourceManager.GetString("TasksOperationMove", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Change {0} connection settings.
        /// </summary>
        public static string ThirdPartyEditorCaption {
            get {
                return ResourceManager.GetString("ThirdPartyEditorCaption", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Cancel.
        /// </summary>
        public static string TitleCancel {
            get {
                return ResourceManager.GetString("TitleCancel", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Save.
        /// </summary>
        public static string TitleCreate {
            get {
                return ResourceManager.GetString("TitleCreate", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to It is currently being edited.
        /// </summary>
        public static string TitleEditingFile {
            get {
                return ResourceManager.GetString("TitleEditingFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to It is currently being edited by: {0}.
        /// </summary>
        public static string TitleEditingFileBy {
            get {
                return ResourceManager.GetString("TitleEditingFileBy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Locked.
        /// </summary>
        public static string TitleLockedFile {
            get {
                return ResourceManager.GetString("TitleLockedFile", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Locked by: {0}.
        /// </summary>
        public static string TitleLockedFileBy {
            get {
                return ResourceManager.GetString("TitleLockedFileBy", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to More Features.
        /// </summary>
        public static string TitleMoreFeaturs {
            get {
                return ResourceManager.GetString("TitleMoreFeaturs", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Presentation.
        /// </summary>
        public static string TitleNewFilePresentation {
            get {
                return ResourceManager.GetString("TitleNewFilePresentation", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Spreadsheet.
        /// </summary>
        public static string TitleNewFileSpreadsheet {
            get {
                return ResourceManager.GetString("TitleNewFileSpreadsheet", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Document.
        /// </summary>
        public static string TitleNewFileText {
            get {
                return ResourceManager.GetString("TitleNewFileText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to New Folder.
        /// </summary>
        public static string TitleNewFolder {
            get {
                return ResourceManager.GetString("TitleNewFolder", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Admin Settings.
        /// </summary>
        public static string TitleSettingsAdmin {
            get {
                return ResourceManager.GetString("TitleSettingsAdmin", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Common Settings.
        /// </summary>
        public static string TitleSettingsCommon {
            get {
                return ResourceManager.GetString("TitleSettingsCommon", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Help.
        /// </summary>
        public static string TitleSettingsHelp {
            get {
                return ResourceManager.GetString("TitleSettingsHelp", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Connected Clouds.
        /// </summary>
        public static string TitleSettingsThirdParty {
            get {
                return ResourceManager.GetString("TitleSettingsThirdParty", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Box.
        /// </summary>
        public static string TypeTitleBoxNet {
            get {
                return ResourceManager.GetString("TypeTitleBoxNet", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to DocuSign.
        /// </summary>
        public static string TypeTitleDocuSign {
            get {
                return ResourceManager.GetString("TypeTitleDocuSign", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Dropbox.
        /// </summary>
        public static string TypeTitleDropBox {
            get {
                return ResourceManager.GetString("TypeTitleDropBox", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Google Drive.
        /// </summary>
        public static string TypeTitleGoogle {
            get {
                return ResourceManager.GetString("TypeTitleGoogle", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to kDrive.
        /// </summary>
        public static string TypeTitlekDrive {
            get {
                return ResourceManager.GetString("TypeTitlekDrive", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to SharePoint.
        /// </summary>
        public static string TypeTitleSharePoint {
            get {
                return ResourceManager.GetString("TypeTitleSharePoint", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to OneDrive.
        /// </summary>
        public static string TypeTitleSkyDrive {
            get {
                return ResourceManager.GetString("TypeTitleSkyDrive", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to WebDAV.
        /// </summary>
        public static string TypeTitleWebDav {
            get {
                return ResourceManager.GetString("TypeTitleWebDav", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Yandex.Disk.
        /// </summary>
        public static string TypeTitleYandex {
            get {
                return ResourceManager.GetString("TypeTitleYandex", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Unknown error....
        /// </summary>
        public static string UnknownErrorText {
            get {
                return ResourceManager.GetString("UnknownErrorText", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Upload complete.
        /// </summary>
        public static string UploadComplete {
            get {
                return ResourceManager.GetString("UploadComplete", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uploading ....
        /// </summary>
        public static string Uploading {
            get {
                return ResourceManager.GetString("Uploading", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Uploading {0} files ({1}% done).
        /// </summary>
        public static string UploadingProgress {
            get {
                return ResourceManager.GetString("UploadingProgress", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to {0} of {1} used.
        /// </summary>
        public static string UsedSize {
            get {
                return ResourceManager.GetString("UsedSize", resourceCulture);
            }
        }
        
        /// <summary>
        ///   Looks up a localized string similar to Users.
        /// </summary>
        public static string Users {
            get {
                return ResourceManager.GetString("Users", resourceCulture);
            }
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/StatusEngine.cs<|end_filename|>
﻿/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;
using System.Linq;

using ASC.Projects.Core.DataInterfaces;
using ASC.Projects.Core.Domain;
using ASC.Web.Projects;

namespace ASC.Projects.Engine
{
    public class StatusEngine
    {
        public IDaoFactory DaoFactory { get; set; }
        public ProjectSecurity ProjectSecurity { get; set; }

        public CustomTaskStatus Create(CustomTaskStatus status)
        {
            if (!ProjectSecurity.CurrentUserAdministrator) ProjectSecurity.CreateSecurityException();

            var statuses = DaoFactory.StatusDao.Get().Where(r => r.StatusType == status.StatusType).OrderBy(r => r.Order);
            var lastStatus = statuses.LastOrDefault();

            if (lastStatus != null)
            {
                status.Order = lastStatus.Order + 1;
            }
            else
            {
                status.Order = 1;
            }

            if (!status.Available.HasValue)
            {
                status.Available = statuses.All(r => r.Available == null || r.Available.Value);
            }

            return DaoFactory.StatusDao.Create(status);
        }

        public void Update(CustomTaskStatus status)
        {
            if (!ProjectSecurity.CurrentUserAdministrator) ProjectSecurity.CreateSecurityException();

            var statuses = DaoFactory.StatusDao.Get().Where(r => r.StatusType == status.StatusType).OrderBy(r => r.Order);

            if (!status.Available.HasValue)
            {
                status.Available = statuses.All(r => r.Available == null || r.Available.Value);
            }

            DaoFactory.StatusDao.Update(status);
        }

        public List<CustomTaskStatus> Get()
        {
            return DaoFactory.StatusDao.Get();
        }

        public List<CustomTaskStatus> GetWithDefaults()
        {
            var result = Get();

            if (!result.Any(r => r.StatusType == TaskStatus.Open && r.IsDefault))
            {
                result.Add(CustomTaskStatus.GetDefault(TaskStatus.Open));
            }
            if (!result.Any(r => r.StatusType == TaskStatus.Closed && r.IsDefault))
            {
                result.Add(CustomTaskStatus.GetDefault(TaskStatus.Closed));
            }

            return result;
        }


        public void Delete(int id)
        {
            if (!ProjectSecurity.CurrentUserAdministrator) ProjectSecurity.CreateSecurityException();
            var defaultTask = CustomTaskStatus.GetDefaults().FirstOrDefault(r => r.Id == id);
            if (defaultTask != null) return;

            DaoFactory.StatusDao.Delete(id);
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Extensions/MailBoxExtensions.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Security.Authentication;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Data.Storage;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Utils;

namespace ASC.Mail.Extensions
{
    public static class MailBoxExtensions
    {
        public static bool IsUserTerminated(this MailBoxData mailbox)
        {
            try
            {
                CoreContext.TenantManager.SetCurrentTenant(mailbox.TenantId);

                var user = CoreContext.UserManager.GetUsers(new Guid(mailbox.UserId));

                return user.Status == EmployeeStatus.Terminated;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static bool IsUserRemoved(this MailBoxData mailbox)
        {
            try
            {
                CoreContext.TenantManager.SetCurrentTenant(mailbox.TenantId);
                Guid user;
                if (!Guid.TryParse(mailbox.UserId, out user))
                    return true;

                return !CoreContext.UserManager.UserExists(user) || CoreContext.UserManager.IsSystemUser(user);
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static UserInfo GetUserInfo(this MailBoxData mailbox)
        {
            try
            {
                CoreContext.TenantManager.SetCurrentTenant(mailbox.TenantId);
                var userInfo = CoreContext.UserManager.GetUsers(new Guid(mailbox.UserId));

                return userInfo;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static Defines.TariffType GetTenantStatus(this MailBoxData mailbox, int tenantOverdueDays,
            string httpContextScheme, ILog log = null)
        {
            log = log ?? new NullLog();

            Defines.TariffType type;

            try
            {
                CoreContext.TenantManager.SetCurrentTenant(mailbox.TenantId);

                var tenantInfo = CoreContext.TenantManager.GetCurrentTenant();

                if (tenantInfo.Status == TenantStatus.RemovePending)
                    return Defines.TariffType.LongDead;

                try
                {
                    SecurityContext.AuthenticateMe(tenantInfo.OwnerId);
                }
                catch (InvalidCredentialException)
                {
                    SecurityContext.AuthenticateMe(new Guid(mailbox.UserId));
                }

                var apiHelper = new ApiHelper(httpContextScheme, log);
                type = apiHelper.GetTenantTariff(tenantOverdueDays);
            }
            catch (Exception ex)
            {
                log.ErrorFormat("GetTenantStatus(Tenant={0}, User='{1}') Exception: {2}",
                    mailbox.TenantId, mailbox.UserId, ex.InnerException != null ? ex.InnerException.Message : ex.Message);
                type = Defines.TariffType.Active;
            }

            return type;
        }

        public static bool IsTenantQuotaEnded(this MailBoxData mailbox, long minBalance, ILog log = null)
        {
            var quotaEnded = false;
            log = log ?? new NullLog();

            try
            {
                var quotaController = new TenantQuotaController(mailbox.TenantId);
                var quota = CoreContext.TenantManager.GetTenantQuota(mailbox.TenantId);
                var usedQuota = quotaController.QuotaCurrentGet();
                quotaEnded = quota.MaxTotalSize - usedQuota < minBalance;
                log.DebugFormat("IsTenantQuotaEnded: {0} Tenant = {1}. Tenant quota = {2}Mb ({3}), used quota = {4}Mb ({5}) ",
                    quotaEnded,
                    mailbox.TenantId,
                    MailUtil.BytesToMegabytes(quota.MaxTotalSize), quota.MaxTotalSize,
                    MailUtil.BytesToMegabytes(usedQuota), usedQuota);
            }
            catch (Exception ex)
            {
                log.ErrorFormat("IsQuotaExhausted(Tenant={0}) Exception: {1}", mailbox.TenantId, ex.Message);
            }

            return quotaEnded;
        }

        public static bool IsCrmAvailable(this MailBoxData mailbox,
            string httpContextScheme, ILog log = null)
        {
            log = log ?? new NullLog();

            try
            {
                CoreContext.TenantManager.SetCurrentTenant(mailbox.TenantId);

                var tenantInfo = CoreContext.TenantManager.GetCurrentTenant();

                if (tenantInfo.Status == TenantStatus.RemovePending)
                    return false;

                SecurityContext.AuthenticateMe(new Guid(mailbox.UserId));

                var apiHelper = new ApiHelper(httpContextScheme, log);
                return apiHelper.IsCrmModuleAvailable();
            }
            catch (Exception ex)
            {
                log.ErrorFormat("GetTenantStatus(Tenant={0}, User='{1}') Exception: {2}",
                    mailbox.TenantId, mailbox.UserId, ex.InnerException != null ? ex.InnerException.Message : ex.Message);
            }

            return true;
        }
    }
}


<|start_filename|>common/ASC.Core.Common/Security/Authentication/CookieStorage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Globalization;
using System.Web;

using ASC.Common.Logging;
using ASC.Core.Tenants;
using ASC.Security.Cryptography;

namespace ASC.Core.Security.Authentication
{
    public class CookieStorage
    {
        private const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss,fff";

        public static bool DecryptCookie(string cookie, out int tenant, out Guid userid, out int indexTenant, out DateTime expire, out int indexUser)
        {
            tenant = Tenant.DEFAULT_TENANT;
            userid = Guid.Empty;
            indexTenant = 0;
            expire = DateTime.MaxValue;
            indexUser = 0;

            if (string.IsNullOrEmpty(cookie))
            {
                return false;
            }

            try
            {
                cookie = (HttpUtility.UrlDecode(cookie) ?? "").Replace(' ', '+');
                var s = InstanceCrypto.Decrypt(cookie).Split('$');

                if (1 < s.Length) tenant = int.Parse(s[1]);
                if (4 < s.Length) userid = new Guid(s[4]);
                if (5 < s.Length) indexTenant = int.Parse(s[5]);
                if (6 < s.Length) expire = DateTime.ParseExact(s[6], DateTimeFormat, CultureInfo.InvariantCulture);
                if (7 < s.Length) indexUser = int.Parse(s[7]);

                return true;
            }
            catch (Exception err)
            {
                LogManager.GetLogger("ASC.Core").ErrorFormat("Authenticate error: cookie {0}, tenant {1}, userid {2}, indexTenant {3}, expire {4}: {5}",
                    cookie, tenant, userid, indexTenant, expire.ToString(DateTimeFormat), err);
            }
            return false;
        }


        public static string EncryptCookie(int tenant, Guid userid)
        {
            var settingsTenant = TenantCookieSettings.GetForTenant(tenant);
            var expires = TenantCookieSettings.GetExpiresTime(tenant);
            var settingsUser = TenantCookieSettings.GetForUser(tenant, userid);
            return EncryptCookie(tenant, userid, settingsTenant.Index, expires, settingsUser.Index);
        }

        public static string EncryptCookie(int tenant, Guid userid, int indexTenant, DateTime expires, int indexUser)
        {
            var s = string.Format("{0}${1}${2}${3}${4}${5}${6}${7}",
                string.Empty, //login
                tenant,
                string.Empty, // password
                GetUserDepenencySalt(),
                userid.ToString("N"),
                indexTenant,
                expires.ToString(DateTimeFormat, CultureInfo.InvariantCulture),
                indexUser);

            return InstanceCrypto.Encrypt(s);
        }


        private static string GetUserDepenencySalt()
        {
            var data = string.Empty;
            try
            {
                if (HttpContext.Current != null && HttpContext.Current.Request != null)
                {
                    var forwarded = HttpContext.Current.Request.Headers["X-Forwarded-For"];
                    data = string.IsNullOrEmpty(forwarded) ? HttpContext.Current.Request.UserHostAddress : forwarded.Split(':')[0];
                }
            }
            catch { }
            return Hasher.Base64Hash(data ?? string.Empty, HashAlg.SHA256);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Code/WikiNotifySource.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Web;

using ASC.Core.Notify;
using ASC.Notify.Model;
using ASC.Notify.Patterns;
using ASC.Web.Community.Modules.Wiki.Code.Patterns;

namespace ASC.Web.UserControls.Wiki
{
    public class WikiNotifySource : NotifySource
    {
        private readonly string defPageHref;


        public static WikiNotifySource Instance
        {
            get;
            private set;
        }


        static WikiNotifySource()
        {
            Instance = new WikiNotifySource();
        }

        public WikiNotifySource()
            : base(WikiManager.ModuleId)
        {
            defPageHref = VirtualPathUtility.ToAbsolute(WikiManager.ViewVirtualPath);
        }


        public string GetDefPageHref()
        {
            return defPageHref;
        }


        protected override IActionProvider CreateActionProvider()
        {
            return new ConstActionProvider(Constants.NewPage, Constants.EditPage);
        }

        protected override IPatternProvider CreatePatternsProvider()
        {
            return new XmlPatternProvider2(WikiPatternsResource.patterns, ChoosePattern);
        }


        private IPattern ChoosePattern(INotifyAction action, string senderName, ASC.Notify.Engine.NotifyRequest request)
        {
            if (action == Constants.EditPage)
            {
                var tag = request.Arguments.Find(t => t.Tag == "ChangeType");
                if (tag != null && tag.Value.ToString() == "new wiki page comment")
                {
                    return PatternProvider.GetPattern(new NotifyAction(tag.Value.ToString()), senderName);
                }
            }
            return null;
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Wiki/Code/BaseDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

using ASC.Common.Data;
using ASC.Common.Data.Sql;

namespace ASC.Web.UserControls.Wiki.Data
{
    class BaseDao : IDisposable
    {
        private const string TenantColumn = "tenant";

        protected readonly DbManager db;
        protected readonly int tenant;


        public BaseDao(string dbid, int tenant)
        {
            this.db = new DbManager(dbid);
            this.tenant = tenant;
        }


        public void Dispose()
        {
            db.Dispose();
        }


        protected SqlQuery Query(string table)
        {
            return new SqlQuery(table).Where(GetTenantColumnName(table), tenant);
        }

        protected SqlInsert Insert(string table)
        {
            return new SqlInsert(table, true).InColumnValue(GetTenantColumnName(table), tenant);
        }

        protected SqlUpdate Update(string table)
        {
            return new SqlUpdate(table).Where(GetTenantColumnName(table), tenant);
        }

        protected SqlDelete Delete(string table)
        {
            return new SqlDelete(table).Where(GetTenantColumnName(table), tenant);
        }

        private string GetTenantColumnName(string table)
        {
            var pos = table.LastIndexOf(' ');
            return (0 < pos ? table.Substring(pos).Trim() + '.' : string.Empty) + TenantColumn;
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/IO/Base64Stream.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.IO
{
    #region usings

    using System;
    using System.Collections.Generic;
    using System.IO;

    #endregion

    /// <summary>
    /// This class implements base64 encoder/decoder. Defined in RFC 4648.
    /// </summary>
    public class Base64Stream : Stream, IDisposable
    {
        #region Members

        private static readonly short[] BASE64_DECODE_TABLE = new short[]
                                                                  {
                                                                      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                                                                      // 0 -    9
                                                                      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                                                                      //10 -   19
                                                                      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                                                                      //20 -   29
                                                                      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                                                                      //30 -   39
                                                                      -1, -1, -1, 62, -1, -1, -1, 63, 52, 53,
                                                                      //40 -   49
                                                                      54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
                                                                      //50 -   59
                                                                      -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
                                                                      //60 -   69
                                                                      5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
                                                                      //70 -   79
                                                                      15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
                                                                      //80 -   89
                                                                      25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
                                                                      //90 -   99
                                                                      29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
                                                                      //100 - 109
                                                                      39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
                                                                      //110 - 119
                                                                      49, 50, 51, -1, -1, -1, -1, -1 //120 - 127
                                                                  };

        private static readonly byte[] BASE64_ENCODE_TABLE = new[]
                                                                 {
                                                                     (byte) 'A', (byte) 'B', (byte) 'C',
                                                                     (byte) 'D', (byte) 'E', (byte) 'F',
                                                                     (byte) 'G', (byte) 'H', (byte) 'I',
                                                                     (byte) 'J', (byte) 'K', (byte) 'L',
                                                                     (byte) 'M', (byte) 'N', (byte) 'O',
                                                                     (byte) 'P', (byte) 'Q', (byte) 'R',
                                                                     (byte) 'S', (byte) 'T', (byte) 'U',
                                                                     (byte) 'V', (byte) 'W', (byte) 'X',
                                                                     (byte) 'Y', (byte) 'Z', (byte) 'a',
                                                                     (byte) 'b', (byte) 'c', (byte) 'd',
                                                                     (byte) 'e', (byte) 'f', (byte) 'g',
                                                                     (byte) 'h', (byte) 'i', (byte) 'j',
                                                                     (byte) 'k', (byte) 'l', (byte) 'm',
                                                                     (byte) 'n', (byte) 'o', (byte) 'p',
                                                                     (byte) 'q', (byte) 'r', (byte) 's',
                                                                     (byte) 't', (byte) 'u', (byte) 'v',
                                                                     (byte) 'w', (byte) 'x', (byte) 'y',
                                                                     (byte) 'z', (byte) '0', (byte) '1',
                                                                     (byte) '2', (byte) '3', (byte) '4',
                                                                     (byte) '5', (byte) '6', (byte) '7',
                                                                     (byte) '8', (byte) '9', (byte) '+',
                                                                     (byte) '/'
                                                                 };

        private readonly FileAccess m_AccessMode = FileAccess.ReadWrite;
        private readonly bool m_AddLineBreaks = true;
        private readonly bool m_IsOwner;
        private readonly Queue<byte> m_pDecodeReminder;
        private readonly byte[] m_pEncode3x8Block = new byte[3];
        private readonly byte[] m_pEncodeBuffer = new byte[78];
        private readonly Stream m_pStream;
        private int m_EncodeBufferOffset;
        private bool m_IsDisposed;
        private bool m_IsFinished;
        private int m_OffsetInEncode3x8Block;

        private static string[] padding_tails = new string[4] { "", "===", "==", "=" };

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this object is disposed.
        /// </summary>
        public bool IsDisposed
        {
            get { return m_IsDisposed; }
        }

        /// <summary>
        /// Gets a value indicating whether the current stream supports reading.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public override bool CanRead
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                return true;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the current stream supports seeking.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public override bool CanSeek
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                return false;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the current stream supports writing.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        public override bool CanWrite
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                return false;
            }
        }

        /// <summary>
        /// Gets the length in bytes of the stream.  This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="NotSupportedException">Is raised when this property is accessed.</exception>
        public override long Length
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                throw new NotSupportedException();
            }
        }

        /// <summary>
        /// Gets or sets the position within the current stream. This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this property is accessed.</exception>
        /// <exception cref="NotSupportedException">Is raised when this property is accessed.</exception>
        public override long Position
        {
            get
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                throw new NotSupportedException();
            }

            set
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException("SmartStream");
                }

                throw new NotSupportedException();
            }
        }

        #endregion

        private MemoryStream decodedDataStream = null;
        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stream">Stream which to encode/decode.</param>
        /// <param name="owner">Specifies if Base64Stream is owner of <b>stream</b>.</param>
        /// <param name="addLineBreaks">Specifies if encoder inserts CRLF after each 76 bytes.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception>
        public Base64Stream(Stream stream, bool owner, bool addLineBreaks)
            : this(stream, owner, addLineBreaks, FileAccess.ReadWrite) {}

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="stream">Stream which to encode/decode.</param>
        /// <param name="owner">Specifies if Base64Stream is owner of <b>stream</b>.</param>
        /// <param name="addLineBreaks">Specifies if encoder inserts CRLF after each 76 bytes.</param>
        /// <param name="access">This stream access mode.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> is null reference.</exception>
        public Base64Stream(Stream stream, bool owner, bool addLineBreaks, FileAccess access)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            
            // Parse all stream
            if (stream.Length > 0)
            {
                stream.Seek(0, SeekOrigin.Begin);
                decodedDataStream = new MemoryStream();
                using (StreamReader reader = new StreamReader(stream))
                {
                    List<string> lines = new List<string>();
                    while (!reader.EndOfStream)
                    {
                        string next_line = reader.ReadLine();
                        lines.Add(next_line);
                        int exc_bytes = next_line.Length & 0x03;
                        // If the line length is not multiple of 4 then we need to process possible wrong message content (it really happens)
                        if (exc_bytes != 0)
                        {
                            // Process even part of the line first
                            string even_part = next_line.Substring(0, next_line.Length - exc_bytes);
                            byte[] decoded = Convert.FromBase64String(even_part);
                            decodedDataStream.Write(decoded, 0, decoded.Length);

                            // then try to recover the odd part by appending "=" to it
                            try
                            {
                                string rest = next_line.Substring(next_line.Length - exc_bytes, exc_bytes);
                                byte[] rest_decoded = Convert.FromBase64String(rest + padding_tails[exc_bytes]);
                                decodedDataStream.Write(decoded, 0, decoded.Length);
                            }
                            catch (System.FormatException) {}
                        }
                        else
                        {
                            byte[] decoded = Convert.FromBase64String(next_line);
                            decodedDataStream.Write(decoded, 0, decoded.Length);
                        }
                    }
                    decodedDataStream.Seek(0, SeekOrigin.Begin);
                }
            }

            m_pStream = stream;
            m_IsOwner = owner;
            m_AddLineBreaks = addLineBreaks;
            m_AccessMode = access;

            m_pDecodeReminder = new Queue<byte>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Celans up any resources being used.
        /// </summary>
        public new void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            try
            {
                Finish();
            }
            catch {}
            m_IsDisposed = true;

            if (m_IsOwner)
            {
                m_pStream.Close();
            }
            if (decodedDataStream!=null)
            {
                decodedDataStream.Close();
                decodedDataStream.Dispose();
            }
        }

        /// <summary>
        /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public override void Flush()
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("Base64Stream");
            }
        }

        /// <summary>
        /// Sets the position within the current stream. This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <param name="offset">A byte offset relative to the <b>origin</b> parameter.</param>
        /// <param name="origin">A value of type SeekOrigin indicating the reference point used to obtain the new position.</param>
        /// <returns>The new position within the current stream.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="NotSupportedException">Is raised when this method is accessed.</exception>
        public override long Seek(long offset, SeekOrigin origin)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("Base64Stream");
            }

            throw new NotSupportedException();
        }

        /// <summary>
        /// Sets the length of the current stream. This method is not supported and always throws a NotSupportedException.
        /// </summary>
        /// <param name="value">The desired length of the current stream in bytes.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="Seek">Is raised when this method is accessed.</exception>
        public override void SetLength(long value)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("Base64Stream");
            }

            throw new NotSupportedException();
        }

        /// <summary>
        /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
        /// </summary>
        /// <param name="buffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source.</param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin storing the data read from the current stream.</param>
        /// <param name="count">The maximum number of bytes to be read from the current stream.</param>
        /// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null reference.</exception>
        /// <exception cref="NotSupportedException">Is raised when reading not supported.</exception>
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("Base64Stream");
            }
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if ((m_AccessMode & FileAccess.Read) == 0)
            {
                throw new NotSupportedException();
            }

            if (decodedDataStream!=null)
            {
                //read from it
                return decodedDataStream.Read(buffer, offset, count);
            }

            /* RFC 4648.
			
				Base64 is processed from left to right by 4 6-bit byte block, 4 6-bit byte block 
				are converted to 3 8-bit bytes.
				If base64 4 byte block doesn't have 3 8-bit bytes, missing bytes are marked with =. 
							
				Value Encoding  Value Encoding  Value Encoding  Value Encoding
					0 A            17 R            34 i            51 z
					1 B            18 S            35 j            52 0
					2 C            19 T            36 k            53 1
					3 D            20 U            37 l            54 2
					4 E            21 V            38 m            55 3
					5 F            22 W            39 n            56 4
					6 G            23 X            40 o            57 5
					7 H            24 Y            41 p            58 6
					8 I            25 Z            42 q            59 7
					9 J            26 a            43 r            60 8
					10 K           27 b            44 s            61 9
					11 L           28 c            45 t            62 +
					12 M           29 d            46 u            63 /
					13 N           30 e            47 v
					14 O           31 f            48 w         (pad) =
					15 P           32 g            49 x
					16 Q           33 h            50 y
					
				NOTE: 4 base64 6-bit bytes = 3 8-bit bytes				
					// |    6-bit    |    6-bit    |    6-bit    |    6-bit    |
					// | 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 |
					// |    8-bit         |    8-bit        |    8-bit         |
			*/

            int storedInBuffer = 0;

            // If we have decoded-buffered bytes, use them first.
            while (m_pDecodeReminder.Count > 0)
            {
                buffer[offset++] = m_pDecodeReminder.Dequeue();
                storedInBuffer++;
                count--;

                // We filled whole "buffer", no more room.
                if (count == 0)
                {
                    return storedInBuffer;
                }
            }

            // 1) Calculate as much we can decode to "buffer". !!! We need to read as 4x7-bit blocks.
            int rawBytesToRead = (int) Math.Ceiling(count/3.0)*4;

            byte[] readBuffer = new byte[rawBytesToRead];
            short[] decodeBlock = new short[4];
            byte[] decodedBlock = new byte[3];
            int decodeBlockOffset = 0;
            int paddedCount = 0;
            // Decode while we have room in "buffer".
            while (storedInBuffer < count)
            {
                int readedCount = m_pStream.Read(readBuffer, 0, rawBytesToRead);
                // We reached end of stream, no more data.
                if (readedCount == 0)
                {
                    // We have last block without padding 1 char.
                    if (decodeBlockOffset == 3)
                    {
                        buffer[offset + storedInBuffer++] = (byte) (decodeBlock[0] << 2 | decodeBlock[1] >> 4);
                        // See if "buffer" can accomodate 2 byte.
                        if (storedInBuffer < count)
                        {
                            buffer[offset + storedInBuffer++] =
                                (byte) ((decodeBlock[1] & 0xF) << 4 | decodeBlock[2] >> 2);
                        }
                        else
                        {
                            m_pDecodeReminder.Enqueue(
                                (byte) ((decodeBlock[1] & 0xF) << 4 | decodeBlock[2] >> 2));
                        }
                    }
                        // We have last block without padding 2 chars.
                    else if (decodeBlockOffset == 2)
                    {
                        buffer[offset + storedInBuffer++] = (byte) (decodeBlock[0] << 2 | decodeBlock[1] >> 4);
                    }
                        // We have invalid base64 data.
                    else if (decodeBlockOffset == 1)
                    {
                        throw new InvalidDataException("Incomplete base64 data..");
                    }

                    return storedInBuffer;
                }

                // Process readed bytes.
                for (int i = 0; i < readedCount; i++)
                {
                    byte b = readBuffer[i];

                    // If padding char.
                    if (b == '=')
                    {
                        decodeBlock[decodeBlockOffset++] = (byte) '=';
                        paddedCount++;
                        rawBytesToRead--;
                    }
                        // If base64 char.
                    else if (BASE64_DECODE_TABLE[b] != -1)
                    {
                        decodeBlock[decodeBlockOffset++] = BASE64_DECODE_TABLE[b];
                        rawBytesToRead--;
                    }
                        // Non-base64 char, skip it.
                    else {}

                    // Decode block full, decode bytes.
                    if (decodeBlockOffset == 4)
                    {
                        // Decode 3x8-bit block.
                        decodedBlock[0] = (byte) (decodeBlock[0] << 2 | decodeBlock[1] >> 4);
                        decodedBlock[1] = (byte) ((decodeBlock[1] & 0xF) << 4 | decodeBlock[2] >> 2);
                        decodedBlock[2] = (byte) ((decodeBlock[2] & 0x3) << 6 | decodeBlock[3] >> 0);

                        // Invalid base64 data. Base64 final quantum may have max 2 padding chars.
                        if (paddedCount > 2)
                        {
                            throw new InvalidDataException(
                                "Invalid base64 data, more than 2 padding chars(=).");
                        }

                        for (int n = 0; n < (3 - paddedCount); n++)
                        {
                            // We have room in "buffer", store byte there.
                            if (storedInBuffer < count)
                            {
                                buffer[offset + storedInBuffer++] = decodedBlock[n];
                            }
                                //No room in "buffer", store reminder.
                            else
                            {
                                m_pDecodeReminder.Enqueue(decodedBlock[n]);
                            }
                        }

                        decodeBlockOffset = 0;
                        paddedCount = 0;
                    }
                }
            }

            return storedInBuffer;
        }

        /// <summary>
        /// Encodes a sequence of bytes, writes to the current stream and advances the current position within this stream by the number of bytes written.
        /// </summary>
        /// <param name="buffer">An array of bytes. This method copies count bytes from buffer to the current stream.</param>
        /// <param name="offset">The zero-based byte offset in buffer at which to begin copying bytes to the current stream.</param>
        /// <param name="count">The number of bytes to be written to the current stream.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when this.Finish has been called and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="NotSupportedException">Is raised when reading not supported.</exception>
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (m_IsFinished)
            {
                throw new InvalidOperationException("Stream is marked as finished by calling Finish method.");
            }
            if (buffer == null)
            {
                throw new ArgumentNullException("buffer");
            }
            if (offset < 0 || offset > buffer.Length)
            {
                throw new ArgumentException("Invalid argument 'offset' value.");
            }
            if (count < 0 || count > (buffer.Length - offset))
            {
                throw new ArgumentException("Invalid argument 'count' value.");
            }
            if ((m_AccessMode & FileAccess.Write) == 0)
            {
                throw new NotSupportedException();
            }

            /* RFC 4648.
			
				Base64 is processed from left to right by 4 6-bit byte block, 4 6-bit byte block 
				are converted to 3 8-bit bytes.
				If base64 4 byte block doesn't have 3 8-bit bytes, missing bytes are marked with =. 
							
				Value Encoding  Value Encoding  Value Encoding  Value Encoding
					0 A            17 R            34 i            51 z
					1 B            18 S            35 j            52 0
					2 C            19 T            36 k            53 1
					3 D            20 U            37 l            54 2
					4 E            21 V            38 m            55 3
					5 F            22 W            39 n            56 4
					6 G            23 X            40 o            57 5
					7 H            24 Y            41 p            58 6
					8 I            25 Z            42 q            59 7
					9 J            26 a            43 r            60 8
					10 K           27 b            44 s            61 9
					11 L           28 c            45 t            62 +
					12 M           29 d            46 u            63 /
					13 N           30 e            47 v
					14 O           31 f            48 w         (pad) =
					15 P           32 g            49 x
					16 Q           33 h            50 y
					
				NOTE: 4 base64 6-bit bytes = 3 8-bit bytes				
					// |    6-bit    |    6-bit    |    6-bit    |    6-bit    |
					// | 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 5 6 |
					// |    8-bit         |    8-bit        |    8-bit         |
			*/

            int encodeBufSize = m_pEncodeBuffer.Length;

            // Process all bytes.
            for (int i = 0; i < count; i++)
            {
                m_pEncode3x8Block[m_OffsetInEncode3x8Block++] = buffer[offset + i];

                // 3x8-bit encode block is full, encode it.
                if (m_OffsetInEncode3x8Block == 3)
                {
                    m_pEncodeBuffer[m_EncodeBufferOffset++] = BASE64_ENCODE_TABLE[m_pEncode3x8Block[0] >> 2];
                    m_pEncodeBuffer[m_EncodeBufferOffset++] =
                        BASE64_ENCODE_TABLE[(m_pEncode3x8Block[0] & 0x03) << 4 | m_pEncode3x8Block[1] >> 4];
                    m_pEncodeBuffer[m_EncodeBufferOffset++] =
                        BASE64_ENCODE_TABLE[(m_pEncode3x8Block[1] & 0x0F) << 2 | m_pEncode3x8Block[2] >> 6];
                    m_pEncodeBuffer[m_EncodeBufferOffset++] =
                        BASE64_ENCODE_TABLE[(m_pEncode3x8Block[2] & 0x3F)];

                    // Encode buffer is full, write buffer to underlaying stream (we reserved 2 bytes for CRLF).
                    if (m_EncodeBufferOffset >= (encodeBufSize - 2))
                    {
                        if (m_AddLineBreaks)
                        {
                            m_pEncodeBuffer[m_EncodeBufferOffset++] = (byte) '\r';
                            m_pEncodeBuffer[m_EncodeBufferOffset++] = (byte) '\n';
                        }

                        m_pStream.Write(m_pEncodeBuffer, 0, m_EncodeBufferOffset);
                        m_EncodeBufferOffset = 0;
                    }

                    m_OffsetInEncode3x8Block = 0;
                }
            }
        }

        /// <summary>
        /// Completes encoding. Call this method if all data has written and no more data. 
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public void Finish()
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (m_IsFinished)
            {
                return;
            }
            m_IsFinished = true;

            // PADD left-over, if any. Write encode buffer to underlaying stream.
            if (m_OffsetInEncode3x8Block == 1)
            {
                m_pEncodeBuffer[m_EncodeBufferOffset++] = BASE64_ENCODE_TABLE[m_pEncode3x8Block[0] >> 2];
                m_pEncodeBuffer[m_EncodeBufferOffset++] =
                    BASE64_ENCODE_TABLE[(m_pEncode3x8Block[0] & 0x03) << 4];
                m_pEncodeBuffer[m_EncodeBufferOffset++] = (byte) '=';
                m_pEncodeBuffer[m_EncodeBufferOffset++] = (byte) '=';
            }
            else if (m_OffsetInEncode3x8Block == 2)
            {
                m_pEncodeBuffer[m_EncodeBufferOffset++] = BASE64_ENCODE_TABLE[m_pEncode3x8Block[0] >> 2];
                m_pEncodeBuffer[m_EncodeBufferOffset++] =
                    BASE64_ENCODE_TABLE[(m_pEncode3x8Block[0] & 0x03) << 4 | m_pEncode3x8Block[1] >> 4];
                m_pEncodeBuffer[m_EncodeBufferOffset++] =
                    BASE64_ENCODE_TABLE[(m_pEncode3x8Block[1] & 0x0F) << 2];
                m_pEncodeBuffer[m_EncodeBufferOffset++] = (byte) '=';
            }

            if (m_EncodeBufferOffset > 0)
            {
                m_pStream.Write(m_pEncodeBuffer, 0, m_EncodeBufferOffset);
            }
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Data.Storage/S3/S3UploadGuard.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Configuration;
using System.Linq;
using System.Threading.Tasks;

using Amazon;
using Amazon.S3;
using Amazon.S3.Model;

using ASC.Core;
using ASC.Data.Storage.Configuration;

namespace ASC.Data.Storage.S3
{
    public class S3UploadGuard
    {
        private string accessKey;
        private string secretAccessKey;
        private string bucket;
        private string region;
        private bool configErrors;
        private bool configured;

        public void DeleteExpiredUploadsAsync(TimeSpan trustInterval)
        {
            var task = new Task(() =>
            {
                DeleteExpiredUploads(trustInterval);
            }, TaskCreationOptions.LongRunning);

            task.Start();
        }

        private void DeleteExpiredUploads(TimeSpan trustInterval)
        {
            Configure();

            if (configErrors)
            {
                return;
            }

            using (var s3 = GetClient())
            {
                var nextKeyMarker = string.Empty;
                var nextUploadIdMarker = string.Empty;
                bool isTruncated;

                do
                {
                    var request = new ListMultipartUploadsRequest { BucketName = bucket };

                    if (!string.IsNullOrEmpty(nextKeyMarker))
                    {
                        request.KeyMarker = nextKeyMarker;
                    }

                    if (!string.IsNullOrEmpty(nextUploadIdMarker))
                    {
                        request.UploadIdMarker = nextUploadIdMarker;
                    }

                    var response = s3.ListMultipartUploads(request);

                    foreach (var u in response.MultipartUploads.Where(x => x.Initiated + trustInterval <= DateTime.UtcNow))
                    {
                        AbortMultipartUpload(u, s3);
                    }

                    isTruncated = response.IsTruncated;
                    nextKeyMarker = response.NextKeyMarker;
                    nextUploadIdMarker = response.NextUploadIdMarker;
                }
                while (isTruncated);

            }
        }

        private void AbortMultipartUpload(MultipartUpload u, AmazonS3Client client)
        {
            var request = new AbortMultipartUploadRequest
            {
                BucketName = bucket,
                Key = u.Key,
                UploadId = u.UploadId,
            };

            client.AbortMultipartUpload(request);
        }

        private AmazonS3Client GetClient()
        {
            var s3Config = new AmazonS3Config { UseHttp = true, MaxErrorRetry = 3, RegionEndpoint = RegionEndpoint.GetBySystemName(region) };
            return new AmazonS3Client(accessKey, secretAccessKey, s3Config);
        }

        private void Configure()
        {
            if (!configured)
            {
                var config = (StorageConfigurationSection)ConfigurationManagerExtension.GetSection(Schema.SECTION_NAME);
                var handler = config.Handlers.GetHandler("s3");
                if (handler != null)
                {
                    var props = handler.GetProperties();
                    bucket = props["bucket"];
                    accessKey = props["acesskey"];
                    secretAccessKey = props["secretaccesskey"];
                    region = props["region"];
                }
                configErrors = string.IsNullOrEmpty(CoreContext.Configuration.BaseDomain) //localhost
                                || string.IsNullOrEmpty(accessKey)
                                || string.IsNullOrEmpty(secretAccessKey)
                                || string.IsNullOrEmpty(bucket)
                                || string.IsNullOrEmpty(region);

                configured = true;
            }
        }
    }
}


<|start_filename|>common/ASC.Data.Backup/Storage/IBackupRepository.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

namespace ASC.Data.Backup.Storage
{
    internal interface IBackupRepository
    {
        void SaveBackupRecord(BackupRecord backupRecord);
        BackupRecord GetBackupRecord(Guid id);
        BackupRecord GetBackupRecord(string hash, int tenant);
        List<BackupRecord> GetExpiredBackupRecords();
        List<BackupRecord> GetScheduledBackupRecords();
        List<BackupRecord> GetBackupRecordsByTenantId(int tenantId);
        void DeleteBackupRecord(Guid id);

        void SaveBackupSchedule(Schedule schedule);
        Schedule GetBackupSchedule(int tenantId);
        List<Schedule> GetBackupSchedules();
        void DeleteBackupSchedule(int tenantId);
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Proxy/SIP_RegistrationBinding.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Proxy
{
    #region usings

    using System;
    using Message;
    using Stack;

    #endregion

    /// <summary>
    /// This class represents SIP registrar registration binding entry. Defined in RFC 3261 10.3.
    /// </summary>
    public class SIP_RegistrationBinding : IComparable
    {
        #region Members

        private readonly AbsoluteUri m_ContactURI;
        private readonly SIP_Registration m_pRegistration;
        private string m_CallID = "";
        private int m_CSeqNo = 1;
        private int m_Expires = 3600;
        private DateTime m_LastUpdate;
        private SIP_Flow m_pFlow;
        private double m_QValue = 1.0;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the last time when the binding was updated.
        /// </summary>
        public DateTime LastUpdate
        {
            get { return m_LastUpdate; }
        }

        /// <summary>
        /// Gets if binding has expired.
        /// </summary>
        public bool IsExpired
        {
            get { return TTL <= 0; }
        }

        /// <summary>
        /// Gets how many seconds binding has time to live. This is live calulated value, so it decreases every second.
        /// </summary>
        public int TTL
        {
            get
            {
                if (DateTime.Now > m_LastUpdate.AddSeconds(m_Expires))
                {
                    return 0;
                }
                else
                {
                    return (int) ((m_LastUpdate.AddSeconds(m_Expires) - DateTime.Now)).TotalSeconds;
                }
            }
        }

        /// <summary>
        /// Gets data flow what added this binding. This value is null if binding was not added through network or
        /// flow has disposed.
        /// </summary>
        public SIP_Flow Flow
        {
            get { return m_pFlow; }
        }

        /// <summary>
        /// Gets contact URI what can be used to contact the registration.
        /// </summary>
        public AbsoluteUri ContactURI
        {
            get { return m_ContactURI; }
        }

        /// <summary>
        /// Gets binding priority. Higher value means greater priority.
        /// </summary>
        public double QValue
        {
            get { return m_QValue; }
        }

        /// <summary>
        /// Gets Call-ID header field value which added this binding.
        /// </summary>
        public string CallID
        {
            get { return m_CallID; }
        }

        /// <summary>
        /// Gets CSeq header field sequence number value which added this binding.
        /// </summary>
        public int CSeqNo
        {
            get { return m_CSeqNo; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner registration.</param>
        /// <param name="contactUri">Contact URI what can be used to contact the registration.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>owner</b> or <b>contactUri</b> is null reference.</exception>
        internal SIP_RegistrationBinding(SIP_Registration owner, AbsoluteUri contactUri)
        {
            if (owner == null)
            {
                throw new ArgumentNullException("owner");
            }
            if (contactUri == null)
            {
                throw new ArgumentNullException("contactUri");
            }

            m_pRegistration = owner;
            m_ContactURI = contactUri;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Updates specified binding.
        /// </summary>
        /// <param name="flow">SIP data flow what updates this binding. This value is null if binding was not added through network or
        /// flow has disposed.</param>
        /// <param name="expires">Time in seconds when binding will expire.</param>
        /// <param name="qvalue">Binding priority. Higher value means greater priority.</param>
        /// <param name="callID">Call-ID header field value which added/updated this binding.</param>
        /// <param name="cseqNo">CSeq header field sequence number value which added/updated this binding.</param>
        public void Update(SIP_Flow flow, int expires, double qvalue, string callID, int cseqNo)
        {
            if (expires < 0)
            {
                throw new ArgumentException("Argument 'expires' value must be >= 0.");
            }
            if (qvalue < 0 || qvalue > 1)
            {
                throw new ArgumentException("Argument 'qvalue' value must be >= 0.000 and <= 1.000");
            }
            if (callID == null)
            {
                throw new ArgumentNullException("callID");
            }
            if (cseqNo < 0)
            {
                throw new ArgumentException("Argument 'cseqNo' value must be >= 0.");
            }

            m_pFlow = flow;
            m_Expires = expires;
            m_QValue = qvalue;
            m_CallID = callID;
            m_CSeqNo = cseqNo;

            m_LastUpdate = DateTime.Now;
        }

        /// <summary>
        /// Removes this binding from the registration.
        /// </summary>
        public void Remove()
        {
            m_pRegistration.RemoveBinding(this);
        }

        /// <summary>
        /// Converts <b>ContactUri</b> to valid Contact header value.
        /// </summary>
        /// <returns>Returns contact header value.</returns>
        public string ToContactValue()
        {
            SIP_t_ContactParam retVal = new SIP_t_ContactParam();
            retVal.Parse(new StringReader(m_ContactURI.ToString()));
            retVal.Expires = m_Expires;

            return retVal.ToStringValue();
        }

        /// <summary>
        /// Compares the current instance with another object of the same type. 
        /// </summary>
        /// <param name="obj">An object to compare with this instance.</param>
        /// <returns>Returns 0 if two objects equal, -1 if this instance is less or 1 this instance is greater.</returns>
        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                return -1;
            }
            if (!(obj is SIP_RegistrationBinding))
            {
                return -1;
            }

            // We must reverse values, because greater value mean higer priority.

            SIP_RegistrationBinding compareValue = (SIP_RegistrationBinding) obj;
            if (compareValue.QValue == QValue)
            {
                return 0;
            }
            else if (compareValue.QValue > QValue)
            {
                return 1;
            }
            else if (compareValue.QValue < QValue)
            {
                return -1;
            }

            return -1;
        }

        #endregion
    }
}

<|start_filename|>common/ASC.Core.Common/Security/Authorizing/PermissionProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Common.Security;
using ASC.Common.Security.Authorizing;

namespace ASC.Core.Security.Authorizing
{
    class PermissionProvider : IPermissionProvider
    {
        public IEnumerable<Ace> GetAcl(ISubject subject, IAction action, ISecurityObjectId objectId, ISecurityObjectProvider secObjProvider)
        {
            if (subject == null) throw new ArgumentNullException("subject");
            if (action == null) throw new ArgumentNullException("action");

            return CoreContext.AuthorizationManager
                .GetAcesWithInherits(subject.ID, action.ID, objectId, secObjProvider)
                .Select(r => new Ace(r.ActionId, r.Reaction));
        }
    }
}

<|start_filename|>module/ASC.Api/ASC.Api.Community/CommunityApiCommon.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.Api.Attributes;
using ASC.Core;
using ASC.Web.Community.Birthdays;
using ASC.Web.Studio.Utility.HtmlUtility;


namespace ASC.Api.Community
{
    public partial class CommunityApi
    {
        /// <summary>
        /// Subscribe or unsubscribe on birthday of user with the ID specified
        /// </summary>
        /// <short>Subscribe/unsubscribe on birthday</short>
        /// <param name="userid">user ID</param>
        /// <param name="onRemind">should be subscribed or unsubscribed</param>
        /// <returns>onRemind value</returns>
        /// <category>Birthday</category>
        [Create("birthday")]
        public bool RemindAboutBirthday(Guid userid, bool onRemind)
        {
            BirthdaysNotifyClient.Instance.SetSubscription(SecurityContext.CurrentAccount.ID, userid, onRemind);
            return onRemind;
        }

        [Create("preview")]
        public object GetPreview(string title, string content)
        {
            return new
            {
                title = HttpUtility.HtmlEncode(title),
                content = HtmlUtility.GetFull(content)
            };
        }

    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/App_Themes/default/css/ganttchart.css<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#studioPageContent .mainPageLayout:last-child {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    cursor: default;
 }

#moveTaskOutMilestone .small-button-container
{
    margin-top: 16px;
}
.gantt-hint
{
    display: inline-block;
    position: absolute;
    border: 1px solid #838383;
    padding: 4px;
    background-color: #fff;
    font-size:11px;
}
/*-------Gantt chart top panel-----*/
.gantt-chart-top-panel, .addition {
    margin: 0;
    background-color: #f2f2f2;
    position: relative;
}
.gantt-chart-top-panel {
    padding:24px;
    height: 32px;
    overflow: visible;
}
.addition {
    background-color:#E9E9E9;
    padding: 9px 24px;
    z-index: 5;
    height: 17px;
    position: relative;
    border-bottom: 1px solid #C8C8C8;
    overflow: hidden;
}
.gantt-chart-top-panel .menu-actions {
    float: left;
    width: auto;
    margin: 0;
}
.addition .tl-combobox .combobox-container {
    max-width: 300px;
    z-index: 10;
}
/*---buttons----*/
.gantt-chart-top-panel .menu-actions .menu-upload-button {
    margin-left: 4px;
}
.gantt-chart-top-panel.page-menu .undo-button,
.gantt-chart-top-panel.page-menu .redo-button,
.addition .print, .addition .refresh {
    padding: 0;
    display: inline-block;
    background-image: url("../images/gantt-icons.png");
    background-repeat: no-repeat;
}
.addition .print,
.addition .refresh {
    cursor: pointer;
    height: 16px;
    width: 16px;
    background-position:-38px 0;
}
.addition .refresh {
    margin-right: 8px;
    background-position: -38px -17px;
}
/*---*/
.gantt-chart-zoom-container.menu-actions,
.zoom-presets {
    float: right;
}
.gantt-chart-zoom-container.menu-actions {
    margin-left: 48px;
}
.gantt-chart-zoom-container.menu-actions .menu-upload-button {
    margin-left: 0;
}
.gantt-chart-zoom {
    min-width: 70px;
    height: 30px;
    background-color: transparent;
    border: none;
    margin-left: 2px;
    margin-right: 16px;
}

.zoom-presets {
    margin-left: 16px;
    padding-top: 8px;
    font-size: 12px;
    z-index: 6;
    position: relative;
}
.zoom-presets .preset {
    display: inline-block;
    margin-left: 16px;
    border-bottom: 1px dotted #333;
    cursor: pointer;
}
.zoom-presets .scale-conteiner {
    margin-left: 8px;
    width: 80px;
    display: inline-block;
}

    .zoom-presets .tl-combobox
    {
        max-width: 95%;
    }
    .zoom-presets .tl-combobox .combobox-title,
    .zoom-presets .tl-combobox .combobox-title .inner-text
    {
        max-width: 80px;
    }
.zoom-presets .combobox-title {
    display: inline-block;
    vertical-align: middle;
}

/*---filter panel-----*/

.filter-container {
    float:left;
}
.filter-container {
    width: 90%;
}
    .filter-container .task-filter-container {
        margin-right: 48px;
        display: inline-block;
        vertical-align: text-top;
        position: relative;
        z-index:4;
    }

.filter-container .tl-combobox .combobox-container .combobox-options
{
    max-height: 250px;
}
    .filter-container .tl-combobox .combobox-container .combobox-options .option-item.separator {
        border-top: 1px dotted #838383;
        padding-top: 4px;
        margin-top: 5px;
    }
    .filter-container input,
    .filter-container label {
        cursor: pointer;
    }
    .filter-container input {
        float:left;
        margin: 2px 6px 0 0;
        padding: 0;
    }
.task-filter-container .tl-combobox
{
    width: 100%;
    max-width: 250px;
}

.mode-button-container {
    float: right;
}
.HelpCenterSwitcher
{
    margin:0 0 0 8px;
}

.gantt-legend.studio-action-panel {
    padding: 16px 22px;
    right: 11px;
    top: 152px;
    max-width: 426px;
}
    .gantt-legend.studio-action-panel .to-full-help
    {
        position: absolute;
        right: 24px;
        top: 18px;
    }
    .gantt-legend .header-base
    {
        margin-bottom: 12px;
    }
    .gantt-legend.studio-action-panel .dropdown-content.cell
    {
        float:left;
        margin: 8px 16px 16px 0;
        width: 184px;
    }
    .gantt-legend.studio-action-panel .dropdown-content .dropdown-item,
    .gantt-legend.studio-action-panel .gantt-colors div
    {
        margin-top: 3px;
        text-decoration: none;
        cursor: default;
        padding-left: 24px;
        background: transparent url("../images/gantt-legend.png") center no-repeat;
    }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.edit {
            background-position: 0 2px;
        }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.delete {
            background-position: 0 -22px;
        }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.close {
            background-position: 0 -46px;
        }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.addlink {
            background-position: 0 -70px;
        }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.addMilestoneTask {
            background-position: 0 -94px;
        }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.fitToScreen {
            background-position: 0 -118px;
        }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.open {
            background-position: 0 -142px;
        }
        .gantt-legend.studio-action-panel .dropdown-content .dropdown-item.responsible {
            background-position: 0 -166px;
        }
       

.gantt-legend.studio-action-panel .gantt-colors td
{
    width: 184px;
}
.gantt-legend.studio-action-panel .gantt-colors
{
    margin-top: 8px;
    margin-bottom: 16px;
}
    .gantt-legend.studio-action-panel .gantt-colors td
    {
        padding-right:11px;
    }
        .gantt-legend.studio-action-panel .gantt-colors td div
        {
            width: 134px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
.gantt-legend.studio-action-panel .gantt-colors .closed
{
    background-position: 0 -192px;
}
.gantt-legend.studio-action-panel .gantt-colors .create
{
    background-position: 0 -264px;
}
.gantt-legend.studio-action-panel .gantt-colors .active
{
    background-position: 0 -216px;
}
.gantt-legend.studio-action-panel .gantt-colors .invalid
{
    background-position: 0 -288px;
}
.gantt-legend.studio-action-panel .gantt-colors .overdue
{
    background-position: 0 -240px;
}
.gantt-legend.studio-action-panel .gantt-colors .priority
{
    background-position: 0 -312px;
}
.gantt-legend.studio-action-panel .gantt-colors .infinity {
    background-position: 0 -336px;
}
.gantt-legend.studio-action-panel .gantt-colors .key {
    background-position: 0 -359px;
}
/*------actions help panel ------*/
.gantt-actions
{
    padding:16px;
    position: fixed;
    z-index: 5;
    bottom: 24px;
    right: 24px;
}
    .gantt-actions .cancelButton,
    .gantt-empty-screen .cancelButton
    {
        background-color: transparent;
        position: absolute;
        right: 10px;
        top: 10px;
    }
    .gantt-actions td {
        border:none;
        font-size: 11px;
        padding-top: 5px;
        width: 250px;
        vertical-align: top;
    }
        .gantt-actions tr:first-child td
        {
            padding-top:0;
        }
        .gantt-actions tr td:last-child
        {
            padding-left: 16px;
            font-style:italic;
        }

/*---mode buttons---*/ /*--locked--*/
    .mode-button-container .mode {
        display: inline-block;
        cursor: pointer;
        height: 16px;
        width: 16px;
        background: transparent url("../images/gantt_mode_butts.png") no-repeat;
    }
    .mode-button-container .mode.full-screen {
        background-position: 0 -14px;
    }
    .mode-button-container .mode.full-screen.active {
        background-position: 0 0;
    }
    .mode-button-container .mode.left-panel {
        background-position: -14px -14px;
    }
    .mode-button-container .mode.left-panel.active {
        background-position: -14px 0;
    }

.vertical-align-top {
    vertical-align: top;
}
#parentTaskName {
    display: inline-block;
    max-width: 280px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}
.link-type-select {
    margin-top: 12px;
}
.task-select {
    margin-top: 16px;
}
/*---change status combobox---*/
#statusListContainer.studio-action-panel, #statusListTaskContainer.studio-action-panel {
    padding: 8px 20px 8px 6px;
}
.studio-action-panel #statusList li.dropdown-item {
    padding-left: 22px;
    background: url('../images/projects_entity_statuses.png') no-repeat 2px center;
}

.studio-action-panel #statusListTask li.dropdown-item {
    padding-left: 22px;
}
.studio-action-panel #statusList li.dropdown-item.open {
    background-position: 0 -58px;
}
.studio-action-panel #statusList li.dropdown-item.closed {
	background-position: 0 -79px;
}

/*-----Responsible selector------*/
#responsiblesContainer.studio-action-panel .dropdown-content
{
    max-height: 232px;
    max-width: 190px;
}
.studio-action-panel .dropdown-content li.check-value
{
    padding-top: 10px;
    white-space: nowrap;
}
    .studio-action-panel .dropdown-content li.check-value input
    {
        padding: 0;
        margin-right: 8px;
    }
    .studio-action-panel .dropdown-content li.check-value input,
    .studio-action-panel .dropdown-content li.check-value label{
            cursor: pointer;
            vertical-align: middle;
    }
.studio-action-panel .small-button-container
{
    margin-top: 16px;
}
/*----Gantt chart---*/
.gantt-canvas, .fake-background {
    top: 164px;
    position: absolute;
}
.fake-background{
    width:30px;
}
.fake-background.gray{
    background-color:#f2f2f2;
}
.gantt-canvas {
    left: 24px;
    z-index: 0;
}
.gantt-canvas.layer1 {
    z-index: 1;
}
       
.hitStyle {
    cursor: pointer;
}
.defaultstyle {
    cursor: default;
}

.gantt-empty-screen {
	padding: 24px 24px 24px 153px;
	position: absolute;
	width: 500px;
	left: 50%;
	margin-left: -320px;
	top: 24%;
}

.gantt-empty-screen:after {
	position: absolute;
	content: "";
	background: url("../images/icon_empty_gantt.png") no-repeat 0px 0px !important;
	width: 150px;
	height: 150px;
	top: 50%;
	left: 24px;
	margin-top: -75px;
}

.gantt-empty-screen-layout {
	position:absolute;
	left:320px;
	top:163px;
	right: 0;
	bottom: 0;
	z-index: 2;
	overflow: hidden;
	display: none;
}

.gantt-empty-screen .header-empty-screen {
    font-size: 14px;
    font-weight: bold;
	margin-top: 20px;
	margin-left: 40px;
}
.gantt-empty-screen p{
    max-width: 500px;
    line-height: 16px;
	margin-left: 40px;
	margin-top: 15px;
}

@media print
{
    @page { size: landscape; }
    .studio-top-panel,
    .gantt-chart-top-panel,
    .mode-button-container{
        display: none;
    }
    .gantt-canvas, .fake-background {
        top: 44px;
        position: absolute;
    }
}

/*------lined panel with checkboxes-------*/

.studio-action-panel .dropdown-content.lined {
    margin-top: 16px;
    max-height:250px;
}
.studio-action-panel .lined .dropdown-item {
    border-top: 1px solid #D1D1D1;
    cursor: default;
}
.studio-action-panel .lined .dropdown-item:hover {
    text-decoration: none;
}
.studio-action-panel .lined .dropdown-item input {
   margin: 5px 6px 0 0;
}
    .studio-action-panel .lined .dropdown-item label {
        vertical-align: top;
        cursor: pointer;
    }

/*-----left panel------*/

span {
    -moz-user-select: none; /*	mozilla fix  */
}

.left-panel {
    top           : 224px;
    left          : 24px;
    width         : 1200px;
    height        : 100px;
    position      : absolute;
    overflow-x    : hidden;
    overflow-y    : hidden;
    background    : #F3F3F3;
	z-index       : 1; 
    border-right  : 1px solid #CCCCCC; 
	
 /*border        : 1px solid black;*/
 
    -moz-user-select: none; /*	mozilla fix  */
}

div.header-element {
    left          : 24px;
    top           : 164px;
    /*width         : 100%;*/
    height        : 60px;
    position      : absolute;
    background    : #D3D3D3;
    border-right  : 1px solid #D3D3D3;
	z-index       : 2;
	/*overflow      : hidden;*/
	/*border        : 1px solid black;*/

    -moz-user-select: none; /*	mozilla fix  */
}

div.header-element-down {
    background    : #F3F3F3;
    position      : absolute;
    left          : 0;
    width         : 100%;
    top           : 46px;
    height        : 14px;
	
    -moz-user-select: none; /*	mozilla fix  */
}

div.filter-projects {
    left          : 25px;
    top           : 6px;
    width         : 38px;
    height        : 30px;
    position      : absolute;
    background    : #F2F2F2;
    border        : 1px solid #BFBFBF;
    cursor        : pointer;
   
    background-image: linear-gradient(rgb(243, 243, 243) 0%, rgb(222, 222, 222) 100%);

    border-bottom-color: rgb(191, 191, 191);
    border-bottom-left-radius: 3px;
    border-bottom-right-radius: 3px;
    border-bottom-style: solid;
    border-bottom-width: 1px;
    border-collapse: separate;
    border-left-color: rgb(191, 191, 191);
    border-left-style: solid;
    border-left-width: 1px;
    border-right-color: rgb(191, 191, 191);
    border-right-style: solid;
    border-right-width: 1px;
    border-top-color: rgb(191, 191, 191);
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;
    border-top-style: solid;
    border-top-width: 1px;
}
div.filter-projects:after{
    position:absolute;
    content: "";
	top: 8px;
	left: 9px;
    width:27px;
    height:22px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -8px -32px;
}
div.filter-projects:hover:after{
    position:absolute;
    content: "";
	top: 8px;
	left: 9px;
    width:27px;
    height:22px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -8px -32px;
}

div.filter-projects:hover {
	background-color: #ebebeb;
	background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f3f3f3), to(#ebebeb));
}

div.filter-fields {
    width         : 20px;
    height        : 20px;
    position      : absolute;
    background    : #F2F2F2;
    cursor        : pointer;
    font		  : normal 13px 'Open Sans', sans-serif;
    color         : #666666;
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;
}
div.filter-fields:after{
    position:absolute;
    content: "";
	top: 5px;
	left: 5px;
    width:11px;
    height:11px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -40px -10px;
}
div.filter-fields:hover:after{
    position:absolute;
    content: "";
	top: 5px;
	left: 5px;
    width:11px;
    height: 11px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -40px -34px;
}

div.filter-fields-disable {
    width         : 20px;
    height        : 20px;
    position      : absolute;
    background    : #F2F2F2;
    cursor        : default;
    font		  : normal 13px 'Open Sans', sans-serif;
    color         : #666666;
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;
}
div.filter-fields-disable:after{
    position:absolute;
    content: "";
	top: 5px;
	left: 5px;
    width:11px;
    height:11px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -40px -10px;
}


div.filter-hidden-fields {
    width         : 20px;
    height        : 20px;
    position      : absolute;
    background    : #F2F2F2;
    cursor        : pointer;
    font		  : normal 13px 'Open Sans', sans-serif;
    color         : #666666;
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;
}
div.filter-hidden-fields:after{
    position:absolute;
    content: "";
	top: 5px;
	left: 5px;
    width:11px;
    height:11px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -64px -10px;
}
div.filter-hidden-fields:hover:after{
    position:absolute;
    content: "";
	top: 5px;
	left: 5px;
    width:11px;
    height: 11px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -64px -34px;
}

span.gantt-cell-pointer {
    cursor: pointer  !important;
	text-decoration: none  !important;
}
span.gantt-cell-pointer:hover {
	text-decoration: none  !important;
}

span.gantt-cell-disable {
    cursor: default  !important;
	text-decoration: none  !important;
}
span.gantt-cell-disable:hover {
    text-decoration: none  !important;
}

div.line-element {
    left          : 0;
    width         : 100%;
    position      : absolute;
    background    : #F3F3F3;
    z-index       : 3;   
	border-bottom : 1px solid #CCCCCC;
    border-top    : 1px solid #CCCCCC;
    /*cursor        : pointer;*/
	font		  : normal 12px 'Open Sans', sans-serif;	
}

span.name-column {
    cursor        : pointer;
    left          : 10px;
    top           : 50%;
    position      : absolute;
    max-width     : 170px;
    text-overflow : ellipsis;
    white-space   : nowrap;
    display       : inline-block;
    overflow      : hidden;
    font-size     : 12px;
	background    : transparent;
	margin-top    : -10px;
    /*border: 1px solid #4b0082;*/
}
span.name-column:hover {
    text-decoration: underline;
}

span.name-column-counter {
	left		 : 170px;
	top          : 50%;
	position     : absolute;
	text-overflow: ellipsis;
	white-space  : nowrap;
	display      : inline-block;
	/* overflow: hidden; */
	font: normal 12px 'Open Sans', sans-serif;
	/* border: 1px solid #4b0082; */
	margin-top    : -10px;
	width         : 75px;
    text-align	  : right;
}

div.button-colapse-open {
    cursor        : pointer;
    position      : relative;
    left          : 242px;
	top			  : 50%;
	width         : 20px; 
	height        : 20px;
	background    : transparent;
	margin-top    : -10px;	
}
div.button-colapse-open:after{
	content       : "";
    cursor        : pointer;
    position      : absolute;
	margin-top	  : -2px;
	margin-left	  : -4px;
	left		  : 50%;
	top			  : 50%;
	width         : 0; 
	height        : 0; 
	border-left   : 4px solid transparent;
	border-right  : 4px solid transparent;	
	border-top    : 5px solid #818181;
}
div.button-colapse-open:hover:after {
	border-left   : 4px solid transparent;
	border-right  : 4px solid transparent;	
	border-top    : 5px solid #666666;
}

div.button-colapse-close {
    cursor        : pointer;
    position      : relative;
    left          : 242px;
    top           : 50%;
	width         : 20px; 
	height        : 20px;
	background    : transparent;	
	margin-top    : -10px;
}
div.button-colapse-close:after{
	content       : "";
    cursor        : pointer;
    position      : absolute;
	margin-top	  : -5px;
	margin-left	  : -1px;
	left		  : 50%;
	top			  : 50%;
	width         : 0; 
	height        : 0; 
	border-top     : 4px solid transparent;
	border-bottom  : 4px solid transparent;	
	border-left    : 5px solid #818181;
}
div.button-colapse-close:hover:after {
	border-top     : 4px solid transparent;
	border-bottom  : 4px solid transparent;	
	border-left    : 5px solid #666666;
}

span.name-column-resp {
    cursor        : pointer;
    left          : 245px;
    top           : 50%;
    position      : absolute;
    max-width     : 140px;
    text-overflow : ellipsis;
    white-space   : nowrap;
    display       : inline-block;
    overflow      : hidden;
    font-size     : 12px;
	margin-top    : -10px;
    /*border: 1px solid #4b0082;*/
}
span.name-column-resp:hover {
    text-decoration: underline;
}

span.name-column-begin-date{
    cursor        : pointer;
    left          : 390px;
    top           : 50%;
    position      : absolute;
    /*text-align	  : right; */
    white-space   : pre-wrap;
    display       : inline-block;
    overflow      : hidden;
    font-size     : 12px;
	max-width     : 85px;
	margin-top    : -10px;
    /*border: 1px solid #4b0082;*/
}
span.name-column-begin-date:hover {
    text-decoration: underline;
}

span.name-column-end-date{
    cursor        : pointer;
    left          : 465px;
    top           : 50%;
    position      : absolute;
   /* text-align	  : right; */
    white-space   : pre-wrap;
    display       : inline-block;
    overflow      : hidden;
    font-size     : 12px;
	max-width     : 85px;
	margin-top    : -10px;
    /*border: 1px solid #4b0082;*/
}
span.name-column-end-date:hover {
    text-decoration: underline;
}

span.name-column-status {
    cursor        : pointer;
    left          : 250px;
    top           : 50%;
    position      : absolute;
    max-width     : 100px;
    text-overflow : ellipsis;
    white-space   : nowrap;
    display       : inline-block;
    overflow      : hidden;
    font-size     : 12px;
	margin-top    : -10px;
    /*border: 1px solid #4b0082;*/
}
span.name-column-status:hover {
    text-decoration: underline;
}

span.name-column-priority {
    /*cursor      : pointer;*/
    left          : 250px;
    top           : 50%;
    position      : absolute;
    max-width     : 60px;
    text-overflow : ellipsis;
    white-space   : nowrap;
    display       : inline-block;
    overflow      : hidden;
    font-size     : 12px;
	margin-top    : -10px;
    /*border: 1px solid #4b0082;*/
}
span.name-column-priority:hover {
    /*text-decoration: underline;*/
}

div.line-project {
    font		  : normal 16px Semibold, sans-serif;
}

div.row-tab {
    width         : 35px;
    height        : 20px;
    position      : absolute;
    background    : #F2F2F2;
    cursor        : pointer;
	font-size	  : 12px;
    font-weight   : normal;
    font-family   : Open Sans;
    color         : #666666;
    padding-left: 5px;
    border-top-left-radius: 3px;
    border-top-right-radius: 3px;

    -moz-user-select: none; /*	mozilla fix  */

}
div.row-tab:hover {
    color         : #333333;
}

div.cell-text-button {

}

div.cell-close-button {    
    width         : 10px;
    height        : 10px;
    position	  : absolute;
    right         : 5px;
    top           : 5px;
    cursor        : pointer;
	background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -87px -11px;
}
div.cell-close-button:hover {    
	background-position: -87px -35px;
}

.project-edit {
	font		  : normal 16px Semibold, sans-serif;
}
.milestone-edit {
	font: normal 12px 'Open Sans', sans-serif;
	font-weight: bold;
}
.task-edit {
	font		  : normal 12px 'Open Sans', sans-serif;
}

div.gantt-splitter {
    background: transparent;
    width: 16px;
    position: absolute;
    z-index: 5;
    height: 100%;
    left: 200px;
    top: 0;
    cursor: ew-resize;
}

div.gantt-splitter-fake {
    background: #F2F2F2;
    width: 16px;
    z-index: 4;
    height: 100%;
    top: 0;
    cursor: ew-resize;
    position: relative;
    margin-left:auto;
    margin-right:0;
}

div.gantt-splitter:after{
    position: relative;
	float: left;
    content: "";
	top: 50%;
	left: 50%;
    width:15px;
    height:15px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -110px -8px;
	margin-left:-2px;
}
div.gantt-splitter:hover:after{
    position: relative;
	float: left;
    content: "";
	top: 50%;
	left: 50%;
    width:15px;
    height: 15px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -110px -32px;	
	margin-left:-2px;
}

.button-drag-drop {
    top:		0;
    width:      10px;
    height:     100%;
    background: transparent;
    position:   absolute;
    left:       2px;
    cursor:     pointer;
}

.button-drag-drop:after{
    position: absolute;
    content: "";
	top: 25%;
	left: 50%;
    width: 15px;
    height: 15px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -110px -8px;
	margin-left:-2px;
}

.element-drag-drop {
	font: normal 12px 'Open Sans', sans-serif;
    position: absolute;
    width: 180px;
    background: white;
    border: 2px solid #bdda7f;
    box-shadow: 2px 2px 4px rgba(0,0,0,0.25);
}

.element-drag-drop:after{
    position:absolute;
    content: "";
	top: 25%;
	left: 10px;
    height:15px;
    background-image: url("../images/gantt_icons_left_panel.png");
	background-position: -110px -8px;
	margin-left:-2px;
}
.icon-private {}
.icon-private:after {
    position: absolute;
    content: "";
	background: url('../../../../../skins/default/images/svg/projects/lockorange.svg') no-repeat;
    background-size:85% 85%;
	width: 16px;
	height: 16px;
	top: 25%;
}
.blocked-panel{
	z-index: 1000;
	position: absolute;
	background: gray;
	opacity: 0;
	top: 48px;
	left: 0;
	bottom: 0;
	right: 0;
}

#showChoosedFields {
    margin:6px 0 12px 12px;
}

nav, aside, main {
    height: calc(100vh - 48px) !important;
    height: calc(var(--vh, 1vh) * 100 - 48px) !important;
}

header {
    margin: 0 !important;
}

main {
    padding: 0 !important;
}

.page-content {
    margin: 0 !important;
    padding: 0 !important;
    overflow: auto !important;
}

<|start_filename|>web/studio/ASC.Web.Studio/js/asc/core/groupselector.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


if (typeof (ASC) == "undefined")
    ASC = { };
if (typeof (ASC.Controls) == "undefined")
    ASC.Controls = { };

ASC.Controls.GroupSelector = function(selectorID, mobileVersion, withGroupEveryone, withGroupAdmin) {
    this.ID = selectorID;

    this.SelectedGroup = null;
    this.Groups = [];
    this._groups = [];

    this.DisabledGroupIds = new Array();
    this.MobileVersion = mobileVersion === true;

    var _groupSelector = this;

    this.AdditionalFunction = null;

    this.Open = function() {

        this.ClearFilter();

        if (this.MobileVersion)
            return;

        var pos = jq("#groupSelectorBtn_" + this.ID).position();

        jq("#groupSelectorContainer_" + this.ID).css({
                display: "block"
            });

        jq("#grpselector_filter_" + this.ID).focus();
    };

    this.Close = function() {
        if (!this.MobileVersion)
            jq("#groupSelectorContainer_" + this.ID).hide();

        if (this.SelectedGroup != null && this.AdditionalFunction != null)
            this.AdditionalFunction(this.SelectedGroup);
    };

    this.SuggestGroups = function() {
        if (this.MobileVersion)
            return;

        var text = jq("#grpselector_filter_" + this.ID).val().trim().toLowerCase();
        if (text == "") {
            this.ClearFilter();
        }

        var filtered = [];
        for (var i = 0; i < this._groups.length; i++) {
            if (this._groups[i].Name.toLowerCase().indexOf(text) >= 0)
                filtered.push(this._groups[i]);
        }

        jq("#grpselector_groupList_" + this.ID).html(jq.tmpl("groupSelectorListTemplate", { Groups: filtered }));
    };

    this.HideGroup = function(groupID, hide) {
        if (hide == undefined)
            hide = true;

        if (hide) {
            this.DisabledGroupIds.push(groupID);
        } else {
            var tmpDisabledGroup = [];
            for (var i = 0; i < this.DisabledGroupIds.length; i++) {
                if (this.DisabledGroupIds[i] != groupID) {
                    tmpDisabledGroup.push(this.DisabledGroupIds[i]);
                }
            }
            this.DisabledGroupIds = tmpDisabledGroup;
        }

        this.ClearFilter();
    };

    this.DisplayAll = function() {
        this.DisabledGroupIds = new Array();
        this.ClearFilter();
    };

    this.ClearFilter = function() {
        this._groups = [];
        for (var i = 0, n = _groupSelector.Groups.length; i < n; i++) {
            var disabled = false;
            for (var k = 0, m = _groupSelector.DisabledGroupIds.length; k < m; k++) {
                if (this.DisabledGroupIds[k] == _groupSelector.Groups[i].Id) {
                    disabled = true;
                    break;
                }
            }
            if (!disabled) {
                this._groups.push(_groupSelector.Groups[i]);
            }
        }

        if (this.MobileVersion) {
            jq("#grpselector_mgroupList_" + this.ID).html(jq.tmpl("groupSelectorListTemplate", { Groups: this._groups }));
            jq("#grpselector_mgroupList_" + this.ID + " option[value='" + this.SelectedGroup + "']").attr("selected", "selected");
            return;
        }

        jq("#grpselector_filter_" + this.ID).val("");
        jq("#grpselector_groupList_" + this.ID).html(jq.tmpl("groupSelectorListTemplate", { Groups: this._groups }));
    };

    if (this.MobileVersion === true) {
        this.Groups.push(ASC.Resources.Master.GroupSelector_MobileVersionGroup);
    }
    if (withGroupEveryone) {
        this.Groups.push(ASC.Resources.Master.GroupSelector_WithGroupEveryone);
    }
    if (withGroupAdmin) {
        this.Groups.push(ASC.Resources.Master.GroupSelector_WithGroupAdmin);
    }

    Array.prototype.push.apply(this.Groups, window.GroupManager.getAllGroups().map(function(group) {
        return {
            Id: group.id,
            Name: group.name
        };
    }));

    jq("#grpselector_filter_" + this.ID).on("keyup", function() { _groupSelector.SuggestGroups(); });
    jq("#grpselector_clearFilterBtn_" + this.ID).on("click", function() { _groupSelector.ClearFilter(); });

    jq(document).click(function(event) {
        if (!jq((event.target) ? event.target : event.srcElement).parents().addBack().is("#groupSelectorBtn_" + selectorID + ", #groupSelectorContainer_" + selectorID))
            jq("#groupSelectorContainer_" + selectorID).hide();
    });

    if (mobileVersion) {
        jq("#grpselector_mgroupList_" + selectorID).bind("change", function() {
            var grpId = jq(this).val();
            if (grpId == "" || grpId == "-1") return;
            jq(_groupSelector.Groups).each(function(i, gpr) {
                if (gpr.Id == grpId) {
                    _groupSelector.SelectedGroup = gpr;
                    return false;
                }
            });

            _groupSelector.Close();
        });
    } else {
        jq("#groupSelectorBtn_" + selectorID).bind("click", function(evnt) {
            _groupSelector.Open();
        });

        jq("#grpselector_clearFilterBtn_" + selectorID).bind("click", function() {
            _groupSelector.ClearFilter();
        });

        jq("#grpselector_groupList_" + selectorID).bind("click", function(evnt) {
            if (!jq(evnt.target).is("div.group"))
                return;

            var grpId = jq(evnt.target).attr("data");
            if (grpId == "") return;
            jq(_groupSelector.Groups).each(function(i, gpr) {
                if (gpr.Id == grpId) {
                    _groupSelector.SelectedGroup = gpr;
                    return false;
                }
            });

            _groupSelector.Close();
        });
    }

};

<|start_filename|>web/studio/ASC.Web.Studio/Products/Projects/Core/Engine/ProjectsReassign.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Projects.Core.Domain;
using ASC.Projects.Engine;

using Autofac;

namespace ASC.Web.Projects.Core.Engine
{
    public class ProjectsReassign
    {
        private ProjectEngine ProjectEngine { get; set; }
        private MilestoneEngine MilestoneEngine { get; set; }
        private TaskEngine TaskEngine { get; set; }
        private SubtaskEngine SubtaskEngine { get; set; }
        private List<Project> FromUserProjects { get; set; }
        private List<Project> ToUserProjects { get; set; }

        public ProjectsReassign()
        {
            FromUserProjects = new List<Project>();
        }

        public void Reassign(Guid fromUserId, Guid toUserId)
        {
            using (var scope = DIHelper.Resolve(true))
            {
                var factory = scope.Resolve<EngineFactory>();
                ProjectEngine = factory.ProjectEngine;
                MilestoneEngine = factory.MilestoneEngine;
                TaskEngine = factory.TaskEngine;
                SubtaskEngine = factory.SubtaskEngine;

                FromUserProjects = ProjectEngine.GetByParticipant(fromUserId).ToList();
                ToUserProjects = ProjectEngine.GetByParticipant(toUserId).ToList();

                ReplaceTeam(fromUserId, toUserId);
                ReassignProjectManager(fromUserId, toUserId);
                ReassignMilestones(fromUserId, toUserId);
                ReassignTasks(fromUserId, toUserId);
                ReassignSubtasks(fromUserId, toUserId);
            }
        }

        private void ReplaceTeam(Guid fromUserId, Guid toUserId)
        {
            foreach (var project in FromUserProjects)
            {
                var teamSecurity = ProjectEngine.GetTeamSecurity(project, fromUserId);

                if (!ToUserProjects.Exists(r => r.ID == project.ID))
                {
                    ProjectEngine.AddToTeam(project, toUserId, false);
                    ProjectEngine.SetTeamSecurity(project, toUserId, teamSecurity);
                }

                ProjectEngine.RemoveFromTeam(project, fromUserId, false);
            }
        }

        private void ReassignProjectManager(Guid fromUserId, Guid toUserId)
        {
            var filter = new TaskFilter { UserId = fromUserId, ProjectStatuses = new List<ProjectStatus> { ProjectStatus.Open, ProjectStatus.Paused } };
            var projects = ProjectEngine.GetByFilter(filter);

            foreach (var project in projects)
            {
                project.Responsible = toUserId;
                ProjectEngine.SaveOrUpdate(project, false);
            }
        }

        private void ReassignMilestones(Guid fromUserId, Guid toUserId)
        {
            var filter = new TaskFilter { UserId = fromUserId, MilestoneStatuses = new List<MilestoneStatus> { MilestoneStatus.Open } };
            var milestones = MilestoneEngine.GetByFilter(filter);

            foreach (var milestone in milestones)
            {
                AddToTeam(milestone.Project, toUserId);
                milestone.Responsible = toUserId;
                MilestoneEngine.SaveOrUpdate(milestone, false);
            }
        }

        private void ReassignTasks(Guid fromUserId, Guid toUserId)
        {
            var tasks = TaskEngine.GetByResponsible(fromUserId, TaskStatus.Open);

            foreach (var task in tasks.Where(r => r.Responsibles.Any()))
            {
                AddToTeam(task.Project, toUserId);
                task.Responsibles = task.Responsibles.Where(r => r != fromUserId).ToList();
                task.Responsibles.Add(toUserId);
                TaskEngine.SaveOrUpdate(task, null, false);
            }
        }

        private void ReassignSubtasks(Guid fromUserId, Guid toUserId)
        {
            var tasks = SubtaskEngine.GetByResponsible(fromUserId, TaskStatus.Open);

            foreach (var task in tasks)
            {
                AddToTeam(task.Project, toUserId);
                foreach (var subtask in task.SubTasks)
                {
                    subtask.Responsible = toUserId;
                    SubtaskEngine.SaveOrUpdate(subtask, task);
                }
            }
        }

        private void AddToTeam(Project project, Guid userId)
        {
            if (!FromUserProjects.Exists(r => r.ID == project.ID) && !ToUserProjects.Exists(r => r.ID == project.ID))
            {
                ProjectEngine.AddToTeam(project, userId, false);
                ToUserProjects.Add(project);
            }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Classes/UrlConstant.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;

namespace ASC.Web.CRM.Classes
{
    public static class UrlConstant
    {
        public const String Filter = "filter";
        public const String Tag = "tag";
        public const String Status = "status";
        public const String ID = "id";
        public const String Action = "action";
        public const String PageNumber = "page";
        public const String Version = "version";
        public const String Search = "searchbytext";
        public const String ReportType = "reportType";
        public const String UserID = "userID";
        public const String View = "view";
        public const String ContactID = "contactID";
        public const String Type = "type";
        public const String FullName = "fullname";
        public const String Email = "email";
        public const String LinkMessageId = "linkMessageId";

    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Data/Contracts/MailFolderData.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Runtime.Serialization;

using ASC.Mail.Enums;

namespace ASC.Mail.Data.Contracts
{
    [Serializable]
    [DataContract(Namespace = "", Name = "Folder")]
    public class MailFolderData
    {
        [DataMember(IsRequired = true, Name = "id")]
        public FolderType Id { get; set; }

        [DataMember(IsRequired = true, Name = "unread")]
        public int UnreadCount { get; set; }

        [DataMember(IsRequired = true, Name = "unread_messages")]
        public int UnreadMessagesCount { get; set; }

        [DataMember(IsRequired = true, Name = "total_count")]
        public int TotalCount { get; set; }

        [DataMember(IsRequired = true, Name = "total_messages_count")]
        public int TotalMessgesCount { get; set; }

        [DataMember(IsRequired = true, Name = "time_modified")]
        public DateTime TimeModified { get; set; }
    }
}


<|start_filename|>module/ASC.Files.Thirdparty/Dropbox/DropboxProviderInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Web;

using ASC.Common.Caching;
using ASC.Common.Web;
using ASC.Core;
using ASC.FederatedLogin;
using ASC.Files.Core;

using Dropbox.Api.Files;

namespace ASC.Files.Thirdparty.Dropbox
{
    [DebuggerDisplay("{CustomerTitle}")]
    public class DropboxProviderInfo : IProviderInfo, IDisposable
    {
        private readonly OAuth20Token _token;
        private readonly FolderType _rootFolderType;
        private readonly DateTime _createOn;

        internal DropboxStorage Storage
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    var key = "__DROPBOX_STORAGE" + ID;
                    var wrapper = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                    if (wrapper == null || !wrapper.Storage.IsOpened)
                    {
                        wrapper = new StorageDisposableWrapper(CreateStorage());
                        DisposableHttpContext.Current[key] = wrapper;
                    }
                    return wrapper.Storage;
                }
                return CreateStorage();
            }
        }

        internal bool StorageOpened
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    var key = "__DROPBOX_STORAGE" + ID;
                    var wrapper = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                    return wrapper != null && wrapper.Storage.IsOpened;
                }
                return false;
            }
        }

        public int ID { get; set; }

        public Guid Owner { get; private set; }

        public string CustomerTitle { get; private set; }

        public DateTime CreateOn
        {
            get { return _createOn; }
        }

        public object RootFolderId
        {
            get { return "dropbox-" + ID; }
        }

        public string ProviderKey { get; private set; }

        public FolderType RootFolderType
        {
            get { return _rootFolderType; }
        }


        public DropboxProviderInfo(int id, string providerKey, string customerTitle, string token, Guid owner, FolderType rootFolderType, DateTime createOn)
        {
            if (string.IsNullOrEmpty(providerKey)) throw new ArgumentNullException("providerKey");
            if (string.IsNullOrEmpty(token)) throw new ArgumentException("Token can't be null");

            ID = id;
            CustomerTitle = customerTitle;
            Owner = owner == Guid.Empty ? SecurityContext.CurrentAccount.ID : owner;

            ProviderKey = providerKey;
            _token = <PASSWORD>Token.FromJson(token);
            _rootFolderType = rootFolderType;
            _createOn = createOn;
        }

        public void Dispose()
        {
            if (StorageOpened)
                Storage.Close();
        }

        public bool CheckAccess()
        {
            try
            {
                Storage.GetUsedSpace();
            }
            catch (AggregateException)
            {
                return false;
            }
            return true;
        }

        public void InvalidateStorage()
        {
            if (HttpContext.Current != null)
            {
                var key = "__DROPBOX_STORAGE" + ID;
                var storage = (StorageDisposableWrapper)DisposableHttpContext.Current[key];
                if (storage != null)
                {
                    storage.Dispose();
                }
            }
            CacheReset();
        }

        internal void UpdateTitle(string newtitle)
        {
            CustomerTitle = newtitle;
        }

        private DropboxStorage CreateStorage()
        {
            var dropboxStorage = new DropboxStorage();

            dropboxStorage.Open(_token);
            return dropboxStorage;
        }


        private class StorageDisposableWrapper : IDisposable
        {
            public DropboxStorage Storage { get; private set; }


            public StorageDisposableWrapper(DropboxStorage storage)
            {
                Storage = storage;
            }

            public void Dispose()
            {
                Storage.Close();
            }
        }


        private static readonly TimeSpan CacheExpiration = TimeSpan.FromMinutes(1);
        private static readonly ICache CacheFile = AscCache.Memory;
        private static readonly ICache CacheFolder = AscCache.Memory;
        private static readonly ICache CacheChildItems = AscCache.Memory;
        private static readonly ICacheNotify CacheNotify;

        static DropboxProviderInfo()
        {
            CacheNotify = AscCache.Notify;
            CacheNotify.Subscribe<DropboxCacheItem>((i, action) =>
                {
                    if (action != CacheNotifyAction.Remove) return;
                    if (i.ResetAll)
                    {
                        CacheFile.Remove(new Regex("^dropboxf-" + i.Key + ".*"));
                        CacheFolder.Remove(new Regex("^dropboxd-" + i.Key + ".*"));
                        CacheChildItems.Remove(new Regex("^dropbox-" + i.Key + ".*"));
                    }

                    if (!i.IsFile.HasValue)
                    {
                        CacheChildItems.Remove("dropbox-" + i.Key);

                        CacheFolder.Remove("dropboxd-" + i.Key);
                    }
                    else
                    {
                        if (i.IsFile.Value)
                        {
                            CacheFile.Remove("dropboxf-" + i.Key);
                        }
                        else
                        {
                            CacheFolder.Remove("dropboxd-" + i.Key);
                        }
                    }
                });
        }

        internal FolderMetadata GetDropboxFolder(string dropboxFolderPath)
        {
            var folder = CacheFolder.Get<FolderMetadata>("dropboxd-" + ID + "-" + dropboxFolderPath);
            if (folder == null)
            {
                folder = Storage.GetFolder(dropboxFolderPath);
                if (folder != null)
                    CacheFolder.Insert("dropboxd-" + ID + "-" + dropboxFolderPath, folder, DateTime.UtcNow.Add(CacheExpiration));
            }
            return folder;
        }

        internal FileMetadata GetDropboxFile(string dropboxFilePath)
        {
            var file = CacheFile.Get<FileMetadata>("dropboxf-" + ID + "-" + dropboxFilePath);
            if (file == null)
            {
                file = Storage.GetFile(dropboxFilePath);
                if (file != null)
                    CacheFile.Insert("dropboxf-" + ID + "-" + dropboxFilePath, file, DateTime.UtcNow.Add(CacheExpiration));
            }
            return file;
        }

        internal List<Metadata> GetDropboxItems(string dropboxFolderPath)
        {
            var items = CacheChildItems.Get<List<Metadata>>("dropbox-" + ID + "-" + dropboxFolderPath);

            if (items == null)
            {
                items = Storage.GetItems(dropboxFolderPath);
                CacheChildItems.Insert("dropbox-" + ID + "-" + dropboxFolderPath, items, DateTime.UtcNow.Add(CacheExpiration));
            }
            return items;
        }

        internal void CacheReset(Metadata dropboxItem)
        {
            if (dropboxItem != null)
            {
                CacheNotify.Publish(new DropboxCacheItem { IsFile = dropboxItem.AsFolder != null, Key = ID + "-" + dropboxItem.PathDisplay }, CacheNotifyAction.Remove);
            }
        }

        internal void CacheReset(string dropboxPath = null, bool? isFile = null)
        {
            var key = ID + "-";
            if (dropboxPath == null)
            {
                CacheNotify.Publish(new DropboxCacheItem { ResetAll = true, Key = key }, CacheNotifyAction.Remove);
            }
            else
            {
                key += dropboxPath;

                CacheNotify.Publish(new DropboxCacheItem { IsFile = isFile, Key = key }, CacheNotifyAction.Remove);
            }
        }

        private class DropboxCacheItem
        {
            public bool ResetAll { get; set; }
            public bool? IsFile { get; set; }
            public string Key { get; set; }
        }
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Utils/ApiHelper.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Authentication;
using System.Web;

using ASC.Common.Logging;
using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Users;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Exceptions;
using ASC.Mail.Extensions;
using ASC.Specific;
using ASC.Web.Core;

using DotNetOpenAuth.Messaging;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using RestSharp;

namespace ASC.Mail.Utils
{
    public class ApiHelper
    {
        private const int MAIL_CRM_HISTORY_CATEGORY = -3;
        private const string ERR_MESSAGE = "Error retrieving response. Check inner details for more info.";
        private readonly ILog _log;

        public string Scheme { get; private set; }

        public UriBuilder BaseUrl { get; private set; }

        public string Token { get; set; }

        /// <summary>
        /// Constructor of class ApiHelper
        /// </summary>
        /// <param name="scheme">Uri.UriSchemeHttps or Uri.UriSchemeHttp</param>
        /// <exception cref="ApiHelperException">Exception happens when scheme is invalid.</exception>>
        public ApiHelper(string scheme, ILog log = null)
        {
            if (!scheme.Equals(Uri.UriSchemeHttps) && !scheme.Equals(Uri.UriSchemeHttp))
                throw new ApiHelperException("ApiHelper: url scheme not setup", HttpStatusCode.InternalServerError, "");

            _log = log ?? LogManager.GetLogger("ASC.Mail.ApiHelper");

            Scheme = scheme;

            if (!scheme.Equals(Uri.UriSchemeHttps) || !Defines.SslCertificatesErrorPermit)
                return;

            ServicePointManager.ServerCertificateValidationCallback =
                (sender, certificate, chain, sslPolicyErrors) => true;
        }

        private void Setup()
        {
            var tenant = CoreContext.TenantManager.GetCurrentTenant();

            var user = SecurityContext.CurrentAccount;

            _log.DebugFormat("Tenant={0} User='{1}' IsAuthenticated={2} Scheme='{3}' HttpContext is {4}",
                      tenant.TenantId, user.ID, user.IsAuthenticated, Scheme,
                      HttpContext.Current != null
                          ? string.Format("not null and UrlRewriter = {0}, RequestUrl = {1}", HttpContext.Current.Request.GetUrlRewriter(), HttpContext.Current.Request.Url)
                          : "null");

            if (!user.IsAuthenticated)
                throw new AuthenticationException("User not authenticated");

            var tempUrl = Defines.ApiPrefix;

            var ubBase = new UriBuilder
            {
                Scheme = Scheme,
                Host = tenant.GetTenantDomain(false)
            };

            if (!string.IsNullOrEmpty(Defines.ApiVirtualDirPrefix))
                tempUrl = string.Format("{0}/{1}", Defines.ApiVirtualDirPrefix, tempUrl);

            if (!string.IsNullOrEmpty(Defines.ApiHost))
                ubBase.Host = Defines.ApiHost;

            if (!string.IsNullOrEmpty(Defines.ApiPort))
                ubBase.Port = int.Parse(Defines.ApiPort);

            ubBase.Path = tempUrl;

            BaseUrl = ubBase;

            Token = SecurityContext.AuthenticateMe(user.ID);
        }

        public IRestResponse Execute(RestRequest request)
        {
            Setup();

            _log.DebugFormat("Execute request url: baseUrl='{0}' resourceUrl='{1}' token='{2}'",
                BaseUrl.Uri.ToString(),
                request.Resource,
                Token);

            var client = new RestClient { BaseUrl = BaseUrl.Uri };

            request.AddHeader("Authorization", Token);

            var response = client.ExecuteSafe(request);

            if (response.ErrorException is ApiHelperException)
                return response;

            if (response.ErrorException != null)
                throw new ApplicationException(ERR_MESSAGE, response.ErrorException);

            return response;
        }

        public Defines.TariffType GetTenantTariff(int tenantOverdueDays)
        {
            var request = new RestRequest("portal/tariff.json", Method.GET);

            request.AddHeader("Payment-Info", "false");

            var response = Execute(request);

            if (response.StatusCode == HttpStatusCode.PaymentRequired)
                return Defines.TariffType.LongDead;

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("Get tenant tariff failed.", response.StatusCode, response.Content);
            }

            var json = JObject.Parse(response.Content);

            TariffState state;

            Enum.TryParse(json["response"]["state"].ToString(), out state);

            Defines.TariffType result;

            if (state < TariffState.NotPaid)
            {
                result = Defines.TariffType.Active;
            }
            else
            {
                var dueDate = DateTime.Parse(json["response"]["dueDate"].ToString());

                var delayDateString = json["response"]["delayDueDate"].ToString();

                var delayDueDate = DateTime.Parse(delayDateString);

                var maxDateStr = DateTime.MaxValue.CutToSecond().ToString(CultureInfo.InvariantCulture);

                delayDateString = delayDueDate.CutToSecond().ToString(CultureInfo.InvariantCulture);

                result = (!delayDateString.Equals(maxDateStr) ? delayDueDate : dueDate)
                             .AddDays(tenantOverdueDays) <= DateTime.UtcNow
                             ? Defines.TariffType.LongDead
                             : Defines.TariffType.Overdue;
            }

            return result;
        }

        public void RemoveTeamlabMailbox(int mailboxId)
        {
            var request = new RestRequest("mailserver/mailboxes/remove/{id}", Method.DELETE);

            request.AddUrlSegment("id", mailboxId.ToString(CultureInfo.InvariantCulture));

            var response = Execute(request);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("Delete teamlab mailbox failed.", response.StatusCode, response.Content);
            }
        }

        public void SendMessage(MailMessageData message, bool isAutoreply = false)
        {
            var request = new RestRequest("mail/messages/send.json", Method.PUT);

            var jObject = new JObject { { "id", message.Id } };

            if (!string.IsNullOrEmpty(message.From))
                jObject.Add("from", message.From);

            jObject.Add("to", message.To);

            if (!string.IsNullOrEmpty(message.Cc))
                jObject.Add("cc", message.Cc);

            if (!string.IsNullOrEmpty(message.Bcc))
                jObject.Add("bcc", message.Bcc);

            jObject.Add("subject", message.Subject);

            jObject.Add("body", message.HtmlBody);

            jObject.Add("mimeReplyToId", message.MimeReplyToId);

            jObject.Add("importance", message.Important);

            if (message.TagIds != null && message.TagIds.Count != 0)
                jObject.Add("tags", JsonConvert.SerializeObject(message.TagIds));

            if (message.Attachments != null && message.Attachments.Count != 0)
                jObject.Add("attachments", JsonConvert.SerializeObject(message.Attachments));

            if (!string.IsNullOrEmpty(message.CalendarEventIcs))
                jObject.Add("calendarIcs", message.CalendarEventIcs);

            jObject.Add("isAutoreply", isAutoreply);

            request.AddParameter("application/json; charset=utf-8", jObject, ParameterType.RequestBody);

            var response = Execute(request);

            if (response.ResponseStatus == ResponseStatus.Completed &&
                (response.StatusCode == HttpStatusCode.Created || response.StatusCode == HttpStatusCode.OK))
                return;

            if (response.ErrorException is ApiHelperException)
                throw response.ErrorException;

            throw new ApiHelperException("Send message to api failed.", response.StatusCode, response.Content);
        }

        public List<string> SearchEmails(string term)
        {
            var request = new RestRequest("mail/emails/search.json", Method.GET);

            request.AddParameter("term", term);

            var response = Execute(request);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                if (response.ErrorException is ApiHelperException)
                {
                    throw response.ErrorException;
                }

                throw new ApiHelperException("Search Emails failed.", response.StatusCode, response.Content);
            }

            var json = JObject.Parse(response.Content);

            return json["response"].ToObject<List<string>>();
        }

        public List<string> SearchCrmEmails(string term, int maxCount)
        {
            var request = new RestRequest("crm/contact/simple/byEmail.json", Method.GET);

            request.AddParameter("term", term)
                .AddParameter("maxCount", maxCount.ToString());

            var response = Execute(request);

            var crmEmails = new List<string>();

            var json = JObject.Parse(response.Content);

            var contacts = json["response"] as JArray;

            if (contacts == null)
                return crmEmails;

            foreach (var contact in contacts)
            {
                var commonData = contact["contact"]["commonData"] as JArray;

                if (commonData == null)
                    continue;

                var emails = commonData.Where(d => int.Parse(d["infoType"].ToString()) == 1).Select(d => (string)d["data"]).ToList();

                if (!emails.Any())
                    continue;

                var displayName = contact["contact"]["displayName"].ToString();

                if (displayName.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1)
                {
                    crmEmails.AddRange(emails.Select(e => MailUtil.CreateFullEmail(displayName, e)));
                }
                else
                {
                    crmEmails.AddRange(emails
                        .Where(e => e.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1)
                        .Select(e => MailUtil.CreateFullEmail(displayName, e)));
                }
            }

            return crmEmails;
        }

        public List<string> SearchPeopleEmails(string term, int startIndex, int count)
        {
            var request = new RestRequest("people/filter.json?filterValue={FilterValue}&StartIndex={StartIndex}&Count={Count}", Method.GET);

            request.AddParameter("FilterValue", term, ParameterType.UrlSegment)
                .AddParameter("StartIndex", startIndex.ToString(), ParameterType.UrlSegment)
                .AddParameter("Count", count.ToString(), ParameterType.UrlSegment);

            var response = Execute(request);

            var peopleEmails = new List<string>();

            var json = JObject.Parse(response.Content);

            var contacts = json["response"] as JArray;

            if (contacts == null)
                return peopleEmails;

            foreach (var contact in contacts)
            {
                var displayName = contact["displayName"].ToString();

                var emails = new List<string>();

                var email = contact["email"].ToString();

                if (!string.IsNullOrEmpty(email))
                    emails.Add(email);

                var contactData = contact["contacts"] as JArray;

                if (contactData != null)
                {
                    emails.AddRange(contactData.Where(d => d["type"].ToString() == "mail").Select(d => (string)d["value"]).ToList());
                }

                if (displayName.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1)
                {
                    peopleEmails.AddRange(emails.Select(e => MailUtil.CreateFullEmail(displayName, e)));
                }
                else
                {
                    peopleEmails.AddRange(emails
                        .Where(e => e.IndexOf(term, StringComparison.OrdinalIgnoreCase) > -1)
                        .Select(e => MailUtil.CreateFullEmail(displayName, e)));
                }
            }

            return peopleEmails;
        }

        public void AddToCrmHistory(MailMessageData message, CrmContactData entity, IEnumerable<object> fileIds)
        {
            var request = new RestRequest("crm/history.json", Method.POST);

            var contentJson = string.Format("{{ message_id : {0} }}", message.Id);

            request.AddParameter("content", contentJson)
                   .AddParameter("categoryId", MAIL_CRM_HISTORY_CATEGORY)
                   .AddParameter("created", new ApiDateTime(message.Date));

            var crmEntityType = entity.EntityTypeName;

            if (crmEntityType == CrmContactData.CrmEntityTypeNames.CONTACT)
            {
                request.AddParameter("contactId", entity.Id)
                       .AddParameter("entityId", 0);
            }
            else
            {
                if (crmEntityType != CrmContactData.CrmEntityTypeNames.CASE
                    && crmEntityType != CrmContactData.CrmEntityTypeNames.OPPORTUNITY)
                    throw new ArgumentException(String.Format("Invalid crm entity type: {0}", crmEntityType));

                request.AddParameter("contactId", 0)
                       .AddParameter("entityId", entity.Id)
                       .AddParameter("entityType", crmEntityType);
            }

            if (fileIds != null)
            {
                fileIds.ToList().ForEach(
                    id => request.AddParameter("fileId[]", id));
            }

            var response = Execute(request);

            if (response.ResponseStatus == ResponseStatus.Completed &&
                (response.StatusCode == HttpStatusCode.Created || response.StatusCode == HttpStatusCode.OK))
                return;

            if (response.ErrorException is ApiHelperException)
                throw response.ErrorException;

            throw new ApiHelperException("Add message to crm history failed.", response.StatusCode, response.Content);
        }

        public object UploadToCrm(Stream fileStream, string filename, string contentType,
                                      CrmContactData entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            var request = new RestRequest("crm/{entityType}/{entityId}/files/upload.json", Method.POST);

            request.AddUrlSegment("entityType", entity.EntityTypeName)
                .AddUrlSegment("entityId", entity.Id.ToString())
                .AddParameter("storeOriginalFileFlag", false);

            request.AddFile(filename, fileStream.CopyTo, filename, fileStream.Length, contentType);

            var response = Execute(request);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("Upload file to crm failed.", response.StatusCode, response.Content);
            }

            var json = JObject.Parse(response.Content);

            var id = json["response"]["id"];

            return id;
        }

        public object UploadToDocuments(Stream fileStream, string filename, string contentType, string folderId, bool createNewIfExist)
        {
            var request = new RestRequest("files/{folderId}/upload.json", Method.POST);

            request.AddUrlSegment("folderId", folderId)
                   .AddParameter("createNewIfExist", createNewIfExist);

            request.AddFile(filename, fileStream.CopyTo, filename, fileStream.Length, contentType);

            var response = Execute(request);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("Upload file to documents failed.", response.StatusCode, response.Content);
            }

            var json = JObject.Parse(response.Content);

            var id = json["response"]["id"];

            return id;
        }

        //TODO: need refactoring to comman execute method
        public void SendEmlToSpamTrainer(string serverIp, string serverProtocol, int serverPort,
                                         string serverApiVersion, string serverApiToken, string urlEml,
                                         bool isSpam)
        {
            if (string.IsNullOrEmpty(urlEml))
                return;

            var saLearnApiClient =
                new RestClient(string.Format("{0}://{1}:{2}/", serverProtocol,
                                             serverIp, serverPort));

            var saLearnRequest =
                new RestRequest(
                    string.Format("/api/{0}/spam/training.json?auth_token={1}", serverApiVersion,
                                  serverApiToken), Method.POST);

            saLearnRequest.AddParameter("url", urlEml)
                          .AddParameter("is_spam", isSpam ? 1 : 0);

            var response = saLearnApiClient.Execute(saLearnRequest);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("Send eml to spam trainer failed.", response.StatusCode, response.Content);
            }
        }

        public void UploadIcsToCalendar(int calendarId, Stream fileStream, string filename, string contentType)
        {
            var request = new RestRequest("calendar/import.json", Method.POST);

            request.AddParameter("calendarId", calendarId);

            request.AddFile(filename, fileStream.CopyTo, filename, fileStream.Length, contentType);

            var response = Execute(request);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("Upload ics-file to calendar failed.", response.StatusCode, response.Content);
            }

            var json = JObject.Parse(response.Content);

            int count;

            if (!int.TryParse(json["response"].ToString(), out count))
            {
                _log.WarnFormat("Upload ics-file to calendar failed. No count number.", BaseUrl.ToString(), response.StatusCode, response.Content);
            }
        }

        public UserInfo CreateEmployee(bool isVisitor, string email, string firstname, string lastname, string password)
        {
            var request = new RestRequest("people.json", Method.POST);

            request.AddParameter("isVisitor", isVisitor)
                .AddParameter("email", email)
                .AddParameter("firstname", firstname)
                .AddParameter("lastname", lastname)
                .AddParameter("password", password);

            var response = Execute(request);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("ApiHelper->CreateEmployee() failed.", response.StatusCode, response.Content);
            }

            var json = JObject.Parse(response.Content);

            _log.Debug(json["response"].ToString());

            var userInfo = new UserInfo
            {
                ID = Guid.Parse(json["response"]["id"].ToString()),
                Email = json["response"]["email"].ToString(),
                FirstName = json["response"]["firstName"].ToString(),
                LastName = json["response"]["lastName"].ToString(),
                UserName = json["response"]["userName"].ToString(),
            };

            return userInfo;
        }

        public JObject GetPortalSettings()
        {
            var request = new RestRequest("settings/security.json", Method.GET);

            var response = Execute(request);

            if (response.ResponseStatus != ResponseStatus.Completed ||
                (response.StatusCode != HttpStatusCode.Created &&
                 response.StatusCode != HttpStatusCode.OK))
            {
                throw new ApiHelperException("GetPortalSettings failed.", response.StatusCode, response.Content);
            }

            var json = JObject.Parse(response.Content);

            return json;
        }

        public bool IsCalendarModuleAvailable()
        {
            var json = GetPortalSettings();

            var jWebItem = json["response"].Children<JObject>()
                .FirstOrDefault(
                    o =>
                        o["webItemId"] != null &&
                        o["webItemId"].ToString() == WebItemManager.CalendarProductID.ToString());

            var isAvailable = jWebItem != null && jWebItem["enabled"] != null && Convert.ToBoolean(jWebItem["enabled"]);

            return isAvailable;
        }

        public bool IsMailModuleAvailable()
        {
            var json = GetPortalSettings();

            var jWebItem = json["response"].Children<JObject>()
                .FirstOrDefault(
                    o =>
                        o["webItemId"] != null &&
                        o["webItemId"].ToString() == WebItemManager.MailProductID.ToString());

            var isAvailable = jWebItem != null && jWebItem["enabled"] != null && Convert.ToBoolean(jWebItem["enabled"]);

            return isAvailable;
        }

        public bool IsCrmModuleAvailable()
        {
            var json = GetPortalSettings();

            var crmId = WebItemManager.CRMProductID.ToString();

            var jWebItem = json["response"].Children<JObject>()
                .FirstOrDefault(
                    o =>
                        o["webItemId"] != null &&
                        o["webItemId"].ToString() == crmId);

            var isAvailable = jWebItem != null && jWebItem["enabled"] != null && Convert.ToBoolean(jWebItem["enabled"]);

            return isAvailable;
        }
    }
}


<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Entities/MailGarbage.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using ASC.Mail.Data.Storage;

namespace ASC.Mail.Core.Entities
{
    public abstract class MailGarbage
    {
        public abstract int Id { get; }
        public abstract string Path { get; }
    }

    public class MailAttachGarbage : MailGarbage
    {
        private readonly int _id;
        public override int Id
        {
            get { return _id; }
        }

        private readonly string _path;
        public override string Path
        {
            get { return _path; }
        }

        public MailAttachGarbage(string user, int attachId, string stream, int number, string storedName)
        {
            _id = attachId;
            _path = MailStoragePathCombiner.GetFileKey(user, stream, number, storedName);
        }
    }

    public class MailMessageGarbage : MailGarbage
    {
        private readonly int _id;
        public override int Id
        {
            get { return _id; }
        }

        private readonly string _path;
        public override string Path
        {
            get { return _path; }
        }

        public MailMessageGarbage(string user, int id, string stream)
        {
            _id = id;
            _path = MailStoragePathCombiner.GetBodyKey(user, stream);
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Utils/FileConverter.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Security;
using System.Threading;
using System.Web;

using ASC.Common.Caching;
using ASC.Common.Security.Authentication;
using ASC.Core;
using ASC.Files.Core;
using ASC.MessagingSystem;
using ASC.Web.Core.Files;
using ASC.Web.Files.Classes;
using ASC.Web.Files.Core;
using ASC.Web.Files.Helpers;
using ASC.Web.Files.Resources;
using ASC.Web.Files.Services.DocumentService;
using ASC.Web.Files.Services.WCFService.FileOperations;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.Utility;

using File = ASC.Files.Core.File;
using SecurityContext = ASC.Core.SecurityContext;

namespace ASC.Web.Files.Utils
{
    public static class FileConverter
    {
        private static readonly object locker = new object();
        private static readonly IDictionary<File, ConvertFileOperationResult> conversionQueue = new Dictionary<File, ConvertFileOperationResult>(new FileComparer());
        private static readonly ICache cache = AscCache.Default;

        private static Timer timer;
        private static readonly object singleThread = new object();
        private const int TIMER_PERIOD = 500;


        public static bool EnableAsUploaded
        {
            get { return FileUtility.ExtsMustConvert.Any() && !string.IsNullOrEmpty(FilesLinkUtility.DocServiceConverterUrl); }
        }

        public static bool MustConvert(File file)
        {
            if (file == null) return false;

            var ext = FileUtility.GetFileExtension(file.Title);
            return FileUtility.ExtsMustConvert.Contains(ext);
        }

        public static bool EnableConvert(File file, string toExtension)
        {
            if (file == null || string.IsNullOrEmpty(toExtension))
            {
                return false;
            }

            if (file.Encrypted)
            {
                return false;
            }

            var fileExtension = file.ConvertedExtension;
            if (fileExtension.Trim('.').Equals(toExtension.Trim('.'), StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }

            fileExtension = FileUtility.GetFileExtension(file.Title);
            if (FileUtility.InternalExtension.Values.Contains(toExtension))
            {
                return true;
            }

            return FileUtility.ExtsConvertible.Keys.Contains(fileExtension) && FileUtility.ExtsConvertible[fileExtension].Contains(toExtension);
        }

        public static Stream Exec(File file)
        {
            return Exec(file, FileUtility.GetInternalExtension(file.Title));
        }

        public static Stream Exec(File file, string toExtension)
        {
            if (!EnableConvert(file, toExtension))
            {
                using (var fileDao = Global.DaoFactory.GetFileDao())
                {
                    return fileDao.GetFileStream(file);
                }
            }

            if (file.ContentLength > SetupInfo.AvailableFileSize)
            {
                throw new Exception(string.Format(FilesCommonResource.ErrorMassage_FileSizeConvert, FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize)));
            }

            var fileUri = PathProvider.GetFileStreamUrl(file);
            var docKey = DocumentServiceHelper.GetDocKey(file);
            string convertUri;
            fileUri = DocumentServiceConnector.ReplaceCommunityAdress(fileUri);
            DocumentServiceConnector.GetConvertedUri(fileUri, file.ConvertedExtension, toExtension, docKey, null, null, null, false, out convertUri);

            if (WorkContext.IsMono && ServicePointManager.ServerCertificateValidationCallback == null)
            {
                ServicePointManager.ServerCertificateValidationCallback += (s, c, n, p) => true; //HACK: http://ubuntuforums.org/showthread.php?t=1841740
            }
            return new ResponseStream(((HttpWebRequest)WebRequest.Create(convertUri)).GetResponse());
        }

        public static File ExecSync(File file, string doc)
        {
            using (var fileDao = Global.DaoFactory.GetFileDao())
            {
                var fileSecurity = Global.GetFilesSecurity();
                if (!fileSecurity.CanRead(file))
                {
                    var readLink = FileShareLink.Check(doc, true, fileDao, out file);
                    if (file == null)
                    {
                        throw new ArgumentNullException("file", FilesCommonResource.ErrorMassage_FileNotFound);
                    }
                    if (!readLink)
                    {
                        throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
                    }
                }
            }

            var fileUri = PathProvider.GetFileStreamUrl(file);
            var fileExtension = file.ConvertedExtension;
            var toExtension = FileUtility.GetInternalExtension(file.Title);
            var docKey = DocumentServiceHelper.GetDocKey(file);

            string convertUri;
            fileUri = DocumentServiceConnector.ReplaceCommunityAdress(fileUri);
            DocumentServiceConnector.GetConvertedUri(fileUri, fileExtension, toExtension, docKey, null, null, null, false, out convertUri);

            return SaveConvertedFile(file, convertUri);
        }

        public static void ExecAsync(File file, bool deleteAfter, string password = null)
        {
            if (!MustConvert(file))
            {
                throw new ArgumentException(FilesCommonResource.ErrorMassage_NotSupportedFormat);
            }
            if (!String.IsNullOrEmpty(file.ConvertedType) || FileUtility.InternalExtension.Values.Contains(FileUtility.GetFileExtension(file.Title)))
            {
                return;
            }

            FileMarker.RemoveMarkAsNew(file);

            lock (locker)
            {
                if (conversionQueue.ContainsKey(file))
                {
                    return;
                }

                var queueResult = new ConvertFileOperationResult
                {
                    Source = String.Format("{{\"id\":\"{0}\", \"version\":\"{1}\"}}", file.ID, file.Version),
                    OperationType = FileOperationType.Convert,
                    Error = String.Empty,
                    Progress = 0,
                    Result = String.Empty,
                    Processed = "",
                    Id = String.Empty,
                    TenantId = TenantProvider.CurrentTenantID,
                    Account = SecurityContext.CurrentAccount,
                    Delete = deleteAfter,
                    StartDateTime = DateTime.Now,
                    Url = HttpContext.Current != null ? HttpContext.Current.Request.GetUrlRewriter().ToString() : null,
                    Password = password
                };
                conversionQueue.Add(file, queueResult);
                cache.Insert(GetKey(file), queueResult, TimeSpan.FromMinutes(10));

                if (timer == null)
                {
                    timer = new Timer(CheckConvertFilesStatus, null, 0, Timeout.Infinite);
                }
                else
                {
                    timer.Change(0, Timeout.Infinite);
                }
            }
        }

        public static bool IsConverting(File file)
        {
            if (!MustConvert(file) || !string.IsNullOrEmpty(file.ConvertedType))
            {
                return false;
            }
            var result = cache.Get<ConvertFileOperationResult>(GetKey(file));
            return result != null && result.Progress != 100 && string.IsNullOrEmpty(result.Error);
        }

        public static IEnumerable<FileOperationResult> GetStatus(IEnumerable<KeyValuePair<File, bool>> filesPair)
        {
            var fileSecurity = Global.GetFilesSecurity();
            var result = new List<FileOperationResult>();
            foreach (var pair in filesPair)
            {
                var file = pair.Key;
                var key = GetKey(file);
                var operation = cache.Get<ConvertFileOperationResult>(key);
                if (operation != null && (pair.Value || fileSecurity.CanRead(file)))
                {
                    result.Add(operation);
                    lock (locker)
                    {
                        if (operation.Progress == 100)
                        {
                            conversionQueue.Remove(file);
                            cache.Remove(key);
                        }
                    }
                }
            }
            return result;
        }

        private static String FileJsonSerializer(File file, string folderTitle)
        {
            if (file == null) return string.Empty;

            EntryManager.SetFileStatus(file);
            return
                string.Format("{{ \"id\": \"{0}\"," +
                              " \"title\": \"{1}\"," +
                              " \"version\": \"{2}\"," +
                              " \"folderId\": \"{3}\"," +
                              " \"folderTitle\": \"{4}\"," +
                              " \"fileXml\": \"{5}\" }}",
                              file.ID,
                              file.Title,
                              file.Version,
                              file.FolderID,
                              folderTitle ?? "",
                              File.Serialize(file).Replace('"', '\''));
        }

        private static void CheckConvertFilesStatus(object _)
        {
            if (Monitor.TryEnter(singleThread))
            {
                try
                {
                    List<File> filesIsConverting;
                    lock (locker)
                    {
                        timer.Change(Timeout.Infinite, Timeout.Infinite);

                        conversionQueue.Where(x => !string.IsNullOrEmpty(x.Value.Processed)
                                                   && (x.Value.Progress == 100 && DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(1) ||
                                                       DateTime.UtcNow - x.Value.StopDateTime > TimeSpan.FromMinutes(10)))
                                       .ToList()
                                       .ForEach(x =>
                                           {
                                               conversionQueue.Remove(x);
                                               cache.Remove(GetKey(x.Key));
                                           });

                        Global.Logger.DebugFormat("Run CheckConvertFilesStatus: count {0}", conversionQueue.Count);

                        if (conversionQueue.Count == 0)
                        {
                            return;
                        }

                        filesIsConverting = conversionQueue
                            .Where(x => String.IsNullOrEmpty(x.Value.Processed))
                            .Select(x => x.Key)
                            .ToList();
                    }

                    var fileSecurity = Global.GetFilesSecurity();
                    foreach (var file in filesIsConverting)
                    {
                        var fileUri = file.ID.ToString();
                        string convertedFileUrl;
                        int operationResultProgress;

                        try
                        {
                            int tenantId;
                            IAccount account;
                            string password;

                            lock (locker)
                            {
                                if (!conversionQueue.Keys.Contains(file)) continue;

                                var operationResult = conversionQueue[file];
                                if (!string.IsNullOrEmpty(operationResult.Processed)) continue;

                                operationResult.Processed = "1";
                                tenantId = operationResult.TenantId;
                                account = operationResult.Account;
                                password = operationResult.Password;

                                if (HttpContext.Current == null && !WorkContext.IsMono)
                                {
                                    HttpContext.Current = new HttpContext(
                                        new HttpRequest("hack", operationResult.Url, string.Empty),
                                        new HttpResponse(new StringWriter()));
                                }

                                cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
                            }

                            CoreContext.TenantManager.SetCurrentTenant(tenantId);
                            SecurityContext.AuthenticateMe(account);

                            var user = CoreContext.UserManager.GetUsers(account.ID);
                            var culture = string.IsNullOrEmpty(user.CultureName) ? CoreContext.TenantManager.GetCurrentTenant().GetCulture() : CultureInfo.GetCultureInfo(user.CultureName);
                            Thread.CurrentThread.CurrentCulture = culture;
                            Thread.CurrentThread.CurrentUICulture = culture;

                            if (!fileSecurity.CanRead(file) && file.RootFolderType != FolderType.BUNCH)
                            {
                                //No rights in CRM after upload before attach
                                throw new SecurityException(FilesCommonResource.ErrorMassage_SecurityException_ReadFile);
                            }
                            if (file.ContentLength > SetupInfo.AvailableFileSize)
                            {
                                throw new Exception(string.Format(FilesCommonResource.ErrorMassage_FileSizeConvert, FileSizeComment.FilesSizeToString(SetupInfo.AvailableFileSize)));
                            }

                            fileUri = PathProvider.GetFileStreamUrl(file);

                            var toExtension = FileUtility.GetInternalExtension(file.Title);
                            var fileExtension = file.ConvertedExtension;
                            var docKey = DocumentServiceHelper.GetDocKey(file);

                            fileUri = DocumentServiceConnector.ReplaceCommunityAdress(fileUri);
                            operationResultProgress = DocumentServiceConnector.GetConvertedUri(fileUri, fileExtension, toExtension, docKey, password, null, null, true, out convertedFileUrl);
                        }
                        catch (Exception exception)
                        {
                            DocumentService.DocumentServiceException documentServiceException;
                            var password = exception.InnerException != null
                                           && ((documentServiceException = exception.InnerException as DocumentService.DocumentServiceException) != null)
                                           && documentServiceException.Code == DocumentService.DocumentServiceException.ErrorCode.ConvertPassword;

                            Global.Logger.Error(string.Format("Error convert {0} with url {1}", file.ID, fileUri), exception);
                            lock (locker)
                            {
                                if (conversionQueue.Keys.Contains(file))
                                {
                                    var operationResult = conversionQueue[file];
                                    if (operationResult.Delete)
                                    {
                                        conversionQueue.Remove(file);
                                        cache.Remove(GetKey(file));
                                    }
                                    else
                                    {
                                        operationResult.Progress = 100;
                                        operationResult.StopDateTime = DateTime.UtcNow;
                                        operationResult.Error = exception.Message;
                                        if (password) operationResult.Result = "password";
                                        cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
                                    }
                                }
                            }
                            continue;
                        }

                        operationResultProgress = Math.Min(operationResultProgress, 100);
                        if (operationResultProgress < 100)
                        {
                            lock (locker)
                            {
                                if (conversionQueue.Keys.Contains(file))
                                {
                                    var operationResult = conversionQueue[file];

                                    if (DateTime.Now - operationResult.StartDateTime > TimeSpan.FromMinutes(10))
                                    {
                                        operationResult.StopDateTime = DateTime.UtcNow;
                                        operationResult.Error = FilesCommonResource.ErrorMassage_ConvertTimeout;
                                        Global.Logger.ErrorFormat("CheckConvertFilesStatus timeout: {0} ({1})", file.ID, file.ContentLengthString);
                                    }
                                    else
                                    {
                                        operationResult.Processed = "";
                                    }
                                    operationResult.Progress = operationResultProgress;
                                    cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
                                }
                            }

                            Global.Logger.Debug("CheckConvertFilesStatus iteration continue");
                            continue;
                        }

                        File newFile = null;
                        var operationResultError = string.Empty;

                        try
                        {
                            newFile = SaveConvertedFile(file, convertedFileUrl);
                        }
                        catch (Exception e)
                        {
                            operationResultError = e.Message;

                            Global.Logger.ErrorFormat("{0} ConvertUrl: {1} fromUrl: {2}: {3}", operationResultError, convertedFileUrl, fileUri, e);
                            continue;
                        }
                        finally
                        {
                            lock (locker)
                            {
                                if (conversionQueue.Keys.Contains(file))
                                {
                                    var operationResult = conversionQueue[file];
                                    if (operationResult.Delete)
                                    {
                                        conversionQueue.Remove(file);
                                        cache.Remove(GetKey(file));
                                    }
                                    else
                                    {
                                        if (newFile != null)
                                        {
                                            using (var folderDao = Global.DaoFactory.GetFolderDao())
                                            {
                                                var folder = folderDao.GetFolder(newFile.FolderID);
                                                var folderTitle = fileSecurity.CanRead(folder) ? folder.Title : null;
                                                operationResult.Result = FileJsonSerializer(newFile, folderTitle);
                                            }
                                        }

                                        operationResult.Progress = 100;
                                        operationResult.StopDateTime = DateTime.UtcNow;
                                        operationResult.Processed = "1";
                                        if (!string.IsNullOrEmpty(operationResultError))
                                        {
                                            operationResult.Error = operationResultError;
                                        }
                                        cache.Insert(GetKey(file), operationResult, TimeSpan.FromMinutes(10));
                                    }
                                }
                            }
                        }

                        Global.Logger.Debug("CheckConvertFilesStatus iteration end");
                    }

                    lock (locker)
                    {
                        timer.Change(TIMER_PERIOD, TIMER_PERIOD);
                    }
                }
                catch (Exception exception)
                {
                    Global.Logger.Error(exception.Message, exception);
                    lock (locker)
                    {
                        timer.Change(Timeout.Infinite, Timeout.Infinite);
                    }
                }
                finally
                {
                    Monitor.Exit(singleThread);
                }
            }
        }

        private static File SaveConvertedFile(File file, string convertedFileUrl)
        {
            var fileSecurity = Global.GetFilesSecurity();
            using (var fileDao = Global.DaoFactory.GetFileDao())
            using (var folderDao = Global.DaoFactory.GetFolderDao())
            {
                File newFile = null;
                var markAsTemplate = false;
                var newFileTitle = FileUtility.ReplaceFileExtension(file.Title, FileUtility.GetInternalExtension(file.Title));

                if (!FilesSettings.StoreOriginalFiles && fileSecurity.CanEdit(file))
                {
                    newFile = (File)file.Clone();
                    newFile.Version++;
                    markAsTemplate = FileUtility.ExtsTemplate.Contains(FileUtility.GetFileExtension(file.Title), StringComparer.CurrentCultureIgnoreCase)
                        && FileUtility.ExtsWebTemplate.Contains(FileUtility.GetFileExtension(newFileTitle), StringComparer.CurrentCultureIgnoreCase);
                }
                else
                {
                    var folderId = Global.FolderMy;

                    var parent = folderDao.GetFolder(file.FolderID);
                    if (parent != null
                        && fileSecurity.CanCreate(parent))
                    {
                        folderId = parent.ID;
                    }

                    if (Equals(folderId, 0)) throw new SecurityException(FilesCommonResource.ErrorMassage_FolderNotFound);

                    if (FilesSettings.UpdateIfExist && (parent != null && folderId != parent.ID || !file.ProviderEntry))
                    {
                        newFile = fileDao.GetFile(folderId, newFileTitle);
                        if (newFile != null && fileSecurity.CanEdit(newFile) && !EntryManager.FileLockedForMe(newFile.ID) && !FileTracker.IsEditing(newFile.ID))
                        {
                            newFile.Version++;
                        }
                        else
                        {
                            newFile = null;
                        }
                    }

                    if (newFile == null)
                    {
                        newFile = new File { FolderID = folderId };
                    }
                }

                newFile.Title = newFileTitle;
                newFile.ConvertedType = null;
                newFile.Comment = string.Format(FilesCommonResource.CommentConvert, file.Title);
                newFile.ThumbnailStatus = Thumbnail.Waiting;

                var req = (HttpWebRequest)WebRequest.Create(convertedFileUrl);

                if (WorkContext.IsMono && ServicePointManager.ServerCertificateValidationCallback == null)
                {
                    ServicePointManager.ServerCertificateValidationCallback += (s, c, n, p) => true; //HACK: http://ubuntuforums.org/showthread.php?t=1841740
                }

                try
                {
                    using (var convertedFileStream = new ResponseStream(req.GetResponse()))
                    {
                        newFile.ContentLength = convertedFileStream.Length;
                        newFile = fileDao.SaveFile(newFile, convertedFileStream);
                    }
                }
                catch (WebException e)
                {
                    using (var response = e.Response)
                    {
                        var httpResponse = (HttpWebResponse)response;
                        var errorString = String.Format("WebException: {0}", httpResponse.StatusCode);

                        if (httpResponse.StatusCode != HttpStatusCode.NotFound)
                        {
                            using (var responseStream = response.GetResponseStream())
                            {
                                if (responseStream != null)
                                {
                                    using (var readStream = new StreamReader(responseStream))
                                    {
                                        var text = readStream.ReadToEnd();
                                        errorString += String.Format(" Error message: {0}", text);
                                    }
                                }
                            }
                        }

                        throw new Exception(errorString);
                    }
                }

                FilesMessageService.Send(newFile, MessageInitiator.DocsService, MessageAction.FileConverted, newFile.Title);
                FileMarker.MarkAsNew(newFile);

                using (var tagDao = Global.DaoFactory.GetTagDao())
                {
                    var tags = tagDao.GetTags(file.ID, FileEntryType.File, TagType.System).ToList();
                    if (tags.Any())
                    {
                        tags.ForEach(r => r.EntryId = newFile.ID);
                        tagDao.SaveTags(tags);
                    }

                    if (markAsTemplate)
                    {
                        tagDao.SaveTags(Tag.Template(SecurityContext.CurrentAccount.ID, newFile));
                    }
                }

                return newFile;
            }
        }

        private static string GetKey(File f)
        {
            return string.Format("fileConvertation-{0}", f.ID);
        }


        private class FileComparer : IEqualityComparer<File>
        {
            public bool Equals(File x, File y)
            {
                return x != null && y != null && Equals(x.ID, y.ID) && x.Version == y.Version;
            }

            public int GetHashCode(File obj)
            {
                return obj.ID.GetHashCode() + obj.Version.GetHashCode();
            }
        }

        [DataContract(Name = "operation_result", Namespace = "")]
        private class ConvertFileOperationResult : FileOperationResult
        {
            public DateTime StartDateTime { get; set; }
            public DateTime StopDateTime { get; set; }
            public int TenantId { get; set; }
            public IAccount Account { get; set; }
            public bool Delete { get; set; }
            public string Url { get; set; }
            public string Password { get; set; }
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Dao/InvoiceItemDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

using ASC.Collections;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.CRM.Core.Entities;
using ASC.Web.CRM.Classes;

namespace ASC.CRM.Core.Dao
{
    public class CachedInvoiceItemDao : InvoiceItemDao
    {
        private readonly HttpRequestDictionary<InvoiceItem> _invoiceItemCache = new HttpRequestDictionary<InvoiceItem>("crm_invoice_item");

        public CachedInvoiceItemDao(int tenantID)
            : base(tenantID)
        {
        }

        public override InvoiceItem GetByID(int invoiceItemID)
        {
            return _invoiceItemCache.Get(invoiceItemID.ToString(CultureInfo.InvariantCulture), () => GetByIDBase(invoiceItemID));
        }

        private InvoiceItem GetByIDBase(int invoiceItemID)
        {
            return base.GetByID(invoiceItemID);
        }

        public override InvoiceItem SaveOrUpdateInvoiceItem(InvoiceItem invoiceItem)
        {
            if (invoiceItem != null && invoiceItem.ID > 0)
                ResetCache(invoiceItem.ID);

            return base.SaveOrUpdateInvoiceItem(invoiceItem);
        }

        public override InvoiceItem DeleteInvoiceItem(int invoiceItemID)
        {
            ResetCache(invoiceItemID);

            return base.DeleteInvoiceItem(invoiceItemID);
        }

        private void ResetCache(int invoiceItemID)
        {
            _invoiceItemCache.Reset(invoiceItemID.ToString(CultureInfo.InvariantCulture));
        }
    }

    public class InvoiceItemDao : AbstractDao
    {
        public InvoiceItemDao(int tenantID)
            : base(tenantID)
        {
        }


        public Boolean IsExist(int invoiceItemID)
        {
            return IsExistInDb(invoiceItemID);
        }

        public Boolean IsExistInDb(int invoiceItemID)
        {
            return Db.ExecuteScalar<bool>(@"select exists(select 1 from crm_invoice_item where tenant_id = @tid and id = @id)",
                           new { tid = TenantID, id = invoiceItemID });
        }

        public Boolean CanDelete(int invoiceItemID)
        {
            return Db.ExecuteScalar<int>(@"select count(*) from crm_invoice_line where tenant_id = @tid and invoice_item_id = @id",
                            new { tid = TenantID, id = invoiceItemID }) == 0;
        }

        #region Get

        public virtual List<InvoiceItem> GetAll()
        {
            return GetAllInDb();
        }
        public virtual List<InvoiceItem> GetAllInDb()
        {
            return Db.ExecuteList(GetInvoiceItemSqlQuery(null)).ConvertAll(ToInvoiceItem);
        }

        public virtual List<InvoiceItem> GetByID(int[] ids)
        {
            return Db.ExecuteList(GetInvoiceItemSqlQuery(Exp.In("id", ids))).ConvertAll(ToInvoiceItem);
        }

        public virtual InvoiceItem GetByID(int id)
        {
            var invoiceItems = Db.ExecuteList(GetInvoiceItemSqlQuery(Exp.Eq("id", id))).ConvertAll(ToInvoiceItem);

            return invoiceItems.Count > 0 ? invoiceItems[0] : null;
        }

        public List<InvoiceItem> GetInvoiceItems(IEnumerable<int> ids)
        {
            if (ids == null || !ids.Any()) return new List<InvoiceItem>();

            var sqlQuery = GetInvoiceItemSqlQuery(Exp.In("id", ids.ToArray()));

            return Db.ExecuteList(sqlQuery).ConvertAll(ToInvoiceItem);
        }

        public List<InvoiceItem> GetInvoiceItems(
                                string searchText,
                                int status,
                                bool? inventoryStock,
                                int from,
                                int count,
                                OrderBy orderBy)
        {

            var sqlQuery = GetInvoiceItemSqlQuery(null);

            var withParams = !(String.IsNullOrEmpty(searchText) || status != 0 || inventoryStock.HasValue);


            var whereConditional = WhereConditional(new List<int>(), searchText, status, inventoryStock);
            // WhereConditional(CRMSecurity.GetPrivateItems(typeof(Invoice)).ToList(), searchText);

            if (withParams && whereConditional == null)
                return new List<InvoiceItem>();

            sqlQuery.Where(whereConditional);

            if (0 < from && from < int.MaxValue) sqlQuery.SetFirstResult(from);
            if (0 < count && count < int.MaxValue) sqlQuery.SetMaxResults(count);

            if (orderBy != null && Enum.IsDefined(typeof(InvoiceItemSortedByType), orderBy.SortedBy))
            {
                switch ((InvoiceItemSortedByType)orderBy.SortedBy)
                {
                    case InvoiceItemSortedByType.Name:
                        sqlQuery.OrderBy("title", orderBy.IsAsc);
                        break;
                    case InvoiceItemSortedByType.SKU:
                        sqlQuery.OrderBy("stock_keeping_unit", orderBy.IsAsc);
                        break;
                    case InvoiceItemSortedByType.Price:
                        sqlQuery.OrderBy("price", orderBy.IsAsc);
                        break;
                    case InvoiceItemSortedByType.Quantity:
                        sqlQuery.OrderBy("stock_quantity", orderBy.IsAsc).OrderBy("title", true);
                        break;
                    case InvoiceItemSortedByType.Created:
                        sqlQuery.OrderBy("create_on", orderBy.IsAsc);
                        break;
                    default:
                        sqlQuery.OrderBy("title", true);
                        break;
                }
            }
            else
            {
                sqlQuery.OrderBy("title", true);
            }

            return Db.ExecuteList(sqlQuery).ConvertAll(ToInvoiceItem);
        }


        public int GetInvoiceItemsCount()
        {
            return GetInvoiceItemsCount(String.Empty, 0, null);
        }

        public int GetInvoiceItemsCount(
                                    String searchText,
                                    int status,
                                    bool? inventoryStock)
        {
            var cacheKey = TenantID.ToString(CultureInfo.InvariantCulture) +
                           "invoiceItem" +
                           SecurityContext.CurrentAccount.ID.ToString() +
                           searchText;

            var fromCache = _cache.Get<string>(cacheKey);

            if (fromCache != null) return Convert.ToInt32(fromCache);

            var withParams = !(String.IsNullOrEmpty(searchText) || status != 0 || inventoryStock.HasValue);

            var exceptIDs = CRMSecurity.GetPrivateItems(typeof(InvoiceItem)).ToList();

            int result;

            if (withParams)
            {
                var whereConditional = WhereConditional(exceptIDs, searchText, status, inventoryStock);
                result = whereConditional != null ? Db.ExecuteScalar<int>(Query("crm_invoice_item").Where(whereConditional).SelectCount()) : 0;
            }
            else
            {
                var countWithoutPrivate = Db.ExecuteScalar<int>(Query("crm_invoice_item").SelectCount());
                var privateCount = exceptIDs.Count;

                if (privateCount > countWithoutPrivate)
                {
                    _log.ErrorFormat(@"Private invoice items count more than all cases. Tenant: {0}. CurrentAccount: {1}",
                                                            TenantID,
                                                            SecurityContext.CurrentAccount.ID);

                    privateCount = 0;
                }

                result = countWithoutPrivate - privateCount;
            }

            if (result > 0)
            {
                _cache.Insert(cacheKey, result, TimeSpan.FromSeconds(30));
            }
            return result;
        }

        #endregion


        #region SaveOrUpdate

        public virtual InvoiceItem SaveOrUpdateInvoiceItem(InvoiceItem invoiceItem)
        {
            /*_cache.Remove(_invoiceItemCacheKey);
            _cache.Insert(_invoiceItemCacheKey, String.Empty);*/

            return SaveOrUpdateInvoiceItemInDb(invoiceItem);
        }

        private InvoiceItem SaveOrUpdateInvoiceItemInDb(InvoiceItem invoiceItem)
        {
            if (invoiceItem.Price <= 0 || String.IsNullOrEmpty(invoiceItem.Title))
                throw new ArgumentException();

            if (invoiceItem.Price > Global.MaxInvoiceItemPrice)
                throw new ArgumentException("Max Invoice Item Price: " + Global.MaxInvoiceItemPrice);

            if (!CRMSecurity.IsAdmin) CRMSecurity.CreateSecurityException();

            if (String.IsNullOrEmpty(invoiceItem.Description))
            {
                invoiceItem.Description = String.Empty;
            }
            if (String.IsNullOrEmpty(invoiceItem.StockKeepingUnit))
            {
                invoiceItem.StockKeepingUnit = String.Empty;
            }

            if (!IsExistInDb(invoiceItem.ID))
            {
                invoiceItem.ID = Db.ExecuteScalar<int>(
                               Insert("crm_invoice_item")
                              .InColumnValue("id", 0)
                              .InColumnValue("title", invoiceItem.Title)
                              .InColumnValue("description", invoiceItem.Description)
                              .InColumnValue("stock_keeping_unit", invoiceItem.StockKeepingUnit)
                              .InColumnValue("price", invoiceItem.Price)
                              .InColumnValue("stock_quantity", invoiceItem.StockQuantity)
                              .InColumnValue("track_inventory", invoiceItem.TrackInventory)
                              .InColumnValue("invoice_tax1_id", invoiceItem.InvoiceTax1ID)
                              .InColumnValue("invoice_tax2_id", invoiceItem.InvoiceTax2ID)
                              .InColumnValue("currency", String.Empty)
                              .InColumnValue("create_on", DateTime.UtcNow)
                              .InColumnValue("create_by", SecurityContext.CurrentAccount.ID)
                              .InColumnValue("last_modifed_on", DateTime.UtcNow)
                              .InColumnValue("last_modifed_by", SecurityContext.CurrentAccount.ID)
                              .Identity(1, 0, true));

                invoiceItem.CreateOn = DateTime.UtcNow;
                invoiceItem.LastModifedOn = invoiceItem.CreateOn;
                invoiceItem.CreateBy = SecurityContext.CurrentAccount.ID;
                invoiceItem.LastModifedBy = invoiceItem.CreateBy;
            }
            else
            {

                var oldInvoiceItem = Db.ExecuteList(GetInvoiceItemSqlQuery(Exp.Eq("id", invoiceItem.ID)))
                    .ConvertAll(ToInvoiceItem)
                    .FirstOrDefault();

                CRMSecurity.DemandEdit(oldInvoiceItem);

                Db.ExecuteNonQuery(
                    Update("crm_invoice_item")
                        .Set("title", invoiceItem.Title)
                        .Set("description", invoiceItem.Description)
                        .Set("stock_keeping_unit", invoiceItem.StockKeepingUnit)
                        .Set("price", invoiceItem.Price)
                        .Set("stock_quantity", invoiceItem.StockQuantity)
                        .Set("track_inventory", invoiceItem.TrackInventory)
                        .Set("invoice_tax1_id", invoiceItem.InvoiceTax1ID)
                        .Set("invoice_tax2_id", invoiceItem.InvoiceTax2ID)
                        .Set("currency", String.Empty)
                        .Set("last_modifed_on", DateTime.UtcNow)
                        .Set("last_modifed_by", SecurityContext.CurrentAccount.ID)
                        .Where(Exp.Eq("id", invoiceItem.ID)));

                invoiceItem.LastModifedOn = DateTime.UtcNow;
                invoiceItem.LastModifedBy = SecurityContext.CurrentAccount.ID;
            }

            return invoiceItem;
        }

        #endregion


        #region Delete

        public virtual InvoiceItem DeleteInvoiceItem(int invoiceItemID)
        {
            var invoiceItem = GetByID(invoiceItemID);
            if (invoiceItem == null) return null;

            CRMSecurity.DemandDelete(invoiceItem);

            Db.ExecuteNonQuery(Delete("crm_invoice_item").Where("id", invoiceItemID));

            /*_cache.Remove(_invoiceItemCacheKey);
            _cache.Insert(_invoiceItemCacheKey, String.Empty);*/

            return invoiceItem;
        }

        public virtual List<InvoiceItem> DeleteBatchInvoiceItems(int[] invoiceItemIDs)
        {
            if (invoiceItemIDs == null || !invoiceItemIDs.Any()) return null;

            var items = GetInvoiceItems(invoiceItemIDs).Where(CRMSecurity.CanDelete).ToList();
            if (!items.Any()) return items;

            // Delete relative  keys
            /*_cache.Remove(_invoiceItemCacheKey);
            _cache.Insert(_invoiceItemCacheKey, String.Empty);*/

            DeleteBatchItemsExecute(items);

            return items;
        }

        #endregion


        #region Private Methods

        private void DeleteBatchItemsExecute(List<InvoiceItem> items)
        {
            var ids = items.Select(x => x.ID).ToArray();

            //using (var tx = db.BeginTransaction(true))
            ///{
            Db.ExecuteNonQuery(Delete("crm_invoice_item").Where(Exp.In("id", ids)));
            //    tx.Commit();
            //}
        }

        private static InvoiceItem ToInvoiceItem(object[] row)
        {
            return new InvoiceItem
            {
                ID = Convert.ToInt32(row[0]),
                Title = Convert.ToString(row[1]),
                Description = Convert.ToString(row[2]),
                StockKeepingUnit = Convert.ToString(row[3]),
                Price = Convert.ToDecimal(row[4]),
                StockQuantity = Convert.ToDecimal(row[5]),
                TrackInventory = Convert.ToBoolean(row[6]),
                InvoiceTax1ID = Convert.ToInt32(row[7]),
                InvoiceTax2ID = Convert.ToInt32(row[8]),
                Currency = Convert.ToString(row[9]),
                CreateOn = TenantUtil.DateTimeFromUtc(DateTime.Parse(row[10].ToString())),
                CreateBy = ToGuid(row[11]),
                LastModifedOn = TenantUtil.DateTimeFromUtc(DateTime.Parse(row[12].ToString())),
                LastModifedBy = ToGuid(row[13])
            };
        }

        private SqlQuery GetInvoiceItemSqlQuery(Exp where)
        {
            var sqlQuery = Query("crm_invoice_item")
                .Select(
                    "id",
                    "title",
                    "description",
                    "stock_keeping_unit",
                    "price",
                    "stock_quantity",
                    "track_inventory",
                    "invoice_tax1_id",
                    "invoice_tax2_id",
                    "currency",
                    "create_on",
                    "create_by",
                    "last_modifed_on",
                    "last_modifed_by");

            if (where != null)
            {
                sqlQuery.Where(where);
            }

            return sqlQuery;
        }

        private Exp WhereConditional(
                                ICollection<int> exceptIDs,
                                String searchText,
                                int status,
                                bool? inventoryStock)
        {
            var conditions = new List<Exp>();

            //if (status != null)
            //{
            //    conditions.Add(Exp.Eq("status", (int)status.Value));
            //}


            if (!String.IsNullOrEmpty(searchText))
            {
                searchText = searchText.Trim();

                var keywords = searchText.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
                   .ToArray();

                if (keywords.Length > 0)
                    //if (FullTextSearch.SupportModule(FullTextSearch.CRMInvoiceItemModule))
                    //{
                    //    ids = FullTextSearch.Search(searchText, FullTextSearch.CRMInvoiceItemModule)
                    //        .GetIdentifiers()
                    //        .Select(item => Convert.ToInt32(item.Split('_')[1])).Distinct().ToList();

                    //    if (ids.Count == 0) return null;
                    //}
                    //else
                    conditions.Add(BuildLike(new[] { "title", "description", "stock_keeping_unit" }, keywords));
            }

            if (exceptIDs.Count > 0)
            {
                conditions.Add(!Exp.In("id", exceptIDs.ToArray()));
            }


            if (inventoryStock.HasValue)
            {
                conditions.Add(Exp.Eq("track_inventory", inventoryStock.Value));
            }

            if (conditions.Count == 0) return null;

            return conditions.Count == 1 ? conditions[0] : conditions.Aggregate((i, j) => i & j);
        }

        #endregion
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/Interfaces/IMailboxSignatureDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Collections.Generic;

using ASC.Mail.Core.Entities;

namespace ASC.Mail.Core.Dao.Interfaces
{
    public interface IMailboxSignatureDao
    {
        /// <summary>
        ///     Get signature by mailbox id.
        /// </summary>
        /// <param name="mailboxId"></param>
        /// <returns>signature</returns>
        MailboxSignature GetSignature(int mailboxId);

        /// <summary>
        ///     Get a list of signature.
        /// </summary>
        /// <param name="mailboxIds"></param>
        /// <returns>list of signature</returns>
        List<MailboxSignature> GetSignatures(List<int> mailboxIds);

        /// <summary>
        ///     Save or update signature
        /// </summary>
        /// <param name="signature"></param>
        /// <returns>count of affected rows: 1 - OK, 0 - Fail</returns>
        int SaveSignature(MailboxSignature signature);

        /// <summary>
        ///     Delete signature
        /// </summary>
        /// <param name="mailboxId">id</param>
        /// <returns>count of affected rows: 1 - OK, 0 - Fail</returns>
        int DeleteSignature(int mailboxId);
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/ServersCore/commonDelegates.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net
{
    /// <summary>
    /// Represent the method what will handle Error event.
    /// </summary>
    /// <param name="sender">Delegate caller.</param>
    /// <param name="e">Event data.</param>
    public delegate void ErrorEventHandler(object sender, Error_EventArgs e);

    /// <summary>
    /// To be supplied.
    /// </summary>
    public delegate void LogEventHandler(object sender, Log_EventArgs e);

    /// <summary>
    /// Represents the method that will handle the <see href="LumiSoftMailServerSMTPSMTP_ServerValidateIPAddressFieldOrEvent.html">SMTP_Server.ValidateIPAddress</see> and <see href="LumiSoftMailServerPOP3POP3_ServerValidateIPAddressFieldOrEvent.html">POP3_Server.ValidateIPAddress</see>event.
    /// </summary>
    /// <param name="sender">The source of the event. </param>
    /// <param name="e">A <see href="LumiSoftMailServerValidateIP_EventArgs.html">ValidateIP_EventArgs</see> that contains the event data.</param>
    public delegate void ValidateIPHandler(object sender, ValidateIP_EventArgs e);
}

<|start_filename|>web/studio/ASC.Web.Studio/Management.aspx.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;

using ASC.Core;
using ASC.Web.Core.Files;
using ASC.Web.Core.Utility.Settings;
using ASC.Web.Studio.Core;
using ASC.Web.Studio.PublicResources;
using ASC.Web.Studio.UserControls.Common.HelpCenter;
using ASC.Web.Studio.UserControls.Common.InviteLink;
using ASC.Web.Studio.UserControls.Common.Support;
using ASC.Web.Studio.UserControls.Common.UserForum;
using ASC.Web.Studio.UserControls.Management;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio
{
    public partial class Management : MainPage
    {
        protected static readonly Lazy<Dictionary<ManagementType, ManagementControlAttribute[]>> ManagementModules =
            new Lazy<Dictionary<ManagementType, ManagementControlAttribute[]>>(LoadModules, LazyThreadSafetyMode.PublicationOnly);

        public TenantAccessSettings TenantAccess { get; private set; }
        protected ManagementType CurrentModule { get; private set; }
        protected List<ManagementType> NavigationList { get; private set; }

        protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);
            if (CoreContext.Configuration.Personal)
            {
                Context.Response.Redirect(FilesLinkUtility.FilesBaseAbsolutePath);
            }

            if (!SecurityContext.CheckPermissions(SecutiryConstants.EditPortalSettings))
            {
                Response.Redirect(CommonLinkUtility.GetDefault());
            }

            TenantAccess = TenantAccessSettings.Load();
        }

        protected void Page_Load(object sender, EventArgs e)
        {

            var help = (HelpCenter)LoadControl(HelpCenter.Location);
            help.IsSideBar = true;
            HelpHolder.Controls.Add(help);
            SupportHolder.Controls.Add(LoadControl(Support.Location));
            UserForumHolder.Controls.Add(LoadControl(UserForum.Location));
            InviteUserHolder.Controls.Add(LoadControl(InviteLink.Location));

            CurrentModule = GetCurrentModule();
            NavigationList = GetNavigationList();
            Page.Title = HeaderStringHelper.GetPageTitle(GetNavigationTitle(CurrentModule));

            if (CurrentModule == ManagementType.HelpCenter)
            {
                SettingsContainer.Controls.Add(LoadControl(HelpCenter.Location));
                return;
            }

            foreach (var control in ManagementModules.Value[CurrentModule])
            {
                SettingsContainer.Controls.Add(LoadControl(control.Location));
            }
        }

        protected ManagementType GetCurrentModule()
        {
            const ManagementType defaultModule = ManagementType.Customization;
            ManagementType currentModule;

            if (!Enum.TryParse(Request["type"], out currentModule))
            {
                return defaultModule;
            }

            if (!ManagementModules.Value.ContainsKey(currentModule) && currentModule != ManagementType.HelpCenter)
            {
                return defaultModule;
            }

            return currentModule;
        }

        private static List<ManagementType> GetNavigationList()
        {
            return ManagementModules.Value
                                    .Where(keyValue => keyValue.Value.Any())
                                    .Select(keyValue => keyValue.Key)
                                    .ToList();
        }

        protected string GetNavigationTitle(ManagementType module)
        {
            switch (module)
            {
                case ManagementType.Customization:
                    return Resource.Customization;

                case ManagementType.ProductsAndInstruments:
                    return Resource.ProductsAndInstruments;

                case ManagementType.PortalSecurity:
                    return Resource.PortalSecurity;

                case ManagementType.AccessRights:
                    return Resource.AccessRights;

                case ManagementType.Backup:
                    return Resource.Backup;

                case ManagementType.LoginHistory:
                    return AuditResource.LoginHistoryNav;

                case ManagementType.AuditTrail:
                    return AuditResource.AuditTrailNav;

                case ManagementType.LdapSettings:
                    return Resource.LdapSettings;

                case ManagementType.ThirdPartyAuthorization:
                    return Resource.ThirdPartyAuthorization;

                case ManagementType.SmtpSettings:
                    return Resource.SmtpSettings;

                case ManagementType.Statistic:
                    return Resource.StatisticsTitle;

                case ManagementType.Monitoring:
                    return Resource.Monitoring;

                case ManagementType.SingleSignOnSettings:
                    return Resource.SingleSignOnSettings;

                case ManagementType.Migration:
                    return Resource.Migration;

                case ManagementType.DeletionPortal:
                    return Resource.DeactivationDeletionPortal;

                case ManagementType.HelpCenter:
                    return Resource.HelpCenter;

                case ManagementType.DocService:
                    return Resource.DocService;

                case ManagementType.FullTextSearch:
                    return Resource.FullTextSearchSettings;

                case ManagementType.WhiteLabel:
                    return Resource.WhiteLabel;

                case ManagementType.MailService:
                    return Resource.MailService;

                case ManagementType.Storage:
                    return Resource.Storage;

                case ManagementType.PrivacyRoom:
                    return Resource.Encryption;
                default:
                    return Resource.ResourceManager.GetString(module.ToString()) ?? module.ToString();
            }
        }

        protected static bool DisplayModule(ManagementControlAttribute control)
        {
            var result = DisplayModule(control.Module);
            if (control.SubModule.HasValue)
                result = result && DisplayModule(control.SubModule.Value);

            return result;
        }

        protected static bool DisplayModule(ManagementType module)
        {
            if (!SetupInfo.IsVisibleSettings(module.ToString())) return false;

            switch (module)
            {
                case ManagementType.Migration:
                    return TransferPortal.TransferRegions.Count > 1;
                case ManagementType.Backup:
                    //only SaaS features
                    return !CoreContext.Configuration.Standalone &&
                        !TenantAccessSettings.Load().Anyone;
                case ManagementType.AuditTrail:
                case ManagementType.LoginHistory:
                case ManagementType.LdapSettings:
                case ManagementType.WhiteLabel:
                case ManagementType.SingleSignOnSettings:
                    //only SaaS features
                    return !CoreContext.Configuration.Standalone;
                case ManagementType.DeletionPortal:
                    //only SaaS or Server+ControlPanel
                    return !CoreContext.Configuration.Standalone || TenantExtra.Enterprise && CoreContext.TenantManager.GetTenants().Count() > 1;
                case ManagementType.MailService:
                    //only if MailServer available
                    return SetupInfo.IsVisibleSettings("AdministrationPage");
                case ManagementType.Storage:
                    //only standalone feature
                    return CoreContext.Configuration.Standalone;
                case ManagementType.PrivacyRoom:
                    return !CoreContext.Configuration.Standalone && PrivacyRoomSettings.Available;
            }

            return true;
        }

        protected bool DisplayModuleList(CategorySettings category)
        {
            return NavigationList.Intersect(category.Modules).Any();
        }

        protected class CategorySettings
        {
            public String Title { get; set; }
            public ManagementType ModuleUrl { get; set; }
            public String ClassName { get; set; }

            private List<ManagementType> modules;
            public IEnumerable<ManagementType> Modules { get { return modules; } }

            public CategorySettings() { }

            public CategorySettings(IEnumerable<ManagementType> managementTypes)
            {
                modules = managementTypes.Where(DisplayModule).ToList();
            }

            public void AddModules(params ManagementType[] newModules)
            {
                if (modules == null) modules = new List<ManagementType>();
                modules.AddRange(newModules.Where(DisplayModule));
            }

            public string GetNavigationUrl()
            {
                return GetNavigationUrl(modules == null ? ModuleUrl : modules.First());
            }

            public string GetNavigationUrl(ManagementType module)
            {
                return CommonLinkUtility.GetAdministration(module);
            }
        }

        protected List<CategorySettings> GetCategoryList()
        {
            var securityCategorySettings = new CategorySettings(new[]
                                                                {
                                                                    ManagementType.PortalSecurity,
                                                                    ManagementType.AccessRights,
                                                                    ManagementType.PrivacyRoom,
                                                                    ManagementType.LoginHistory,
                                                                    ManagementType.AuditTrail
                                                                })
            {
                Title = Resource.ManagementCategorySecurity,
                ClassName = "security"
            };

            var generalSettings = new CategorySettings(new[]
                                                       {
                                                           ManagementType.Customization,
                                                           ManagementType.ProductsAndInstruments,
                                                           ManagementType.WhiteLabel
                                                       })
            {
                Title = Resource.ManagementCategoryCommon,
                ClassName = "general"
            };

            var backupSettings =
                new CategorySettings(new[]
                                     {
                                         ManagementType.Migration,
                                         ManagementType.Backup,
                                         ManagementType.DeletionPortal,
                                         ManagementType.Storage
                                     })
                {
                    Title = Resource.DataManagement,
                    ClassName = "backup"
                };

            var integrationCategorySettings = new CategorySettings(new[]
                                                                   {
                                                                       ManagementType.LdapSettings,
                                                                       ManagementType.SingleSignOnSettings,
                                                                       ManagementType.ThirdPartyAuthorization,
                                                                       ManagementType.DocService,
                                                                       ManagementType.MailService,
                                                                       ManagementType.SmtpSettings
                                                                   })
            {
                Title = Resource.ManagementCategoryIntegration,
                ClassName = "productsandinstruments"
            };

            if (CoreContext.Configuration.Standalone)
            {
                integrationCategorySettings.AddModules(ManagementType.FullTextSearch);
            }

            var statisticSettings = new CategorySettings
            {
                Title = Resource.ManagementCategoryStatistic,
                ModuleUrl = ManagementType.Statistic,
                ClassName = "statistic"
            };
            var monitoringSettings = new CategorySettings
            {
                Title = Resource.Monitoring,
                ModuleUrl = ManagementType.Monitoring,
                ClassName = "monitoring"
            };

            var result = new List<CategorySettings>
                   {
                       generalSettings,
                       securityCategorySettings,
                       backupSettings,
                       integrationCategorySettings,
                       statisticSettings,
                       monitoringSettings
                   };

            return result;
        }

        private static Dictionary<ManagementType, ManagementControlAttribute[]> LoadModules()
        {
            return Assembly.GetExecutingAssembly()
                           .GetTypes()
                           .Select(type => type.GetCustomAttribute<ManagementControlAttribute>())
                           .Where(control => control != null && DisplayModule(control))
                           .GroupBy(control => control.Module)
                           .OrderBy(group => (int)group.Key)
                           .ToDictionary(
                           group => group.Key,
                           group => group.OrderBy(control => control.SortOrder).ToArray());
        }
    }

    [AttributeUsage(AttributeTargets.Class)]
    public class ManagementControlAttribute : Attribute
    {
        public ManagementType Module { get; private set; }

        public ManagementType? SubModule { get; private set; }

        public string Location { get; private set; }

        public int SortOrder { get; set; }

        public ManagementControlAttribute(ManagementType module, string location)
        {
            Module = module;
            Location = location;
        }

        public ManagementControlAttribute(ManagementType module, ManagementType submodule, string location)
        {
            Module = module;
            SubModule = submodule;
            Location = location;
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/HttpHandlers/ImportFileHandler.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Web;

using ASC.CRM.Core;
using ASC.Web.Core;
using ASC.Web.Core.Utility;
using ASC.Web.CRM.Configuration;
using ASC.Web.Studio.Controls.FileUploader;


namespace ASC.Web.CRM.Classes
{
    public class ImportFileHandler : IFileUploadHandler
    {
        public FileUploadResult ProcessUpload(HttpContext context)
        {
            if (!WebItemSecurity.IsAvailableForMe(ProductEntryPoint.ID))
                throw CRMSecurity.CreateSecurityException();

            var fileUploadResult = new FileUploadResult();

            if (!FileToUpload.HasFilesToUpload(context)) return fileUploadResult;

            var file = new FileToUpload(context);

            String assignedPath;

            Global.GetStore().SaveTemp("temp", out assignedPath, file.InputStream);

            file.InputStream.Position = 0;

            var jObject = ImportFromCSV.GetInfo(file.InputStream, context.Request["importSettings"]);

            jObject.Add("assignedPath", assignedPath);

            fileUploadResult.Success = true;
            fileUploadResult.Data = Global.EncodeTo64(jObject.ToString());

            return fileUploadResult;
        }
    }
}

<|start_filename|>common/ASC.Data.Backup/Tasks/Data/DataRowInfo.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Text;

namespace ASC.Data.Backup.Tasks.Data
{
    internal class DataRowInfo
    {
        private readonly List<string> _columnNames = new List<string>();
        private readonly List<object> _values = new List<object>();

        public string TableName { get; private set; }

        public IReadOnlyCollection<string> ColumnNames
        {
            get { return _columnNames.AsReadOnly(); }
        }

        public object this[int index]
        {
            get { return _values[index]; }
        }

        public object this[string columnName]
        {
            get { return _values[GetIndex(columnName)]; }
        }

        public DataRowInfo(string tableName)
        {
            TableName = tableName;
        }

        public void SetValue(string columnName, object item)
        {
            var index = GetIndex(columnName);
            if (index == -1)
            {
                _columnNames.Add(columnName);
                _values.Add(item);
            }
            else
            {
                _values[index] = item;
            }
        }

        private int GetIndex(string columnName)
        {
            return _columnNames.FindIndex(name => name.Equals(columnName, StringComparison.OrdinalIgnoreCase));
        }

        public override string ToString()
        {
            const int maxStrLength = 150;

            var sb = new StringBuilder(maxStrLength);

            int i = 0;
            while (i < _values.Count && sb.Length <= maxStrLength)
            {
                var strVal = Convert.ToString(_values[i]);
                sb.AppendFormat("\"{0}\", ", strVal);
                i++;
            }

            if (sb.Length > maxStrLength + 2)
            {
                sb.Length = maxStrLength - 3;
                sb.Append("...");
            }
            else if (sb.Length > 0)
            {
                sb.Length = sb.Length - 2;
            }

            return sb.ToString();
        }
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Products/CRM/Core/Enums/ReportTimePeriodEnum.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.CRM.Core
{
    public enum ReportTimePeriod
    {
        Today,
        Yesterday,
        Tomorrow,

        CurrentWeek,
        PreviousWeek,
        NextWeek,

        CurrentMonth,
        PreviousMonth,
        NextMonth,

        CurrentQuarter,
        PreviousQuarter,
        NextQuarter,

        CurrentYear,
        PreviousYear,
        NextYear,

        DuringAllTime
    }
}


<|start_filename|>web/studio/ASC.Web.Studio/Controls/Common/FeedControl.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.ComponentModel;
using System.Web.UI;

using ASC.Web.Core;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.Controls.Common
{
    [DefaultProperty("Title")]
    [ToolboxData("<{0}:FeedControl runat=server></{0}:FeedControl>")]
    public class FeedControl : Control
    {
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string Title { get; set; }

        [DefaultValue("")]
        [Localizable(false)]
        public string ProductId { get; set; }

        [DefaultValue("")]
        [Localizable(false)]
        public string ContainerId { get; set; }

        [DefaultValue("")]
        [Localizable(true)]
        public string ModuleId { get; set; }

        [DefaultValue(false)]
        [Localizable(false)]
        public bool ContentOnly { get; set; }

        [DefaultValue(true)]
        [Localizable(false)]
        public bool AutoFill { get; set; }

        public FeedControl()
        {
            ContentOnly = false;
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if (AutoFill)
            {
                if (string.IsNullOrEmpty(ProductId))
                {
                    ProductId = CommonLinkUtility.GetProductID().ToString("D");
                }
                if (string.IsNullOrEmpty(ModuleId))
                {
                    IProduct product;
                    IModule module;
                    CommonLinkUtility.GetLocationByRequest(out product, out module);
                    if (module != null)
                    {
                        ModuleId = module.ID.ToString("D");
                    }
                }
            }

            writer.Write(Services.WhatsNew.feed.RenderRssMeta(Title, ProductId));
        }
    }
}

<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/SIP/Stack/SIP_DialogState.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.SIP.Stack
{
    /// <summary>
    /// Specifies dialog state.
    /// </summary>
    public enum SIP_DialogState
    {
        /// <summary>
        /// Dialog isn't established yet.
        /// </summary>
        Early,

        /// <summary>
        /// Dialog has got 2xx response.
        /// </summary>
        Confirmed,

        /// <summary>
        /// Dialog is terminating.
        /// </summary>
        Terminating,

        /// <summary>
        /// Dialog is terminated.
        /// </summary>
        Terminated,

        /// <summary>
        /// Dialog is disposed.
        /// </summary>
        Disposed,
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/CrmLinkDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Mail.Core.Dao.Interfaces;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Data.Contracts;

namespace ASC.Mail.Core.Dao
{
    public class CrmLinkDao : ICrmLinkDao
    {
        public IDbManager Db { get; private set; }
        public int Tenant { get; private set; }

        protected string CurrentUserId { get; private set; }

        public CrmLinkDao(IDbManager dbManager, int tenant, string user)
        {
            Db = dbManager;
            Tenant = tenant;
            CurrentUserId = user;
        }

        public List<CrmContactData> GetLinkedCrmContactEntities(string chainId, int mailboxId)
        {
            var query = new SqlQuery(ChainXCrmContactEntityTable.TABLE_NAME)
                .Select(ChainXCrmContactEntityTable.Columns.EntityId)
                .Select(ChainXCrmContactEntityTable.Columns.EntityType)
                .Where(ChainXCrmContactEntityTable.Columns.MailboxId, mailboxId)
                .Where(ChainXCrmContactEntityTable.Columns.Tenant, Tenant)
                .Where(ChainXCrmContactEntityTable.Columns.ChainId, chainId);

            return Db.ExecuteList(query)
                .ConvertAll(r => new CrmContactData
                {
                    Id = Convert.ToInt32(r[0]),
                    Type = (CrmContactData.EntityTypes)r[1]
                });
        }

        public int SaveCrmLinks(string chainId, int mailboxId, IEnumerable<CrmContactData> crmContactEntities)
        {
            var query = new SqlInsert(ChainXCrmContactEntityTable.TABLE_NAME)
                .InColumns(ChainXCrmContactEntityTable.Columns.ChainId,
                    ChainXCrmContactEntityTable.Columns.MailboxId,
                    ChainXCrmContactEntityTable.Columns.Tenant,
                    ChainXCrmContactEntityTable.Columns.EntityId,
                    ChainXCrmContactEntityTable.Columns.EntityType);

            foreach (var contactEntity in crmContactEntities)
            {
                query.Values(chainId, mailboxId, Tenant, contactEntity.Id, contactEntity.Type);
            }

            return Db.ExecuteNonQuery(query);
        }

        public int UpdateCrmLinkedMailboxId(string chainId, int oldMailboxId, int newMailboxId)
        {
            var updateOldChainIdQuery = new SqlUpdate(ChainXCrmContactEntityTable.TABLE_NAME)
                .Set(ChainXCrmContactEntityTable.Columns.MailboxId, newMailboxId)
                .Where(ChainXCrmContactEntityTable.Columns.ChainId, chainId)
                .Where(ChainXCrmContactEntityTable.Columns.MailboxId, oldMailboxId)
                .Where(ChainXCrmContactEntityTable.Columns.Tenant, Tenant);

            return Db.ExecuteNonQuery(updateOldChainIdQuery);
        }

        public int UpdateCrmLinkedChainId(string chainId, int mailboxId, string newChainId)
        {
            var query = new SqlUpdate(ChainXCrmContactEntityTable.TABLE_NAME)
                .Set(ChainXCrmContactEntityTable.Columns.ChainId, newChainId)
                .Where(ChainXCrmContactEntityTable.Columns.ChainId, chainId)
                .Where(ChainXCrmContactEntityTable.Columns.MailboxId, mailboxId)
                .Where(ChainXCrmContactEntityTable.Columns.Tenant, Tenant);

            return Db.ExecuteNonQuery(query);
        }

        public void RemoveCrmLinks(string chainId, int mailboxId, IEnumerable<CrmContactData> crmContactEntities)
        {
            foreach (var crmContactEntity in crmContactEntities)
            {
                var removeLinkQuery = new SqlDelete(ChainXCrmContactEntityTable.TABLE_NAME)
                    .Where(ChainXCrmContactEntityTable.Columns.ChainId, chainId)
                    .Where(ChainXCrmContactEntityTable.Columns.MailboxId, mailboxId)
                    .Where(ChainXCrmContactEntityTable.Columns.Tenant, Tenant)
                    .Where(ChainXCrmContactEntityTable.Columns.EntityId, crmContactEntity.Id)
                    .Where(ChainXCrmContactEntityTable.Columns.EntityType, crmContactEntity.Type);

                Db.ExecuteNonQuery(removeLinkQuery);
            }
        }

        public int RemoveCrmLinks(int mailboxId)
        {
            var query =
                new SqlDelete(ChainXCrmContactEntityTable.TABLE_NAME)
                    .Where(ChainXCrmContactEntityTable.Columns.Tenant, Tenant)
                    .Where(ChainXCrmContactEntityTable.Columns.MailboxId, mailboxId);

            return Db.ExecuteNonQuery(query);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/StorageSettings/js/storagesettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


ASC.StorageSettings = (function () {
    function init() {
        var $storageSettingsTemplateBlock = jq("#storageSettingsBlockTemplate");
        var storageBlock = { id: "storage", title: ASC.Resources.Master.ResourceJS.StorageStorageTitle };
        var cdnBlock = { id: "cdn", title: ASC.Resources.Master.ResourceJS.StorageCdnTitle };

        jq(".storageBlock")
            .append($storageSettingsTemplateBlock.tmpl(storageBlock))
            .append($storageSettingsTemplateBlock.tmpl(cdnBlock));

        Teamlab.getAllStorages({},
        {
            success: onGet.bind(null, storageBlock.id, Teamlab.updateStorage, Teamlab.resetToDefaultStorage)
        });

        Teamlab.getAllCdnStorages({},
        {
            success: onGet.bind(null, cdnBlock.id, Teamlab.updateCdnStorage, Teamlab.resetToDefaultCdn)
        });
    }

    function onGet(storageid, updateFunc, resetFunc, params, data) {
        var current = data.find(function (item) { return item.current; }) ||
            data.find(function (item) { return item.isSet; }) ||
            data[0];

        var selected = current;
        var $storage = jq("#" + storageid);
        var $authService = $storage.find(".auth-service");
        var $link = $authService.find(".link");
        var $storageSettingsTemplate = jq("#storageSettingsTemplate");
        var $storageBlock = $storage.find(".auth-data");

        $link.advancedSelector(
                {
                    itemsChoose: data,
                    showSearch: false,
                    onechosen: true,
                    sortMethod: function() { return 0; }
                }
            );

        $link.on("showList", function (event, item) {
            selected = data.find(function (dataItem) { return dataItem.id === item.id; });
            $link.text(selected.title);
            $storageBlock.html($storageSettingsTemplate.tmpl(selected));
        });

        $link.advancedSelector("selectBeforeShow", current);

        $authService.removeClass("display-none");

        var clickEvent = "click";
        $storageBlock.on(clickEvent, "[id^='saveBtn']",function () {
            var $currentButton = jq(this);
            if ($currentButton.hasClass("disable")) return;
            $currentButton.addClass("disable");

            var $item = $currentButton.parents(".storageItem");

            var data = {
                module: selected.id,
                props: initProps($item.find("input"))
            };

            updateFunc({},
            data,
            {
                success: function () {
                    location.reload();
                },
                error: function (params, data) {
                    toastr.error(data);
                }
            });
        });

        $storageBlock.on(clickEvent, "[id^='setDefault']", function () {
            var $currentButton = jq(this);
            if ($currentButton.hasClass("disable")) return;
            $currentButton.addClass("disable");

            resetFunc({},
            {
                success: function () {
                    location.reload();
                },
                error: function (params, data) {
                    toastr.error(data);
                }
            });
        });
    }

    function initProps($inputs) {
        var result = [];
        for (var i = 0; i < $inputs.length; i++) {
            var $inputItem = jq($inputs[i]);
            result.push({
                key: $inputItem.attr("id"),
                value: $inputItem.val()
            });
        }
        return result;
    }

    return { init: init };
})();

jq(document).ready(function () {
    ASC.StorageSettings.init();
});

<|start_filename|>common/ASC.Data.Storage/IDataStore.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

using ASC.Data.Storage.Configuration;

namespace ASC.Data.Storage
{
    ///<summary>
    /// Interface for working with files
    ///</summary>
    public interface IDataStore
    {
        IQuotaController QuotaController { get; set; }

        TimeSpan GetExpire(string domain);

        ///<summary>
        /// Get absolute Uri for html links to handler
        ///</summary>
        ///<param name="path"></param>
        ///<returns></returns>
        Uri GetUri(string path);

        ///<summary>
        /// Get absolute Uri for html links to handler
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        ///<returns></returns>
        Uri GetUri(string domain, string path);

        /// <summary>
        /// Get absolute Uri for html links to handler
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="path"></param>
        /// <param name="expire"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        Uri GetPreSignedUri(string domain, string path, TimeSpan expire, IEnumerable<string> headers);

        ///<summary>
        /// Supporting generate uri to the file
        ///</summary>
        ///<returns></returns>
        bool IsSupportInternalUri { get; }

        /// <summary>
        /// Get absolute Uri for html links
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="path"></param>
        /// <param name="expire"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        Uri GetInternalUri(string domain, string path, TimeSpan expire, IEnumerable<string> headers);

        ///<summary>
        /// A stream of read-only. In the case of the C3 stream NetworkStream general, and with him we have to work
        /// Very carefully as a Jedi cutter groin lightsaber.
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        ///<returns></returns>
        Stream GetReadStream(string domain, string path);

        ///<summary>
        /// A stream of read-only. In the case of the C3 stream NetworkStream general, and with him we have to work
        /// Very carefully as a Jedi cutter groin lightsaber.
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        ///<returns></returns>
        Stream GetReadStream(string domain, string path, int offset);

        Task<Stream> GetReadStreamAsync(string domain, string path, int offset);

        ///<summary>
        /// Saves the contents of the stream in the repository.
        ///</ Summary>
        /// <param Name="domain"> </param>
        /// <param Name="path"> </param>
        /// <param Name="stream"> flow. Is read from the current position! Desirable to set to 0 when the transmission MemoryStream instance </param>
        /// <returns> </Returns>
        Uri Save(string domain, string path, Stream stream);

        /// <summary>
        /// Saves the contents of the stream in the repository.
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="path"></param>
        /// <param name="stream"></param>
        /// <param name="acl"></param>
        /// <returns></returns>
        Uri Save(string domain, string path, Stream stream, ACL acl);

        /// <summary>
        /// Saves the contents of the stream in the repository.
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="path"></param>
        /// <param name="stream"></param>
        /// <param name="attachmentFileName"></param>
        /// <returns></returns>
        Uri Save(string domain, string path, Stream stream, string attachmentFileName);

        /// <summary>
        /// Saves the contents of the stream in the repository.
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="path"></param>
        /// <param name="stream"></param>
        /// <param name="contentType"></param>
        /// <param name="contentDisposition"></param>
        /// <returns></returns>
        Uri Save(string domain, string path, Stream stream, string contentType, string contentDisposition);

        /// <summary>
        /// Saves the contents of the stream in the repository.
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="path"></param>
        /// <param name="stream"></param>
        /// <param name="contentEncoding"></param>
        /// <param name="cacheDays"></param>
        /// <returns></returns>
        Uri Save(string domain, string path, Stream stream, string contentEncoding, int cacheDays);

        string InitiateChunkedUpload(string domain, string path);

        string UploadChunk(string domain, string path, string uploadId, Stream stream, long defaultChunkSize, int chunkNumber, long chunkLength);

        Uri FinalizeChunkedUpload(string domain, string path, string uploadId, Dictionary<int, string> eTags);

        void AbortChunkedUpload(string domain, string path, string uploadId);

        bool IsSupportChunking { get; }

        bool IsSupportedPreSignedUri { get; }

        ///<summary>
        /// Deletes file
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        void Delete(string domain, string path);

        ///<summary>
        /// Deletes file by mask
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="folderPath"></param>
        ///<param name="pattern">Wildcard mask (*.png)</param>
        ///<param name="recursive"></param>
        void DeleteFiles(string domain, string folderPath, string pattern, bool recursive);

        ///<summary>
        /// Deletes files
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="listPaths"></param>
        void DeleteFiles(string domain, List<string> paths);

        ///<summary>
        /// Deletes file by last modified date
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="folderPath"></param>
        ///<param name="fromDate"></param>
        ///<param name="toDate"></param>
        void DeleteFiles(string domain, string folderPath, DateTime fromDate, DateTime toDate);

        ///<summary>
        /// Moves the contents of one directory to another. s3 for a very expensive procedure.
        ///</summary>
        ///<param name="srcdomain"></param>
        ///<param name="srcdir"></param>
        ///<param name="newdomain"></param>
        ///<param name="newdir"></param>
        void MoveDirectory(string srcdomain, string srcdir, string newdomain, string newdir);

        ///<summary>
        /// Moves file
        ///</summary>
        ///<param name="srcdomain"></param>
        ///<param name="srcpath"></param>
        ///<param name="newdomain"></param>
        ///<param name="newpath"></param>
        ///<returns></returns>
        Uri Move(string srcdomain, string srcpath, string newdomain, string newpath, bool quotaCheckFileSize = true);

        ///<summary>
        /// Saves the file in the temp. In fact, almost no different from the usual Save except that generates the file name itself. An inconvenient thing.
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="assignedPath"></param>
        ///<param name="stream"></param>
        ///<returns></returns>
        Uri SaveTemp(string domain, out string assignedPath, Stream stream);

        /// <summary>
        ///  Returns a list of links to all subfolders
        /// </summary>
        /// <param name="domain"></param>
        /// <param name="path"></param>
        /// <param name="recursive">iterate subdirectories or not</param>
        /// <returns></returns>
        string[] ListDirectoriesRelative(string domain, string path, bool recursive);

        ///<summary>
        /// Returns a list of links to all files
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        ///<param name="pattern">Wildcard mask (*. jpg for example)</param>
        ///<param name="recursive">iterate subdirectories or not</param>
        ///<returns></returns>
        Uri[] ListFiles(string domain, string path, string pattern, bool recursive);

        ///<summary>
        /// Returns a list of relative paths for all files
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        ///<param name="pattern">Wildcard mask (*. jpg for example)</param>
        ///<param name="recursive">iterate subdirectories or not</param>
        ///<returns></returns>
        string[] ListFilesRelative(string domain, string path, string pattern, bool recursive);

        ///<summary>
        /// Checks whether a file exists. On s3 it took long time.
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        ///<returns></returns>
        bool IsFile(string domain, string path);

        Task<bool> IsFileAsync(string domain, string path);

        ///<summary>
        /// Checks whether a directory exists. On s3 it took long time.
        ///</summary>
        ///<param name="domain"></param>
        ///<param name="path"></param>
        ///<returns></returns>
        bool IsDirectory(string domain, string path);

        void DeleteDirectory(string domain, string path);

        long GetFileSize(string domain, string path);

        long GetDirectorySize(string domain, string path);

        long ResetQuota(string domain);

        long GetUsedQuota(string domain);

        Uri Copy(string srcdomain, string path, string newdomain, string newpath);
        void CopyDirectory(string srcdomain, string dir, string newdomain, string newdir);

        //Then there are restarted methods without domain. functionally identical to the top

#pragma warning disable 1591
        Stream GetReadStream(string path);
        Uri Save(string path, Stream stream, string attachmentFileName);
        Uri Save(string path, Stream stream);
        void Delete(string path);
        void DeleteFiles(string folderPath, string pattern, bool recursive);
        Uri Move(string srcpath, string newdomain, string newpath);
        Uri SaveTemp(out string assignedPath, Stream stream);
        string[] ListDirectoriesRelative(string path, bool recursive);
        Uri[] ListFiles(string path, string pattern, bool recursive);
        bool IsFile(string path);
        bool IsDirectory(string path);
        void DeleteDirectory(string path);
        long GetFileSize(string path);
        long GetDirectorySize(string path);
        Uri Copy(string path, string newdomain, string newpath);
        void CopyDirectory(string dir, string newdomain, string newdir);
#pragma warning restore 1591


        IDataStore Configure(IDictionary<string, string> props);
        IDataStore SetQuotaController(IQuotaController controller);

        string SavePrivate(string domain, string path, Stream stream, DateTime expires);
        void DeleteExpired(string domain, string path, TimeSpan oldThreshold);

        string GetUploadForm(string domain, string directoryPath, string redirectTo, long maxUploadSize,
                             string contentType, string contentDisposition, string submitLabel);

        string GetUploadedUrl(string domain, string directoryPath);
        string GetUploadUrl();

        string GetPostParams(string domain, string directoryPath, long maxUploadSize, string contentType,
                             string contentDisposition);
    }
}

<|start_filename|>module/ASC.Mail/ASC.Mail/Core/Dao/MailGarbageDao.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;

using ASC.Common.Data;
using ASC.Common.Data.Sql;
using ASC.Common.Data.Sql.Expressions;
using ASC.Mail.Core.Dao.Expressions.Mailbox;
using ASC.Mail.Core.DbSchema.Tables;
using ASC.Mail.Core.Entities;
using ASC.Mail.Data.Contracts;
using ASC.Mail.Extensions;

namespace ASC.Mail.Core.Dao
{
    public class MailGarbageDao
    {
        public void CleanupMailboxData(MailBoxData mailbox, bool totalRemove)
        {
            if (!mailbox.IsRemoved)
                throw new Exception("Mailbox is not removed.");

            var deleteMailboxMessagesQuery = new SqlDelete(MailTable.TABLE_NAME)
                                            .Where(MailTable.Columns.MailboxId, mailbox.MailBoxId)
                                            .Where(MailTable.Columns.Tenant, mailbox.TenantId)
                                            .Where(MailTable.Columns.User, mailbox.UserId);

            var deleteMailboxAttachmentsQuery = new SqlDelete(AttachmentTable.TABLE_NAME)
                                            .Where(AttachmentTable.Columns.MailboxId, mailbox.MailBoxId)
                                            .Where(AttachmentTable.Columns.Tenant, mailbox.TenantId);

            using (var db = GetDb())
            {
                using (var tx = db.BeginTransaction(IsolationLevel.ReadUncommitted))
                {
                    var daoFactory = new DaoFactory(db);

                    var daoMailbox = daoFactory.CreateMailboxDao();

                    var mb = daoMailbox.GetMailBox(
                        new СoncreteUserMailboxExp(mailbox.MailBoxId, mailbox.TenantId, mailbox.UserId, true));

                    db.ExecuteNonQuery(deleteMailboxAttachmentsQuery);

                    db.ExecuteNonQuery(deleteMailboxMessagesQuery);

                    daoFactory.CreateMailboxDao().RemoveMailbox(mb);

                    if (totalRemove)
                    {
                        daoFactory.CreateFolderDao(mailbox.TenantId, mailbox.UserId).Delete();

                        var deleteContactInfoQuery = new SqlDelete(ContactInfoTable.TABLE_NAME)
                                            .Where(ContactInfoTable.Columns.User, mailbox.UserId)
                                            .Where(ContactInfoTable.Columns.Tenant, mailbox.TenantId);

                        db.ExecuteNonQuery(deleteContactInfoQuery);

                        var deleteContactsQuery = new SqlDelete(ContactsTable.TABLE_NAME)
                                            .Where(ContactsTable.Columns.User, mailbox.UserId)
                                            .Where(ContactsTable.Columns.Tenant, mailbox.TenantId);

                        db.ExecuteNonQuery(deleteContactsQuery);

                        var deleteDisplayImagesQuery = new SqlDelete(DisplayImagesTable.TABLE_NAME)
                                            .Where(DisplayImagesTable.Columns.User, mailbox.UserId)
                                            .Where(DisplayImagesTable.Columns.Tenant, mailbox.TenantId);

                        db.ExecuteNonQuery(deleteDisplayImagesQuery);

                    }

                    tx.Commit();
                }
            }

        }

        public int GetMailboxAttachsCount(MailBoxData mailBoxData)
        {
            int count;

            const string m = "m";
            const string a = "a";

            using (var db = GetDb())
            {
                var query = new SqlQuery(MailTable.TABLE_NAME.Alias(m))
                    .InnerJoin(AttachmentTable.TABLE_NAME.Alias(a),
                               Exp.EqColumns(MailTable.Columns.Id.Prefix(m), AttachmentTable.Columns.MailId.Prefix(a)))
                    .SelectCount()
                    .Where(MailTable.Columns.MailboxId.Prefix(m), mailBoxData.MailBoxId)
                    .Where(MailTable.Columns.Tenant.Prefix(m), mailBoxData.TenantId)
                    .Where(MailTable.Columns.User.Prefix(m), mailBoxData.UserId);

                count = db.ExecuteScalar<int>(query);
            }

            return count;
        }

        public List<MailAttachGarbage> GetMailboxAttachs(MailBoxData mailBoxData, int limit)
        {
            List<MailAttachGarbage> list;

            const string m = "m";
            const string a = "a";

            using (var db = GetDb())
            {
                var queryAttachemnts = new SqlQuery(MailTable.TABLE_NAME.Alias(m))
                    .InnerJoin(AttachmentTable.TABLE_NAME.Alias(a),
                               Exp.EqColumns(MailTable.Columns.Id.Prefix(m), AttachmentTable.Columns.MailId.Prefix(a)))
                    .Select(AttachmentTable.Columns.Id.Prefix(a),
                            MailTable.Columns.Stream.Prefix(m),
                            AttachmentTable.Columns.FileNumber.Prefix(a),
                            AttachmentTable.Columns.StoredName.Prefix(a),
                            AttachmentTable.Columns.Name.Prefix(a),
                            MailTable.Columns.Id.Prefix(m))
                    .Where(MailTable.Columns.MailboxId.Prefix(m), mailBoxData.MailBoxId)
                    .Where(MailTable.Columns.Tenant.Prefix(m), mailBoxData.TenantId)
                    .Where(MailTable.Columns.User.Prefix(m), mailBoxData.UserId)
                    .SetMaxResults(limit);

                list =
                    db.ExecuteList(queryAttachemnts)
                      .ConvertAll(
                          r =>
                          new MailAttachGarbage(mailBoxData.UserId, Convert.ToInt32(r[0]), r[1].ToString(), Convert.ToInt32(r[2]),
                                                r[3] != null ? r[3].ToString() : r[4].ToString()))
                      .ToList();
            }

            return list;
        }

        public void CleanupMailboxAttachs(List<MailAttachGarbage> attachGarbageList)
        {
            if (!attachGarbageList.Any()) return;

            using (var db = GetDb())
            {
                var deleteQuery = new SqlDelete(AttachmentTable.TABLE_NAME)
                    .Where(Exp.In(AttachmentTable.Columns.Id, attachGarbageList.Select(a => a.Id).ToList()));

                db.ExecuteNonQuery(deleteQuery);
            }
        }

        public int GetMailboxMessagesCount(MailBoxData mailBoxData)
        {
            int count;

            using (var db = GetDb())
            {
                var query = new SqlQuery(MailTable.TABLE_NAME)
                    .SelectCount()
                    .Where(MailTable.Columns.MailboxId, mailBoxData.MailBoxId)
                    .Where(MailTable.Columns.Tenant, mailBoxData.TenantId)
                    .Where(MailTable.Columns.User, mailBoxData.UserId);

                count = db.ExecuteScalar<int>(query);
            }

            return count;
        }

        public List<MailMessageGarbage> GetMailboxMessages(MailBoxData mailBoxData, int limit)
        {
            List<MailMessageGarbage> list;

            using (var db = GetDb())
            {
                var queryAttachemnts = new SqlQuery(MailTable.TABLE_NAME)
                    .Select(MailTable.Columns.Id,
                            MailTable.Columns.Stream)
                    .Where(MailTable.Columns.MailboxId, mailBoxData.MailBoxId)
                    .Where(MailTable.Columns.Tenant, mailBoxData.TenantId)
                    .Where(MailTable.Columns.User, mailBoxData.UserId)
                    .SetMaxResults(limit);

                list =
                    db.ExecuteList(queryAttachemnts)
                      .ConvertAll(r => new MailMessageGarbage(mailBoxData.UserId, Convert.ToInt32(r[0]), r[1].ToString()))
                      .ToList();
            }

            return list;
        }

        public void CleanupMailboxMessages(List<MailMessageGarbage> messageGarbageList)
        {
            if (!messageGarbageList.Any()) return;

            using (var db = GetDb())
            {
                var deleteQuery = new SqlDelete(MailTable.TABLE_NAME)
                    .Where(Exp.In(MailTable.Columns.Id, messageGarbageList.Select(a => a.Id).ToList()));

                db.ExecuteNonQuery(deleteQuery);
            }
        }

        private DbManager GetDb()
        {
            return new DbManager(Defines.CONNECTION_STRING_NAME);
        }

    }


}


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Management/MailDomainSettings/js/maildomainsettings.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


jq(function () {
    jq('#saveMailDomainSettingsBtn').click(MailDomainSettingsManager.SaveSettings);
    jq('input[name="signInType"]').click(MailDomainSettingsManager.SwitchSignInType);
    jq('#addTrustDomainBtn').click(MailDomainSettingsManager.AddTrustedDomain);
    jq("input[type=radio][name=signInType][checked=checked]").prop("checked", true);
});

MailDomainSettingsManager = new function() {

    this.SwitchSignInType = function () {
        if (jq('#trustedMailDomains').is(':checked')) {
            jq('#offMailDomainsDescription').hide();
            jq('#allMailDomainsDescription').hide();
            jq('#trustedMailDomainsDescription').show();
            jq('#domainSettingsCbxContainer').show();
        } else if (jq('#allMailDomains').is(':checked')) {
            jq('#offMailDomainsDescription').hide();
            jq('#trustedMailDomainsDescription').hide();
            jq('#allMailDomainsDescription').show();
            jq('#domainSettingsCbxContainer').show();
        } else {
            jq('#trustedMailDomainsDescription').hide();
            jq('#allMailDomainsDescription').hide();
            jq('#offMailDomainsDescription').show();
            jq('#domainSettingsCbxContainer').hide();
        }
    };

    this.RemoveTrustedDomain = function(number) {
        jq('#studio_domain_box_' + number).remove();
    };

    this.AddTrustedDomain = function () {
        var maxNumb = -1;
        jq('div[id^="studio_domain_box_"]').each(function (i, pel) {

            var n = parseInt(jq(this).attr('name'));
            if (n > maxNumb)
                maxNumb = n + 1;
        });

        maxNumb++;
        var sb = new String();
        sb += '<div name="' + maxNumb + '" id="studio_domain_box_' + maxNumb + '" class="clearFix" style="margin-bottom:15px;">';
        sb += '<input type="text" value="" id="studio_domain_' + maxNumb + '" class="textEdit" maxlength="60" style="width:300px;"/>';
        sb += '<a class="removeDomain" href="javascript:void(0);" onclick="MailDomainSettingsManager.RemoveTrustedDomain(\'' + maxNumb + '\');"><img alt="" align="absmiddle" border="0" src="' + StudioManager.GetImage("trash_16.png") + '"/></a>';
        sb += '</div>';

        jq('#studio_domainListBox').append(sb);

        document.getElementById('studio_domain_' + maxNumb).focus();
    };

    this.SaveSettings = function () {

        if (jq(this).hasClass("disable")) return;

        var domains = new Array();
        var type = '';
        if (jq('#trustedMailDomains').is(':checked')) {

            type = jq('#trustedMailDomains').val();
            jq('input[id^="studio_domain_"]').each(function (i, pel) {
                domains.push(jq(this).val());
            });
        }
        else if (jq('#allMailDomains').is(':checked')) {
            type = jq('#allMailDomains').val();
        }
        else
            type = jq('#offMailDomains').val();

        var inviteUsersAsVisitors = jq("#cbxInviteUsersAsVisitors").is(":checked");

        AjaxPro.onLoading = function (b) {
            if (b)
                LoadingBanner.showLoaderBtn("#studio_domainSettings");
            else
                LoadingBanner.hideLoaderBtn("#studio_domainSettings");
        };

        MailDomainSettingsController.SaveMailDomainSettings(type, domains, inviteUsersAsVisitors, function (result) {
            var res = result.value;
            LoadingBanner.showMesInfoBtn("#studio_domainSettings", res.Message, res.Status == 1 ? "success" : "error");
        });
    };

}

<|start_filename|>web/studio/ASC.Web.Studio/Products/People/js/reassigns.js<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


; if (typeof (ASC) === 'undefined')
    ASC = {};

if (typeof ASC.People === "undefined")
    ASC.People = (function () { return {}; })();

ASC.People.Reassigns = (function () {
    var isInit = false,
        removeData = false,
        aborted = false,
        fromUserId = null,
        toUserId = null,
        timeoutDelay = 3000,
        progressStatus = {
            queued: 0,
            started: 1,
            done: 2,
            failed: 3
        };

    function renderStatus(targetObj, statusClass, statusMessage, errorMessage) {
        targetObj.html(jq.tmpl("reassignStatus", { statusClass: statusClass, statusMessage: statusMessage, errorMessage: errorMessage }));
    }

    function renderItemStatus(item, data) {
        var step = item.attr("data-step");

        if (data.status == progressStatus.queued) {
            renderStatus(item, "queued", ASC.People.Resources.PeopleResource.ReassignStatusQueued, null);
            return;
        }

        if (step < data.percentage) {
            renderStatus(item, "finished", removeData ? ASC.People.Resources.PeopleResource.RemovingStatusFinished : ASC.People.Resources.PeopleResource.ReassignStatusFinished, null);
        } else if (step == data.percentage) {
            if (data.status == progressStatus.failed) {
                renderStatus(item, "error", removeData ? ASC.People.Resources.PeopleResource.RemovingStatusAborted : ASC.People.Resources.PeopleResource.ReassignStatusAborted, data.error);
            } else {
                renderStatus(item, "started", ASC.People.Resources.PeopleResource.ReassignStatusStarted, null);
            }
        } else {
            renderStatus(item, "notstarted", removeData ? ASC.People.Resources.PeopleResource.RemovingStatusNotStarted : ASC.People.Resources.PeopleResource.ReassignStatusNotStarted, null);
        }
    }

    function renderUserInfo(from, to) {
        if (from) {
            fromUserId = from;
            var fromUser = window.UserManager.getUser(fromUserId);
            jq(".from-user-link").attr("href", fromUser.profileUrl).html(fromUser.displayName);
        }

        if (to) {
            toUserId = to;
            var toUser = window.UserManager.getUser(toUserId);
            jq(".to-user-link").attr("href", toUser.profileUrl).html(toUser.displayName);
        }
    }

    function setBindings() {
        var $userSelector = jq("#userSelector");

        if ($userSelector.length) {
            $userSelector.useradvancedSelector({
                itemsChoose: [],
                itemsDisabledIds: [],
                canadd: false,
                isAdmin: false,
                showGroups: true,
                withGuests: false,
                onechosen: true
            });

            $userSelector.on("showList", function(event, item) {
                jq(this).html(item.title);
                toUserId = item.id;
                jq(".start-btn").removeClass("disable");
            });
        }

        jq(".start-btn").on("click", function () {
            if (jq(this).hasClass("disable")) return;

            aborted = false;

            var options = {
                before: LoadingBanner.displayLoading,
                after: LoadingBanner.hideLoading,
                success: function(params, data) {
                    renderUserInfo(data.fromUser, data.toUser);
                    showActionContainer(false);
                    renderProgress(data);
                },
                error: function(params, errors) {
                    toastr.error(errors[0]);
                }
            };

            if (removeData) {
                Teamlab.startRemove({}, fromUserId, options);
            } else {
                var deleteProfile = jq(".delete-profile-container input[type=checkbox]").is(":checked");
                Teamlab.startReassign({}, fromUserId, toUserId, deleteProfile, options);
            }
        });

        jq(".abort-btn").on("click", function () {
            aborted = true;

            var options = {
                before: LoadingBanner.displayLoading,
                after: LoadingBanner.hideLoading,
                success: function() {
                    var started = jq(".progress-container .progress-block .started");
                    var targetObj = started.length ? started.parent() : jq(".progress-container .progress-block .progress-desc:first");
                    renderStatus(targetObj, "aborted", removeData ? ASC.People.Resources.PeopleResource.RemovingStatusAborted : ASC.People.Resources.PeopleResource.ReassignStatusAborted, null);
                    toastr.warning(removeData ? ASC.People.Resources.PeopleResource.RemovingAbortToastrMsg : ASC.People.Resources.PeopleResource.ReassignAbortToastrMsg);
                    showButtons(false, true, false);
                },
                error: function(params, errors) {
                    toastr.error(errors[0]);
                }
            };

            if (removeData) {
                Teamlab.terminateRemove({}, fromUserId, options);
            } else {
                Teamlab.terminateReassign({}, fromUserId, options);
            }
        });
        
        jq(".restart-btn").on("click", function () {
            showActionContainer(true);
        });
    }

    function showActionContainer(show) {
        if (show) {
            jq(".action-container").removeClass("display-none");
            jq(".progress-container").addClass("display-none");
        } else {
            jq(".action-container").addClass("display-none");
            jq(".progress-container").removeClass("display-none");
        }
    }

    function showButtons(abort, restart, ok) {
        if (abort) {
            jq(".abort-btn").removeClass("display-none");
        } else {
            jq(".abort-btn").addClass("display-none");
        }
        
        if (restart) {
            jq(".restart-btn").removeClass("display-none");
        } else {
            jq(".restart-btn").addClass("display-none");
        }
        
        if (ok) {
            jq(".ok-btn").removeClass("display-none");
        } else {
            jq(".ok-btn").addClass("display-none");
        }
    }

    function renderProgress(data) {
        jq(".progress-block .progress-row .progress-desc").each(function (index, obj) {
            renderItemStatus(jq(obj), data);
        });

        if (data.status == progressStatus.failed)
            toastr.error(removeData ? ASC.People.Resources.PeopleResource.RemovingErrorToastrMsg : ASC.People.Resources.PeopleResource.ReassignErrorToastrMsg);

        if (data.isCompleted) {
            showButtons(false, data.status == progressStatus.failed, data.status == progressStatus.done);
        } else {
            showButtons(true, false, false);
            setTimeout(trackProgress, timeoutDelay);
        }  
    }

    function checkProgress() {
        var options = {
            before: LoadingBanner.displayLoading,
            after: LoadingBanner.hideLoading,
            success: function(params, data) {
                if (data && data.hasOwnProperty("isCompleted")) {
                    renderUserInfo(data.fromUser, data.toUser);
                    showActionContainer(false);
                    renderProgress(data);
                } else {
                    showActionContainer(true);
                }
            },
            error: function(params, errors) {
                showActionContainer(true);
                toastr.error(errors[0]);
            }
        };

        if (removeData) {
            Teamlab.getRemoveProgress({}, fromUserId, options);
        } else {
            Teamlab.getReassignProgress({}, fromUserId, options);
        }
    }
    
    function trackProgress() {
        if (aborted) return;

        var options = {
            success: function(params, data) {
                renderProgress(data);
            },
            error: function(params, errors) {
                toastr.error(errors[0]);
            }
        };

        if (removeData) {
            Teamlab.getRemoveProgress({}, fromUserId, options);
        } else {
            Teamlab.getReassignProgress({}, fromUserId, options);
        }
    }

    function init(userId, remove) {
        if (!userId || isInit) return;

        fromUserId = userId;
        removeData = remove;
        setBindings();
        checkProgress();
        isInit = true;
    };

    return {
        init: init
    };
})();


<|start_filename|>web/studio/ASC.Web.Studio/UserControls/Statistics/TenantStatisticsProvider.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;

using ASC.Core;
using ASC.Core.Billing;
using ASC.Core.Tenants;
using ASC.Core.Users;
using ASC.Web.Studio.Utility;

namespace ASC.Web.Studio.UserControls.Statistics
{
    public static class TenantStatisticsProvider
    {
        public static bool IsNotPaid()
        {
            Tariff tariff;
            return TenantExtra.EnableTariffSettings
                   && ((tariff = TenantExtra.GetCurrentTariff()).State >= TariffState.NotPaid
                       || TenantExtra.Enterprise && !TenantExtra.EnterprisePaid && tariff.LicenseDate == DateTime.MaxValue);
        }

        public static int GetUsersCount()
        {
            return CoreContext.UserManager.GetUsersByGroup(Constants.GroupUser.ID).Length;
        }

        public static int GetVisitorsCount()
        {
            return CoreContext.UserManager.GetUsersByGroup(Constants.GroupVisitor.ID).Length;
        }

        public static int GetAdminsCount()
        {
            return CoreContext.UserManager.GetUsersByGroup(Constants.GroupAdmin.ID).Length;
        }

        public static long GetUsedSize()
        {
            return GetUsedSize(TenantProvider.CurrentTenantID);
        }

        public static long GetUsedSize(int tenant)
        {
            return GetQuotaRows(tenant).Sum(r => r.Counter);
        }

        public static long GetUsedSize(Guid moduleId)
        {
            return GetQuotaRows(TenantProvider.CurrentTenantID).Where(r => new Guid(r.Tag).Equals(moduleId)).Sum(r => r.Counter);
        }

        public static IEnumerable<TenantQuotaRow> GetQuotaRows(int tenant)
        {
            return CoreContext.TenantManager.FindTenantQuotaRows(tenant)
                .Where(r => !string.IsNullOrEmpty(r.Tag) && new Guid(r.Tag) != Guid.Empty);
        }
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Files/Core/Security/FileShareRecord.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;

namespace ASC.Files.Core.Security
{
    public class FileShareRecord
    {
        public int Tenant { get; set; }

        public object EntryId { get; set; }

        public FileEntryType EntryType { get; set; }

        public Guid Subject { get; set; }

        public Guid Owner { get; set; }

        public FileShare Share { get; set; }

        public int Level { get; set; }


        public class ShareComparer : IComparer<FileShare>
        {
            private static readonly int[] ShareOrder = new[]
                {
                    (int)FileShare.None,
                    (int)FileShare.ReadWrite,
                    (int)FileShare.CustomFilter,
                    (int)FileShare.Review,
                    (int)FileShare.FillForms,
                    (int)FileShare.Comment,
                    (int)FileShare.Read,
                    (int)FileShare.Restrict,
                    (int)FileShare.Varies
                };

            public int Compare(FileShare x, FileShare y)
            {
                return Array.IndexOf(ShareOrder, (int)x).CompareTo(Array.IndexOf(ShareOrder, (int)y));
            }
        }
    }

    public class SmallShareRecord
    {
        public Guid ShareTo { get; set; }
        public Guid ShareParentTo { get; set; }
        public Guid ShareBy { get; set; }
        public DateTime ShareOn { get; set; }
        public FileShare Share { get; set; }
    }
}


<|start_filename|>common/ASC.Common/DependencyInjection/ContainerElementCollection.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System.Configuration;

namespace ASC.Common.DependencyInjection
{
    public class ContainerElementCollection : ConfigurationElementCollection<ComponentElementCollection>
    {
        [ConfigurationProperty("name", IsRequired = false)]
        public string Name { get { return (string)this["name"]; } }

        public ContainerElementCollection()
          : base("container")
        {
        }
    }

    public class ComponentElementCollection : ConfigurationElementCollection<ComponentElement>
    {
        [ConfigurationProperty("name", IsRequired = false)]
        public string Name { get { return (string)this["name"]; } }

        public ComponentElementCollection()
          : base("component")
        {
        }
    }
}


<|start_filename|>common/ASC.Data.Storage/StorageUploader.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;

using ASC.Common.Caching;
using ASC.Common.Logging;
using ASC.Common.Threading;
using ASC.Common.Threading.Progress;
using ASC.Core;
using ASC.Core.Tenants;
using ASC.Data.Storage.Configuration;

namespace ASC.Data.Storage
{
    public class StorageUploader
    {
        private static readonly TaskScheduler Scheduler;
        private static readonly CancellationTokenSource TokenSource;

        private static readonly ICache Cache;
        private static readonly object Locker;

        static StorageUploader()
        {
            Scheduler = new LimitedConcurrencyLevelTaskScheduler(4);
            TokenSource = new CancellationTokenSource();
            Cache = AscCache.Memory;
            Locker = new object();
        }

        public static void Start(int tenantId, StorageSettings newStorageSettings)
        {
            if (TokenSource.Token.IsCancellationRequested) return;

            MigrateOperation migrateOperation;

            lock (Locker)
            {
                migrateOperation = Cache.Get<MigrateOperation>(GetCacheKey(tenantId));
                if (migrateOperation != null) return;

                migrateOperation = new MigrateOperation(tenantId, newStorageSettings);
                Cache.Insert(GetCacheKey(tenantId), migrateOperation, DateTime.MaxValue);
            }

            var task = new Task(migrateOperation.RunJob, TokenSource.Token, TaskCreationOptions.LongRunning);

            task.ConfigureAwait(false)
                .GetAwaiter()
                .OnCompleted(() =>
                {
                    lock (Locker)
                    {
                        Cache.Remove(GetCacheKey(tenantId));
                    }
                });

            task.Start(Scheduler);
        }

        public static MigrateOperation GetProgress(int tenantId)
        {
            lock (Locker)
            {
                return Cache.Get<MigrateOperation>(GetCacheKey(tenantId));
            }
        }

        public static void Stop()
        {
            TokenSource.Cancel();
        }

        private static string GetCacheKey(int tenantId)
        {
            return typeof(MigrateOperation).FullName + tenantId;
        }
    }

    [DataContract]
    public class MigrateOperation : ProgressBase
    {
        private static readonly ILog Log;
        private static readonly string ConfigPath;
        private static readonly IEnumerable<string> Modules;
        private readonly StorageSettings settings;
        private readonly int tenantId;

        static MigrateOperation()
        {
            Log = LogManager.GetLogger("ASC");
            ConfigPath = "";
            Modules = StorageFactory.GetModuleList(ConfigPath, true);
        }

        public MigrateOperation(int tenantId, StorageSettings settings)
        {
            this.tenantId = tenantId;
            this.settings = settings;
            StepCount = Modules.Count();
        }

        protected override void DoJob()
        {
            try
            {
                Log.DebugFormat("Tenant: {0}", tenantId);
                var tenant = CoreContext.TenantManager.GetTenant(tenantId);
                CoreContext.TenantManager.SetCurrentTenant(tenant);
                SecurityContext.AuthenticateMe(tenant.OwnerId);

                foreach (var module in Modules)
                {
                    var oldStore = StorageFactory.GetStorage(ConfigPath, tenantId.ToString(), module);
                    var store = StorageFactory.GetStorageFromConsumer(ConfigPath, tenantId.ToString(), module, settings.DataStoreConsumer);
                    var domains = StorageFactory.GetDomainList(ConfigPath, module).ToList();

                    var crossModuleTransferUtility = new CrossModuleTransferUtility(oldStore, store);

                    string[] files;
                    foreach (var domain in domains)
                    {
                        Status = module + domain;
                        Log.DebugFormat("Domain: {0}", domain);
                        files = oldStore.ListFilesRelative(domain, "\\", "*.*", true);

                        foreach (var file in files)
                        {
                            Log.DebugFormat("File: {0}", file);
                            crossModuleTransferUtility.CopyFile(domain, file, domain, file);
                        }
                    }

                    Log.DebugFormat("Module:{0},Domain:", module);

                    files = oldStore.ListFilesRelative(string.Empty, "\\", "*.*", true)
                        .Where(path => domains.All(domain => !path.Contains(domain + "/")))
                        .ToArray();

                    foreach (var file in files)
                    {
                        Log.DebugFormat("File: {0}", file);
                        crossModuleTransferUtility.CopyFile("", file, "", file);
                    }

                    StepDone();
                    Log.DebugFormat("Percentage:{0}", Percentage);
                }

                settings.Save();
                Log.Debug("StaticUploader Save");
                tenant.SetStatus(TenantStatus.Active);
                CoreContext.TenantManager.SaveTenant(tenant);
                Log.Debug("StaticUploader SetStatus");
            }
            catch (Exception e)
            {
                Error = e;
                Log.Error(e);
            }
        }
    }
}


<|start_filename|>common/Tests/ASC.Data.Storage.Tests/DataStorageTest.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


#if DEBUG
namespace ASC.Data.Storage.Tests
{
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using ASC.Data.Storage;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class DataStorageTest
    {
        private readonly IDataStore store;
        private const string defaultModule = "forum";
        private const string defaultDomain = "";
        private const string defaultDirectory = "directory";
        private const string defaultFile = "test.txt";


        public DataStorageTest()
        {
            store = GetStorageWithoutQuota();
        }

        private static IDataStore GetStorageWithoutQuota()
        {
            return GetStorageWithoutQuota(0);
        }

        private static IDataStore GetStorageWithoutQuota(int tennant)
        {
            return GetStorageWithoutQuota(tennant, defaultModule);
        }

        private static IDataStore GetStorageWithoutQuota(int tennant, string module)
        {
            return StorageFactory.GetStorage(null, tennant.ToString(), module, null);
        }


        private Stream GetDataStream()
        {
            return new MemoryStream(Encoding.UTF8.GetBytes("unit test generated file"));
        }


        [TestMethod]
        public void SslLinkGeneration()
        {
            Assert.IsNotNull(store);

            var uri = store.Save(defaultDomain, defaultFile, GetDataStream());
            Assert.AreEqual(true, store.IsFile(defaultDomain, defaultFile));
            Assert.IsNotNull(uri);

            store.Delete(defaultDomain, defaultFile);
            Assert.AreEqual(false, store.IsFile(defaultDomain, defaultFile));
        }

        [TestMethod]
        public void MoveTest()
        {
            
            Assert.IsNotNull(store);

            var srcFilePath = Path.Combine(defaultDirectory, defaultFile);
            var srcUri = store.Save(defaultDomain, srcFilePath, GetDataStream());
            Assert.IsNotNull(srcUri);

            var files = store.ListFiles(defaultDomain, defaultDirectory, defaultFile, true);
            Assert.IsNotNull(files);
            Assert.AreEqual(true, files.Any());

            var size = store.GetFileSize(defaultDomain, srcFilePath);
            Assert.AreEqual(size, GetDataStream().Length);

            var movedFileName = "moved-" + defaultFile;
            var destFilePath = Path.Combine(defaultDirectory, movedFileName);
            var movedUri = store.Move(defaultDomain, srcFilePath, defaultDomain, destFilePath);
            Assert.IsNotNull(movedUri);

            files = store.ListFiles(defaultDomain, defaultDirectory, movedFileName, true);
            Assert.IsNotNull(files);
            Assert.AreEqual(true, files.Any());

            store.Delete(defaultDomain, destFilePath);

            files = store.ListFiles(defaultDomain, defaultDirectory, "*.*", true);
            Assert.IsNotNull(files);
            Assert.AreEqual(false, files.Any());

            store.DeleteDirectory(defaultDomain, defaultDirectory);
            Assert.AreEqual(false, store.IsDirectory(defaultDomain, defaultDirectory));
        }

        [TestMethod]
        public void DisposeStreamTest()
        {
            Assert.IsNotNull(store);

            var stream = GetDataStream();
            Assert.IsNotNull(stream);

            var uri = store.Save(defaultDomain, defaultFile, stream);
            Assert.AreEqual(true, store.IsFile(defaultDomain, defaultFile));
            Assert.IsNotNull(uri);

            Assert.AreEqual(false, stream.Position == 0);

            store.Delete(defaultDomain, defaultFile);
            Assert.AreEqual(false, store.IsFile(defaultDomain, defaultFile));
        }


        [TestMethod]
        public void ListFilesTest()
        {
            Assert.IsNotNull(store);

            var path = Path.Combine(defaultDirectory, defaultFile);
            var uri = store.Save(defaultDomain, path, GetDataStream());
            Assert.AreEqual(true, store.IsFile(defaultDomain, path));
            Assert.IsNotNull(uri);

            var list = store.ListFiles(defaultDomain, defaultDirectory, "*.*", true);
            Assert.IsNotNull(list);
            Assert.AreEqual(true, list.Any());

            store.DeleteFiles(defaultDomain, defaultDirectory, "*.*", true);

            list = store.ListFiles(defaultDomain, defaultDirectory, "*.*", true);
            Assert.IsNotNull(list);
            Assert.AreEqual(false, list.Any());

            store.DeleteDirectory(defaultDomain, defaultDirectory);
            Assert.AreEqual(false, store.IsDirectory(defaultDomain, defaultDirectory));
        }

        [TestMethod]
        public void ListFilesRelativeTest()
        {
            Assert.IsNotNull(store);

            var path = Path.Combine(defaultDirectory, defaultFile);
            var uri = store.Save(defaultDomain, path, GetDataStream());
            Assert.AreEqual(true, store.IsFile(defaultDomain, path));
            Assert.IsNotNull(uri);

            var listRel = store.ListFilesRelative(defaultDomain, defaultDirectory, "*.*", true);
            Assert.IsNotNull(listRel);
            Assert.AreEqual(true, listRel.Any());

            store.DeleteFiles(defaultDomain, defaultDirectory, "*.*", true);

            listRel = store.ListFilesRelative(defaultDomain, defaultDirectory, " *.*", true);
            Assert.IsNotNull(listRel);
            Assert.AreEqual(false, listRel.Any());

            store.DeleteDirectory(defaultDomain, defaultDirectory);
            Assert.AreEqual(false, store.IsDirectory(defaultDomain, defaultDirectory));
        }

        [TestMethod]
        public void GetReadStreamTest()
        {
            Assert.IsNotNull(store);

            var path = Path.Combine(defaultDirectory, defaultFile);
            var uri = store.Save(path, GetDataStream());
            Assert.IsNotNull(uri);
            Assert.AreEqual(true, store.IsFile(defaultDomain, path));

            var list = store.ListFilesRelative(defaultDomain, defaultDirectory, "*", false);
            Assert.IsNotNull(list);
            Assert.AreEqual(true, list.Any());

            foreach (var file in list)
            {
                var stream = store.GetReadStream(Path.Combine(defaultDirectory, file));
                Assert.IsNotNull(stream);
                stream.Close();
            }

            store.Delete(path);
            Assert.AreEqual(false, store.IsFile(defaultDomain, path));

            store.DeleteDirectory(defaultDirectory);
            Assert.AreEqual(false, store.IsDirectory(defaultDomain, defaultDirectory));
        }

        private void ReadFile(IDataStore dataStore, string directory, string file)
        {
            using (var stream = dataStore.GetReadStream(Path.Combine(directory, file)))
            {
                byte[] array = new byte[81920];
                while (stream.Read(array, 0, array.Length) != 0)
                {
                }
            }
        }

        [TestMethod]
        public void ParallelGetReadStreamTest()
        {
            var path = Path.Combine(defaultDirectory, defaultFile);
            var uri = store.Save(path, GetDataStream());

            var array = new int[10];

            Parallel.ForEach(array, (item) =>
            {
                ReadFile(store, defaultDirectory, defaultFile);
            });

            store.Delete(path);
            store.DeleteDirectory(defaultDirectory);
        }
    }
}
#endif

<|start_filename|>common/ASC.Core.Common/Configuration/Consumer.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;

using ASC.Common.Caching;
using ASC.Core.Tenants;

using Autofac;

namespace ASC.Core.Common.Configuration
{
    public class Consumer : IDictionary<string, string>
    {
        private static readonly ICacheNotify Cache = AscCache.Notify;

        public bool CanSet { get; private set; }

        public int Order { get; private set; }

        public string Name { get; private set; }

        protected readonly Dictionary<string, string> Props;
        public IEnumerable<string> ManagedKeys
        {
            get { return Props.Select(r => r.Key).ToList(); }
        }

        protected readonly Dictionary<string, string> Additional;
        public virtual IEnumerable<string> AdditionalKeys
        {
            get { return Additional.Select(r => r.Key).ToList(); }
        }

        public ICollection<string> Keys { get { return AllProps.Keys; } }
        public ICollection<string> Values { get { return AllProps.Values; } }

        private Dictionary<string, string> AllProps
        {
            get
            {
                var result = Props.ToDictionary(item => item.Key, item => item.Value);

                foreach (var item in Additional.Where(item => !result.ContainsKey(item.Key)))
                {
                    result.Add(item.Key, item.Value);
                }

                return result;
            }
        }

        private static readonly bool OnlyDefault;

        public bool IsSet
        {
            get { return Props.Any() && !Props.All(r => string.IsNullOrEmpty(this[r.Key])); }
        }

        static Consumer()
        {
            OnlyDefault = ConfigurationManagerExtension.AppSettings["core.default-consumers"] == "true";
        }

        public Consumer()
        {
            Name = "";
            Order = int.MaxValue;
            Props = new Dictionary<string, string>();
            Additional = new Dictionary<string, string>();
        }

        public Consumer(string name, int order, Dictionary<string, string> additional)
        {
            Name = name;
            Order = order;
            Props = new Dictionary<string, string>();
            Additional = additional;
        }

        public Consumer(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional)
        {
            Name = name;
            Order = order;
            Props = props ?? new Dictionary<string, string>();
            Additional = additional ?? new Dictionary<string, string>();

            if (props != null && props.Any())
            {
                CanSet = props.All(r => string.IsNullOrEmpty(r.Value));
            }
        }

        public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
        {
            return AllProps.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void Add(KeyValuePair<string, string> item)
        {
        }

        public void Clear()
        {
            if (!CanSet)
            {
                throw new NotSupportedException("Key for read only. Consumer " + Name);
            }

            foreach (var providerProp in Props)
            {
                this[providerProp.Key] = null;
            }

            Cache.Publish(this, CacheNotifyAction.Remove);
        }

        public bool Contains(KeyValuePair<string, string> item)
        {
            return AllProps.Contains(item);
        }

        public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
        {
        }

        public bool Remove(KeyValuePair<string, string> item)
        {
            return AllProps.Remove(item.Key);
        }

        public int Count { get { return AllProps.Count; } }

        public bool IsReadOnly { get { return true; } }

        public bool ContainsKey(string key)
        {
            return AllProps.ContainsKey(key);
        }

        public void Add(string key, string value)
        {
        }

        public bool Remove(string key)
        {
            return false;
        }

        public bool TryGetValue(string key, out string value)
        {
            return AllProps.TryGetValue(key, out value);
        }

        public string this[string key]
        {
            get { return Get(key); }
            set { Set(key, value); }
        }

        private string Get(string name)
        {
            string value = null;

            if (!OnlyDefault && CanSet)
            {
                var tenant = CoreContext.Configuration.Standalone
                                 ? Tenant.DEFAULT_TENANT
                                 : CoreContext.TenantManager.GetCurrentTenant().TenantId;

                value = CoreContext.Configuration.GetSetting(GetSettingsKey(name), tenant);
            }

            if (string.IsNullOrEmpty(value))
            {
                if (AllProps.ContainsKey(name))
                {
                    value = AllProps[name];
                }
            }

            return value;
        }

        private void Set(string name, string value)
        {
            if (!CanSet)
            {
                throw new NotSupportedException("Key for read only. Key " + name);
            }

            if (!ManagedKeys.Contains(name))
            {
                if (Additional.ContainsKey(name))
                {
                    Additional[name] = value;
                }
                else
                {
                    Additional.Add(name, value);
                }
                return;
            }

            var tenant = CoreContext.Configuration.Standalone
                             ? Tenant.DEFAULT_TENANT
                             : CoreContext.TenantManager.GetCurrentTenant().TenantId;
            CoreContext.Configuration.SaveSetting(GetSettingsKey(name), value, tenant);
        }

        protected virtual string GetSettingsKey(string name)
        {
            return "AuthKey_" + name;
        }
    }

    public class DataStoreConsumer : Consumer, ICloneable
    {
        public Type HandlerType { get; private set; }
        public DataStoreConsumer Cdn { get; private set; }

        public const string HandlerTypeKey = "handlerType";
        public const string CdnKey = "cdn";

        public DataStoreConsumer()
        {

        }

        public DataStoreConsumer(string name, int order, Dictionary<string, string> additional)
            : base(name, order, additional)
        {
            Init(additional);
        }

        public DataStoreConsumer(string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional)
            : base(name, order, props, additional)
        {
            Init(additional);
        }

        public override IEnumerable<string> AdditionalKeys
        {
            get { return base.AdditionalKeys.Where(r => r != HandlerTypeKey && r != "cdn").ToList(); }
        }

        protected override string GetSettingsKey(string name)
        {
            return base.GetSettingsKey(Name + name);
        }

        private void Init(IReadOnlyDictionary<string, string> additional)
        {
            if (additional == null || !additional.ContainsKey(HandlerTypeKey))
                throw new ArgumentException(HandlerTypeKey);

            HandlerType = Type.GetType(additional[HandlerTypeKey]);

            if (additional.ContainsKey(CdnKey))
            {
                Cdn = GetCdn(additional[CdnKey]);
            }
        }

        private DataStoreConsumer GetCdn(string cdn)
        {
            var fromConfig = ConsumerFactory.GetByName<Consumer>(cdn);

            var props = ManagedKeys.ToDictionary(prop => prop, prop => this[prop]);
            var additional = fromConfig.AdditionalKeys.ToDictionary(prop => prop, prop => fromConfig[prop]);
            additional.Add(HandlerTypeKey, HandlerType.AssemblyQualifiedName);

            return new DataStoreConsumer(fromConfig.Name, fromConfig.Order, props, additional);
        }

        public object Clone()
        {
            return new DataStoreConsumer(Name, Order, Props.ToDictionary(r => r.Key, r => r.Value), Additional.ToDictionary(r => r.Key, r => r.Value));
        }
    }

    public class ConsumerFactory
    {
        public static IEnumerable<Consumer> Consumers { get; private set; }

        private static IContainer Builder { get; set; }

        static ConsumerFactory()
        {
            var container = ConsumerConfigLoader.LoadConsumers("consumers");
            Builder = container.Build();
            Consumers = Builder.Resolve<IEnumerable<Consumer>>();
        }

        public static Consumer GetByName(string name)
        {
            object result;
            if (Builder.TryResolveNamed(name, typeof(Consumer), out result))
            {
                return (Consumer)result;
            }

            return new Consumer();
        }

        public static T GetByName<T>(string name) where T : Consumer, new()
        {
            object result;
            if (Builder.TryResolveNamed(name, typeof(T), out result))
            {
                return (T)result;
            }

            return new T();
        }

        public static T Get<T>() where T : Consumer, new()
        {
            T result;
            if (Builder.TryResolve(out result))
            {
                return result;
            }

            return new T();
        }

        public static IEnumerable<T> GetAll<T>() where T : Consumer, new()
        {
            return Builder.Resolve<IEnumerable<T>>();
        }
    }
}


<|start_filename|>module/ASC.Mail/Services/ASC.Mail.PasswordFinder/Program.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ASC.Core.Users;
using ASC.Mail.Enums;
using ASC.Mail.Extensions;
using ASC.Mail.Iterators;
using Newtonsoft.Json;

namespace ASC.Mail.PasswordFinder
{
    internal partial class Program
    {
        const string IMAP = "IMAP";
        const string POP3 = "POP3";
        const string SMTP = "SMTP";

        private static void Main(string[] args)
        {
            var options = new Options();

            if (!CommandLine.Parser.Default.ParseArgumentsStrict(args, options,
                () => Console.WriteLine(@"Bad command line parameters.")))
            {
                return;
            }
            
            try
            {
                var mailboxIterator = new MailboxIterator();

                var mailbox = mailboxIterator.First();

                if (mailbox == null)
                {
                    Console.WriteLine(@"Accounts not found.");
                    ShowAnyKey(options);
                    return;
                }

                StringBuilder sbuilder = null;
                List<MailAccount> accounts = null;

                if (!options.NeedJson)
                {
                    sbuilder = new StringBuilder();
                }
                else
                {
                    accounts = new List<MailAccount>();
                }

                var i = 0;

                while (!mailboxIterator.IsDone)
                {
                    if (mailbox.IsRemoved || !mailbox.IsTeamlab)
                    {
                        mailbox = mailboxIterator.Next();
                        continue;
                    }

                    var current = new StringBuilder();

                    var userInfo = mailbox.GetUserInfo();

                    var isUserRemoved = userInfo == null || userInfo.Equals(Constants.LostUser);

                    var user = isUserRemoved ? "user is removed" : userInfo.UserName;

                    current.AppendFormat("#{0}. Id: {1} MailBox: {2}, Tenant: {3}, User: '{4}' ID: {5}\r\n",
                        ++i, mailbox.MailBoxId, mailbox.EMail, mailbox.TenantId, user,
                        mailbox.UserId);

                    current.AppendLine();

                    var inType = mailbox.Imap ? IMAP : POP3;

                    current.AppendFormat("\t\t{0} settings:\r\n", inType);
                    current.AppendFormat("\t\tLogin:\t\t{0}\r\n", mailbox.Account);

                    string inPassword;

                    if (!mailbox.IsOAuth)
                    {
                        inPassword = 
                            string.IsNullOrEmpty(mailbox.Password)
                                ? "[-=! ERROR: Invalid Decription !=-]"
                                : mailbox.Password;
                    }
                    else
                    {
                        inPassword = "[-=! OAuth: no password stored !=-]";
                    }

                     current.AppendFormat("\t\tPassword:\t{0}\r\n", inPassword);

                    current.AppendFormat("\t\tHost:\t\t{0}\r\n", mailbox.Server);
                    current.AppendFormat("\t\tPort:\t\t{0}\r\n", mailbox.Port);

                    var inAuthentication = Enum.GetName(typeof(SaslMechanism), mailbox.Authentication);

                    current.AppendFormat("\t\tAuthType:\t{0}\r\n", inAuthentication);

                    var inEncryption = Enum.GetName(typeof(EncryptionType), mailbox.Encryption);

                    current.AppendFormat("\t\tEncryptType:\t{0}\r\n", inEncryption);

                    current.AppendLine();

                    current.AppendFormat("\t\t{0} settings:\r\n", SMTP);
                    current.AppendFormat("\t\tSmtpAuth:\t{0}\r\n", mailbox.SmtpAuth);
                    if (mailbox.SmtpAuth)
                    {
                        current.AppendFormat("\t\tSmtpLogin:\t{0}\r\n", mailbox.SmtpAccount);
                        if (!mailbox.IsOAuth)
                        {
                            current.AppendFormat("\t\tSmtPassword:\t{0}\r\n",
                                string.IsNullOrEmpty(mailbox.SmtpPassword)
                                    ? "[-=! ERROR: Invalid Decription !=-]"
                                    : mailbox.SmtpPassword);
                        }
                        else
                        {
                            current.AppendFormat("\t\tSmtPassword:\t[-=! OAuth: no password stored !=-]\r\n");
                        }
                    }
                    current.AppendFormat("\t\tHost:\t\t{0}\r\n", mailbox.SmtpServer);
                    current.AppendFormat("\t\tPort:\t\t{0}\r\n", mailbox.SmtpPort);

                    var outAuthentication = Enum.GetName(typeof(SaslMechanism), mailbox.SmtpAuthentication);

                    current.AppendFormat("\t\tAuthType:\t{0}\r\n", outAuthentication);

                    var outEncryption = Enum.GetName(typeof(EncryptionType), mailbox.SmtpEncryption);

                    current.AppendFormat("\t\tEncryptType:\t{0}\r\n", outEncryption);

                    current.AppendLine();

                    Console.WriteLine(current.ToString());

                    if (!options.NeedJson)
                    {
                        if (sbuilder != null) 
                            sbuilder.Append(current);
                    }
                    else
                    {
                        if (accounts != null)
                        {
                            accounts.Add(new MailAccount
                            {
                                email = mailbox.EMail.Address,
                                tenantId = mailbox.TenantId,
                                user = user,
                                userId = mailbox.UserId,
                                settings = new List<MailAccountSetting>
                                {
                                    new MailAccountSetting
                                    {
                                        type = inType,
                                        host = mailbox.Server,
                                        port = mailbox.Port.ToString(),
                                        authentication = inAuthentication,
                                        encryption = inEncryption,
                                        login = mailbox.Account,
                                        password = <PASSWORD>
                                    },
                                    new MailAccountSetting
                                    {
                                        type = SMTP,
                                        host = mailbox.SmtpServer,
                                        port = mailbox.SmtpPort.ToString(),
                                        authentication = outAuthentication,
                                        encryption = outEncryption,
                                        login = mailbox.SmtpAccount,
                                        password = <PASSWORD>
                                    }
                                }
                            });
                        }
                    }

                    mailbox = mailboxIterator.Next();
                }

                string text = null;

                if (!options.NeedJson)
                {
                    if (sbuilder != null)
                    {
                        text = sbuilder.ToString();
                    }
                }
                else
                {
                    text = JsonConvert.SerializeObject(accounts, Formatting.Indented);
                }

                if (!string.IsNullOrEmpty(text))
                {
                    Console.WriteLine(@"Try StoreToFile");

                    var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                        options.NeedJson ? "mailboxes.json" : "mailboxes.txt");

                    var pathFile = StoreToFile(text, path, true);

                    Console.WriteLine(@"[SUCCESS] File was stored into path ""{0}""", pathFile);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            ShowAnyKey(options);
        }

        private static void ShowAnyKey(Options options)
        {
            Console.WriteLine();

            if (options.ExitOnEnd)
                return;

            Console.WriteLine(@"Any key to exit...");
            Console.Read();
        }

        private static string StoreToFile(string text, string fileName, bool useTemp)
        {
            var tempPath = useTemp ? Path.GetTempFileName() : fileName;
            var sw = File.CreateText(tempPath);
            sw.Write(text);
            sw.Close();

            if (!useTemp)
                return tempPath;

            if (string.IsNullOrEmpty(fileName))
                return tempPath;

            var directory = Path.GetDirectoryName(fileName);
            // Create the traget path iof it does not exist
            if (directory != null && !Directory.Exists(directory))
                Directory.CreateDirectory(directory);

            if (string.IsNullOrEmpty(Path.GetFileName(fileName)))
            {
                var savePath = Path.Combine(fileName, Path.GetFileNameWithoutExtension(tempPath) + ".txt");
                File.Move(tempPath, savePath);
                File.Delete(tempPath);
                return savePath;
            }

            File.Delete(fileName);
            File.Move(tempPath, fileName);
            File.Delete(tempPath);

            return fileName;
        }
    }

    internal class MailAccount
    {
        public string email;

        public string user;

        public int tenantId;

        public string userId;

        public List<MailAccountSetting> settings;
    }

    internal class MailAccountSetting
    {
        public string type;

        public string host;

        public string port;

        public string authentication;

        public string encryption;

        public string login;

        public string password;
    }
}


<|start_filename|>module/ASC.Mail.Autoreply/ASC.Mail.Core/Net/MIME/MIME_h_Unparsed.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


namespace ASC.Mail.Net.MIME
{
    #region usings

    using System;
    using System.Text;

    #endregion

    /// <summary>
    /// This class represent header field what parsing has failed.
    /// </summary>
    public class MIME_h_Unparsed : MIME_h
    {
        #region Members

        private readonly string m_Name;
        private readonly string m_ParseValue;
        private readonly Exception m_pException;
        private readonly string m_Value;

        #endregion

        #region Properties

        /// <summary>
        /// Gets if this header field is modified since it has loaded.
        /// </summary>
        /// <remarks>All new added header fields has <b>IsModified = true</b>.</remarks>
        /// <exception cref="ObjectDisposedException">Is riased when this class is disposed and this property is accessed.</exception>
        public override bool IsModified
        {
            get { return false; }
        }

        /// <summary>
        /// Gets header field name.
        /// </summary>
        public override string Name
        {
            get { return m_Name; }
        }

        /// <summary>
        /// Gets header field value.
        /// </summary>
        public string Value
        {
            get { return m_Value; }
        }

        /// <summary>
        /// Gets error happened during parse.
        /// </summary>
        public Exception Exception
        {
            get { return m_pException; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <param name="exception">Parsing error.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>value</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when header field parsing errors.</exception>
        internal MIME_h_Unparsed(string value, Exception exception)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }

            string[] name_value = value.Split(new[] {':'}, 2);
            if (name_value.Length != 2)
            {
                throw new ParseException("Invalid Content-Type: header field value '" + value + "'.");
            }

            m_Name = name_value[0];
            m_Value = name_value[1].Trim();
            m_ParseValue = value;
            m_pException = exception;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Parses header field from the specified value.
        /// </summary>
        /// <param name="value">Header field value. Header field name must be included. For example: 'Content-Type: text/plain'.</param>
        /// <returns>Returns parsed header field.</returns>
        /// <exception cref="InvalidOperationException">Is alwyas raised when this mewthod is accsessed.</exception>
        public static MIME_h_Unparsed Parse(string value)
        {
            throw new InvalidOperationException();
        }

        /// <summary>
        /// Returns header field as string.
        /// </summary>
        /// <param name="wordEncoder">8-bit words ecnoder. Value null means that words are not encoded.</param>
        /// <param name="parmetersCharset">Charset to use to encode 8-bit characters. Value null means parameters not encoded.</param>
        /// <returns>Returns header field as string.</returns>
        public override string ToString(MIME_Encoding_EncodedWord wordEncoder, Encoding parmetersCharset)
        {
            return m_ParseValue;
        }

        #endregion
    }
}

<|start_filename|>web/studio/ASC.Web.Studio/Products/Community/Modules/Bookmarking/UserControls/Common/Util/BookmarkingThumbnailSize.cs<|end_filename|>
/*
 *
 * (c) Copyright Ascensio System Limited 2010-2021
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
*/


using System;
using System.Text.RegularExpressions;

namespace ASC.Web.UserControls.Bookmarking.Common.Util
{
    public class BookmarkingThumbnailSize
    {
        public int Width { get; set; }

        public int Height { get; set; }

        public BookmarkingThumbnailSize()
        {
            Width = BookmarkingSettings.ThumbSmallSize.Width;
            Height = BookmarkingSettings.ThumbSmallSize.Height;
        }

        public BookmarkingThumbnailSize(int width, int height)
        {
            Width = width;
            Height = height;
        }

        private const string SizePrefix = "_size";

        public override string ToString()
        {
            return String.Format("{0}{1}-{2}", SizePrefix, Width, Height);
        }

        public static BookmarkingThumbnailSize ParseThumbnailSize(string fileName)
        {
            if (!fileName.Contains(SizePrefix))
            {
                return new BookmarkingThumbnailSize();
            }
            var m = Regex.Match(fileName, String.Format(".*{0}(?<size>).*", SizePrefix));
            var sizeAsString = m.Groups["size"].Value;
            var dimensions = sizeAsString.Split('-');
            if (dimensions.Length == 2)
            {
                try
                {
                    var width = Int32.Parse(dimensions[0]);
                    var height = Int32.Parse(dimensions[1]);
                    return new BookmarkingThumbnailSize(width, height);
                }
                catch
                {
                    return new BookmarkingThumbnailSize();
                }
            }
            return new BookmarkingThumbnailSize();
        }
    }
}
